aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2008-08-21 18:49:27 +0000
committerdrh <drh@noemail.net>2008-08-21 18:49:27 +0000
commit70a8ca3c1e3ceb0446908fea3e15ef06587b570a (patch)
tree6ac4d0650241f6a99c12e9fd17d169af84d89940 /src
parent801880f66cc3de3a30b36d6a2d38c49c08da3a75 (diff)
downloadsqlite-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.c87
-rw-r--r--src/func.c12
-rw-r--r--src/global.c10
-rw-r--r--src/main.c24
-rw-r--r--src/sqliteInt.h29
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*);