Index: third_party/sqlite/src/src/func.c |
diff --git a/third_party/sqlite/src/src/func.c b/third_party/sqlite/src/src/func.c |
index 3fbd2b736bb9ca6a706d4862132a4952227f0237..885725bc6b4757021092ad122a515998ca43accd 100644 |
--- a/third_party/sqlite/src/src/func.c |
+++ b/third_party/sqlite/src/src/func.c |
@@ -200,23 +200,28 @@ static void instrFunc( |
if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return; |
nHaystack = sqlite3_value_bytes(argv[0]); |
nNeedle = sqlite3_value_bytes(argv[1]); |
- if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ |
- zHaystack = sqlite3_value_blob(argv[0]); |
- zNeedle = sqlite3_value_blob(argv[1]); |
- isText = 0; |
- }else{ |
- zHaystack = sqlite3_value_text(argv[0]); |
- zNeedle = sqlite3_value_text(argv[1]); |
- isText = 1; |
- } |
- while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ |
- N++; |
- do{ |
- nHaystack--; |
- zHaystack++; |
- }while( isText && (zHaystack[0]&0xc0)==0x80 ); |
+ if( nNeedle>0 ){ |
+ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){ |
+ zHaystack = sqlite3_value_blob(argv[0]); |
+ zNeedle = sqlite3_value_blob(argv[1]); |
+ assert( zNeedle!=0 ); |
+ assert( zHaystack!=0 || nHaystack==0 ); |
+ isText = 0; |
+ }else{ |
+ zHaystack = sqlite3_value_text(argv[0]); |
+ zNeedle = sqlite3_value_text(argv[1]); |
+ isText = 1; |
+ if( zHaystack==0 || zNeedle==0 ) return; |
+ } |
+ while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){ |
+ N++; |
+ do{ |
+ nHaystack--; |
+ zHaystack++; |
+ }while( isText && (zHaystack[0]&0xc0)==0x80 ); |
+ } |
+ if( nNeedle>nHaystack ) N = 0; |
} |
- if( nNeedle>nHaystack ) N = 0; |
sqlite3_result_int(context, N); |
} |
@@ -239,7 +244,8 @@ static void printfFunc( |
x.nUsed = 0; |
x.apArg = argv+1; |
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]); |
- sqlite3XPrintf(&str, SQLITE_PRINTF_SQLFUNC, zFormat, &x); |
+ str.printfFlags = SQLITE_PRINTF_SQLFUNC; |
+ sqlite3XPrintf(&str, zFormat, &x); |
n = str.nChar; |
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, |
SQLITE_DYNAMIC); |
@@ -567,10 +573,10 @@ static void total_changes( |
** A structure defining how to do GLOB-style comparisons. |
*/ |
struct compareInfo { |
- u8 matchAll; |
- u8 matchOne; |
- u8 matchSet; |
- u8 noCase; |
+ u8 matchAll; /* "*" or "%" */ |
+ u8 matchOne; /* "?" or "_" */ |
+ u8 matchSet; /* "[" or 0 */ |
+ u8 noCase; /* true to ignore case differences */ |
}; |
/* |
@@ -595,9 +601,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 }; |
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 }; |
/* |
-** Compare two UTF-8 strings for equality where the first string can |
-** potentially be a "glob" or "like" expression. Return true (1) if they |
-** are the same and false (0) if they are different. |
+** Possible error returns from patternMatch() |
+*/ |
+#define SQLITE_MATCH 0 |
+#define SQLITE_NOMATCH 1 |
+#define SQLITE_NOWILDCARDMATCH 2 |
+ |
+/* |
+** Compare two UTF-8 strings for equality where the first string is |
+** a GLOB or LIKE expression. Return values: |
+** |
+** SQLITE_MATCH: Match |
+** SQLITE_NOMATCH: No match |
+** SQLITE_NOWILDCARDMATCH: No match in spite of having * or % wildcards. |
** |
** Globbing rules: |
** |
@@ -633,22 +649,14 @@ static int patternCompare( |
const u8 *zPattern, /* The glob pattern */ |
const u8 *zString, /* The string to compare against the glob */ |
const struct compareInfo *pInfo, /* Information about how to do the compare */ |
- u32 esc /* The escape character */ |
+ u32 matchOther /* The escape char (LIKE) or '[' (GLOB) */ |
){ |
u32 c, c2; /* Next pattern and input string chars */ |
u32 matchOne = pInfo->matchOne; /* "?" or "_" */ |
u32 matchAll = pInfo->matchAll; /* "*" or "%" */ |
- u32 matchOther; /* "[" or the escape character */ |
u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */ |
const u8 *zEscaped = 0; /* One past the last escaped input char */ |
- /* The GLOB operator does not have an ESCAPE clause. And LIKE does not |
- ** have the matchSet operator. So we either have to look for one or |
- ** the other, never both. Hence the single variable matchOther is used |
- ** to store the one we have to look for. |
- */ |
- matchOther = esc ? esc : pInfo->matchSet; |
- |
while( (c = Utf8Read(zPattern))!=0 ){ |
if( c==matchAll ){ /* Match "*" */ |
/* Skip over multiple "*" characters in the pattern. If there |
@@ -656,30 +664,31 @@ static int patternCompare( |
** single character of the input string for each "?" skipped */ |
while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){ |
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){ |
- return 0; |
+ return SQLITE_NOWILDCARDMATCH; |
} |
} |
if( c==0 ){ |
- return 1; /* "*" at the end of the pattern matches */ |
+ return SQLITE_MATCH; /* "*" at the end of the pattern matches */ |
}else if( c==matchOther ){ |
- if( esc ){ |
+ if( pInfo->matchSet==0 ){ |
c = sqlite3Utf8Read(&zPattern); |
- if( c==0 ) return 0; |
+ if( c==0 ) return SQLITE_NOWILDCARDMATCH; |
}else{ |
/* "[...]" immediately follows the "*". We have to do a slow |
** recursive search in this case, but it is an unusual case. */ |
assert( matchOther<0x80 ); /* '[' is a single-byte character */ |
- while( *zString |
- && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){ |
+ while( *zString ){ |
+ int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther); |
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
SQLITE_SKIP_UTF8(zString); |
} |
- return *zString!=0; |
+ return SQLITE_NOWILDCARDMATCH; |
} |
} |
/* At this point variable c contains the first character of the |
** pattern string past the "*". Search in the input string for the |
- ** first matching character and recursively contine the match from |
+ ** first matching character and recursively continue the match from |
** that point. |
** |
** For a case-insensitive search, set variable cx to be the same as |
@@ -688,6 +697,7 @@ static int patternCompare( |
*/ |
if( c<=0x80 ){ |
u32 cx; |
+ int bMatch; |
if( noCase ){ |
cx = sqlite3Toupper(c); |
c = sqlite3Tolower(c); |
@@ -696,27 +706,30 @@ static int patternCompare( |
} |
while( (c2 = *(zString++))!=0 ){ |
if( c2!=c && c2!=cx ) continue; |
- if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; |
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther); |
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
} |
}else{ |
+ int bMatch; |
while( (c2 = Utf8Read(zString))!=0 ){ |
if( c2!=c ) continue; |
- if( patternCompare(zPattern,zString,pInfo,esc) ) return 1; |
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther); |
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch; |
} |
} |
- return 0; |
+ return SQLITE_NOWILDCARDMATCH; |
} |
if( c==matchOther ){ |
- if( esc ){ |
+ if( pInfo->matchSet==0 ){ |
c = sqlite3Utf8Read(&zPattern); |
- if( c==0 ) return 0; |
+ 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 0; |
+ if( c==0 ) return SQLITE_NOMATCH; |
c2 = sqlite3Utf8Read(&zPattern); |
if( c2=='^' ){ |
invert = 1; |
@@ -740,34 +753,36 @@ static int patternCompare( |
c2 = sqlite3Utf8Read(&zPattern); |
} |
if( c2==0 || (seen ^ invert)==0 ){ |
- return 0; |
+ return SQLITE_NOMATCH; |
} |
continue; |
} |
} |
c2 = Utf8Read(zString); |
if( c==c2 ) continue; |
- if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){ |
+ if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ |
continue; |
} |
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; |
- return 0; |
+ return SQLITE_NOMATCH; |
} |
- return *zString==0; |
+ return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH; |
} |
/* |
-** The sqlite3_strglob() interface. |
+** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and |
+** non-zero if there is no match. |
*/ |
int sqlite3_strglob(const char *zGlobPattern, const char *zString){ |
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0; |
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); |
} |
/* |
-** The sqlite3_strlike() interface. |
+** The sqlite3_strlike() interface. Return 0 on a match and non-zero for |
+** a miss - like strcmp(). |
*/ |
int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ |
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0; |
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); |
} |
/* |
@@ -798,9 +813,10 @@ static void likeFunc( |
sqlite3_value **argv |
){ |
const unsigned char *zA, *zB; |
- u32 escape = 0; |
+ u32 escape; |
int nPat; |
sqlite3 *db = sqlite3_context_db_handle(context); |
+ struct compareInfo *pInfo = sqlite3_user_data(context); |
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
if( sqlite3_value_type(argv[0])==SQLITE_BLOB |
@@ -840,14 +856,14 @@ static void likeFunc( |
return; |
} |
escape = sqlite3Utf8Read(&zEsc); |
+ }else{ |
+ escape = pInfo->matchSet; |
} |
if( zA && zB ){ |
- struct compareInfo *pInfo = sqlite3_user_data(context); |
#ifdef SQLITE_TEST |
sqlite3_like_count++; |
#endif |
- |
- sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); |
+ sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); |
} |
} |
@@ -1322,6 +1338,26 @@ static void trimFunc( |
} |
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION |
+/* |
+** The "unknown" function is automatically substituted in place of |
+** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN |
+** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. |
+** When the "sqlite3" command-line shell is built using this functionality, |
+** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries |
+** involving application-defined functions to be examined in a generic |
+** sqlite3 shell. |
+*/ |
+static void unknownFunc( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ /* no-op */ |
+} |
+#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ |
+ |
+ |
/* IMP: R-25361-16150 This function is omitted from SQLite by default. It |
** is only available if the SQLITE_SOUNDEX compile-time option is used |
** when SQLite is built. |
@@ -1392,6 +1428,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ |
sqlite3 *db = sqlite3_context_db_handle(context); |
char *zErrMsg = 0; |
+ /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc |
+ ** flag is set. See the sqlite3_enable_load_extension() API. |
+ */ |
+ 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{ |
@@ -1590,7 +1634,7 @@ static void groupConcatStep( |
zSep = ","; |
nSep = 1; |
} |
- if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); |
+ if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep); |
} |
zVal = (char*)sqlite3_value_text(argv[0]); |
nVal = sqlite3_value_bytes(argv[0]); |
@@ -1617,11 +1661,11 @@ static void groupConcatFinalize(sqlite3_context *context){ |
** of the built-in functions above are part of the global function set. |
** This routine only deals with those that are not global. |
*/ |
-void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ |
+void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ |
int rc = sqlite3_overload_function(db, "MATCH", 2); |
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); |
if( rc==SQLITE_NOMEM ){ |
- db->mallocFailed = 1; |
+ sqlite3OomFault(db); |
} |
} |
@@ -1630,8 +1674,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){ |
*/ |
static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ |
FuncDef *pDef; |
- pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName), |
- 2, SQLITE_UTF8, 0); |
+ pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); |
if( ALWAYS(pDef) ){ |
pDef->funcFlags |= flagVal; |
} |
@@ -1679,9 +1722,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
return 0; |
} |
assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); |
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, |
- sqlite3Strlen30(pExpr->u.zToken), |
- 2, SQLITE_UTF8, 0); |
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0); |
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ |
return 0; |
} |
@@ -1705,7 +1746,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ |
** |
** After this routine runs |
*/ |
-void sqlite3RegisterGlobalFunctions(void){ |
+void sqlite3RegisterBuiltinFunctions(void){ |
/* |
** The following array holds FuncDef structures for all of the functions |
** defined in this file. |
@@ -1713,8 +1754,30 @@ void sqlite3RegisterGlobalFunctions(void){ |
** The array cannot be constant since changes are made to the |
** FuncDef.pHash elements at start-time. The elements of this array |
** are read-only after initialization is complete. |
+ ** |
+ ** For peak efficiency, put the most frequently used function last. |
*/ |
- static SQLITE_WSD FuncDef aBuiltinFunc[] = { |
+ static FuncDef aBuiltinFunc[] = { |
+#ifdef SQLITE_SOUNDEX |
+ FUNCTION(soundex, 1, 0, 0, soundexFunc ), |
+#endif |
+#ifndef SQLITE_OMIT_LOAD_EXTENSION |
+ VFUNCTION(load_extension, 1, 0, 0, loadExt ), |
+ VFUNCTION(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 ), |
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
+ FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
+ FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
+ FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
+#ifdef SQLITE_DEBUG |
+ FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY), |
+#endif |
FUNCTION(ltrim, 1, 1, 0, trimFunc ), |
FUNCTION(ltrim, 2, 1, 0, trimFunc ), |
FUNCTION(rtrim, 1, 2, 0, trimFunc ), |
@@ -1732,8 +1795,6 @@ void sqlite3RegisterGlobalFunctions(void){ |
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), |
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), |
FUNCTION(instr, 2, 0, 0, instrFunc ), |
- FUNCTION(substr, 2, 0, 0, substrFunc ), |
- FUNCTION(substr, 3, 0, 0, substrFunc ), |
FUNCTION(printf, -1, 0, 0, printfFunc ), |
FUNCTION(unicode, 1, 0, 0, unicodeFunc ), |
FUNCTION(char, -1, 0, 0, charFunc ), |
@@ -1744,40 +1805,22 @@ void sqlite3RegisterGlobalFunctions(void){ |
#endif |
FUNCTION(upper, 1, 0, 0, upperFunc ), |
FUNCTION(lower, 1, 0, 0, lowerFunc ), |
- FUNCTION(coalesce, 1, 0, 0, 0 ), |
- FUNCTION(coalesce, 0, 0, 0, 0 ), |
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), |
FUNCTION(hex, 1, 0, 0, hexFunc ), |
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), |
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), |
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 ), |
-#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 ), |
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
FUNCTION(quote, 1, 0, 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 ), |
- #ifdef SQLITE_SOUNDEX |
- FUNCTION(soundex, 1, 0, 0, soundexFunc ), |
- #endif |
- #ifndef SQLITE_OMIT_LOAD_EXTENSION |
- VFUNCTION(load_extension, 1, 0, 0, loadExt ), |
- VFUNCTION(load_extension, 2, 0, 0, loadExt ), |
- #endif |
+ FUNCTION(substr, 2, 0, 0, substrFunc ), |
+ FUNCTION(substr, 3, 0, 0, substrFunc ), |
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), |
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), |
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), |
@@ -1788,27 +1831,42 @@ void sqlite3RegisterGlobalFunctions(void){ |
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), |
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), |
- #ifdef SQLITE_CASE_SENSITIVE_LIKE |
+#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 |
+#else |
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), |
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), |
- #endif |
+#endif |
+#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 ), |
+ FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), |
}; |
- |
- int i; |
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); |
- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc); |
- |
- for(i=0; i<ArraySize(aBuiltinFunc); i++){ |
- sqlite3FuncDefInsert(pHash, &aFunc[i]); |
- } |
- sqlite3RegisterDateTimeFunctions(); |
#ifndef SQLITE_OMIT_ALTERTABLE |
sqlite3AlterFunctions(); |
#endif |
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) |
sqlite3AnalyzeFunctions(); |
#endif |
+ sqlite3RegisterDateTimeFunctions(); |
+ sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); |
+ |
+#if 0 /* Enable to print out how the built-in functions are hashed */ |
+ { |
+ 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; |
+ printf(" %s(%d)", p->zName, h); |
+ } |
+ printf("\n"); |
+ } |
+ } |
+#endif |
} |