| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "sqliteInt.h" |
| #include <stdlib.h> |
| #include <assert.h> |
| #ifndef SQLITE_OMIT_FLOATING_POINT |
| #include <math.h> |
| #endif |
| #include "vdbeInt.h" |
|
|
| |
| |
| |
| static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){ |
| VdbeOp *pOp; |
| assert( context->pVdbe!=0 ); |
| pOp = &context->pVdbe->aOp[context->iOp-1]; |
| assert( pOp->opcode==OP_CollSeq ); |
| assert( pOp->p4type==P4_COLLSEQ ); |
| return pOp->p4.pColl; |
| } |
|
|
| |
| |
| |
| |
| static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){ |
| assert( context->isError<=0 ); |
| context->isError = -1; |
| context->skipFlag = 1; |
| } |
|
|
| |
| |
| |
| static void minmaxFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int i; |
| int mask; |
| int iBest; |
| CollSeq *pColl; |
|
|
| assert( argc>1 ); |
| mask = sqlite3_user_data(context)==0 ? 0 : -1; |
| pColl = sqlite3GetFuncCollSeq(context); |
| assert( pColl ); |
| assert( mask==-1 || mask==0 ); |
| iBest = 0; |
| if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| for(i=1; i<argc; i++){ |
| if( sqlite3_value_type(argv[i])==SQLITE_NULL ) return; |
| if( (sqlite3MemCompare(argv[iBest], argv[i], pColl)^mask)>=0 ){ |
| testcase( mask==0 ); |
| iBest = i; |
| } |
| } |
| sqlite3_result_value(context, argv[iBest]); |
| } |
|
|
| |
| |
| |
| static void typeofFunc( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **argv |
| ){ |
| static const char *azType[] = { "integer", "real", "text", "blob", "null" }; |
| int i = sqlite3_value_type(argv[0]) - 1; |
| UNUSED_PARAMETER(NotUsed); |
| assert( i>=0 && i<ArraySize(azType) ); |
| assert( SQLITE_INTEGER==1 ); |
| assert( SQLITE_FLOAT==2 ); |
| assert( SQLITE_TEXT==3 ); |
| assert( SQLITE_BLOB==4 ); |
| assert( SQLITE_NULL==5 ); |
| |
| |
| |
| |
| sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC); |
| } |
|
|
| |
| |
| |
| |
| static void subtypeFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| UNUSED_PARAMETER(argc); |
| sqlite3_result_int(context, sqlite3_value_subtype(argv[0])); |
| } |
|
|
| |
| |
| |
| static void lengthFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| switch( sqlite3_value_type(argv[0]) ){ |
| case SQLITE_BLOB: |
| case SQLITE_INTEGER: |
| case SQLITE_FLOAT: { |
| sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); |
| break; |
| } |
| case SQLITE_TEXT: { |
| const unsigned char *z = sqlite3_value_text(argv[0]); |
| const unsigned char *z0; |
| unsigned char c; |
| if( z==0 ) return; |
| z0 = z; |
| while( (c = *z)!=0 ){ |
| z++; |
| if( c>=0xc0 ){ |
| while( (*z & 0xc0)==0x80 ){ z++; z0++; } |
| } |
| } |
| sqlite3_result_int(context, (int)(z-z0)); |
| break; |
| } |
| default: { |
| sqlite3_result_null(context); |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| static void bytelengthFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| switch( sqlite3_value_type(argv[0]) ){ |
| case SQLITE_BLOB: { |
| sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); |
| break; |
| } |
| case SQLITE_INTEGER: |
| case SQLITE_FLOAT: { |
| i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2; |
| sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m); |
| break; |
| } |
| case SQLITE_TEXT: { |
| if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){ |
| sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); |
| }else{ |
| sqlite3_result_int(context, sqlite3_value_bytes16(argv[0])); |
| } |
| break; |
| } |
| default: { |
| sqlite3_result_null(context); |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| switch( sqlite3_value_type(argv[0]) ){ |
| case SQLITE_INTEGER: { |
| i64 iVal = sqlite3_value_int64(argv[0]); |
| if( iVal<0 ){ |
| if( iVal==SMALLEST_INT64 ){ |
| |
| |
| |
| sqlite3_result_error(context, "integer overflow", -1); |
| return; |
| } |
| iVal = -iVal; |
| } |
| sqlite3_result_int64(context, iVal); |
| break; |
| } |
| case SQLITE_NULL: { |
| |
| sqlite3_result_null(context); |
| break; |
| } |
| default: { |
| |
| |
| |
| |
| |
| double rVal = sqlite3_value_double(argv[0]); |
| if( rVal<0 ) rVal = -rVal; |
| sqlite3_result_double(context, rVal); |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void instrFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *zHaystack; |
| const unsigned char *zNeedle; |
| int nHaystack; |
| int nNeedle; |
| int typeHaystack, typeNeedle; |
| int N = 1; |
| int isText; |
| unsigned char firstChar; |
| sqlite3_value *pC1 = 0; |
| sqlite3_value *pC2 = 0; |
|
|
| UNUSED_PARAMETER(argc); |
| typeHaystack = sqlite3_value_type(argv[0]); |
| typeNeedle = sqlite3_value_type(argv[1]); |
| if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; |
| nHaystack = sqlite3_value_bytes(argv[0]); |
| nNeedle = sqlite3_value_bytes(argv[1]); |
| if( nNeedle>0 ){ |
| if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ |
| zHaystack = sqlite3_value_blob(argv[0]); |
| zNeedle = sqlite3_value_blob(argv[1]); |
| isText = 0; |
| }else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){ |
| zHaystack = sqlite3_value_text(argv[0]); |
| zNeedle = sqlite3_value_text(argv[1]); |
| isText = 1; |
| }else{ |
| pC1 = sqlite3_value_dup(argv[0]); |
| zHaystack = sqlite3_value_text(pC1); |
| if( zHaystack==0 ) goto endInstrOOM; |
| nHaystack = sqlite3_value_bytes(pC1); |
| pC2 = sqlite3_value_dup(argv[1]); |
| zNeedle = sqlite3_value_text(pC2); |
| if( zNeedle==0 ) goto endInstrOOM; |
| nNeedle = sqlite3_value_bytes(pC2); |
| isText = 1; |
| } |
| if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM; |
| firstChar = zNeedle[0]; |
| while( nNeedle<=nHaystack |
| && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0) |
| ){ |
| N++; |
| do{ |
| nHaystack--; |
| zHaystack++; |
| }while( isText && (zHaystack[0]&0xc0)==0x80 ); |
| } |
| if( nNeedle>nHaystack ) N = 0; |
| } |
| sqlite3_result_int(context, N); |
| endInstr: |
| sqlite3_value_free(pC1); |
| sqlite3_value_free(pC2); |
| return; |
| endInstrOOM: |
| sqlite3_result_error_nomem(context); |
| goto endInstr; |
| } |
|
|
| |
| |
| |
| static void printfFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| PrintfArguments x; |
| StrAccum str; |
| const char *zFormat; |
| int n; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
|
|
| if( argc>=1 && (zFormat = (const char*)sqlite3_value_text(argv[0]))!=0 ){ |
| x.nArg = argc-1; |
| x.nUsed = 0; |
| x.apArg = argv+1; |
| sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); |
| str.printfFlags = SQLITE_PRINTF_SQLFUNC; |
| sqlite3_str_appendf(&str, zFormat, &x); |
| n = str.nChar; |
| sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, |
| SQLITE_DYNAMIC); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void substrFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *z; |
| const unsigned char *z2; |
| int len; |
| int p0type; |
| i64 p1, p2; |
|
|
| assert( argc==3 || argc==2 ); |
| p0type = sqlite3_value_type(argv[0]); |
| p1 = sqlite3_value_int64(argv[1]); |
| if( p0type==SQLITE_BLOB ){ |
| len = sqlite3_value_bytes(argv[0]); |
| z = sqlite3_value_blob(argv[0]); |
| if( z==0 ) return; |
| assert( len==sqlite3_value_bytes(argv[0]) ); |
| }else{ |
| z = sqlite3_value_text(argv[0]); |
| if( z==0 ) return; |
| len = 0; |
| if( p1<0 ){ |
| for(z2=z; *z2; len++){ |
| SQLITE_SKIP_UTF8(z2); |
| } |
| } |
| } |
| if( argc==3 ){ |
| 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 |
| |
| |
| |
| |
| |
| p1 = 1; |
| #endif |
| if( sqlite3_value_type(argv[1])==SQLITE_NULL ) return; |
| } |
| if( p1<0 ){ |
| p1 += len; |
| if( p1<0 ){ |
| if( p2<0 ){ |
| p2 = 0; |
| }else{ |
| p2 += p1; |
| } |
| p1 = 0; |
| } |
| }else if( p1>0 ){ |
| p1--; |
| }else if( p2>0 ){ |
| p2--; |
| } |
| if( p2<0 ){ |
| if( p2<-p1 ){ |
| p2 = p1; |
| }else{ |
| p2 = -p2; |
| } |
| p1 -= p2; |
| } |
| assert( p1>=0 && p2>=0 ); |
| if( p0type!=SQLITE_BLOB ){ |
| while( *z && p1 ){ |
| SQLITE_SKIP_UTF8(z); |
| p1--; |
| } |
| for(z2=z; *z2 && p2; p2--){ |
| SQLITE_SKIP_UTF8(z2); |
| } |
| sqlite3_result_text64(context, (char*)z, z2-z, SQLITE_TRANSIENT, |
| SQLITE_UTF8); |
| }else{ |
| if( p1>=len ){ |
| p1 = p2 = 0; |
| }else if( p2>len-p1 ){ |
| p2 = len-p1; |
| assert( p2>0 ); |
| } |
| sqlite3_result_blob64(context, (char*)&z[p1], (u64)p2, SQLITE_TRANSIENT); |
| } |
| } |
|
|
| |
| |
| |
| #ifndef SQLITE_OMIT_FLOATING_POINT |
| static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| 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_int64(argv[1]); |
| if( n>30 ) n = 30; |
| if( n<0 ) n = 0; |
| } |
| if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| r = sqlite3_value_double(argv[0]); |
| |
| |
| |
| |
| if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ |
| |
| }else if( n==0 ){ |
| r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); |
| }else{ |
| zBuf = sqlite3_mprintf("%!.*f",(int)n,r); |
| if( zBuf==0 ){ |
| sqlite3_result_error_nomem(context); |
| return; |
| } |
| sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); |
| sqlite3_free(zBuf); |
| } |
| sqlite3_result_double(context, r); |
| } |
| #endif |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void *contextMalloc(sqlite3_context *context, i64 nByte){ |
| char *z; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| assert( nByte>0 ); |
| testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] ); |
| testcase( nByte==(i64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); |
| if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
| sqlite3_result_error_toobig(context); |
| z = 0; |
| }else{ |
| z = sqlite3Malloc(nByte); |
| if( !z ){ |
| sqlite3_result_error_nomem(context); |
| } |
| } |
| return z; |
| } |
|
|
| |
| |
| |
| static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| char *z1; |
| const char *z2; |
| int i, n; |
| UNUSED_PARAMETER(argc); |
| z2 = (char*)sqlite3_value_text(argv[0]); |
| n = sqlite3_value_bytes(argv[0]); |
| |
| assert( z2==(char*)sqlite3_value_text(argv[0]) ); |
| if( z2 ){ |
| z1 = contextMalloc(context, ((i64)n)+1); |
| if( z1 ){ |
| for(i=0; i<n; i++){ |
| z1[i] = (char)sqlite3Toupper(z2[i]); |
| } |
| sqlite3_result_text(context, z1, n, sqlite3_free); |
| } |
| } |
| } |
| static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| char *z1; |
| const char *z2; |
| int i, n; |
| UNUSED_PARAMETER(argc); |
| z2 = (char*)sqlite3_value_text(argv[0]); |
| n = sqlite3_value_bytes(argv[0]); |
| |
| assert( z2==(char*)sqlite3_value_text(argv[0]) ); |
| if( z2 ){ |
| z1 = contextMalloc(context, ((i64)n)+1); |
| if( z1 ){ |
| for(i=0; i<n; i++){ |
| z1[i] = sqlite3Tolower(z2[i]); |
| } |
| sqlite3_result_text(context, z1, n, sqlite3_free); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| #define noopFunc versionFunc |
|
|
| |
| |
| |
| static void randomFunc( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| sqlite_int64 r; |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| sqlite3_randomness(sizeof(r), &r); |
| if( r<0 ){ |
| |
| |
| |
| |
| |
| |
| |
| |
| r = -(r & LARGEST_INT64); |
| } |
| sqlite3_result_int64(context, r); |
| } |
|
|
| |
| |
| |
| |
| static void randomBlob( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| sqlite3_int64 n; |
| unsigned char *p; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| n = sqlite3_value_int64(argv[0]); |
| if( n<1 ){ |
| n = 1; |
| } |
| p = contextMalloc(context, n); |
| if( p ){ |
| sqlite3_randomness(n, p); |
| sqlite3_result_blob(context, (char*)p, n, sqlite3_free); |
| } |
| } |
|
|
| |
| |
| |
| |
| static void last_insert_rowid( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| |
| |
| |
| sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void changes( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| sqlite3_result_int64(context, sqlite3_changes64(db)); |
| } |
|
|
| |
| |
| |
| |
| static void total_changes( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| |
| |
| sqlite3_result_int64(context, sqlite3_total_changes64(db)); |
| } |
|
|
| |
| |
| |
| struct compareInfo { |
| u8 matchAll; |
| u8 matchOne; |
| u8 matchSet; |
| u8 noCase; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| #if defined(SQLITE_EBCDIC) |
| # define sqlite3Utf8Read(A) (*((*A)++)) |
| # define Utf8Read(A) (*(A++)) |
| #else |
| # define Utf8Read(A) (A[0]<0x80?*(A++):sqlite3Utf8Read(&A)) |
| #endif |
|
|
| static const struct compareInfo globInfo = { '*', '?', '[', 0 }; |
| |
| |
| static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; |
| |
| |
| static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; |
|
|
| |
| |
| |
| #define SQLITE_MATCH 0 |
| #define SQLITE_NOMATCH 1 |
| #define SQLITE_NOWILDCARDMATCH 2 |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int patternCompare( |
| const u8 *zPattern, |
| const u8 *zString, |
| const struct compareInfo *pInfo, |
| u32 matchOther |
| ){ |
| u32 c, c2; |
| u32 matchOne = pInfo->matchOne; |
| u32 matchAll = pInfo->matchAll; |
| u8 noCase = pInfo->noCase; |
| const u8 *zEscaped = 0; |
| |
| while( (c = Utf8Read(zPattern))!=0 ){ |
| if( c==matchAll ){ |
| |
| |
| |
| while( (c=Utf8Read(zPattern)) == matchAll |
| || (c == matchOne && matchOne!=0) ){ |
| if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ |
| return SQLITE_NOWILDCARDMATCH; |
| } |
| } |
| if( c==0 ){ |
| return SQLITE_MATCH; |
| }else if( c==matchOther ){ |
| if( pInfo->matchSet==0 ){ |
| c = sqlite3Utf8Read(&zPattern); |
| if( c==0 ) return SQLITE_NOWILDCARDMATCH; |
| }else{ |
| |
| |
| assert( matchOther<0x80 ); |
| while( *zString ){ |
| int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther); |
| if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
| SQLITE_SKIP_UTF8(zString); |
| } |
| return SQLITE_NOWILDCARDMATCH; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if( c<0x80 ){ |
| char zStop[3]; |
| int bMatch; |
| if( noCase ){ |
| zStop[0] = sqlite3Toupper(c); |
| zStop[1] = sqlite3Tolower(c); |
| zStop[2] = 0; |
| }else{ |
| zStop[0] = c; |
| zStop[1] = 0; |
| } |
| while(1){ |
| zString += strcspn((const char*)zString, zStop); |
| if( zString[0]==0 ) break; |
| zString++; |
| bMatch = patternCompare(zPattern,zString,pInfo,matchOther); |
| if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
| } |
| }else{ |
| int bMatch; |
| while( (c2 = Utf8Read(zString))!=0 ){ |
| if( c2!=c ) continue; |
| bMatch = patternCompare(zPattern,zString,pInfo,matchOther); |
| if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
| } |
| } |
| return SQLITE_NOWILDCARDMATCH; |
| } |
| if( c==matchOther ){ |
| if( pInfo->matchSet==0 ){ |
| c = sqlite3Utf8Read(&zPattern); |
| if( c==0 ) return SQLITE_NOMATCH; |
| zEscaped = zPattern; |
| }else{ |
| u32 prior_c = 0; |
| int seen = 0; |
| int invert = 0; |
| c = sqlite3Utf8Read(&zString); |
| if( c==0 ) return SQLITE_NOMATCH; |
| c2 = sqlite3Utf8Read(&zPattern); |
| if( c2=='^' ){ |
| invert = 1; |
| c2 = sqlite3Utf8Read(&zPattern); |
| } |
| if( c2==']' ){ |
| if( c==']' ) seen = 1; |
| c2 = sqlite3Utf8Read(&zPattern); |
| } |
| while( c2 && c2!=']' ){ |
| if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ |
| c2 = sqlite3Utf8Read(&zPattern); |
| if( c>=prior_c && c<=c2 ) seen = 1; |
| prior_c = 0; |
| }else{ |
| if( c==c2 ){ |
| seen = 1; |
| } |
| prior_c = c2; |
| } |
| c2 = sqlite3Utf8Read(&zPattern); |
| } |
| if( c2==0 || (seen ^ invert)==0 ){ |
| return SQLITE_NOMATCH; |
| } |
| continue; |
| } |
| } |
| c2 = Utf8Read(zString); |
| if( c==c2 ) continue; |
| if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ |
| continue; |
| } |
| if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; |
| return SQLITE_NOMATCH; |
| } |
| return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH; |
| } |
|
|
| |
| |
| |
| |
| int sqlite3_strglob(const char *zGlobPattern, const char *zString){ |
| if( zString==0 ){ |
| return zGlobPattern!=0; |
| }else if( zGlobPattern==0 ){ |
| return 1; |
| }else { |
| return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); |
| } |
| } |
|
|
| |
| |
| |
| |
| int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ |
| if( zStr==0 ){ |
| return zPattern!=0; |
| }else if( zPattern==0 ){ |
| return 1; |
| }else{ |
| return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| #ifdef SQLITE_TEST |
| int sqlite3_like_count = 0; |
| #endif |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void likeFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *zA, *zB; |
| u32 escape; |
| int nPat; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| struct compareInfo *pInfo = sqlite3_user_data(context); |
| struct compareInfo backupInfo; |
|
|
| #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
| if( sqlite3_value_type(argv[0])==SQLITE_BLOB |
| || sqlite3_value_type(argv[1])==SQLITE_BLOB |
| ){ |
| #ifdef SQLITE_TEST |
| sqlite3_like_count++; |
| #endif |
| sqlite3_result_int(context, 0); |
| return; |
| } |
| #endif |
|
|
| |
| |
| |
| nPat = sqlite3_value_bytes(argv[0]); |
| testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ); |
| testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 ); |
| if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){ |
| sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); |
| return; |
| } |
| if( argc==3 ){ |
| |
| |
| |
| const unsigned char *zEsc = sqlite3_value_text(argv[2]); |
| if( zEsc==0 ) return; |
| if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ |
| sqlite3_result_error(context, |
| "ESCAPE expression must be a single character", -1); |
| return; |
| } |
| escape = sqlite3Utf8Read(&zEsc); |
| if( escape==pInfo->matchAll || escape==pInfo->matchOne ){ |
| memcpy(&backupInfo, pInfo, sizeof(backupInfo)); |
| pInfo = &backupInfo; |
| if( escape==pInfo->matchAll ) pInfo->matchAll = 0; |
| if( escape==pInfo->matchOne ) pInfo->matchOne = 0; |
| } |
| }else{ |
| escape = pInfo->matchSet; |
| } |
| zB = sqlite3_value_text(argv[0]); |
| zA = sqlite3_value_text(argv[1]); |
| if( zA && zB ){ |
| #ifdef SQLITE_TEST |
| sqlite3_like_count++; |
| #endif |
| sqlite3_result_int(context, |
| patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| static void nullifFunc( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **argv |
| ){ |
| CollSeq *pColl = sqlite3GetFuncCollSeq(context); |
| UNUSED_PARAMETER(NotUsed); |
| if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ |
| sqlite3_result_value(context, argv[0]); |
| } |
| } |
|
|
| |
| |
| |
| |
| static void versionFunc( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| |
| |
| sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC); |
| } |
|
|
| |
| |
| |
| |
| |
| static void sourceidFunc( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **NotUsed2 |
| ){ |
| UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| |
| |
| sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); |
| } |
|
|
| |
| |
| |
| |
| |
| static void errlogFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| UNUSED_PARAMETER(argc); |
| UNUSED_PARAMETER(context); |
| sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); |
| } |
|
|
| |
| |
| |
| |
| |
| #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| static void compileoptionusedFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const char *zOptName; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| |
| |
| |
| |
| if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){ |
| sqlite3_result_int(context, sqlite3_compileoption_used(zOptName)); |
| } |
| } |
| #endif |
|
|
| |
| |
| |
| |
| |
| #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| static void compileoptiongetFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int n; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| |
| |
| |
| n = sqlite3_value_int(argv[0]); |
| sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC); |
| } |
| #endif |
|
|
| |
| |
| static const char hexdigits[] = { |
| '0', '1', '2', '3', '4', '5', '6', '7', |
| '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' |
| }; |
|
|
| |
| |
| |
| |
| void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){ |
| |
| |
| |
| assert( pStr!=0 && pStr->nChar==0 ); |
|
|
| switch( sqlite3_value_type(pValue) ){ |
| case SQLITE_FLOAT: { |
| double r1, r2; |
| const char *zVal; |
| r1 = sqlite3_value_double(pValue); |
| sqlite3_str_appendf(pStr, "%!0.15g", r1); |
| zVal = sqlite3_str_value(pStr); |
| if( zVal ){ |
| sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); |
| if( r1!=r2 ){ |
| sqlite3_str_reset(pStr); |
| sqlite3_str_appendf(pStr, "%!0.20e", r1); |
| } |
| } |
| break; |
| } |
| case SQLITE_INTEGER: { |
| sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue)); |
| break; |
| } |
| case SQLITE_BLOB: { |
| char const *zBlob = sqlite3_value_blob(pValue); |
| i64 nBlob = sqlite3_value_bytes(pValue); |
| assert( zBlob==sqlite3_value_blob(pValue) ); |
| sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4); |
| if( pStr->accError==0 ){ |
| char *zText = pStr->zText; |
| int i; |
| for(i=0; i<nBlob; i++){ |
| zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; |
| zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F]; |
| } |
| zText[(nBlob*2)+2] = '\''; |
| zText[(nBlob*2)+3] = '\0'; |
| zText[0] = 'X'; |
| zText[1] = '\''; |
| pStr->nChar = nBlob*2 + 3; |
| } |
| break; |
| } |
| case SQLITE_TEXT: { |
| const unsigned char *zArg = sqlite3_value_text(pValue); |
| sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg); |
| break; |
| } |
| default: { |
| assert( sqlite3_value_type(pValue)==SQLITE_NULL ); |
| sqlite3_str_append(pStr, "NULL", 4); |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| static int isNHex(const char *z, int N, u32 *pVal){ |
| int i; |
| u32 v = 0; |
| for(i=0; i<N; i++){ |
| if( !sqlite3Isxdigit(z[i]) ) return 0; |
| v = (v<<4) + sqlite3HexToInt(z[i]); |
| } |
| *pVal = v; |
| return 1; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| sqlite3_str str; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); |
| 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 ){ |
| sqlite3_result_null(context); |
| sqlite3_result_error_code(context, str.accError); |
| } |
| } |
|
|
| |
| |
| |
| |
| static void unicodeFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *z = sqlite3_value_text(argv[0]); |
| (void)argc; |
| if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z)); |
| } |
|
|
| |
| |
| |
| |
| |
| static void charFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| unsigned char *z, *zOut; |
| int i; |
| zOut = z = sqlite3_malloc64( argc*4+1 ); |
| if( z==0 ){ |
| sqlite3_result_error_nomem(context); |
| return; |
| } |
| for(i=0; i<argc; i++){ |
| sqlite3_int64 x; |
| unsigned c; |
| x = sqlite3_value_int64(argv[i]); |
| if( x<0 || x>0x10ffff ) x = 0xfffd; |
| c = (unsigned)(x & 0x1fffff); |
| if( c<0x00080 ){ |
| *zOut++ = (u8)(c&0xFF); |
| }else if( c<0x00800 ){ |
| *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); |
| *zOut++ = 0x80 + (u8)(c & 0x3F); |
| }else if( c<0x10000 ){ |
| *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); |
| *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); |
| *zOut++ = 0x80 + (u8)(c & 0x3F); |
| }else{ |
| *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); |
| *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); |
| *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); |
| *zOut++ = 0x80 + (u8)(c & 0x3F); |
| } \ |
| } |
| *zOut = 0; |
| sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8); |
| } |
|
|
| |
| |
| |
| |
| static void hexFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int i, n; |
| const unsigned char *pBlob; |
| char *zHex, *z; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| pBlob = sqlite3_value_blob(argv[0]); |
| n = sqlite3_value_bytes(argv[0]); |
| assert( pBlob==sqlite3_value_blob(argv[0]) ); |
| z = zHex = contextMalloc(context, ((i64)n)*2 + 1); |
| if( zHex ){ |
| for(i=0; i<n; i++, pBlob++){ |
| unsigned char c = *pBlob; |
| *(z++) = hexdigits[(c>>4)&0xf]; |
| *(z++) = hexdigits[c&0xf]; |
| } |
| *z = 0; |
| sqlite3_result_text64(context, zHex, (u64)(z-zHex), |
| sqlite3_free, SQLITE_UTF8); |
| } |
| } |
|
|
| |
| |
| |
| |
| static int strContainsChar(const u8 *zStr, int nStr, u32 ch){ |
| const u8 *zEnd = &zStr[nStr]; |
| const u8 *z = zStr; |
| while( z<zEnd ){ |
| u32 tst = Utf8Read(z); |
| if( tst==ch ) return 1; |
| } |
| return 0; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void unhexFunc( |
| sqlite3_context *pCtx, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const u8 *zPass = (const u8*)""; |
| int nPass = 0; |
| const u8 *zHex = sqlite3_value_text(argv[0]); |
| int nHex = sqlite3_value_bytes(argv[0]); |
| #ifdef SQLITE_DEBUG |
| const u8 *zEnd = zHex ? &zHex[nHex] : 0; |
| #endif |
| u8 *pBlob = 0; |
| u8 *p = 0; |
|
|
| assert( argc==1 || argc==2 ); |
| if( argc==2 ){ |
| zPass = sqlite3_value_text(argv[1]); |
| nPass = sqlite3_value_bytes(argv[1]); |
| } |
| if( !zHex || !zPass ) return; |
|
|
| p = pBlob = contextMalloc(pCtx, (nHex/2)+1); |
| if( pBlob ){ |
| u8 c; |
| u8 d; |
|
|
| while( (c = *zHex)!=0x00 ){ |
| while( !sqlite3Isxdigit(c) ){ |
| u32 ch = Utf8Read(zHex); |
| assert( zHex<=zEnd ); |
| if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null; |
| c = *zHex; |
| if( c==0x00 ) goto unhex_done; |
| } |
| zHex++; |
| assert( *zEnd==0x00 ); |
| assert( zHex<=zEnd ); |
| d = *(zHex++); |
| if( !sqlite3Isxdigit(d) ) goto unhex_null; |
| *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d); |
| } |
| } |
|
|
| unhex_done: |
| sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free); |
| return; |
|
|
| unhex_null: |
| sqlite3_free(pBlob); |
| return; |
| } |
|
|
|
|
| |
| |
| |
| static void zeroblobFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| i64 n; |
| int rc; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| n = sqlite3_value_int64(argv[0]); |
| if( n<0 ) n = 0; |
| rc = sqlite3_result_zeroblob64(context, n); |
| if( rc ){ |
| sqlite3_result_error_code(context, rc); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static void replaceFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *zStr; |
| const unsigned char *zPattern; |
| const unsigned char *zRep; |
| unsigned char *zOut; |
| int nStr; |
| int nPattern; |
| int nRep; |
| i64 nOut; |
| int loopLimit; |
| int i, j; |
| unsigned cntExpand; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
|
|
| assert( argc==3 ); |
| UNUSED_PARAMETER(argc); |
| zStr = sqlite3_value_text(argv[0]); |
| if( zStr==0 ) return; |
| nStr = sqlite3_value_bytes(argv[0]); |
| assert( zStr==sqlite3_value_text(argv[0]) ); |
| zPattern = sqlite3_value_text(argv[1]); |
| if( zPattern==0 ){ |
| assert( sqlite3_value_type(argv[1])==SQLITE_NULL |
| || sqlite3_context_db_handle(context)->mallocFailed ); |
| return; |
| } |
| if( zPattern[0]==0 ){ |
| assert( sqlite3_value_type(argv[1])!=SQLITE_NULL ); |
| sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT); |
| return; |
| } |
| nPattern = sqlite3_value_bytes(argv[1]); |
| assert( zPattern==sqlite3_value_text(argv[1]) ); |
| zRep = sqlite3_value_text(argv[2]); |
| if( zRep==0 ) return; |
| nRep = sqlite3_value_bytes(argv[2]); |
| assert( zRep==sqlite3_value_text(argv[2]) ); |
| nOut = nStr + 1; |
| assert( nOut<SQLITE_MAX_LENGTH ); |
| zOut = contextMalloc(context, nOut); |
| if( zOut==0 ){ |
| return; |
| } |
| loopLimit = nStr - nPattern; |
| cntExpand = 0; |
| for(i=j=0; i<=loopLimit; i++){ |
| if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ |
| zOut[j++] = zStr[i]; |
| }else{ |
| if( nRep>nPattern ){ |
| nOut += nRep - nPattern; |
| testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] ); |
| testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); |
| if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ |
| sqlite3_result_error_toobig(context); |
| sqlite3_free(zOut); |
| return; |
| } |
| cntExpand++; |
| if( (cntExpand&(cntExpand-1))==0 ){ |
| |
| |
| u8 *zOld; |
| zOld = zOut; |
| zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1)); |
| if( zOut==0 ){ |
| sqlite3_result_error_nomem(context); |
| sqlite3_free(zOld); |
| return; |
| } |
| } |
| } |
| memcpy(&zOut[j], zRep, nRep); |
| j += nRep; |
| i += nPattern-1; |
| } |
| } |
| assert( j+nStr-i+1<=nOut ); |
| memcpy(&zOut[j], &zStr[i], nStr-i); |
| j += nStr - i; |
| assert( j<=nOut ); |
| zOut[j] = 0; |
| sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); |
| } |
|
|
| |
| |
| |
| |
| static void trimFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const unsigned char *zIn; |
| const unsigned char *zCharSet; |
| unsigned int nIn; |
| int flags; |
| int i; |
| unsigned int *aLen = 0; |
| unsigned char **azChar = 0; |
| int nChar; |
|
|
| if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ |
| return; |
| } |
| zIn = sqlite3_value_text(argv[0]); |
| if( zIn==0 ) return; |
| nIn = (unsigned)sqlite3_value_bytes(argv[0]); |
| assert( zIn==sqlite3_value_text(argv[0]) ); |
| if( argc==1 ){ |
| static const unsigned lenOne[] = { 1 }; |
| static unsigned char * const azOne[] = { (u8*)" " }; |
| nChar = 1; |
| aLen = (unsigned*)lenOne; |
| azChar = (unsigned char **)azOne; |
| zCharSet = 0; |
| }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ |
| return; |
| }else{ |
| const unsigned char *z; |
| for(z=zCharSet, nChar=0; *z; nChar++){ |
| SQLITE_SKIP_UTF8(z); |
| } |
| if( nChar>0 ){ |
| azChar = contextMalloc(context, |
| ((i64)nChar)*(sizeof(char*)+sizeof(unsigned))); |
| if( azChar==0 ){ |
| return; |
| } |
| aLen = (unsigned*)&azChar[nChar]; |
| for(z=zCharSet, nChar=0; *z; nChar++){ |
| azChar[nChar] = (unsigned char *)z; |
| SQLITE_SKIP_UTF8(z); |
| aLen[nChar] = (unsigned)(z - azChar[nChar]); |
| } |
| } |
| } |
| if( nChar>0 ){ |
| flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); |
| if( flags & 1 ){ |
| while( nIn>0 ){ |
| unsigned int len = 0; |
| for(i=0; i<nChar; i++){ |
| len = aLen[i]; |
| if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break; |
| } |
| if( i>=nChar ) break; |
| zIn += len; |
| nIn -= len; |
| } |
| } |
| if( flags & 2 ){ |
| while( nIn>0 ){ |
| unsigned int len = 0; |
| for(i=0; i<nChar; i++){ |
| len = aLen[i]; |
| if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break; |
| } |
| if( i>=nChar ) break; |
| nIn -= len; |
| } |
| } |
| if( zCharSet ){ |
| sqlite3_free(azChar); |
| } |
| } |
| sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static void concatFuncCore( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv, |
| int nSep, |
| const char *zSep |
| ){ |
| i64 j, n = 0; |
| int i; |
| int bNotNull = 0; |
| char *z; |
| for(i=0; i<argc; i++){ |
| n += sqlite3_value_bytes(argv[i]); |
| } |
| n += (argc-1)*(i64)nSep; |
| z = sqlite3_malloc64(n+1); |
| if( z==0 ){ |
| sqlite3_result_error_nomem(context); |
| return; |
| } |
| j = 0; |
| for(i=0; i<argc; i++){ |
| 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( bNotNull && nSep>0 ){ |
| memcpy(&z[j], zSep, nSep); |
| j += nSep; |
| } |
| memcpy(&z[j], v, k); |
| j += k; |
| bNotNull = 1; |
| } |
| } |
| } |
| z[j] = 0; |
| assert( j<=n ); |
| sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8); |
| } |
|
|
| |
| |
| |
| |
| static void concatFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| concatFuncCore(context, argc, argv, 0, ""); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void concatwsFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int nSep = sqlite3_value_bytes(argv[0]); |
| const char *zSep = (const char*)sqlite3_value_text(argv[0]); |
| if( zSep==0 ) return; |
| concatFuncCore(context, argc-1, argv+1, nSep, zSep); |
| } |
|
|
|
|
| #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void unknownFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| |
| (void)context; |
| (void)argc; |
| (void)argv; |
| } |
| #endif |
|
|
|
|
| |
| |
| |
| |
| #ifdef SQLITE_SOUNDEX |
| |
| |
| |
| |
| |
| |
| static void soundexFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| char zResult[8]; |
| const u8 *zIn; |
| int i, j; |
| static const unsigned char iCode[] = { |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, |
| 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, |
| 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, |
| 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, |
| }; |
| assert( argc==1 ); |
| zIn = (u8*)sqlite3_value_text(argv[0]); |
| if( zIn==0 ) zIn = (u8*)""; |
| for(i=0; zIn[i] && !sqlite3Isalpha(zIn[i]); i++){} |
| if( zIn[i] ){ |
| u8 prevcode = iCode[zIn[i]&0x7f]; |
| zResult[0] = sqlite3Toupper(zIn[i]); |
| for(j=1; j<4 && zIn[i]; i++){ |
| int code = iCode[zIn[i]&0x7f]; |
| if( code>0 ){ |
| if( code!=prevcode ){ |
| prevcode = code; |
| zResult[j++] = code + '0'; |
| } |
| }else{ |
| prevcode = 0; |
| } |
| } |
| while( j<4 ){ |
| zResult[j++] = '0'; |
| } |
| zResult[j] = 0; |
| sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT); |
| }else{ |
| |
| |
| sqlite3_result_text(context, "?000", 4, SQLITE_STATIC); |
| } |
| } |
| #endif |
|
|
| #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| |
| |
| |
| static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| const char *zFile = (const char *)sqlite3_value_text(argv[0]); |
| const char *zProc; |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| char *zErrMsg = 0; |
|
|
| |
| |
| |
| if( (db->flags & SQLITE_LoadExtFunc)==0 ){ |
| sqlite3_result_error(context, "not authorized", -1); |
| return; |
| } |
|
|
| if( argc==2 ){ |
| zProc = (const char *)sqlite3_value_text(argv[1]); |
| }else{ |
| zProc = 0; |
| } |
| if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){ |
| sqlite3_result_error(context, zErrMsg, -1); |
| sqlite3_free(zErrMsg); |
| } |
| } |
| #endif |
|
|
|
|
| |
| |
| |
| |
| typedef struct SumCtx SumCtx; |
| struct SumCtx { |
| double rSum; |
| double rErr; |
| i64 iSum; |
| i64 cnt; |
| u8 approx; |
| u8 ovrfl; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static void kahanBabuskaNeumaierStep( |
| volatile SumCtx *pSum, |
| volatile double r |
| ){ |
| volatile double s = pSum->rSum; |
| volatile double t = s + r; |
| if( fabs(s) > fabs(r) ){ |
| pSum->rErr += (s - t) + r; |
| }else{ |
| pSum->rErr += (r - t) + s; |
| } |
| pSum->rSum = t; |
| } |
|
|
| |
| |
| |
| static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){ |
| if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){ |
| i64 iBig, iSm; |
| iSm = iVal % 16384; |
| iBig = iVal - iSm; |
| kahanBabuskaNeumaierStep(pSum, iBig); |
| kahanBabuskaNeumaierStep(pSum, iSm); |
| }else{ |
| kahanBabuskaNeumaierStep(pSum, (double)iVal); |
| } |
| } |
|
|
| |
| |
| |
| static void kahanBabuskaNeumaierInit( |
| volatile SumCtx *p, |
| i64 iVal |
| ){ |
| if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){ |
| i64 iSm = iVal % 16384; |
| p->rSum = (double)(iVal - iSm); |
| p->rErr = (double)iSm; |
| }else{ |
| p->rSum = (double)iVal; |
| p->rErr = 0.0; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| SumCtx *p; |
| int type; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| p = sqlite3_aggregate_context(context, sizeof(*p)); |
| type = sqlite3_value_numeric_type(argv[0]); |
| if( p && type!=SQLITE_NULL ){ |
| p->cnt++; |
| if( p->approx==0 ){ |
| if( type!=SQLITE_INTEGER ){ |
| kahanBabuskaNeumaierInit(p, p->iSum); |
| p->approx = 1; |
| kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); |
| }else{ |
| i64 x = p->iSum; |
| if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){ |
| p->iSum = x; |
| }else{ |
| p->ovrfl = 1; |
| kahanBabuskaNeumaierInit(p, p->iSum); |
| p->approx = 1; |
| kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); |
| } |
| } |
| }else{ |
| if( type==SQLITE_INTEGER ){ |
| kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0])); |
| }else{ |
| p->ovrfl = 0; |
| kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0])); |
| } |
| } |
| } |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){ |
| SumCtx *p; |
| int type; |
| assert( argc==1 ); |
| UNUSED_PARAMETER(argc); |
| p = sqlite3_aggregate_context(context, sizeof(*p)); |
| type = sqlite3_value_numeric_type(argv[0]); |
| |
| |
| if( ALWAYS(p) && type!=SQLITE_NULL ){ |
| assert( p->cnt>0 ); |
| p->cnt--; |
| if( !p->approx ){ |
| 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 ){ |
| kahanBabuskaNeumaierStepInt64(p, -iVal); |
| }else{ |
| kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64); |
| kahanBabuskaNeumaierStepInt64(p, 1); |
| } |
| }else{ |
| kahanBabuskaNeumaierStep(p, -sqlite3_value_double(argv[0])); |
| } |
| } |
| } |
| #else |
| # define sumInverse 0 |
| #endif |
| static void sumFinalize(sqlite3_context *context){ |
| SumCtx *p; |
| p = sqlite3_aggregate_context(context, 0); |
| if( p && p->cnt>0 ){ |
| if( p->approx ){ |
| if( p->ovrfl ){ |
| sqlite3_result_error(context,"integer overflow",-1); |
| }else if( !sqlite3IsOverflow(p->rErr) ){ |
| sqlite3_result_double(context, p->rSum+p->rErr); |
| }else{ |
| sqlite3_result_double(context, p->rSum); |
| } |
| }else{ |
| sqlite3_result_int64(context, p->iSum); |
| } |
| } |
| } |
| static void avgFinalize(sqlite3_context *context){ |
| SumCtx *p; |
| p = sqlite3_aggregate_context(context, 0); |
| if( p && p->cnt>0 ){ |
| double r; |
| if( p->approx ){ |
| r = p->rSum; |
| if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; |
| }else{ |
| r = (double)(p->iSum); |
| } |
| sqlite3_result_double(context, r/(double)p->cnt); |
| } |
| } |
| static void totalFinalize(sqlite3_context *context){ |
| SumCtx *p; |
| double r = 0.0; |
| p = sqlite3_aggregate_context(context, 0); |
| if( p ){ |
| if( p->approx ){ |
| r = p->rSum; |
| if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr; |
| }else{ |
| r = (double)(p->iSum); |
| } |
| } |
| sqlite3_result_double(context, r); |
| } |
|
|
| |
| |
| |
| |
| typedef struct CountCtx CountCtx; |
| struct CountCtx { |
| i64 n; |
| #ifdef SQLITE_DEBUG |
| int bInverse; |
| #endif |
| }; |
|
|
| |
| |
| |
| static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ |
| CountCtx *p; |
| p = sqlite3_aggregate_context(context, sizeof(*p)); |
| if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p ){ |
| p->n++; |
| } |
|
|
| #ifndef SQLITE_OMIT_DEPRECATED |
| |
| |
| |
| |
| assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse |
| || p->n==sqlite3_aggregate_count(context) ); |
| #endif |
| } |
| static void countFinalize(sqlite3_context *context){ |
| CountCtx *p; |
| p = sqlite3_aggregate_context(context, 0); |
| sqlite3_result_int64(context, p ? p->n : 0); |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){ |
| CountCtx *p; |
| p = sqlite3_aggregate_context(ctx, sizeof(*p)); |
| |
| if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){ |
| p->n--; |
| #ifdef SQLITE_DEBUG |
| p->bInverse = 1; |
| #endif |
| } |
| } |
| #else |
| # define countInverse 0 |
| #endif |
|
|
| |
| |
| |
| static void minmaxStep( |
| sqlite3_context *context, |
| int NotUsed, |
| sqlite3_value **argv |
| ){ |
| Mem *pArg = (Mem *)argv[0]; |
| Mem *pBest; |
| UNUSED_PARAMETER(NotUsed); |
|
|
| pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest)); |
| if( !pBest ) return; |
|
|
| if( sqlite3_value_type(pArg)==SQLITE_NULL ){ |
| if( pBest->flags ) sqlite3SkipAccumulatorLoad(context); |
| }else if( pBest->flags ){ |
| int max; |
| int cmp; |
| CollSeq *pColl = sqlite3GetFuncCollSeq(context); |
| |
| |
| |
| |
| |
| |
| |
| |
| max = sqlite3_user_data(context)!=0; |
| cmp = sqlite3MemCompare(pBest, pArg, pColl); |
| if( (max && cmp<0) || (!max && cmp>0) ){ |
| sqlite3VdbeMemCopy(pBest, pArg); |
| }else{ |
| sqlite3SkipAccumulatorLoad(context); |
| } |
| }else{ |
| pBest->db = sqlite3_context_db_handle(context); |
| sqlite3VdbeMemCopy(pBest, pArg); |
| } |
| } |
| static void minMaxValueFinalize(sqlite3_context *context, int bValue){ |
| sqlite3_value *pRes; |
| pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0); |
| if( pRes ){ |
| if( pRes->flags ){ |
| sqlite3_result_value(context, pRes); |
| } |
| if( bValue==0 ) sqlite3VdbeMemRelease(pRes); |
| } |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| static void minMaxValue(sqlite3_context *context){ |
| minMaxValueFinalize(context, 1); |
| } |
| #else |
| # define minMaxValue 0 |
| #endif |
| static void minMaxFinalize(sqlite3_context *context){ |
| minMaxValueFinalize(context, 0); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| typedef struct { |
| StrAccum str; |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| int nAccum; |
| int nFirstSepLength; |
| |
| |
| |
| |
| |
| int *pnSepLengths; |
| #endif |
| } GroupConcatCtx; |
|
|
| static void groupConcatStep( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| const char *zVal; |
| GroupConcatCtx *pGCC; |
| const char *zSep; |
| int nVal, nSep; |
| assert( argc==1 || argc==2 ); |
| if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); |
| if( pGCC ){ |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| int firstTerm = pGCC->str.mxAlloc==0; |
| pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; |
| if( argc==1 ){ |
| if( !firstTerm ){ |
| sqlite3_str_appendchar(&pGCC->str, 1, ','); |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| else{ |
| pGCC->nFirstSepLength = 1; |
| } |
| #endif |
| }else if( !firstTerm ){ |
| zSep = (char*)sqlite3_value_text(argv[1]); |
| nSep = sqlite3_value_bytes(argv[1]); |
| if( zSep ){ |
| sqlite3_str_append(&pGCC->str, zSep, nSep); |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| else{ |
| nSep = 0; |
| } |
| if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){ |
| int *pnsl = pGCC->pnSepLengths; |
| if( pnsl == 0 ){ |
| |
| pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int)); |
| if( pnsl!=0 ){ |
| int i = 0, nA = pGCC->nAccum-1; |
| while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength; |
| } |
| }else{ |
| pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int)); |
| } |
| if( pnsl!=0 ){ |
| if( ALWAYS(pGCC->nAccum>0) ){ |
| pnsl[pGCC->nAccum-1] = nSep; |
| } |
| pGCC->pnSepLengths = pnsl; |
| }else{ |
| sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM); |
| } |
| } |
| #endif |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| else{ |
| pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]); |
| } |
| pGCC->nAccum += 1; |
| #endif |
| zVal = (char*)sqlite3_value_text(argv[0]); |
| nVal = sqlite3_value_bytes(argv[0]); |
| if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal); |
| } |
| } |
|
|
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| static void groupConcatInverse( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| GroupConcatCtx *pGCC; |
| assert( argc==1 || argc==2 ); |
| (void)argc; |
| if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC)); |
| |
| |
| if( ALWAYS(pGCC) ){ |
| int nVS; |
| |
| |
| (void)sqlite3_value_text(argv[0]); |
| nVS = sqlite3_value_bytes(argv[0]); |
| pGCC->nAccum -= 1; |
| if( pGCC->pnSepLengths!=0 ){ |
| assert(pGCC->nAccum >= 0); |
| if( pGCC->nAccum>0 ){ |
| nVS += *pGCC->pnSepLengths; |
| memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1, |
| (pGCC->nAccum-1)*sizeof(int)); |
| } |
| }else{ |
| |
| nVS += pGCC->nFirstSepLength; |
| } |
| if( nVS>=(int)pGCC->str.nChar ){ |
| pGCC->str.nChar = 0; |
| }else{ |
| pGCC->str.nChar -= nVS; |
| memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar); |
| } |
| if( pGCC->str.nChar==0 ){ |
| pGCC->str.mxAlloc = 0; |
| sqlite3_free(pGCC->pnSepLengths); |
| pGCC->pnSepLengths = 0; |
| } |
| } |
| } |
| #else |
| # define groupConcatInverse 0 |
| #endif |
| static void groupConcatFinalize(sqlite3_context *context){ |
| GroupConcatCtx *pGCC |
| = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); |
| if( pGCC ){ |
| sqlite3ResultStrAccum(context, &pGCC->str); |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| sqlite3_free(pGCC->pnSepLengths); |
| #endif |
| } |
| } |
| #ifndef SQLITE_OMIT_WINDOWFUNC |
| static void groupConcatValue(sqlite3_context *context){ |
| GroupConcatCtx *pGCC |
| = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0); |
| if( pGCC ){ |
| StrAccum *pAccum = &pGCC->str; |
| if( pAccum->accError==SQLITE_TOOBIG ){ |
| sqlite3_result_error_toobig(context); |
| }else if( pAccum->accError==SQLITE_NOMEM ){ |
| sqlite3_result_error_nomem(context); |
| }else if( pGCC->nAccum>0 && pAccum->nChar==0 ){ |
| sqlite3_result_text(context, "", 1, SQLITE_STATIC); |
| }else{ |
| const char *zText = sqlite3_str_value(pAccum); |
| sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT); |
| } |
| } |
| } |
| #else |
| # define groupConcatValue 0 |
| #endif |
|
|
| |
| |
| |
| |
| |
| void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ |
| int rc = sqlite3_overload_function(db, "MATCH", 2); |
| assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); |
| if( rc==SQLITE_NOMEM ){ |
| sqlite3OomFault(db); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ |
| FuncDef *pDef; |
| struct compareInfo *pInfo; |
| int flags; |
| int nArg; |
| if( caseSensitive ){ |
| pInfo = (struct compareInfo*)&likeInfoAlt; |
| flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; |
| }else{ |
| pInfo = (struct compareInfo*)&likeInfoNorm; |
| flags = SQLITE_FUNC_LIKE; |
| } |
| for(nArg=2; nArg<=3; nArg++){ |
| sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc, |
| 0, 0, 0, 0, 0); |
| pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0); |
| pDef->funcFlags |= flags; |
| pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
| FuncDef *pDef; |
| int nExpr; |
| assert( pExpr!=0 ); |
| assert( pExpr->op==TK_FUNCTION ); |
| assert( ExprUseXList(pExpr) ); |
| if( !pExpr->x.pList ){ |
| return 0; |
| } |
| nExpr = pExpr->x.pList->nExpr; |
| assert( !ExprHasProperty(pExpr, EP_IntValue) ); |
| pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); |
| #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
| if( pDef==0 ) return 0; |
| #endif |
| if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ |
| return 0; |
| } |
|
|
| |
| |
| |
| |
| memcpy(aWc, pDef->pUserData, 3); |
| assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll ); |
| assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne ); |
| assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet ); |
|
|
| if( nExpr<3 ){ |
| aWc[3] = 0; |
| }else{ |
| Expr *pEscape = pExpr->x.pList->a[2].pExpr; |
| char *zEscape; |
| if( pEscape->op!=TK_STRING ) return 0; |
| assert( !ExprHasProperty(pEscape, EP_IntValue) ); |
| zEscape = pEscape->u.zToken; |
| if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; |
| if( zEscape[0]==aWc[0] ) return 0; |
| if( zEscape[0]==aWc[1] ) return 0; |
| aWc[3] = zEscape[0]; |
| } |
|
|
| *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; |
| return 1; |
| } |
|
|
| |
| #ifndef M_PI |
| # define M_PI 3.141592653589793238462643383279502884 |
| #endif |
| #ifndef M_LN10 |
| # define M_LN10 2.302585092994045684017991454684364208 |
| #endif |
| #ifndef M_LN2 |
| # define M_LN2 0.693147180559945309417232121458176568 |
| #endif |
|
|
|
|
| |
| |
| #ifdef SQLITE_ENABLE_MATH_FUNCTIONS |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void ceilingFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| assert( argc==1 ); |
| switch( sqlite3_value_numeric_type(argv[0]) ){ |
| case SQLITE_INTEGER: { |
| sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); |
| break; |
| } |
| case SQLITE_FLOAT: { |
| double (*x)(double) = (double(*)(double))sqlite3_user_data(context); |
| sqlite3_result_double(context, x(sqlite3_value_double(argv[0]))); |
| break; |
| } |
| default: { |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| static double xCeil(double x){ return ceil(x); } |
| static double xFloor(double x){ return floor(x); } |
|
|
| |
| |
| |
| |
| #if defined(HAVE_LOG10) && HAVE_LOG10==0 |
| # define log10(X) (0.4342944819032517867*log(X)) |
| #endif |
| #if defined(HAVE_LOG2) && HAVE_LOG2==0 |
| # define log2(X) (1.442695040888963456*log(X)) |
| #endif |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static void logFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| double x, b, ans; |
| assert( argc==1 || argc==2 ); |
| switch( sqlite3_value_numeric_type(argv[0]) ){ |
| case SQLITE_INTEGER: |
| case SQLITE_FLOAT: |
| x = sqlite3_value_double(argv[0]); |
| if( x<=0.0 ) return; |
| break; |
| default: |
| return; |
| } |
| if( argc==2 ){ |
| switch( sqlite3_value_numeric_type(argv[0]) ){ |
| case SQLITE_INTEGER: |
| case SQLITE_FLOAT: |
| b = log(x); |
| if( b<=0.0 ) return; |
| x = sqlite3_value_double(argv[1]); |
| if( x<=0.0 ) return; |
| break; |
| default: |
| return; |
| } |
| ans = log(x)/b; |
| }else{ |
| switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ |
| case 1: |
| ans = log10(x); |
| break; |
| case 2: |
| ans = log2(x); |
| break; |
| default: |
| ans = log(x); |
| break; |
| } |
| } |
| sqlite3_result_double(context, ans); |
| } |
|
|
| |
| |
| |
| static double degToRad(double x){ return x*(M_PI/180.0); } |
| static double radToDeg(double x){ return x*(180.0/M_PI); } |
|
|
| |
| |
| |
| |
| |
| static void math1Func( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int type0; |
| double v0, ans; |
| double (*x)(double); |
| assert( argc==1 ); |
| type0 = sqlite3_value_numeric_type(argv[0]); |
| if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; |
| v0 = sqlite3_value_double(argv[0]); |
| x = (double(*)(double))sqlite3_user_data(context); |
| ans = x(v0); |
| sqlite3_result_double(context, ans); |
| } |
|
|
| |
| |
| |
| |
| |
| static void math2Func( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int type0, type1; |
| double v0, v1, ans; |
| double (*x)(double,double); |
| assert( argc==2 ); |
| type0 = sqlite3_value_numeric_type(argv[0]); |
| if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; |
| type1 = sqlite3_value_numeric_type(argv[1]); |
| if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return; |
| v0 = sqlite3_value_double(argv[0]); |
| v1 = sqlite3_value_double(argv[1]); |
| x = (double(*)(double,double))sqlite3_user_data(context); |
| ans = x(v0, v1); |
| sqlite3_result_double(context, ans); |
| } |
|
|
| |
| |
| |
| static void piFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| assert( argc==0 ); |
| (void)argv; |
| sqlite3_result_double(context, M_PI); |
| } |
|
|
| #endif |
|
|
| |
| |
| |
| static void signFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| int type0; |
| double x; |
| UNUSED_PARAMETER(argc); |
| assert( argc==1 ); |
| type0 = sqlite3_value_numeric_type(argv[0]); |
| if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; |
| x = sqlite3_value_double(argv[0]); |
| sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0); |
| } |
|
|
| #if defined(SQLITE_ENABLE_PERCENTILE) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| typedef struct Percentile Percentile; |
| struct Percentile { |
| u64 nAlloc; |
| u64 nUsed; |
| char bSorted; |
| char bKeepSorted; |
| char bPctValid; |
| double rPct; |
| double *a; |
| }; |
|
|
| |
| |
| |
| static int percentIsInfinity(double r){ |
| sqlite3_uint64 u; |
| assert( sizeof(u)==sizeof(r) ); |
| memcpy(&u, &r, sizeof(u)); |
| return ((u>>52)&0x7ff)==0x7ff; |
| } |
|
|
| |
| |
| |
| static int percentSameValue(double a, double b){ |
| a -= b; |
| return a>=-0.001 && a<=0.001; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static i64 percentBinarySearch(Percentile *p, double y, int bExact){ |
| i64 iFirst = 0; |
| i64 iLast = (i64)p->nUsed - 1; |
| while( iLast>=iFirst ){ |
| i64 iMid = (iFirst+iLast)/2; |
| double x = p->a[iMid]; |
| if( x<y ){ |
| iFirst = iMid + 1; |
| }else if( x>y ){ |
| iLast = iMid - 1; |
| }else{ |
| return iMid; |
| } |
| } |
| if( bExact ) return -1; |
| return iFirst; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){ |
| char *zMsg1; |
| char *zMsg2; |
| va_list ap; |
|
|
| va_start(ap, zFormat); |
| zMsg1 = sqlite3_vmprintf(zFormat, ap); |
| va_end(ap); |
| zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, sqlite3VdbeFuncName(pCtx)) : 0; |
| sqlite3_result_error(pCtx, zMsg2, -1); |
| sqlite3_free(zMsg1); |
| sqlite3_free(zMsg2); |
| } |
|
|
| |
| |
| |
| |
| static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ |
| Percentile *p; |
| double rPct; |
| int eType; |
| double y; |
| assert( argc==2 || argc==1 ); |
|
|
| if( argc==1 ){ |
| |
| rPct = 0.5; |
| }else{ |
| |
| |
| |
| |
| |
| double mxFrac = (SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx))&2)? 100.0 : 1.0; |
| eType = sqlite3_value_numeric_type(argv[1]); |
| rPct = sqlite3_value_double(argv[1])/mxFrac; |
| if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) |
| || rPct<0.0 || rPct>1.0 |
| ){ |
| percentError(pCtx, "the fraction argument to %%s()" |
| " is not between 0.0 and %.1f", |
| (double)mxFrac); |
| return; |
| } |
| } |
|
|
| |
| p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
| if( p==0 ) return; |
|
|
| |
| |
| if( !p->bPctValid ){ |
| p->rPct = rPct; |
| p->bPctValid = 1; |
| }else if( !percentSameValue(p->rPct,rPct) ){ |
| percentError(pCtx, "the fraction argument to %%s()" |
| " is not the same for all input rows"); |
| return; |
| } |
|
|
| |
| eType = sqlite3_value_type(argv[0]); |
| if( eType==SQLITE_NULL ) return; |
|
|
| |
| |
| if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ |
| percentError(pCtx, "input to %%s() is not numeric"); |
| return; |
| } |
|
|
| |
| y = sqlite3_value_double(argv[0]); |
| if( percentIsInfinity(y) ){ |
| percentError(pCtx, "Inf input to %%s()"); |
| return; |
| } |
|
|
| |
| if( p->nUsed>=p->nAlloc ){ |
| u64 n = p->nAlloc*2 + 250; |
| double *a = sqlite3_realloc64(p->a, sizeof(double)*n); |
| if( a==0 ){ |
| sqlite3_free(p->a); |
| memset(p, 0, sizeof(*p)); |
| sqlite3_result_error_nomem(pCtx); |
| return; |
| } |
| p->nAlloc = n; |
| p->a = a; |
| } |
| if( p->nUsed==0 ){ |
| p->a[p->nUsed++] = y; |
| p->bSorted = 1; |
| }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){ |
| p->a[p->nUsed++] = y; |
| }else if( p->bKeepSorted ){ |
| i64 i; |
| i = percentBinarySearch(p, y, 0); |
| if( i<(int)p->nUsed ){ |
| memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0])); |
| } |
| p->a[i] = y; |
| p->nUsed++; |
| }else{ |
| p->a[p->nUsed++] = y; |
| p->bSorted = 0; |
| } |
| } |
|
|
| |
| |
| |
| #define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;} |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void percentSort(double *a, unsigned int n){ |
| int iLt; |
| int iGt; |
| int i; |
| double rPivot; |
| |
| assert( n>=2 ); |
| if( a[0]>a[n-1] ){ |
| SWAP_DOUBLE(a[0],a[n-1]) |
| } |
| if( n==2 ) return; |
| iGt = n-1; |
| i = n/2; |
| if( a[0]>a[i] ){ |
| SWAP_DOUBLE(a[0],a[i]) |
| }else if( a[i]>a[iGt] ){ |
| SWAP_DOUBLE(a[i],a[iGt]) |
| } |
| if( n==3 ) return; |
| rPivot = a[i]; |
| iLt = i = 1; |
| do{ |
| if( a[i]<rPivot ){ |
| if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt]) |
| iLt++; |
| i++; |
| }else if( a[i]>rPivot ){ |
| do{ |
| iGt--; |
| }while( iGt>i && a[iGt]>rPivot ); |
| SWAP_DOUBLE(a[i],a[iGt]) |
| }else{ |
| i++; |
| } |
| }while( i<iGt ); |
| if( iLt>=2 ) percentSort(a, iLt); |
| if( n-iGt>=2 ) percentSort(a+iGt, n-iGt); |
| |
| |
| #if 0 |
| for(i=0; i<n-1; i++){ |
| assert( a[i]<=a[i+1] ); |
| } |
| #endif |
| } |
|
|
|
|
| |
| |
| |
| |
| static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){ |
| Percentile *p; |
| int eType; |
| double y; |
| i64 i; |
| assert( argc==2 || argc==1 ); |
|
|
| |
| p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); |
| assert( p!=0 ); |
|
|
| |
| eType = sqlite3_value_type(argv[0]); |
| if( eType==SQLITE_NULL ) return; |
|
|
| |
| |
| if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ |
| return; |
| } |
|
|
| |
| y = sqlite3_value_double(argv[0]); |
| if( percentIsInfinity(y) ){ |
| return; |
| } |
| if( p->bSorted==0 ){ |
| assert( p->nUsed>1 ); |
| percentSort(p->a, p->nUsed); |
| p->bSorted = 1; |
| } |
| p->bKeepSorted = 1; |
|
|
| |
| i = percentBinarySearch(p, y, 1); |
| if( i>=0 ){ |
| p->nUsed--; |
| if( i<(int)p->nUsed ){ |
| memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0])); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| static void percentCompute(sqlite3_context *pCtx, int bIsFinal){ |
| Percentile *p; |
| int settings = SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx))&1; |
| unsigned i1, i2; |
| double v1, v2; |
| double ix, vx; |
| p = (Percentile*)sqlite3_aggregate_context(pCtx, 0); |
| if( p==0 ) return; |
| if( p->a==0 ) return; |
| if( p->nUsed ){ |
| if( p->bSorted==0 ){ |
| assert( p->nUsed>1 ); |
| percentSort(p->a, p->nUsed); |
| p->bSorted = 1; |
| } |
| ix = p->rPct*(p->nUsed-1); |
| i1 = (unsigned)ix; |
| if( settings & 1 ){ |
| vx = p->a[i1]; |
| }else{ |
| i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; |
| v1 = p->a[i1]; |
| v2 = p->a[i2]; |
| vx = v1 + (v2-v1)*(ix-i1); |
| } |
| sqlite3_result_double(pCtx, vx); |
| } |
| if( bIsFinal ){ |
| sqlite3_free(p->a); |
| memset(p, 0, sizeof(*p)); |
| }else{ |
| p->bKeepSorted = 1; |
| } |
| } |
| static void percentFinal(sqlite3_context *pCtx){ |
| percentCompute(pCtx, 1); |
| } |
| static void percentValue(sqlite3_context *pCtx){ |
| percentCompute(pCtx, 0); |
| } |
| |
| #endif |
|
|
| #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) |
| |
| |
| |
| |
| |
| |
| static void filestatFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| sqlite3 *db = sqlite3_context_db_handle(context); |
| const char *zDbName; |
| sqlite3_str *pStr; |
| Btree *pBtree; |
|
|
| zDbName = (const char*)sqlite3_value_text(argv[0]); |
| pBtree = sqlite3DbNameToBtree(db, zDbName); |
| if( pBtree ){ |
| Pager *pPager; |
| sqlite3_file *fd; |
| int rc; |
| sqlite3BtreeEnter(pBtree); |
| pPager = sqlite3BtreePager(pBtree); |
| assert( pPager!=0 ); |
| fd = sqlite3PagerFile(pPager); |
| pStr = sqlite3_str_new(db); |
| if( pStr==0 ){ |
| sqlite3_result_error_nomem(context); |
| }else{ |
| sqlite3_str_append(pStr, "{\"db\":", 6); |
| rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr); |
| if( rc ) sqlite3_str_append(pStr, "null", 4); |
| fd = sqlite3PagerJrnlFile(pPager); |
| if( fd && fd->pMethods!=0 ){ |
| sqlite3_str_appendall(pStr, ",\"journal\":"); |
| rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_FILESTAT, pStr); |
| if( rc ) sqlite3_str_append(pStr, "null", 4); |
| } |
| sqlite3_str_append(pStr, "}", 1); |
| sqlite3_result_text(context, sqlite3_str_finish(pStr), -1, |
| sqlite3_free); |
| } |
| sqlite3BtreeLeave(pBtree); |
| }else{ |
| sqlite3_result_text(context, "{}", 2, SQLITE_STATIC); |
| } |
| } |
| #endif |
|
|
| #ifdef SQLITE_DEBUG |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static void fpdecodeFunc( |
| sqlite3_context *context, |
| int argc, |
| sqlite3_value **argv |
| ){ |
| FpDecode s; |
| double x; |
| int y, z; |
| char zBuf[100]; |
| UNUSED_PARAMETER(argc); |
| assert( argc==3 ); |
| x = sqlite3_value_double(argv[0]); |
| y = sqlite3_value_int(argv[1]); |
| z = sqlite3_value_int(argv[2]); |
| if( z<=0 ) z = 1; |
| sqlite3FpDecode(&s, x, y, z); |
| if( s.isSpecial==2 ){ |
| sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN"); |
| }else{ |
| sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP); |
| } |
| sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); |
| } |
| #endif |
|
|
| #ifdef SQLITE_DEBUG |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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 |
|
|
| |
| |
| |
| |
| |
| |
| |
| void sqlite3RegisterBuiltinFunctions(void){ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static FuncDef aBuiltinFunc[] = { |
| |
| #if !defined(SQLITE_UNTESTABLE) |
| TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), |
| TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), |
| TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), |
| TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), |
| #endif |
| |
| #ifdef SQLITE_SOUNDEX |
| FUNCTION(soundex, 1, 0, 0, soundexFunc ), |
| #endif |
| #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| SFUNCTION(load_extension, 1, 0, 0, loadExt ), |
| SFUNCTION(load_extension, 2, 0, 0, loadExt ), |
| #endif |
| #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), |
| DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), |
| #endif |
| INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), |
| INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), |
| INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), |
| #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC |
| INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ), |
| #endif |
| #if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_FILESTAT) |
| FUNCTION(sqlite_filestat, 1, 0, 0, filestatFunc ), |
| #endif |
| FUNCTION(ltrim, 1, 1, 0, trimFunc ), |
| FUNCTION(ltrim, 2, 1, 0, trimFunc ), |
| FUNCTION(rtrim, 1, 2, 0, trimFunc ), |
| FUNCTION(rtrim, 2, 2, 0, trimFunc ), |
| FUNCTION(trim, 1, 3, 0, trimFunc ), |
| FUNCTION(trim, 2, 3, 0, trimFunc ), |
| FUNCTION(min, -3, 0, 1, minmaxFunc ), |
| WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, |
| SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ), |
| 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|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 ), |
| FUNCTION(printf, -1, 0, 0, printfFunc ), |
| FUNCTION(format, -1, 0, 0, printfFunc ), |
| FUNCTION(unicode, 1, 0, 0, unicodeFunc ), |
| FUNCTION(char, -1, 0, 0, charFunc ), |
| 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 ), |
| FUNCTION(round, 2, 0, 0, roundFunc ), |
| #endif |
| FUNCTION(upper, 1, 0, 0, upperFunc ), |
| FUNCTION(lower, 1, 0, 0, lowerFunc ), |
| FUNCTION(hex, 1, 0, 0, hexFunc ), |
| FUNCTION(unhex, 1, 0, 0, unhexFunc ), |
| FUNCTION(unhex, 2, 0, 0, unhexFunc ), |
| 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 ), |
| FUNCTION(nullif, 2, 0, 1, nullifFunc ), |
| 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 ), |
| FUNCTION(replace, 3, 0, 0, replaceFunc ), |
| FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), |
| FUNCTION(substr, 2, 0, 0, substrFunc ), |
| FUNCTION(substr, 3, 0, 0, substrFunc ), |
| FUNCTION(substring, 2, 0, 0, substrFunc ), |
| FUNCTION(substring, 3, 0, 0, substrFunc ), |
| WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), |
| WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), |
| WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), |
| WAGGREGATE(count, 0,0,0, countStep, |
| countFinalize, countFinalize, countInverse, |
| SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ), |
| WAGGREGATE(count, 1,0,0, countStep, |
| countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ), |
| WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, |
| groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), |
| WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, |
| groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), |
| WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep, |
| groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), |
|
|
| #ifdef SQLITE_ENABLE_PERCENTILE |
| WAGGREGATE(median, 1, 0,0, percentStep, |
| percentFinal, percentValue, percentInverse, |
| SQLITE_INNOCUOUS|SQLITE_SELFORDER1), |
| WAGGREGATE(percentile, 2, 0x2,0, percentStep, |
| percentFinal, percentValue, percentInverse, |
| SQLITE_INNOCUOUS|SQLITE_SELFORDER1), |
| WAGGREGATE(percentile_cont, 2, 0,0, percentStep, |
| percentFinal, percentValue, percentInverse, |
| SQLITE_INNOCUOUS|SQLITE_SELFORDER1), |
| WAGGREGATE(percentile_disc, 2, 0x1,0, percentStep, |
| percentFinal, percentValue, percentInverse, |
| SQLITE_INNOCUOUS|SQLITE_SELFORDER1), |
| #endif |
| |
| LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), |
| #ifdef SQLITE_CASE_SENSITIVE_LIKE |
| LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), |
| LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), |
| #else |
| LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), |
| LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), |
| #endif |
| #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
| FUNCTION(unknown, -1, 0, 0, unknownFunc ), |
| #endif |
| #ifdef SQLITE_ENABLE_MATH_FUNCTIONS |
| MFUNCTION(ceil, 1, xCeil, ceilingFunc ), |
| MFUNCTION(ceiling, 1, xCeil, ceilingFunc ), |
| MFUNCTION(floor, 1, xFloor, ceilingFunc ), |
| #if SQLITE_HAVE_C99_MATH_FUNCS |
| MFUNCTION(trunc, 1, trunc, ceilingFunc ), |
| #endif |
| FUNCTION(ln, 1, 0, 0, logFunc ), |
| FUNCTION(log, 1, 1, 0, logFunc ), |
| FUNCTION(log10, 1, 1, 0, logFunc ), |
| FUNCTION(log2, 1, 2, 0, logFunc ), |
| FUNCTION(log, 2, 0, 0, logFunc ), |
| MFUNCTION(exp, 1, exp, math1Func ), |
| MFUNCTION(pow, 2, pow, math2Func ), |
| MFUNCTION(power, 2, pow, math2Func ), |
| MFUNCTION(mod, 2, fmod, math2Func ), |
| MFUNCTION(acos, 1, acos, math1Func ), |
| MFUNCTION(asin, 1, asin, math1Func ), |
| MFUNCTION(atan, 1, atan, math1Func ), |
| MFUNCTION(atan2, 2, atan2, math2Func ), |
| MFUNCTION(cos, 1, cos, math1Func ), |
| MFUNCTION(sin, 1, sin, math1Func ), |
| MFUNCTION(tan, 1, tan, math1Func ), |
| MFUNCTION(cosh, 1, cosh, math1Func ), |
| MFUNCTION(sinh, 1, sinh, math1Func ), |
| MFUNCTION(tanh, 1, tanh, math1Func ), |
| #if SQLITE_HAVE_C99_MATH_FUNCS |
| MFUNCTION(acosh, 1, acosh, math1Func ), |
| MFUNCTION(asinh, 1, asinh, math1Func ), |
| MFUNCTION(atanh, 1, atanh, math1Func ), |
| #endif |
| MFUNCTION(sqrt, 1, sqrt, math1Func ), |
| MFUNCTION(radians, 1, degToRad, math1Func ), |
| MFUNCTION(degrees, 1, radToDeg, math1Func ), |
| MFUNCTION(pi, 0, 0, piFunc ), |
| #endif |
| FUNCTION(sign, 1, 0, 0, signFunc ), |
| 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(); |
| #endif |
| sqlite3WindowFunctions(); |
| sqlite3RegisterDateTimeFunctions(); |
| sqlite3RegisterJsonFunctions(); |
| sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); |
|
|
| #if 0 |
| { |
| int i; |
| FuncDef *p; |
| for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ |
| printf("FUNC-HASH %02d:", i); |
| for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){ |
| int n = sqlite3Strlen30(p->zName); |
| int h = p->zName[0] + n; |
| assert( p->funcFlags & SQLITE_FUNC_BUILTIN ); |
| printf(" %s(%d)", p->zName, h); |
| } |
| printf("\n"); |
| } |
| } |
| #endif |
| } |
|
|