Improvements to the application-defined function mechanism so that it is

more compact and runs faster, especially when the application defines
thousands of new SQL functions.

FossilOrigin-Name: 3201fbcc5105d23132e6b8b7ac825e66af4f8a39
This commit is contained in:
drh 2016-02-15 00:34:16 +00:00
parent e75a9eb9bb
commit 80738d9c3e
15 changed files with 189 additions and 182 deletions

View File

@ -1,5 +1,5 @@
C Provide\sSqlite3_SafeInit()\sand\sSqlite3_SafeUnload()\sentry\spoints\son\sthe\sTCL\ninterface,\sbut\shave\sthe\salways\sreturn\sTCL_ERROR,\sbecause\sthe\snon-standard\s\nTCL\sbuilds\son\sMacs\srequire\sthis.
D 2016-02-13T18:54:10.051
C Improvements\sto\sthe\sapplication-defined\sfunction\smechanism\sso\sthat\sit\sis\nmore\scompact\sand\sruns\sfaster,\sespecially\swhen\sthe\sapplication\sdefines\nthousands\sof\snew\sSQL\sfunctions.
D 2016-02-15T00:34:16.170
F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 30f075dc4f27a07abb76088946b2944178d85347
@ -284,9 +284,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 1fbb01c26c64528088f1df8015992fefda387889
F src/analyze.c fbf0e80d83cc893734e872f932f249a056b86e11
F src/attach.c c16c2648a577fa3def2adfa48c28901376389bc5
F src/alter.c 7603afbd61f55e7c644b8de4a42f33e58c0b7eaa
F src/analyze.c b148441c7d35b5514ec1a66f9df97be8fa4c68a1
F src/attach.c 07aa6e77c3906d46d4c36d7c81641dedd6adac91
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c 2869a76c03eb393ee795416e2387005553df72bc
F src/bitvec.c 1a78d450a17c5016710eec900bedfc5729bf9bdf
@ -295,17 +295,17 @@ F src/btree.c 4c8caaeed7878aafdb607c3d2bcbc365bb0d19a1
F src/btree.h 368ceeb4bd9312dc8df2ffd64b4b7dbcf4db5f8e
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
F src/build.c 54866fbafa09d494269bdefc79995eb7207003a6
F src/callback.c ed6c2a4a712eb7287ff64e20e3c23265dfb8a7ce
F src/callback.c 0643b8fb06c95a8977beb201b268210d4b131a22
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198
F src/date.c ca17321bc17cca8f40e0843edea4fafff974998e
F src/date.c 0b73e681c11fca867fec554750c07fe0d4e417c1
F src/dbstat.c b2ec6793eef97aebb4d171d490a4ffdfa9f2475c
F src/delete.c 48802aa3ee6339f576d074336d3ae1b5f40e240f
F src/expr.c fbf0706199aea23c54efe36b6932d8307c4eb872
F src/expr.c 9adb58153f6e943b703d43e9a1f67f77b5a75721
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 08edad1fce30f761f14b3997e89bad58f9f7f4e0
F src/func.c 86e55fee35b9577e485f47d9dd5c1d34cd513288
F src/global.c bd5a0af3f30b0c01be6db756c626cd3c33a3d260
F src/func.c 552d300265aed09eea21f68ac742a440550c0062
F src/global.c ded7b97efd16efda5062b65e857198e46c40e652
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@ -313,7 +313,7 @@ F src/insert.c 9ca97272e9f74ed0efddf3b4350ee12740cebbef
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c b1b0880fc474abfab89e737b0ecfde0bd7a60902
F src/loadext.c 84996d7d70a605597d79c1f1d7b2012a5fd34f2b
F src/main.c b67a45397b93b7ba8fbd6bfcb03423d245baed05
F src/main.c 17cfc8ba39fd86bc8201213140db53a65ff3cf2a
F src/malloc.c 337e9808b5231855fe28857950f4f60ae42c417f
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
@ -346,14 +346,14 @@ F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
F src/prepare.c c12b786713df3e8270c0f85f988c5359d8b4d87c
F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
F src/shell.c 0367440658104bf2ce8d8a9a5a713a4b11c9acbe
F src/sqlite.h.in f80c6ebd85588fc514bfedf3ecb00cec269cb410
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
F src/sqliteInt.h 04ca5b3cdb3bcf87ba6300d5d36b51498f65f28c
F src/sqliteInt.h ddd4a48f3ac2a423f003027e73bd8422bfa4d991
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
@ -411,7 +411,7 @@ F src/treeview.c dc39ccf04e9331237388b9cb73289c9d87ea050b
F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
F src/update.c a7eeeaffad59c6506f01303a071dac11de8269ca
F src/utf.c 10cc2519e82e3369344d0969ad4b1a333dc86d18
F src/util.c 49ce0a65306c1c51d61cb5bc214c71cb62452de6
F src/util.c 8073bbdab9cc7209f6741bd44264ede606cbadc6
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c c193299e595a13eba247738e22fce25c49346a6c
F src/vdbe.h c743791f723049db94f009e3e30958952bc2d512
@ -419,7 +419,7 @@ F src/vdbeInt.h 4b69d5451bcadd473e745af53ef1e8abfdce0a79
F src/vdbeapi.c 9324f6baee1a1b2284c6543e98f916888a81e459
F src/vdbeaux.c deae5d3bd45da0e57c7d9e1d7436333d142dc3bb
F src/vdbeblob.c 3b570b730109e8f653d9d2081649f6e7015113db
F src/vdbemem.c 68fcfac37dc6601d98c32cc5adee4d39f2c1b7b4
F src/vdbemem.c e0dbb7bb9c2ec566c53c6575b4f51b3fcd426811
F src/vdbesort.c ef3c6d1f1a7d44cf67bb2bee59ea3d1fe5bad174
F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
F src/vtab.c bef51b4f693d82b4b0184457faa8625654534091
@ -1427,7 +1427,10 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh ef6ebc6fd8d2dc35db3b622015c16a023d4fef4f
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P a049fbbde5da2e43d41aa8c2b41f9eb21507ac76
R 0ed7109e4c77d1cb323166614bc90c67
P 37ec3015ec95035d31e3672f520908a0d36c9d67
R 8daa9c28aeb9b7a90a9f45db47e6f0fa
T *branch * many-app-functions
T *sym-many-app-functions *
T -sym-trunk *
U drh
Z 0875f4eabfb763252145d2214f48fc91
Z 4df4dc22cfe3910711fb118d648968ac

