diff options
author | drh <drh@noemail.net> | 2008-08-21 18:49:27 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-08-21 18:49:27 +0000 |
commit | 70a8ca3c1e3ceb0446908fea3e15ef06587b570a (patch) | |
tree | 6ac4d0650241f6a99c12e9fd17d169af84d89940 /src | |
parent | 801880f66cc3de3a30b36d6a2d38c49c08da3a75 (diff) | |
download | sqlite-70a8ca3c1e3ceb0446908fea3e15ef06587b570a.tar.gz sqlite-70a8ca3c1e3ceb0446908fea3e15ef06587b570a.zip |
Initialize the global built-in function table at start-time
instead of at compile-time. This is less prone to malfunction when
compile-time parameters very. (CVS 5583)
FossilOrigin-Name: ef6936e50adb9ebea39c890167403fff01bbb5ed
Diffstat (limited to 'src')
-rw-r--r-- | src/callback.c | 87 | ||||
-rw-r--r-- | src/func.c | 12 | ||||
-rw-r--r-- | src/global.c | 10 | ||||
-rw-r--r-- | src/main.c | 24 | ||||
-rw-r--r-- | src/sqliteInt.h | 29 |
5 files changed, 120 insertions, 42 deletions
diff --git a/src/callback.c b/src/callback.c index 90d9e594d..d25836b43 100644 --- a/src/callback.c +++ b/src/callback.c @@ -13,7 +13,7 @@ ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. ** -** $Id: callback.c,v 1.27 2008/08/20 14:49:24 danielk1977 Exp $ +** $Id: callback.c,v 1.28 2008/08/21 18:49:28 drh Exp $ */ #include "sqliteInt.h" @@ -261,6 +261,49 @@ static int matchQuality(FuncDef *p, int nArg, u8 enc){ } /* +** Search a FuncDefHash for a function with the given name. Return +** 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 */ +){ + FuncDef *p; + for(p=pHash->a[h]; p; p=p->pHash){ + if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){ + return p; + } + } + return 0; +} + +/* +** 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 */ +){ + FuncDef *pOther; + int nName = strlen(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 ){ + pDef->pNext = pOther->pNext; + pOther->pNext = pDef; + }else{ + pDef->pNext = 0; + pDef->pHash = pHash->a[h]; + pHash->a[h] = pDef; + } +} + + + +/* ** Locate a user function given a name, a number of arguments and a flag ** indicating whether the function prefers UTF-16 over UTF-8. Return a ** pointer to the FuncDef structure that defines that function, or return @@ -289,21 +332,24 @@ FuncDef *sqlite3FindFunction( int createFlag /* Create new entry if true and does not otherwise exist */ ){ FuncDef *p; /* Iterator variable */ - FuncDef *pFirst; /* First function with this name */ FuncDef *pBest = 0; /* Best match found so far */ - int bestmatch = 0; + int bestScore = 0; /* Score of best match */ + int h; /* Hash value */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); if( nArg<-1 ) nArg = -1; + h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a); - pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); - for(p=pFirst; p; p=p->pNext){ - int match = matchQuality(p, nArg, enc); - if( match>bestmatch ){ + + p = functionSearch(&db->aFunc, h, zName, nName); + while( p ){ + int score = matchQuality(p, nArg, enc); + if( score>bestScore ){ pBest = p; - bestmatch = match; + bestScore = score; } + p = p->pNext; } /* If the createFlag parameter is false and no match was found amongst @@ -311,16 +357,14 @@ FuncDef *sqlite3FindFunction( ** function to use. */ if( !createFlag && !pBest ){ - FuncDef *aFunc; - int nFunc; - int i; - nFunc = sqlite3GetBuiltinFunction(zName, nName, &aFunc); - for(i=0; i<nFunc; i++){ - int match = matchQuality(&aFunc[i], nArg, enc); - if( match>bestmatch ){ - pBest = &aFunc[i]; - bestmatch = match; + p = functionSearch(&sqlite3FuncBuiltins, h, zName, nName); + while( p ){ + int score = matchQuality(p, nArg, enc); + if( score>bestScore ){ + pBest = p; + bestScore = score; } + p = p->pNext; } } @@ -328,19 +372,14 @@ FuncDef *sqlite3FindFunction( ** exact match for the name, number of arguments and encoding, then add a ** new entry to the hash table and return it. */ - if( createFlag && bestmatch<6 && + if( createFlag && bestScore<6 && (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){ pBest->zName = (char *)&pBest[1]; pBest->nArg = nArg; - pBest->pNext = pFirst; pBest->iPrefEnc = enc; memcpy(pBest->zName, zName, nName); pBest->zName[nName] = 0; - if( pBest==sqlite3HashInsert(&db->aFunc,pBest->zName,nName,(void*)pBest) ){ - db->mallocFailed = 1; - sqlite3DbFree(db, pBest); - return 0; - } + sqlite3FuncDefInsert(&db->aFunc, pBest); } if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){ diff --git a/src/func.c b/src/func.c index 975f7dc81..0f4f0a6e1 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.197 2008/08/20 14:49:24 danielk1977 Exp $ +** $Id: func.c,v 1.198 2008/08/21 18:49:28 drh Exp $ */ #ifndef CREATE_BUILTIN_HASHTABLE @@ -1422,3 +1422,13 @@ static FuncDef aBuiltinFunc[] = { #endif }; +/* +** Build up the global built-in function table at initialization +** time. +*/ +void sqlite3RegisterGlobalFunctions(void){ + int i; + for(i=0; i<ArraySize(aBuiltinFunc); i++){ + sqlite3FuncDefInsert(&sqlite3FuncBuiltins, &aBuiltinFunc[i]); + } +} diff --git a/src/global.c b/src/global.c index fa59d4a84..2f0782e3f 100644 --- a/src/global.c +++ b/src/global.c @@ -12,7 +12,7 @@ ** ** This file contains definitions of global variables and contants. ** -** $Id: global.c,v 1.4 2008/07/28 19:34:53 drh Exp $ +** $Id: global.c,v 1.5 2008/08/21 18:49:28 drh Exp $ */ #include "sqliteInt.h" @@ -75,3 +75,11 @@ struct Sqlite3Config sqlite3Config = { 500, /* nLookaside */ /* Other fields all default to zero */ }; + + +/* +** Hash table for global functions - functions common to all +** database connections. After initialization, this table is +** read-only. +*/ +FuncDefHash sqlite3FuncBuiltins; diff --git a/src/main.c b/src/main.c index 42ca5cc13..9421a08ec 100644 --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.491 2008/08/20 16:35:10 drh Exp $ +** $Id: main.c,v 1.492 2008/08/21 18:49:28 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -147,6 +147,8 @@ int sqlite3_initialize(void){ sqlite3_mutex_enter(sqlite3Config.pInitMutex); if( sqlite3Config.isInit==0 && inProgress==0 ){ inProgress = 1; + memset(&sqlite3FuncBuiltins, 0, sizeof(sqlite3FuncBuiltins)); + sqlite3RegisterGlobalFunctions(); rc = sqlite3_os_init(); if( rc==SQLITE_OK ){ rc = sqlite3PcacheInitialize(); @@ -566,14 +568,17 @@ int sqlite3_close(sqlite3 *db){ sqlite3ResetInternalSchema(db, 0); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); - for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ - FuncDef *pFunc, *pNext; - for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){ - pNext = pFunc->pNext; - sqlite3DbFree(db, pFunc); + 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 ){ + pNext = p->pNext; + sqlite3DbFree(db, p); + p = pNext; + } } } - for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ CollSeq *pColl = (CollSeq *)sqliteHashData(i); /* Invoke any destructors registered for collation sequence user data. */ @@ -596,7 +601,6 @@ int sqlite3_close(sqlite3 *db){ sqlite3HashClear(&db->aModule); #endif - sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ if( db->pErr ){ sqlite3ValueFree(db->pErr); @@ -1371,6 +1375,9 @@ static const int aHardLimit[] = { #if SQLITE_MAX_VARIABLE_NUMBER<1 # error SQLITE_MAX_VARIABLE_NUMBER must be at least 1 #endif +#if SQLITE_MAX_COLUMN>32767 +# error SQLITE_MAX_COLUMN must not exceed 32767 +#endif /* @@ -1466,7 +1473,6 @@ static int openDatabase( | SQLITE_LoadExtension #endif ; - sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule, SQLITE_HASH_STRING, 0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1d1474a28..167b21cf4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.757 2008/08/20 16:35:10 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.758 2008/08/21 18:49:28 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -366,7 +366,7 @@ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ -typedef UINT8_TYPE i8; /* 1-byte signed integer */ +typedef INT8_TYPE i8; /* 1-byte signed integer */ /* ** Macros to determine whether the machine is big or little endian, @@ -455,6 +455,7 @@ typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FuncDef FuncDef; +typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct KeyClass KeyClass; @@ -593,6 +594,16 @@ struct LookasideSlot { }; /* +** A hash table for function definitions. +** +** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. +** Collisions are on the FuncDef.pHash chain. +*/ +struct FuncDefHash { + FuncDef *a[23]; /* Hash table for functions */ +}; + +/* ** Each database is an instance of the following structure. ** ** The sqlite.lastRowid records the last insert rowid generated by an @@ -688,7 +699,7 @@ struct sqlite3 { sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ #endif - Hash aFunc; /* All functions that can be in SQL exprs */ + FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ @@ -753,7 +764,7 @@ struct sqlite3 { ** points to a linked list of these structures. */ struct FuncDef { - i16 nArg; /* Number of arguments. -1 means unlimited */ + i8 nArg; /* Number of arguments. -1 means unlimited */ u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */ u8 needCollSeq; /* True if sqlite3GetFuncCollSeq() might be called */ u8 flags; /* Some combination of SQLITE_FUNC_* */ @@ -763,14 +774,15 @@ struct FuncDef { void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ void (*xFinalize)(sqlite3_context*); /* Aggregate finializer */ char *zName; /* SQL name of the function. */ + FuncDef *pHash; /* Next with a different name but the same hash */ }; /* ** Possible values for FuncDef.flags */ -#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ -#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ -#define SQLITE_FUNC_EPHEM 0x04 /* Ephermeral. Delete with VDBE */ +#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ +#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ +#define SQLITE_FUNC_EPHEM 0x04 /* Ephermeral. Delete with VDBE */ /* ** Each SQLite module (virtual table definition) is defined by an @@ -2127,9 +2139,11 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*); +void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int); void sqlite3RegisterBuiltinFunctions(sqlite3*); void sqlite3RegisterDateTimeFunctions(sqlite3*); +void sqlite3RegisterGlobalFunctions(void); int sqlite3GetBuiltinFunction(const char *, int, FuncDef **); #ifdef SQLITE_DEBUG int sqlite3SafetyOn(sqlite3*); @@ -2268,6 +2282,7 @@ void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3UpperToLower[]; extern struct Sqlite3Config sqlite3Config; +extern FuncDefHash sqlite3FuncBuiltins; #endif void sqlite3RootPageMoved(Db*, int, int); void sqlite3Reindex(Parse*, Token*, Token*); |