aboutsummaryrefslogtreecommitdiff
path: root/src/func.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/func.c')
-rw-r--r--src/func.c313
1 files changed, 250 insertions, 63 deletions
diff --git a/src/func.c b/src/func.c
index 8fcda11dc..b0a1359b7 100644
--- a/src/func.c
+++ b/src/func.c
@@ -354,16 +354,10 @@ static void substrFunc(
int len;
int p0type;
i64 p1, p2;
- int negP2 = 0;
assert( argc==3 || argc==2 );
- if( sqlite3_value_type(argv[1])==SQLITE_NULL
- || (argc==3 && sqlite3_value_type(argv[2])==SQLITE_NULL)
- ){
- return;
- }
p0type = sqlite3_value_type(argv[0]);
- p1 = sqlite3_value_int(argv[1]);
+ p1 = sqlite3_value_int64(argv[1]);
if( p0type==SQLITE_BLOB ){
len = sqlite3_value_bytes(argv[0]);
z = sqlite3_value_blob(argv[0]);
@@ -379,28 +373,31 @@ static void substrFunc(
}
}
}
-#ifdef SQLITE_SUBSTR_COMPATIBILITY
- /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
- ** as substr(X,1,N) - it returns the first N characters of X. This
- ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
- ** from 2009-02-02 for compatibility of applications that exploited the
- ** old buggy behavior. */
- if( p1==0 ) p1 = 1; /* <rdar://problem/6778339> */
-#endif
if( argc==3 ){
- p2 = sqlite3_value_int(argv[2]);
- if( p2<0 ){
- p2 = -p2;
- negP2 = 1;
- }
+ p2 = sqlite3_value_int64(argv[2]);
+ if( p2==0 && sqlite3_value_type(argv[2])==SQLITE_NULL ) return;
}else{
p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH];
}
+ if( p1==0 ){
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
+ /* If SUBSTR_COMPATIBILITY is defined then substr(X,0,N) work the same as
+ ** as substr(X,1,N) - it returns the first N characters of X. This
+ ** is essentially a back-out of the bug-fix in check-in [5fc125d362df4b8]
+ ** from 2009-02-02 for compatibility of applications that exploited the
+ ** old buggy behavior. */
+ p1 = 1; /* <rdar://problem/6778339> */
+#endif
+ if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return;
+ }
if( p1<0 ){
p1 += len;
if( p1<0 ){
- p2 += p1;
- if( p2<0 ) p2 = 0;
+ if( p2<0 ){
+ p2 = 0;
+ }else{
+ p2 += p1;
+ }
p1 = 0;
}
}else if( p1>0 ){
@@ -408,12 +405,13 @@ static void substrFunc(
}else if( p2>0 ){
p2--;
}
- if( negP2 ){
- p1 -= p2;
- if( p1<0 ){
- p2 += p1;
- p1 = 0;
+ if( p2<0 ){
+ if( p2<-p1 ){
+ p2 = p1;
+ }else{
+ p2 = -p2;
}
+ p1 -= p2;
}
assert( p1>=0 && p2>=0 );
if( p0type!=SQLITE_BLOB ){
@@ -427,9 +425,11 @@ static void substrFunc(
sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT,
SQLITE_UTF8);
}else{
- if( p1+p2>len ){
+ if( p1>=len ){
+ p1 = p2 = 0;
+ }else if( p2>len-p1 ){
p2 = len-p1;
- if( p2<0 ) p2 = 0;
+ assert( p2>0 );
}
sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT);
}
@@ -440,13 +440,13 @@ static void substrFunc(
*/
#ifndef SQLITE_OMIT_FLOATING_POINT
static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
- int n = 0;
+ i64 n = 0;
double r;
char *zBuf;
assert( argc==1 || argc==2 );
if( argc==2 ){
if( SQLITE_NULL==sqlite3_value_type(argv[1]) ) return;
- n = sqlite3_value_int(argv[1]);
+ n = sqlite3_value_int64(argv[1]);
if( n>30 ) n = 30;
if( n<0 ) n = 0;
}
@@ -461,7 +461,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = sqlite3_mprintf("%!.*f",n,r);
+ zBuf = sqlite3_mprintf("%!.*f",(int)n,r);
if( zBuf==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -1090,7 +1090,7 @@ static const char hexdigits[] = {
** Append to pStr text that is the SQL literal representation of the
** value contained in pValue.
*/
-void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
+void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
/* As currently implemented, the string must be initially empty.
** we might relax this requirement in the future, but that will
** require enhancements to the implementation. */
@@ -1138,7 +1138,7 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
}
case SQLITE_TEXT: {
const unsigned char *zArg = sqlite3_value_text(pValue);
- sqlite3_str_appendf(pStr, "%Q", zArg);
+ sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg);
break;
}
default: {
@@ -1150,6 +1150,105 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
}
/*
+** Return true if z[] begins with N hexadecimal digits, and write
+** a decoding of those digits into *pVal. Or return false if any
+** one of the first N characters in z[] is not a hexadecimal digit.
+*/
+static int isNHex(const char *z, int N, u32 *pVal){
+ int i;
+ int v = 0;
+ for(i=0; i<N; i++){
+ if( !sqlite3Isxdigit(z[i]) ) return 0;
+ v = (v<<4) + sqlite3HexToInt(z[i]);
+ }
+ *pVal = v;
+ return 1;
+}
+
+/*
+** Implementation of the UNISTR() function.
+**
+** This is intended to be a work-alike of the UNISTR() function in
+** PostgreSQL. Quoting from the PG documentation (PostgreSQL 17 -
+** scraped on 2025-02-22):
+**
+** Evaluate escaped Unicode characters in the argument. Unicode
+** characters can be specified as \XXXX (4 hexadecimal digits),
+** \+XXXXXX (6 hexadecimal digits), \uXXXX (4 hexadecimal digits),
+** or \UXXXXXXXX (8 hexadecimal digits). To specify a backslash,
+** write two backslashes. All other characters are taken literally.
+*/
+static void unistrFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ char *zOut;
+ const char *zIn;
+ int nIn;
+ int i, j, n;
+ u32 v;
+
+ assert( argc==1 );
+ UNUSED_PARAMETER( argc );
+ zIn = (const char*)sqlite3_value_text(argv[0]);
+ if( zIn==0 ) return;
+ nIn = sqlite3_value_bytes(argv[0]);
+ zOut = sqlite3_malloc64(nIn+1);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ i = j = 0;
+ while( i<nIn ){
+ char *z = strchr(&zIn[i],'\\');
+ if( z==0 ){
+ n = nIn - i;
+ memmove(&zOut[j], &zIn[i], n);
+ j += n;
+ break;
+ }
+ n = z - &zIn[i];
+ if( n>0 ){
+ memmove(&zOut[j], &zIn[i], n);
+ j += n;
+ i += n;
+ }
+ if( zIn[i+1]=='\\' ){
+ i += 2;
+ zOut[j++] = '\\';
+ }else if( sqlite3Isxdigit(zIn[i+1]) ){
+ if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error;
+ i += 5;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='+' ){
+ if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error;
+ i += 8;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='u' ){
+ if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error;
+ i += 6;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else if( zIn[i+1]=='U' ){
+ if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error;
+ i += 10;
+ j += sqlite3AppendOneUtf8Character(&zOut[j], v);
+ }else{
+ goto unistr_error;
+ }
+ }
+ zOut[j] = 0;
+ sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8);
+ return;
+
+unistr_error:
+ sqlite3_free(zOut);
+ sqlite3_result_error(context, "invalid Unicode escape", -1);
+ return;
+}
+
+
+/*
** Implementation of the QUOTE() function.
**
** The quote(X) function returns the text of an SQL literal which is the
@@ -1158,6 +1257,10 @@ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
** as needed. BLOBs are encoded as hexadecimal literals. Strings with
** embedded NUL characters cannot be represented as string literals in SQL
** and hence the returned string literal is truncated prior to the first NUL.
+**
+** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is
+** implemented instead. The difference is that UNISTR_QUOTE() uses the
+** UNISTR() function to escape control characters.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_str str;
@@ -1165,7 +1268,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
assert( argc==1 );
UNUSED_PARAMETER(argc);
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
- sqlite3QuoteValue(&str,argv[0]);
+ sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context)));
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
SQLITE_DYNAMIC);
if( str.accError!=SQLITE_OK ){
@@ -1420,7 +1523,7 @@ static void replaceFunc(
assert( zRep==sqlite3_value_text(argv[2]) );
nOut = nStr + 1;
assert( nOut<SQLITE_MAX_LENGTH );
- zOut = contextMalloc(context, (i64)nOut);
+ zOut = contextMalloc(context, nOut);
if( zOut==0 ){
return;
}
@@ -1564,13 +1667,13 @@ static void concatFuncCore(
int nSep,
const char *zSep
){
- i64 j, k, n = 0;
+ i64 j, n = 0;
int i;
char *z;
for(i=0; i<argc; i++){
n += sqlite3_value_bytes(argv[i]);
}
- n += (argc-1)*nSep;
+ n += (argc-1)*(i64)nSep;
z = sqlite3_malloc64(n+1);
if( z==0 ){
sqlite3_result_error_nomem(context);
@@ -1578,8 +1681,8 @@ static void concatFuncCore(
}
j = 0;
for(i=0; i<argc; i++){
- k = sqlite3_value_bytes(argv[i]);
- if( k>0 ){
+ if( sqlite3_value_type(argv[i])!=SQLITE_NULL ){
+ int k = sqlite3_value_bytes(argv[i]);
const char *v = (const char*)sqlite3_value_text(argv[i]);
if( v!=0 ){
if( j>0 && nSep>0 ){
@@ -1816,7 +1919,7 @@ static void kahanBabuskaNeumaierInit(
** that it returns NULL if it sums over no inputs. TOTAL returns
** 0.0 in that case. In addition, TOTAL always returns a float where
** SUM might return an integer if it never encounters a floating point
-** value. TOTAL never fails, but SUM might through an exception if
+** value. TOTAL never fails, but SUM might throw an exception if
** it overflows an integer.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
@@ -1868,7 +1971,10 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
assert( p->cnt>0 );
p->cnt--;
if( !p->approx ){
- p->iSum -= sqlite3_value_int64(argv[0]);
+ if( sqlite3SubInt64(&p->iSum, sqlite3_value_int64(argv[0])) ){
+ p->ovrfl = 1;
+ p->approx = 1;
+ }
}else if( type==SQLITE_INTEGER ){
i64 iVal = sqlite3_value_int64(argv[0]);
if( iVal!=SMALLEST_INT64 ){
@@ -2049,7 +2155,11 @@ static void minMaxFinalize(sqlite3_context *context){
** group_concat(EXPR, ?SEPARATOR?)
** string_agg(EXPR, SEPARATOR)
**
-** The SEPARATOR goes before the EXPR string. This is tragic. The
+** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
+** coming before the EXPR value, except for the first entry which
+** omits the SEPARATOR.
+**
+** It is tragic that the SEPARATOR goes before the EXPR string. The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR. And the order is undocumented,
** so we could change it, in theory. But the old behavior has been
@@ -2153,7 +2263,7 @@ static void groupConcatInverse(
/* pGCC is always non-NULL since groupConcatStep() will have always
** run first to initialize it */
if( ALWAYS(pGCC) ){
- int nVS;
+ int nVS; /* Number of characters to remove */
/* Must call sqlite3_value_text() to convert the argument into text prior
** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
(void)sqlite3_value_text(argv[0]);
@@ -2531,7 +2641,13 @@ static void signFunc(
** Implementation of fpdecode(x,y,z) function.
**
** x is a real number that is to be decoded. y is the precision.
-** z is the maximum real precision.
+** z is the maximum real precision. Return a string that shows the
+** results of the sqlite3FpDecode() function.
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3FpDecode() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
*/
static void fpdecodeFunc(
sqlite3_context *context,
@@ -2558,6 +2674,82 @@ static void fpdecodeFunc(
}
#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of parseuri(uri,flags) function.
+**
+** Required Arguments:
+** "uri" The URI to parse.
+** "flags" Bitmask of flags, as if to sqlite3_open_v2().
+**
+** Additional arguments beyond the first two make calls to
+** sqlite3_uri_key() for integers and sqlite3_uri_parameter for
+** anything else.
+**
+** The result is a string showing the results of calling sqlite3ParseUri().
+**
+** Used for testing and debugging only, specifically testing and debugging
+** of the sqlite3ParseUri() function. This SQL function does not appear
+** in production builds. This function is not an API and is subject to
+** modification or removal in future versions of SQLite.
+*/
+static void parseuriFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_str *pResult;
+ const char *zVfs;
+ const char *zUri;
+ unsigned int flgs;
+ int rc;
+ sqlite3_vfs *pVfs = 0;
+ char *zFile = 0;
+ char *zErr = 0;
+
+ if( argc<2 ) return;
+ pVfs = sqlite3_vfs_find(0);
+ assert( pVfs );
+ zVfs = pVfs->zName;
+ zUri = (const char*)sqlite3_value_text(argv[0]);
+ if( zUri==0 ) return;
+ flgs = (unsigned int)sqlite3_value_int(argv[1]);
+ rc = sqlite3ParseUri(zVfs, zUri, &flgs, &pVfs, &zFile, &zErr);
+ pResult = sqlite3_str_new(0);
+ if( pResult ){
+ int i;
+ sqlite3_str_appendf(pResult, "rc=%d", rc);
+ sqlite3_str_appendf(pResult, ", flags=0x%x", flgs);
+ sqlite3_str_appendf(pResult, ", vfs=%Q", pVfs ? pVfs->zName: 0);
+ sqlite3_str_appendf(pResult, ", err=%Q", zErr);
+ sqlite3_str_appendf(pResult, ", file=%Q", zFile);
+ if( zFile ){
+ const char *z = zFile;
+ z += sqlite3Strlen30(z)+1;
+ while( z[0] ){
+ sqlite3_str_appendf(pResult, ", %Q", z);
+ z += sqlite3Strlen30(z)+1;
+ }
+ for(i=2; i<argc; i++){
+ const char *zArg;
+ if( sqlite3_value_type(argv[i])==SQLITE_INTEGER ){
+ int k = sqlite3_value_int(argv[i]);
+ sqlite3_str_appendf(pResult, ", '%d:%q'",k,sqlite3_uri_key(zFile, k));
+ }else if( (zArg = (const char*)sqlite3_value_text(argv[i]))!=0 ){
+ sqlite3_str_appendf(pResult, ", '%q:%q'",
+ zArg, sqlite3_uri_parameter(zFile,zArg));
+ }else{
+ sqlite3_str_appendf(pResult, ", NULL");
+ }
+ }
+ }
+ sqlite3_result_text(ctx, sqlite3_str_finish(pResult), -1, sqlite3_free);
+ }
+ sqlite3_free_filename(zFile);
+ sqlite3_free(zErr);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -2592,9 +2784,6 @@ void sqlite3RegisterBuiltinFunctions(void){
SFUNCTION(load_extension, 1, 0, 0, loadExt ),
SFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
-#if SQLITE_USER_AUTHENTICATION
- FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
-#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
@@ -2611,16 +2800,15 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(rtrim, 2, 2, 0, trimFunc ),
FUNCTION(trim, 1, 3, 0, trimFunc ),
FUNCTION(trim, 2, 3, 0, trimFunc ),
- FUNCTION(min, -1, 0, 1, minmaxFunc ),
- FUNCTION(min, 0, 0, 1, 0 ),
+ FUNCTION(min, -3, 0, 1, minmaxFunc ),
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
- FUNCTION(max, -1, 1, 1, minmaxFunc ),
- FUNCTION(max, 0, 1, 1, 0 ),
+ FUNCTION(max, -3, 1, 1, minmaxFunc ),
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
- FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc,
+ SQLITE_FUNC_TYPEOF|SQLITE_SUBTYPE),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
@@ -2631,6 +2819,7 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(abs, 1, 0, 0, absFunc ),
#ifdef SQLITE_DEBUG
FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+ FUNCTION(parseuri, -1, 0, 0, parseuriFunc ),
#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
@@ -2641,11 +2830,8 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
- FUNCTION(concat, -1, 0, 0, concatFunc ),
- FUNCTION(concat, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
- FUNCTION(concat_ws, 0, 0, 0, 0 ),
- FUNCTION(concat_ws, 1, 0, 0, 0 ),
+ FUNCTION(concat, -3, 0, 0, concatFunc ),
+ FUNCTION(concat_ws, -4, 0, 0, concatwsFunc ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -2653,7 +2839,9 @@ void sqlite3RegisterBuiltinFunctions(void){
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
+ FUNCTION(unistr, 1, 0, 0, unistrFunc ),
FUNCTION(quote, 1, 0, 0, quoteFunc ),
+ FUNCTION(unistr_quote, 1, 1, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
@@ -2689,8 +2877,6 @@ void sqlite3RegisterBuiltinFunctions(void){
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
#endif
- FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, 0, 0, 0, 0 ),
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
MFUNCTION(ceil, 1, xCeil, ceilingFunc ),
MFUNCTION(ceiling, 1, xCeil, ceilingFunc ),
@@ -2725,11 +2911,12 @@ void sqlite3RegisterBuiltinFunctions(void){
MFUNCTION(sqrt, 1, sqrt, math1Func ),
MFUNCTION(radians, 1, degToRad, math1Func ),
MFUNCTION(degrees, 1, radToDeg, math1Func ),
- FUNCTION(pi, 0, 0, 0, piFunc ),
+ MFUNCTION(pi, 0, 0, piFunc ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
FUNCTION(sign, 1, 0, 0, signFunc ),
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
- INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(coalesce, -4, INLINEFUNC_coalesce, 0 ),
+ INLINE_FUNC(iif, -4, INLINEFUNC_iif, 0 ),
+ INLINE_FUNC(if, -4, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();