View File

@ -1 +1 @@
37ec3015ec95035d31e3672f520908a0d36c9d67
3201fbcc5105d23132e6b8b7ac825e66af4f8a39

View File

@ -229,7 +229,7 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
static FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
@ -238,13 +238,7 @@ void sqlite3AlterFunctions(void){
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
for(i=0; i<ArraySize(aAlterTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
/*

View File

@ -481,8 +481,7 @@ static const FuncDef statInitFuncdef = {
statInit, /* xSFunc */
0, /* xFinalize */
"stat_init", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
#ifdef SQLITE_ENABLE_STAT4
@ -781,8 +780,7 @@ static const FuncDef statPushFuncdef = {
statPush, /* xSFunc */
0, /* xFinalize */
"stat_push", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
@ -927,8 +925,7 @@ static const FuncDef statGetFuncdef = {
statGet, /* xSFunc */
0, /* xFinalize */
"stat_get", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){

View File

@ -392,8 +392,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
detachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_detach", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@ -412,8 +411,7 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
attachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_attach", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}

View File

@ -284,14 +284,12 @@ static int matchQuality(
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
const char *zFunc, /* Name of function */
int nFunc /* Number of bytes in zFunc */
const char *zFunc /* Name of function */
){
FuncDef *p;
for(p=pHash->a[h]; p; p=p->pHash){
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
if( sqlite3StrICmp(p->zName, zFunc)==0 ){
return p;
}
}
@ -301,23 +299,26 @@ static FuncDef *functionSearch(
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
void sqlite3FuncDefInsert(
FuncDefHash *pHash, /* The hash table into which to insert */
FuncDef *pDef /* The function definition to insert */
void sqlite3InsertBuiltinFuncs(
FuncDef *aDef, /* List of global functions to be inserted */
int nDef /* Length of the apDef[] list */
){
FuncDef *pOther;
int nName = sqlite3Strlen30(pDef->zName);
u8 c1 = (u8)pDef->zName[0];
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
pOther = functionSearch(pHash, h, pDef->zName, nName);
if( pOther ){
assert( pOther!=pDef && pOther->pNext!=pDef );
pDef->pNext = pOther->pNext;
pOther->pNext = pDef;
}else{
pDef->pNext = 0;
pDef->pHash = pHash->a[h];
pHash->a[h] = pDef;
int i;
for(i=0; i<nDef; i++){
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
pOther = functionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
aDef[i].pNext = pOther->pNext;
pOther->pNext = &aDef[i];
}else{
aDef[i].pNext = 0;
aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
sqlite3BuiltinFunctions.a[h] = &aDef[i];
}
}
}
@ -344,8 +345,7 @@ void sqlite3FuncDefInsert(
*/
FuncDef *sqlite3FindFunction(
sqlite3 *db, /* An open database */
const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */
const char *zName, /* Name of the function. zero-terminated */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
u8 createFlag /* Create new entry if true and does not otherwise exist */
@ -354,14 +354,15 @@ FuncDef *sqlite3FindFunction(
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
int nName; /* Length of the name */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
nName = sqlite3Strlen30(zName);
/* First search for a match amongst the application-defined functions.
*/
p = functionSearch(&db->aFunc, h, zName, nName);
p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@ -384,9 +385,9 @@ FuncDef *sqlite3FindFunction(
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
p = functionSearch(pHash, h, zName, nName);
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@ -403,12 +404,19 @@ FuncDef *sqlite3FindFunction(
*/
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;
sqlite3FuncDefInsert(&db->aFunc, pBest);
memcpy(pBest->zName, zName, nName+1);
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
sqlite3OomFault(db);
return 0;
}else{
pBest->pNext = pOther;
}
}
if( pBest && (pBest->xSFunc || createFlag) ){

View File

@ -1136,7 +1136,7 @@ static void currentTimeFunc(
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
DFUNCTION(date, -1, 0, 0, dateFunc ),
@ -1152,11 +1152,5 @@ void sqlite3RegisterDateTimeFunctions(void){
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
for(i=0; i<ArraySize(aDateTimeFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}

View File

@ -2888,7 +2888,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
u32 constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
@ -2904,10 +2903,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
if( pDef==0 || pDef->xFinalize!=0 ){
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
break;
}
@ -4132,7 +4130,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
pExpr->u.zToken,
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;

View File

@ -1611,7 +1611,7 @@ 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 ){
@ -1624,8 +1624,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;
}
@ -1673,9 +1672,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;
}
@ -1699,7 +1696,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.
@ -1707,8 +1704,27 @@ 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),
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@ -1726,8 +1742,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 ),
@ -1738,40 +1752,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 ),
@ -1789,20 +1785,32 @@ void sqlite3RegisterGlobalFunctions(void){
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#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
}

View File

@ -219,7 +219,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
** database connections. After initialization, this table is
** read-only.
*/
SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
FuncDefHash sqlite3BuiltinFunctions;
/*
** Constant tokens for values 0 and 1.

View File

@ -218,7 +218,6 @@ int sqlite3_initialize(void){
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
sqlite3GlobalConfig.inProgress = 1;
#ifdef SQLITE_ENABLE_SQLLOG
{
@ -226,8 +225,8 @@ int sqlite3_initialize(void){
sqlite3_init_sqllog();
}
#endif
memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
sqlite3RegisterGlobalFunctions();
memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
sqlite3RegisterBuiltinFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
@ -958,7 +957,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding.
*/
static void functionDestroy(sqlite3 *db, FuncDef *p){
FuncDestructor *pDestructor = p->pDestructor;
FuncDestructor *pDestructor = p->u.pDestructor;
if( pDestructor ){
pDestructor->nRef--;
if( pDestructor->nRef==0 ){
@ -1140,18 +1139,17 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
*/
sqlite3ConnectionClosed(db);
for(j=0; j<ArraySize(db->aFunc.a); j++){
FuncDef *pNext, *pHash, *p;
for(p=db->aFunc.a[j]; p; p=pHash){
pHash = p->pHash;
while( p ){
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}
}
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
FuncDef *pNext, *p;
p = sqliteHashData(i);
do{
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}while( p );
}
sqlite3HashClear(&db->aFunc);
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* Invoke any destructors registered for collation sequence user data. */
@ -1630,7 +1628,7 @@ int sqlite3CreateFunc(
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
@ -1642,7 +1640,7 @@ int sqlite3CreateFunc(
}
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
assert(p || db->mallocFailed);
if( !p ){
return SQLITE_NOMEM;
@ -1655,7 +1653,7 @@ int sqlite3CreateFunc(
if( pDestructor ){
pDestructor->nRef++;
}
p->pDestructor = pDestructor;
p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xSFunc = xSFunc ? xSFunc : xStep;
@ -1770,7 +1768,6 @@ int sqlite3_overload_function(
const char *zName,
int nArg
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
@ -1779,7 +1776,7 @@ int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
@ -2361,8 +2358,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@ -2886,7 +2883,7 @@ static int openDatabase(
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
sqlite3RegisterBuiltinFunctions(db);
sqlite3RegisterPerConnectionBuiltinFunctions(db);
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.

View File

@ -656,9 +656,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
notValid(pParse, pNC, "functions", NC_PartIdx);
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{

View File

@ -1109,13 +1109,15 @@ struct LookasideSlot {
};
/*
** A hash table for function definitions.
** A hash table for built-in function definitions. (Application-defined
** functions use a regular table table from hash.h.)
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
** Collisions are on the FuncDef.pHash chain.
** Collisions are on the FuncDef.u.pHash chain.
*/
#define SQLITE_FUNC_HASH_SZ 23
struct FuncDefHash {
FuncDef *a[23]; /* Hash table for functions */
FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
};
#ifdef SQLITE_USER_AUTHENTICATION
@ -1243,7 +1245,7 @@ struct sqlite3 {
VTable **aVTrans; /* Virtual tables with open transactions */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
FuncDefHash aFunc; /* Hash table of connection functions */
Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
Db aDbStatic[2]; /* Static space for the 2 default backends */
@ -1370,20 +1372,26 @@ struct sqlite3 {
/*
** Each SQL function is defined by an instance of the following
** structure. A pointer to this structure is stored in the sqlite.aFunc
** hash table. When multiple functions have the same name, the hash table
** points to a linked list of these structures.
** structure. For global built-in functions (ex: substr(), max(), count())
** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
** For per-connection application-defined functions, a pointer to this
** structure is held in the db->aHash hash table.
**
** The u.pHash field is used by the global built-ins. The u.pDestructor
** field is used by per-connection app-def functions.
*/
struct FuncDef {
i16 nArg; /* Number of arguments. -1 means unlimited */
i8 nArg; /* Number of arguments. -1 means unlimited */
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
char *zName; /* SQL name of the function. */
FuncDef *pHash; /* Next with a different name but the same hash */
FuncDestructor *pDestructor; /* Reference counted destructor function */
union {
FuncDef *pHash; /* Next with a different name but the same hash */
FuncDestructor *pDestructor; /* Reference counted destructor function */
} u;
};
/*
@ -1463,28 +1471,28 @@ struct FuncDestructor {
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
pArg, 0, xFunc, 0, #zName, 0, 0}
pArg, 0, xFunc, 0, #zName, }
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
(void *)arg, 0, likeFunc, 0, #zName, 0, 0}
(void *)arg, 0, likeFunc, 0, #zName, {0} }
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
/*
** All current savepoints are stored in a linked list starting at
@ -3225,7 +3233,7 @@ int sqlite3IsIdChar(u8);
/*
** Internal function prototypes
*/
#define sqlite3StrICmp sqlite3_stricmp
int sqlite3StrICmp(const char*,const char*);
int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp
@ -3572,11 +3580,11 @@ void sqlite3SelectSetName(Select*,const char*);
#else
# define sqlite3SelectSetName(A,B)
#endif
void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
void sqlite3RegisterBuiltinFunctions(sqlite3*);
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
void sqlite3RegisterBuiltinFunctions(void);
void sqlite3RegisterDateTimeFunctions(void);
void sqlite3RegisterGlobalFunctions(void);
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
int sqlite3SafetyCheckOk(sqlite3*);
int sqlite3SafetyCheckSickOrOk(sqlite3*);
void sqlite3ChangeCookie(Parse*, int);
@ -3737,7 +3745,7 @@ extern const unsigned char sqlite3UpperToLower[];
extern const unsigned char sqlite3CtypeMap[];
extern const Token sqlite3IntTokens[];
extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
extern FuncDefHash sqlite3BuiltinFunctions;
#ifndef SQLITE_OMIT_WSD
extern int sqlite3PendingByte;
#endif

View File

@ -256,16 +256,25 @@ void sqlite3TokenInit(Token *p, char *z){
** independence" that SQLite uses internally when comparing identifiers.
*/
int sqlite3_stricmp(const char *zLeft, const char *zRight){
register unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
return 1;
}
return sqlite3StrICmp(zLeft, zRight);
}
int sqlite3StrICmp(const char *zLeft, const char *zRight){
unsigned char *a, *b;
int c;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
return UpperToLower[*a] - UpperToLower[*b];
for(;;){
c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
if( c || *a==0 ) break;
a++;
b++;
}
return c;
}
int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;

View File

@ -1186,7 +1186,6 @@ static int valueFromFunction(
FuncDef *pFunc = 0; /* Function definition */
sqlite3_value *pVal = 0; /* New value */
int rc = SQLITE_OK; /* Return code */
int nName; /* Size of function name in bytes */
ExprList *pList = 0; /* Function arguments */
int i; /* Iterator variable */
@ -1194,8 +1193,7 @@ static int valueFromFunction(
assert( (p->flags & EP_TokenOnly)==0 );
pList = p->x.pList;
if( pList ) nVal = pList->nExpr;
nName = sqlite3Strlen30(p->u.zToken);
pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
@ -1457,15 +1455,10 @@ static void recordFunc(
** Register built-in functions used to help read ANALYZE data.
*/
void sqlite3AnalyzeFunctions(void){
static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
static FuncDef aAnalyzeTableFuncs[] = {
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
}
/*