diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 131 | ||||
-rw-r--r-- | src/date.c | 14 | ||||
-rw-r--r-- | src/expr.c | 87 | ||||
-rw-r--r-- | src/func.c | 133 | ||||
-rw-r--r-- | src/main.c | 60 | ||||
-rw-r--r-- | src/md5.c | 5 | ||||
-rw-r--r-- | src/select.c | 5 | ||||
-rw-r--r-- | src/sqlite.h.in | 33 | ||||
-rw-r--r-- | src/sqliteInt.h | 7 | ||||
-rw-r--r-- | src/tclsqlite.c | 8 | ||||
-rw-r--r-- | src/test1.c | 33 | ||||
-rw-r--r-- | src/trigger.c | 9 | ||||
-rw-r--r-- | src/vdbe.c | 14 | ||||
-rw-r--r-- | src/vdbeInt.h | 4 | ||||
-rw-r--r-- | src/vdbeapi.c | 54 | ||||
-rw-r--r-- | src/vdbeaux.c | 96 | ||||
-rw-r--r-- | src/vdbemem.c | 65 |
17 files changed, 457 insertions, 301 deletions
diff --git a/src/build.c b/src/build.c index 5823b2477..0af83089a 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.217 2004/06/12 00:42:35 danielk1977 Exp $ +** $Id: build.c,v 1.218 2004/06/12 09:25:12 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -480,6 +480,21 @@ int sqlite3TwoPartName( } /* +** This routine is used to check if the UTF-8 string zName is a legal +** unqualified name for a new schema object (table, index, view or +** trigger). All names are legal except those that begin with the string +** "sqlite_" (in upper, lower or mixed case). This portion of the namespace +** is reserved for internal use. +*/ +int sqlite3CheckObjectName(Parse *pParse, const char *zName){ + if( !pParse->db->init.busy && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ + sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +/* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response ** to a CREATE TABLE statement. In particular, this routine is called @@ -541,6 +556,9 @@ void sqlite3StartTable( pParse->sNameToken = *pName; zName = sqlite3TableNameFromToken(pName); + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + return; + } if( zName==0 ) return; if( db->init.iDb==1 ) isTemp = 1; #ifndef SQLITE_OMIT_AUTHORIZATION @@ -1854,7 +1872,7 @@ void sqlite3CreateIndex( Token *pEnd /* The ")" that closes the CREATE INDEX statement */ ){ Table *pTab = 0; /* Table to be indexed */ - Index *pIndex; /* The index to be created */ + Index *pIndex = 0; /* The index to be created */ char *zName = 0; int i, j; Token nullId; /* Fake token for an empty ID list */ @@ -1927,30 +1945,33 @@ void sqlite3CreateIndex( ** dealing with a primary key or UNIQUE constraint. We have to invent our ** own name. */ - if( pName && !db->init.busy ){ - Index *pISameName; /* Another index with the same name */ - Table *pTSameName; /* A table with same name as the index */ - zName = sqliteStrNDup(pName->z, pName->n); + if( pName ){ + zName = sqlite3TableNameFromToken(pName); if( zName==0 ) goto exit_create_index; - if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){ - sqlite3ErrorMsg(pParse, "index %s already exists", zName); + if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } - if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){ - sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); - goto exit_create_index; + if( !db->init.busy ){ + Index *pISameName; /* Another index with the same name */ + Table *pTSameName; /* A table with same name as the index */ + if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); + goto exit_create_index; + } + if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){ + sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); + goto exit_create_index; + } } }else if( pName==0 ){ char zBuf[30]; int n; Index *pLoop; for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} - sprintf(zBuf,"%d)",n); + sprintf(zBuf,"_%d",n); zName = 0; - sqlite3SetString(&zName, "(", pTab->zName, " autoindex ", zBuf, (char*)0); + sqlite3SetString(&zName, "sqlite_autoindex_", pTab->zName, zBuf, (char*)0); if( zName==0 ) goto exit_create_index; - }else{ - zName = sqliteStrNDup(pName->z, pName->n); } /* Check for authorization to create an index. @@ -2006,7 +2027,6 @@ void sqlite3CreateIndex( if( j>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "table %s has no column named %s", pTab->zName, pList->a[i].zName); - sqliteFree(pIndex); goto exit_create_index; } pIndex->aiColumn[i] = j; @@ -2025,6 +2045,46 @@ void sqlite3CreateIndex( } pIndex->keyInfo.nField = pList->nExpr; + if( pTab==pParse->pNewTable ){ + /* This routine has been called to create an automatic index as a + ** result of a PRIMARY KEY or UNIQUE clause on a column definition, or + ** a PRIMARY KEY or UNIQUE clause following the column definitions. + ** i.e. one of: + ** + ** CREATE TABLE t(x PRIMARY KEY, y); + ** CREATE TABLE t(x, y, UNIQUE(x, y)); + ** + ** Either way, check to see if the table already has such an index. If + ** so, don't bother creating this one. This only applies to + ** automatically created indices. Users can do as they wish with + ** explicit indices. + */ + Index *pIdx; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int k; + assert( pIdx->onError!=OE_None ); + assert( pIdx->autoIndex ); + assert( pIndex->onError!=OE_None ); + + if( pIdx->nColumn!=pIndex->nColumn ) continue; + for(k=0; k<pIdx->nColumn; k++){ + if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; + if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break; + } + if( k==pIdx->nColumn ){ + /* FIX ME: It's possible the onError of the old index should be + ** adjusted. For example in the statement: + ** + ** CREATE TABLE t (x UNIQUE, UNIQUE(x) ON CONFLICT ROLLBACK); + ** + ** The Index.onError should be upgraded from OE_Abort to + ** OE_Rollback when the second UNIQUE is parsed. + */ + goto exit_create_index; + } + } + } + /* Link the new Index structure to its table and to the other ** in-memory database structures. */ @@ -2034,30 +2094,11 @@ void sqlite3CreateIndex( pIndex->zName, strlen(pIndex->zName)+1, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ - sqliteFree(pIndex); goto exit_create_index; } db->flags |= SQLITE_InternChanges; } - /* When adding an index to the list of indices for a table, make - ** sure all indices labeled OE_Replace come after all those labeled - ** OE_Ignore. This is necessary for the correct operation of UPDATE - ** and INSERT. - */ - if( onError!=OE_Replace || pTab->pIndex==0 - || pTab->pIndex->onError==OE_Replace){ - pIndex->pNext = pTab->pIndex; - pTab->pIndex = pIndex; - }else{ - Index *pOther = pTab->pIndex; - while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ - pOther = pOther->pNext; - } - pIndex->pNext = pOther->pNext; - pOther->pNext = pIndex; - } - /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" table on the disk. So do not write to the disk ** again. Extract the table number from the db->init.newTnum field. @@ -2145,8 +2186,28 @@ void sqlite3CreateIndex( } } + /* When adding an index to the list of indices for a table, make + ** sure all indices labeled OE_Replace come after all those labeled + ** OE_Ignore. This is necessary for the correct operation of UPDATE + ** and INSERT. + */ + if( onError!=OE_Replace || pTab->pIndex==0 + || pTab->pIndex->onError==OE_Replace){ + pIndex->pNext = pTab->pIndex; + pTab->pIndex = pIndex; + }else{ + Index *pOther = pTab->pIndex; + while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ + pOther = pOther->pNext; + } + pIndex->pNext = pOther->pNext; + pOther->pNext = pIndex; + } + pIndex = 0; + /* Clean up before exiting */ exit_create_index: + if( pIndex ) sqliteFree(pIndex); sqlite3ExprListDelete(pList); /* sqlite3SrcListDelete(pTable); */ sqliteFree(zName); diff --git a/src/date.c b/src/date.c index 51ffb3410..e2c502bc1 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.28 2004/06/12 00:42:35 danielk1977 Exp $ +** $Id: date.c,v 1.29 2004/06/12 09:25:14 danielk1977 Exp $ ** ** NOTES: ** @@ -692,7 +692,7 @@ static void datetimeFunc( computeYMD_HMS(&x); sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); - sqlite3_result_text(context, zBuf, -1, 1); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } @@ -711,7 +711,7 @@ static void timeFunc( char zBuf[100]; computeHMS(&x); sprintf(zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); - sqlite3_result_text(context, zBuf, -1, 1); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } @@ -730,7 +730,7 @@ static void dateFunc( char zBuf[100]; computeYMD(&x); sprintf(zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); - sqlite3_result_text(context, zBuf, -1, 1); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } @@ -854,7 +854,7 @@ static void strftimeFunc( } } z[j] = 0; - sqlite3_result_text(context, z, -1, 1); + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); if( z!=zBuf ){ sqliteFree(z); } @@ -885,7 +885,7 @@ void sqlite3RegisterDateTimeFunctions(sqlite *db){ int i; for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){ - sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, 0, 0, 0, - aFuncs[i].xFunc, 0, 0); + sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg, + SQLITE_UTF8, 0, 0, aFuncs[i].xFunc, 0, 0); } } diff --git a/src/expr.c b/src/expr.c index 4c80f4400..45401649a 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.140 2004/06/12 00:42:35 danielk1977 Exp $ +** $Id: expr.c,v 1.141 2004/06/12 09:25:14 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1012,12 +1012,12 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; - int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; + int enc = pParse->db->enc; getFunctionName(pExpr, &zId, &nId); - pDef = sqlite3FindFunction(pParse->db, zId, nId, n, iPrefEnc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); if( pDef==0 ){ - pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, iPrefEnc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ @@ -1280,10 +1280,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ const char *zId; int p2 = 0; int i; - int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; + u8 enc = pParse->db->enc; CollSeq *pColl = 0; getFunctionName(pExpr, &zId, &nId); - pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, iPrefEnc, 0); + pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); assert( pDef!=0 ); nExpr = sqlite3ExprCodeExprList(pParse, pList); for(i=0; i<nExpr && i<32; i++){ @@ -1296,7 +1296,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ } if( pDef->needCollSeq ){ if( !pColl ) pColl = pParse->db->pDfltColl; - sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, pColl, P3_COLLSEQ); + sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); } sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF); break; @@ -1724,14 +1724,14 @@ int sqlite3ExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ } } if( i>=pParse->nAgg ){ - int iPrefEnc = (pParse->db->enc==SQLITE_UTF8)?0:1; + u8 enc = pParse->db->enc; i = appendAggInfo(pParse); if( i<0 ) return 1; pParse->aAgg[i].isAgg = 1; pParse->aAgg[i].pExpr = pExpr; pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db, pExpr->token.z, pExpr->token.n, - pExpr->pList ? pExpr->pList->nExpr : 0, iPrefEnc, 0); + pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); } pExpr->iAgg = i; break; @@ -1781,53 +1781,68 @@ FuncDef *sqlite3FindFunction( const char *zName, /* Name of the function. Not null-terminated */ int nName, /* Number of characters in the name */ int nArg, /* Number of arguments. -1 means any number */ - int eTextRep, /* True to retrieve UTF-16 versions. */ + u8 enc, /* Preferred text encoding */ 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 matchqual = 0; + int bestmatch = 0; - /* Normalize argument values to simplify comparisons below. */ - if( eTextRep ) eTextRep = 1; + + assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); if( nArg<-1 ) nArg = -1; pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName); for(p=pFirst; p; p=p->pNext){ - if( 1 || p->xFunc || p->xStep ){ - if( p->nArg==nArg && p->iPrefEnc==eTextRep ){ - /* A perfect match. */ - pBest = p; - matchqual = 4; - break; + /* During the search for the best function definition, bestmatch is set + ** as follows to indicate the quality of the match with the definition + ** pointed to by pBest: + ** + ** 0: pBest is NULL. No match has been found. + ** 1: A variable arguments function that prefers UTF-8 when a UTF-16 + ** encoding is requested, or vice versa. + ** 2: A variable arguments function that uses UTF-16BE when UTF-16LE is + ** requested, or vice versa. + ** 3: A variable arguments function using the same text encoding. + ** 4: A function with the exact number of arguments requested that + ** prefers UTF-8 when a UTF-16 encoding is requested, or vice versa. + ** 5: A function with the exact number of arguments requested that + ** prefers UTF-16LE when UTF-16BE is requested, or vice versa. + ** 6: An exact match. + ** + ** A larger value of 'matchqual' indicates a more desirable match. + */ + if( p->nArg==-1 || p->nArg==nArg || nArg==-1 ){ + int match = 1; /* Quality of this match */ + if( p->nArg==nArg || nArg==-1 ){ + match = 4; } - if( p->nArg==nArg ){ - /* Number of arguments matches, but not the text encoding */ - pBest = p; - matchqual = 3; + if( enc==p->iPrefEnc ){ + match += 2; } - else if( (p->nArg<0) || (nArg<0) ){ - if( matchqual<2 && p->iPrefEnc==eTextRep ){ - /* Matched a varargs function with correct text encoding */ - pBest = p; - matchqual = 2; - } - if( matchqual<1 ){ - /* Matched a varargs function with incorrect text encoding */ - pBest = p; - matchqual = 1; - } + else if( (enc==SQLITE_UTF16LE && p->iPrefEnc==SQLITE_UTF16BE) || + (enc==SQLITE_UTF16BE && p->iPrefEnc==SQLITE_UTF16LE) ){ + match += 1; + } + + if( match>bestmatch ){ + pBest = p; + bestmatch = match; } } } - if( createFlag && matchqual<4 && + /* If the createFlag parameter is true, and the seach did not reveal an + ** 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 && (pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){ pBest->nArg = nArg; pBest->pNext = pFirst; pBest->zName = (char*)&pBest[1]; - pBest->iPrefEnc = eTextRep; + pBest->iPrefEnc = enc; memcpy(pBest->zName, zName, nName); pBest->zName[nName] = 0; sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest); diff --git a/src/func.c b/src/func.c index 394f7f173..534486e49 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.67 2004/06/12 00:42:35 danielk1977 Exp $ +** $Id: func.c,v 1.68 2004/06/12 09:25:14 danielk1977 Exp $ */ #include <ctype.h> #include <math.h> @@ -75,7 +75,7 @@ static void typeofFunc( case SQLITE_FLOAT: z = "real"; break; case SQLITE_BLOB: z = "blob"; break; } - sqlite3_result_text(context, z, -1, 0); + sqlite3_result_text(context, z, -1, SQLITE_STATIC); } /* @@ -174,7 +174,7 @@ static void substrFunc( } while( z[i] && (z[i]&0xc0)==0x80 ){ i++; p2++; } if( p2<0 ) p2 = 0; - sqlite3_result_text(context, &z[p1], p2, 1); + sqlite3_result_text(context, &z[p1], p2, SQLITE_TRANSIENT); } /* @@ -194,7 +194,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; r = sqlite3_value_double(argv[0]); sprintf(zBuf,"%.*f",n,r); - sqlite3_result_text(context, zBuf, -1, 1); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } /* @@ -210,7 +210,7 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ for(i=0; z[i]; i++){ if( islower(z[i]) ) z[i] = toupper(z[i]); } - sqlite3_result_text(context, z, -1, 1); + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); sqliteFree(z); } static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ @@ -223,7 +223,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ for(i=0; z[i]; i++){ if( isupper(z[i]) ) z[i] = tolower(z[i]); } - sqlite3_result_text(context, z, -1, 1); + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); sqliteFree(z); } @@ -586,7 +586,7 @@ static void versionFunc( int argc, sqlite3_value **argv ){ - sqlite3_result_text(context, sqlite3_version, -1, 0); + sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); } /* @@ -604,7 +604,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ if( argc<1 ) return; switch( sqlite3_value_type(argv[0]) ){ case SQLITE_NULL: { - sqlite3_result_text(context, "NULL", 4, 0); + sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); break; } case SQLITE_INTEGER: @@ -634,7 +634,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ zText[(nBlob*2)+3] = '\0'; zText[0] = 'X'; zText[1] = '\''; - sqlite3_result_text(context, zText, -1, 1); + sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); sqliteFree(zText); } break; @@ -656,7 +656,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ } z[j++] = '\''; z[j] = 0; - sqlite3_result_text(context, z, j, 1); + sqlite3_result_text(context, z, j, SQLITE_TRANSIENT); sqliteFree(z); } } @@ -695,9 +695,9 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv zResult[j++] = '0'; } zResult[j] = 0; - sqlite3_result_text(context, zResult, 4, 1); + sqlite3_result_text(context, zResult, 4, SQLITE_TRANSIENT); }else{ - sqlite3_result_text(context, "?000", 4, 0); + sqlite3_result_text(context, "?000", 4, SQLITE_STATIC); } } #endif @@ -741,7 +741,49 @@ static void randStr(sqlite3_context *context, int argc, sqlite3_value **argv){ zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)]; } zBuf[n] = 0; - sqlite3_result_text(context, zBuf, n, 1); + sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT); +} + +/* +** The following two SQL functions are used to test returning a text +** result with a destructor. Function 'test_destructor' takes one argument +** and returns the same argument interpreted as TEXT. A destructor is +** passed with the sqlite3_result_text() call. +** +** SQL function 'test_destructor_count' returns the number of outstanding +** allocations made by 'test_destructor'; +** +** WARNING: Not threadsafe. +*/ +static int test_destructor_count_var = 0; +static void destructor(void *p){ + char *zVal = (char *)p; + assert(zVal); + zVal--; + sqliteFree(zVal); + test_destructor_count_var--; +} +static void test_destructor( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + char *zVal; + test_destructor_count_var++; + assert( nArg==1 ); + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + zVal = sqliteMalloc(sqlite3_value_bytes(argv[0]) + 2); + assert( zVal ); + zVal++; + strcpy(zVal, sqlite3_value_text(argv[0])); + sqlite3_result_text(pCtx, zVal, -1, destructor); +} +static void test_destructor_count( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **argv +){ + sqlite3_result_int(pCtx, test_destructor_count_var); } #endif @@ -905,37 +947,40 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){ u8 needCollSeq; void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { - { "min", -1, 0, 0, 1, minmaxFunc }, - { "min", 0, 0, 0, 1, 0 }, - { "max", -1, 2, 0, 1, minmaxFunc }, - { "max", 0, 2, 0, 1, 0 }, - { "typeof", 1, 0, 0, 0, typeofFunc }, - { "length", 1, 0, 0, 0, lengthFunc }, - { "substr", 3, 0, 0, 0, substrFunc }, - { "abs", 1, 0, 0, 0, absFunc }, - { "round", 1, 0, 0, 0, roundFunc }, - { "round", 2, 0, 0, 0, roundFunc }, - { "upper", 1, 0, 0, 0, upperFunc }, - { "lower", 1, 0, 0, 0, lowerFunc }, - { "coalesce", -1, 0, 0, 0, ifnullFunc }, - { "coalesce", 0, 0, 0, 0, 0 }, - { "coalesce", 1, 0, 0, 0, 0 }, - { "ifnull", 2, 0, 0, 1, ifnullFunc }, - { "random", -1, 0, 0, 0, randomFunc }, - { "like", 2, 0, 0, 0, likeFunc }, /* UTF-8 */ - { "like", 2, 2, 1, 0, likeFunc }, /* UTF-16 */ - { "glob", 2, 0, 0, 0, globFunc }, - { "nullif", 2, 0, 0, 0, nullifFunc }, - { "sqlite_version", 0, 0, 0, 0, versionFunc}, - { "quote", 1, 0, 0, 0, quoteFunc }, - { "last_insert_rowid", 0, 1, 0, 0, last_insert_rowid }, - { "change_count", 0, 1, 0, 0, change_count }, - { "last_statement_change_count", 0, 1, 0, 0, last_statement_change_count }, + { "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc }, + { "min", 0, 0, SQLITE_UTF8, 1, 0 }, + { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc }, + { "max", 0, 2, SQLITE_UTF8, 1, 0 }, + { "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc }, + { "length", 1, 0, SQLITE_UTF8, 0, lengthFunc }, + { "substr", 3, 0, SQLITE_UTF8, 0, substrFunc }, + { "abs", 1, 0, SQLITE_UTF8, 0, absFunc }, + { "round", 1, 0, SQLITE_UTF8, 0, roundFunc }, + { "round", 2, 0, SQLITE_UTF8, 0, roundFunc }, + { "upper", 1, 0, SQLITE_UTF8, 0, upperFunc }, + { "lower", 1, 0, SQLITE_UTF8, 0, lowerFunc }, + { "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc }, + { "coalesce", 0, 0, SQLITE_UTF8, 0, 0 }, + { "coalesce", 1, 0, SQLITE_UTF8, 0, 0 }, + { "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc }, + { "random", -1, 0, SQLITE_UTF8, 0, randomFunc }, + { "like", 2, 0, SQLITE_UTF8, 0, likeFunc }, + { "like", 2, 2, SQLITE_UTF16,0, likeFunc }, + { "glob", 2, 0, SQLITE_UTF8, 0, globFunc }, + { "nullif", 2, 0, SQLITE_UTF8, 0, nullifFunc }, + { "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc}, + { "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc }, + { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid }, + { "change_count", 0, 1, SQLITE_UTF8, 0, change_count }, + { "last_statement_change_count", 0, 1, SQLITE_UTF8, 0, + last_statement_change_count }, #ifdef SQLITE_SOUNDEX - { "soundex", 1, 0, 0, 0, soundexFunc}, + { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc}, #endif #ifdef SQLITE_TEST - { "randstr", 2, 0, 0, 0, randStr }, + { "randstr", 2, 0, SQLITE_UTF8, 0, randStr }, + { "test_destructor", 1, 0, SQLITE_UTF8, 0, test_destructor}, + { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count}, #endif }; static struct { @@ -980,11 +1025,11 @@ void sqlite3RegisterBuiltinFunctions(sqlite *db){ case 1: pArg = db; break; case 2: pArg = (void *)(-1); break; } - sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, 0, 0, pArg, - 0, aAggs[i].xStep, aAggs[i].xFinalize); + sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8, + 0, pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize); if( aAggs[i].needCollSeq ){ FuncDef *pFunc = sqlite3FindFunction( db, aAggs[i].zName, - strlen(aAggs[i].zName), aAggs[i].nArg, 0, 0); + strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0); if( pFunc && aAggs[i].needCollSeq ){ pFunc->needCollSeq = 1; } diff --git a/src/main.c b/src/main.c index f031de50e..712d997f9 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.217 2004/06/12 01:43:26 danielk1977 Exp $ +** $Id: main.c,v 1.218 2004/06/12 09:25:15 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -495,10 +495,11 @@ void sqlite3_close(sqlite *db){ } } - for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){ CollSeq *pColl = (CollSeq *)sqliteHashData(i); - /* sqliteFree(pColl); */ + sqliteFree(pColl); } + sqlite3HashClear(&db->aCollSeq); sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ @@ -567,7 +568,6 @@ const char *sqlite3ErrStr(int rc){ */ static int sqliteDefaultBusyCallback( void *Timeout, /* Maximum amount of time to wait */ - const char *NotUsed, /* The name of the table that is busy */ int count /* Number of times table has been busy */ ){ #if SQLITE_MIN_SLEEP_MS==1 @@ -678,7 +678,7 @@ int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, - int eTextRep, + int enc, int iCollateArg, void *pUserData, void (*xFunc)(sqlite3_context*,int,sqlite3_value **), @@ -696,8 +696,28 @@ int sqlite3_create_function( (255<(nName = strlen(zFunctionName))) ){ return SQLITE_ERROR; } + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + ** + ** If SQLITE_ANY is specified, add three versions of the function + ** to the hash table. + */ + if( enc==SQLITE_UTF16 ){ + enc = SQLITE_UTF16NATIVE; + }else if( enc==SQLITE_ANY ){ + int rc; + rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF8, + iCollateArg, pUserData, xFunc, xStep, xFinal); + if( rc!=SQLITE_OK ) return rc; + rc = sqlite3_create_function(db, zFunctionName, nArg, SQLITE_UTF16LE, + iCollateArg, pUserData, xFunc, xStep, xFinal); + if( rc!=SQLITE_OK ) return rc; + enc = SQLITE_UTF16BE; + } - p = sqlite3FindFunction(db, zFunctionName, nName, nArg, eTextRep, 1); + p = sqlite3FindFunction(db, zFunctionName, nName, nArg, enc, 1); if( p==0 ) return 1; p->xFunc = xFunc; p->xStep = xStep; @@ -804,7 +824,7 @@ int sqlite3BtreeFactory( } return sqlite3BtreeOpen(zFilename, ppBtree, nCache, btree_flags, - &db->busyHandler); + (void *)&db->busyHandler); } /* @@ -1182,6 +1202,9 @@ int sqlite3_reset(sqlite3_stmt *pStmt){ return rc; } +/* +** Register a new collation sequence with the database handle db. +*/ int sqlite3_create_collation( sqlite3* db, const char *zName, @@ -1191,10 +1214,19 @@ int sqlite3_create_collation( ){ CollSeq *pColl; int rc = SQLITE_OK; + + /* If SQLITE_UTF16 is specified as the encoding type, transform this + ** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the + ** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally. + */ + if( enc==SQLITE_UTF16 ){ + enc = SQLITE_UTF16NATIVE; + } + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){ sqlite3Error(db, SQLITE_ERROR, "Param 3 to sqlite3_create_collation() must be one of " - "SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE" + "SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE" ); return SQLITE_ERROR; } @@ -1209,6 +1241,9 @@ int sqlite3_create_collation( return rc; } +/* +** Register a new collation sequence with the database handle db. +*/ int sqlite3_create_collation16( sqlite3* db, const char *zName, @@ -1223,6 +1258,10 @@ int sqlite3_create_collation16( return rc; } +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ int sqlite3_collation_needed( sqlite3 *db, void *pCollNeededArg, @@ -1233,6 +1272,11 @@ int sqlite3_collation_needed( db->pCollNeededArg = pCollNeededArg; return SQLITE_OK; } + +/* +** Register a collation sequence factory callback with the database handle +** db. Replace any previously installed collation sequence factory. +*/ int sqlite3_collation_needed16( sqlite3 *db, void *pCollNeededArg, @@ -379,8 +379,9 @@ static void md5finalize(sqlite3_context *context){ p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); DigestToBase16(digest, zBuf); - sqlite3_result_text(context, zBuf, -1, 1); + sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } void Md5_Register(sqlite *db){ - sqlite3_create_function(db, "md5sum", -1, 0, 0, 0, 0, md5step, md5finalize); + sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, 0, + md5step, md5finalize); } diff --git a/src/select.c b/src/select.c index b0e54208b..7538b9726 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.188 2004/06/11 13:19:21 danielk1977 Exp $ +** $Id: select.c,v 1.189 2004/06/12 09:25:18 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -706,7 +706,7 @@ static void generateColumnNames( if( p==0 ) continue; if( pEList->a[i].zName ){ char *zName = pEList->a[i].zName; - sqlite3VdbeSetColName(v, i, zName, 0); + sqlite3VdbeSetColName(v, i, zName, strlen(zName)); continue; } if( p->op==TK_COLUMN && pTabList ){ @@ -725,7 +725,6 @@ static void generateColumnNames( } if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); - /* sqlite3VdbeCompressSpace(v, addr); */ }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ char *zName = 0; char *zTab; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 9c0eec4a3..a91aac972 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.100 2004/06/12 01:43:27 danielk1977 Exp $ +** @(#) $Id: sqlite.h.in,v 1.101 2004/06/12 09:25:20 danielk1977 Exp $ */ #ifndef _SQLITE_H_ #define _SQLITE_H_ @@ -604,13 +604,13 @@ typedef struct Mem sqlite3_value; ** an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted ** as NULL. */ -int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, int eCopy); +int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int64(sqlite3_stmt*, int, long long int); int sqlite3_bind_null(sqlite3_stmt*, int); -int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, int eCopy); -int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, int eCopy); +int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); /* @@ -833,12 +833,12 @@ int sqlite3_reset(sqlite3_stmt *pStmt); ** aggregate takes. If this parameter is negative, then the function or ** aggregate may take any number of arguments. ** -** If the fourth parameter is non-zero, this indicates that the function is -** more likely to handle text in UTF-16 encoding than UTF-8. This does not -** change the behaviour of the programming interface. However, if two -** versions of the same function are registered, one with eTextRep non-zero -** and the other zero, SQLite invokes the version likely to minimize -** conversions between unicode encodings. +** The fourth parameter is one of SQLITE_UTF* values defined below, +** indicating the encoding that the function is most likely to handle +** values in. This does not change the behaviour of the programming +** interface. However, if two versions of the same function are registered +** with different encoding values, SQLite invokes the version likely to +** minimize conversions between text encodings. ** ** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are ** pointers to user implemented C functions that implement the user @@ -897,6 +897,8 @@ int sqlite3_value_int(sqlite3_value*); long long int sqlite3_value_int64(sqlite3_value*); const unsigned char *sqlite3_value_text(sqlite3_value*); const void *sqlite3_value_text16(sqlite3_value*); +const void *sqlite3_value_text16le(sqlite3_value*); +const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); /* @@ -948,19 +950,24 @@ void *sqlite3_user_data(sqlite3_context*); void *sqlite3_get_auxdata(sqlite3_context*, int); void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*)); +#define SQLITE_STATIC ((void(*)(void *))0) +#define SQLITE_TRANSIENT ((void(*)(void *))-1) + /* ** User-defined functions invoke the following routines in order to ** set their return value. */ -void sqlite3_result_blob(sqlite3_context*, const void*, int n, int eCopy); +void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, long long int); void sqlite3_result_null(sqlite3_context*); -void sqlite3_result_text(sqlite3_context*, const char*, int n, int eCopy); -void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy); +void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_value(sqlite3_context*, sqlite3_value*); /* diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e69fe5651..554e3c68e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.284 2004/06/12 01:43:27 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.285 2004/06/12 09:25:21 danielk1977 Exp $ */ #include "config.h" #include "sqlite3.h" @@ -473,7 +473,7 @@ struct sqlite { struct FuncDef { char *zName; /* SQL name of the function */ int nArg; /* Number of arguments. -1 means unlimited */ - int iPrefEnc; /* Preferred text encoding */ + u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ @@ -1324,7 +1324,7 @@ ExprList *sqlite3ExprListDup(ExprList*); SrcList *sqlite3SrcListDup(SrcList*); IdList *sqlite3IdListDup(IdList*); Select *sqlite3SelectDup(Select*); -FuncDef *sqlite3FindFunction(sqlite*,const char*,int,int,int,int); +FuncDef *sqlite3FindFunction(sqlite*,const char*,int,int,u8,int); void sqlite3RegisterBuiltinFunctions(sqlite*); void sqlite3RegisterDateTimeFunctions(sqlite*); int sqlite3SafetyOn(sqlite*); @@ -1407,6 +1407,7 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckIndexCollSeq(Parse *, Index *); +int sqlite3CheckObjectName(Parse *, const char *); const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); diff --git a/src/tclsqlite.c b/src/tclsqlite.c index c0b751a60..03edc162a 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.84 2004/06/12 01:43:27 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.85 2004/06/12 09:25:22 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -277,7 +277,8 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv) if( rc ){ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ - sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1); + sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, + SQLITE_TRANSIENT); } } #ifndef SQLITE_OMIT_AUTHORIZATION @@ -784,7 +785,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ pFunc->pNext = pDb->pFunc; pFunc->zScript = (char*)&pFunc[1]; strcpy(pFunc->zScript, zScript); - sqlite3_create_function(pDb->db, zName, -1, 0, 0, pFunc, tclSqlFunc, 0, 0); + sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, 0, + pFunc, tclSqlFunc, 0, 0); break; } diff --git a/src/test1.c b/src/test1.c index 39a3f5377..7ec937095 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.75 2004/06/10 14:01:08 danielk1977 Exp $ +** $Id: test1.c,v 1.76 2004/06/12 09:25:23 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -341,7 +341,8 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv) int i; for(i=0; i<argc; i++){ if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ - sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1, 1); + sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1, + SQLITE_TRANSIENT); break; } } @@ -416,7 +417,7 @@ static void sqlite3ExecFunc( sqlite3_exec((sqlite*)sqlite3_user_data(context), sqlite3_value_text(argv[0]), execFuncCallback, &x, 0); - sqlite3_result_text(context, x.z, x.nUsed, 1); + sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT); sqliteFree(x.z); } @@ -449,8 +450,9 @@ static int test_create_function( return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; - sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0); - sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db, + sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, 0, + ifnullFunc, 0, 0); + sqlite3_create_function(db, "x_sqlite3_exec", 1, SQLITE_UTF8, 0, db, sqlite3ExecFunc, 0, 0); return TCL_OK; } @@ -499,8 +501,10 @@ static int test_create_aggregate( return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; - sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize); - sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize); + sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, 0, + countStep,countFinalize); + sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, 0, + countStep,countFinalize); return TCL_OK; } @@ -693,7 +697,8 @@ static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ }else if( sqlite3StrICmp(zArg0,"int64")==0 ){ sqlite3_result_int64(context, sqlite3_value_int64(argv[1])); }else if( sqlite3StrICmp(zArg0,"string")==0 ){ - sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1, 1); + sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1, + SQLITE_TRANSIENT); }else if( sqlite3StrICmp(zArg0,"double")==0 ){ sqlite3_result_double(context, sqlite3_value_double(argv[1])); }else if( sqlite3StrICmp(zArg0,"null")==0 ){ @@ -735,7 +740,8 @@ static int test_register_func( return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; - rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0); + rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, + testFunc, 0, 0); if( rc!=0 ){ Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); return TCL_ERROR; @@ -845,7 +851,7 @@ static int test_bind( }else if( strcmp(argv[4],"static")==0 ){ rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); }else if( strcmp(argv[4],"normal")==0 ){ - rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1); + rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT); }else{ Tcl_AppendResult(interp, "4th argument should be " "\"null\" or \"static\" or \"normal\"", 0); @@ -1122,7 +1128,7 @@ static int test_bind_text( value = Tcl_GetString(objv[3]); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; - rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); + rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( rc!=SQLITE_OK ){ return TCL_ERROR; } @@ -1154,7 +1160,7 @@ static int test_bind_text16( value = Tcl_GetByteArrayFromObj(objv[3], 0); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; - rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); + rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT); if( rc!=SQLITE_OK ){ return TCL_ERROR; } @@ -1186,7 +1192,7 @@ static int test_bind_blob( value = Tcl_GetString(objv[3]); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; - rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); + rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( rc!=SQLITE_OK ){ return TCL_ERROR; } @@ -1892,6 +1898,7 @@ static int test_sqlite3OsUnlock( return TCL_OK; } + /* ** Register commands with the TCL interpreter. */ diff --git a/src/trigger.c b/src/trigger.c index a842d9b0a..86f0664cf 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -97,9 +97,12 @@ void sqlite3BeginTrigger( goto trigger_cleanup; } - /* Check that no trigger of the specified name exists */ - zName = sqliteStrNDup(pName->z, pName->n); - sqlite3Dequote(zName); + /* Check that the trigger name is not reserved and that no trigger of the + ** specified name exists */ + zName = sqlite3TableNameFromToken(pName); + if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ + goto trigger_cleanup; + } if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); goto trigger_cleanup; diff --git a/src/vdbe.c b/src/vdbe.c index 3736ebbf9..fc2d9cff8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.367 2004/06/12 01:43:27 danielk1977 Exp $ +** $Id: vdbe.c,v 1.368 2004/06/12 09:25:25 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -73,7 +73,7 @@ int sqlite3_interrupt_count = 0; ** Release the memory associated with the given stack level. This ** leaves the Mem.flags field in an inconsistent state. */ -#define Release(P) if((P)->flags&MEM_Dyn){ sqliteFree((P)->z); } +#define Release(P) if((P)->flags&MEM_Dyn){ sqlite3VdbeMemRelease(P); } /* ** Convert the given stack entity into a string if it isn't one @@ -822,6 +822,7 @@ case OP_Variable: { pTos++; memcpy(pTos, &p->apVar[j], sizeof(*pTos)-NBFS); + pTos->xDel = 0; if( pTos->flags&(MEM_Str|MEM_Blob) ){ pTos->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Short); pTos->flags |= MEM_Static; @@ -912,6 +913,7 @@ case OP_Dup: { assert( pFrom<=pTos && pFrom>=p->aStack ); pTos++; memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS); + pTos->xDel = 0; if( pTos->flags & (MEM_Str|MEM_Blob) ){ if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){ pTos->flags &= ~MEM_Dyn; @@ -1120,6 +1122,7 @@ case OP_Concat: { pTos++; pTos->n = j; pTos->flags = MEM_Str|MEM_Dyn|MEM_Term; + pTos->xDel = 0; pTos->enc = db->enc; pTos->z = zNew; } @@ -2282,6 +2285,7 @@ case OP_MakeRecord: { assert( zNewRecord!=(unsigned char *)zTemp ); pTos->z = zNewRecord; pTos->flags = MEM_Blob | MEM_Dyn; + pTos->xDel = 0; } /* If P2 is non-zero, and if the key contains a NULL value, and if this @@ -3308,6 +3312,7 @@ case OP_RowData: { char *z = sqliteMallocRaw( n ); if( z==0 ) goto no_mem; pTos->flags = MEM_Blob | MEM_Dyn; + pTos->xDel = 0; pTos->z = z; } if( pC->keyAsData || pOp->opcode==OP_RowKey ){ @@ -3393,6 +3398,7 @@ case OP_FullKey: { z = sqliteMallocRaw( amt ); if( z==0 ) goto no_mem; pTos->flags = MEM_Blob | MEM_Dyn; + pTos->xDel = 0; }else{ z = pTos->zShort; pTos->flags = MEM_Blob | MEM_Short; @@ -3919,6 +3925,7 @@ case OP_IntegrityCk: { pTos->z = z; pTos->n = strlen(z); pTos->flags = MEM_Str | MEM_Dyn | MEM_Term; + pTos->xDel = 0; } pTos->enc = SQLITE_UTF8; sqlite3VdbeChangeEncoding(pTos, db->enc); @@ -4163,6 +4170,7 @@ case OP_SortNext: { pTos->z = pSorter->pData; pTos->n = pSorter->nData; pTos->flags = MEM_Blob|MEM_Dyn|MEM_Term; + pTos->xDel = 0; pTos->enc = 0; sqliteFree(pSorter->zKey); sqliteFree(pSorter); @@ -4252,6 +4260,7 @@ case OP_MemLoad: { assert( i>=0 && i<p->nMem ); pTos++; memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);; + pTos->xDel = 0; if( pTos->flags & (MEM_Str|MEM_Blob) ){ pTos->flags |= MEM_Ephem; pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); @@ -4456,6 +4465,7 @@ case OP_AggGet: { pTos++; pMem = &pFocus->aMem[i]; *pTos = *pMem; + pTos->xDel = 0; if( pTos->flags & (MEM_Str|MEM_Blob) ){ pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTos->flags |= MEM_Ephem; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 809974751..709287d92 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -136,6 +136,7 @@ struct Mem { double r; /* Real value */ char *z; /* String or BLOB value */ char zShort[NBFS]; /* Space for short strings */ + void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ }; typedef struct Mem Mem; @@ -373,7 +374,7 @@ int sqlite3VdbeList(Vdbe*); int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemCopy(Mem*, const Mem*); int sqlite3VdbeMemNulTerminate(Mem*); -int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, int); +int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, long long int); void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetNull(Mem*); @@ -383,6 +384,7 @@ int sqlite3VdbeMemStringify(Mem*, int); int sqlite3VdbeMemIntegerify(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); +void sqlite3VdbeMemRelease(Mem *p); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*, u8); #endif diff --git a/src/vdbeapi.c b/src/vdbeapi.c index a3fc2f03f..dff0a10ad 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -63,6 +63,12 @@ const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ const void *sqlite3_value_text16(sqlite3_value* pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); } +const void *sqlite3_value_text16be(sqlite3_value *pVal){ + return sqlite3ValueText(pVal, SQLITE_UTF16BE); +} +const void *sqlite3_value_text16le(sqlite3_value *pVal){ + return sqlite3ValueText(pVal, SQLITE_UTF16LE); +} int sqlite3_value_type(sqlite3_value* pVal){ return pVal->type; } @@ -75,21 +81,21 @@ void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, int n, - int eCopy + void (*xDel)(void *) ){ assert( n>0 ); - sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, eCopy); + sqlite3VdbeMemSetStr(&pCtx->s, z, n, 0, xDel); } void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ sqlite3VdbeMemSetDouble(&pCtx->s, rVal); } void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ pCtx->isError = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, 1); + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ pCtx->isError = 1; - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, 1); + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); @@ -104,17 +110,33 @@ void sqlite3_result_text( sqlite3_context *pCtx, const char *z, int n, - int eCopy + void (*xDel)(void *) ){ - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, eCopy); + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, xDel); } void sqlite3_result_text16( sqlite3_context *pCtx, const void *z, int n, - int eCopy + void (*xDel)(void *) +){ + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, xDel); +} +void sqlite3_result_text16be( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) ){ - sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, eCopy); + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16BE, xDel); +} +void sqlite3_result_text16le( + sqlite3_context *pCtx, + const void *z, + int n, + void (*xDel)(void *) +){ + sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16LE, xDel); } void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ sqlite3VdbeMemCopy(&pCtx->s, pValue); @@ -404,9 +426,7 @@ static int vdbeUnbind(Vdbe *p, int i){ } i--; pVar = &p->apVar[i]; - if( pVar->flags&MEM_Dyn ){ - sqliteFree(pVar->z); - } + sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; sqlite3Error(p->db, SQLITE_OK, 0); return SQLITE_OK; @@ -420,7 +440,7 @@ int sqlite3_bind_blob( int i, const void *zData, int nData, - int eCopy + void (*xDel)(void*) ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; @@ -431,7 +451,7 @@ int sqlite3_bind_blob( return rc; } pVar = &p->apVar[i-1]; - rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, eCopy); + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, 0, xDel); return rc; } int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ @@ -463,7 +483,7 @@ int sqlite3_bind_text( int i, const char *zData, int nData, - int eCopy + void (*xDel)(void*) ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; @@ -474,7 +494,7 @@ int sqlite3_bind_text( return rc; } pVar = &p->apVar[i-1]; - rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, eCopy); + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, SQLITE_UTF8, xDel); if( rc ){ return rc; } @@ -486,7 +506,7 @@ int sqlite3_bind_text16( int i, const void *zData, int nData, - int eCopy + void (*xDel)(void*) ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; @@ -511,7 +531,7 @@ int sqlite3_bind_text16( }else{ txt_enc = SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE; } - rc = sqlite3VdbeMemSetStr(pVar, zData, nData, txt_enc, eCopy); + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, txt_enc, xDel); if( rc ){ return rc; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 494ace2c5..fbf21483d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -544,9 +544,7 @@ int sqlite3VdbeList( */ if( p->pTos==&p->aStack[4] ){ for(i=0; i<5; i++){ - if( p->aStack[i].flags & MEM_Dyn ){ - sqliteFree(p->aStack[i].z); - } + sqlite3VdbeMemRelease(&p->aStack[i]); p->aStack[i].flags = 0; } } @@ -701,54 +699,6 @@ void sqlite3VdbeSorterReset(Vdbe *p){ } /* -** Reset an Agg structure. Delete all its contents. -** -** For installable aggregate functions, if the step function has been -** called, make sure the finalizer function has also been called. The -** finalizer might need to free memory that was allocated as part of its -** private context. If the finalizer has not been called yet, call it -** now. -*/ -#if 0 -void sqlite3VdbeAggReset(Agg *pAgg){ - int i; - HashElem *p; - for(p = sqliteHashFirst(&pAgg->hash); p; p = sqliteHashNext(p)){ - AggElem *pElem = sqliteHashData(p); - assert( pAgg->apFunc!=0 ); - for(i=0; i<pAgg->nMem; i++){ - Mem *pMem = &pElem->aMem[i]; - if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){ - sqlite3_context ctx; - ctx.pFunc = pAgg->apFunc[i]; - ctx.s.flags = MEM_Null; - ctx.pAgg = pMem->z; - ctx.cnt = pMem->i; - ctx.isStep = 0; - ctx.isError = 0; - (*pAgg->apFunc[i]->xFinalize)(&ctx); - if( pMem->z!=0 && pMem->z!=pMem->zShort ){ - sqliteFree(pMem->z); - } - if( ctx.s.flags & MEM_Dyn ){ - sqliteFree(ctx.s.z); - } - }else if( pMem->flags & MEM_Dyn ){ - sqliteFree(pMem->z); - } - } - sqliteFree(pElem); - } - sqlite3HashClear(&pAgg->hash); - sqliteFree(pAgg->apFunc); - pAgg->apFunc = 0; - pAgg->pCurrent = 0; - pAgg->pSearch = 0; - pAgg->nMem = 0; -} -#endif - -/* ** Reset an Agg structure. Delete all its contents. ** ** For installable aggregate functions, if the step function has been @@ -806,8 +756,8 @@ int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){ if( pMem->z!=0 && pMem->z!=pMem->z ){ sqliteFree(pMem->z); } - }else if( pMem->flags&MEM_Dyn ){ - sqliteFree(pMem->z); + }else{ + sqlite3VdbeMemRelease(pMem); } } sqliteFree(pElem); @@ -915,9 +865,7 @@ static void Cleanup(Vdbe *p){ if( p->aStack ){ Mem *pTos = p->pTos; while( pTos>=p->aStack ){ - if( pTos->flags & MEM_Dyn ){ - sqliteFree(pTos->z); - } + sqlite3VdbeMemRelease(pTos); pTos--; } p->pTos = pTos; @@ -925,9 +873,7 @@ static void Cleanup(Vdbe *p){ closeAllCursors(p); if( p->aMem ){ for(i=0; i<p->nMem; i++){ - if( p->aMem[i].flags & MEM_Dyn ){ - sqliteFree(p->aMem[i].z); - } + sqlite3VdbeMemRelease(&p->aMem[i]); } } sqliteFree(p->aMem); @@ -985,7 +931,10 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ ** ** This call must be made after a call to sqlite3VdbeSetNumCols(). ** -** Parameter N may be either P3_DYNAMIC or P3_STATIC. +** If N==P3_STATIC it means that zName is a pointer to a constant static +** string and we can just copy the pointer. If it is P3_DYNAMIC, then +** the string is freed using sqliteFree() when the vdbe is finished with +** it. Otherwise, N bytes of zName are copied. */ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ int rc; @@ -1007,13 +956,14 @@ int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ } pColName = &(p->aColName[idx]); - if( N==0 ){ - rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, 1); + if( N==P3_DYNAMIC || N==P3_STATIC ){ + rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); }else{ - rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8, N>0); + rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT); } if( rc==SQLITE_OK && N==P3_DYNAMIC ){ pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn; + pColName->xDel = 0; } return rc; } @@ -1396,9 +1346,7 @@ void sqlite3VdbeDelete(Vdbe *p){ #endif } for(i=0; i<p->nVar; i++){ - if( p->apVar[i].flags&MEM_Dyn ){ - sqliteFree(p->apVar[i].z); - } + sqlite3VdbeMemRelease(&p->apVar[i]); } if( p->azColName16 ){ for(i=0; i<p->nResColumn; i++){ @@ -1678,12 +1626,8 @@ int sqlite3VdbeRecordCompare( d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2); rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0); - if( mem1.flags&MEM_Dyn ){ - sqliteFree(mem1.z); - } - if( mem2.flags&MEM_Dyn ){ - sqliteFree(mem2.z); - } + sqlite3VdbeMemRelease(&mem1); + sqlite3VdbeMemRelease(&mem2); if( rc!=0 ){ break; } @@ -1753,9 +1697,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){ lenRowid = sqlite3VdbeSerialTypeLen(typeRowid); sqlite3VdbeSerialGet(&m.z[m.n-lenRowid], typeRowid, &v); *rowid = v.i; - if( m.flags & MEM_Dyn ){ - sqliteFree(m.z); - } + sqlite3VdbeMemRelease(&m); return SQLITE_OK; } @@ -1791,8 +1733,6 @@ int sqlite3VdbeIdxKeyCompare( } lenRowid = sqlite3VdbeIdxRowidLen(m.n, m.z); *res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey); - if( m.flags & MEM_Dyn ){ - sqliteFree(m.z); - } + sqlite3VdbeMemRelease(&m); return SQLITE_OK; } diff --git a/src/vdbemem.c b/src/vdbemem.c index b74c84e59..8265aaff3 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -54,9 +54,8 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ if( rc!=SQLITE_OK ){ return rc; } - if( pMem->flags&MEM_Dyn ){ - sqliteFree(pMem->z); - } + sqlite3VdbeMemRelease(pMem); + /* Result of sqlite3utfTranslate is currently always dynamically ** allocated and nul terminated. This might be altered as a performance ** enhancement later. @@ -65,6 +64,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ pMem->n = n; pMem->flags &= ~(MEM_Ephem | MEM_Short | MEM_Static); pMem->flags |= MEM_Str | MEM_Dyn | MEM_Term; + pMem->xDel = 0; }else{ /* Must be translating between UTF-16le and UTF-16be. */ int i; @@ -98,6 +98,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){ return SQLITE_NOMEM; } pMem->flags |= MEM_Dyn|MEM_Term; + pMem->xDel = 0; memcpy(z, pMem->z, n ); z[n] = 0; z[n+1] = 0; @@ -129,6 +130,7 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ return SQLITE_NOMEM; } pMem->flags |= MEM_Dyn|MEM_Term; + pMem->xDel = 0; } memcpy(z, pMem->z, n ); z[n] = 0; @@ -199,12 +201,19 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ } /* -** Release any memory held by the Mem +** Release any memory held by the Mem. This may leave the Mem in an +** inconsistent state, for example with (Mem.z==0) and +** (Mem.type==SQLITE_TEXT). */ -static void releaseMem(Mem *p){ +void sqlite3VdbeMemRelease(Mem *p){ if( p->flags & MEM_Dyn ){ - sqliteFree(p->z); + if( p->xDel ){ + p->xDel((void *)p->z); + }else{ + sqliteFree(p->z); + } p->z = 0; + p->xDel = 0; } } @@ -260,7 +269,7 @@ int sqlite3VdbeMemRealify(Mem *pMem){ ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - releaseMem(pMem); + sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Null; pMem->type = SQLITE_NULL; } @@ -270,7 +279,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){ ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ - releaseMem(pMem); + sqlite3VdbeMemRelease(pMem); pMem->i = val; pMem->flags = MEM_Int; pMem->type = SQLITE_INTEGER; @@ -281,7 +290,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ ** manifest type REAL. */ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ - releaseMem(pMem); + sqlite3VdbeMemRelease(pMem); pMem->r = val; pMem->flags = MEM_Real; pMem->type = SQLITE_FLOAT; @@ -291,8 +300,9 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ ** Copy the contents of memory cell pFrom into pTo. */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ - releaseMem(pTo); + sqlite3VdbeMemRelease(pTo); memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); + pTo->xDel = 0; if( pTo->flags & (MEM_Str|MEM_Blob) ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTo->flags |= MEM_Ephem; @@ -309,9 +319,9 @@ int sqlite3VdbeMemSetStr( const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ - int eCopy /* True if this function should make a copy of z */ + void (*xDel)(void*) /* Destructor function */ ){ - releaseMem(pMem); + sqlite3VdbeMemRelease(pMem); if( !z ){ pMem->flags = MEM_Null; pMem->type = SQLITE_NULL; @@ -319,14 +329,19 @@ int sqlite3VdbeMemSetStr( } pMem->z = (char *)z; - if( eCopy ){ + if( xDel==SQLITE_STATIC ){ + pMem->flags = MEM_Static; + }else if( xDel==SQLITE_TRANSIENT ){ pMem->flags = MEM_Ephem; }else{ - pMem->flags = MEM_Static; + pMem->flags = MEM_Dyn; + pMem->xDel = xDel; } + pMem->enc = enc; pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT; pMem->n = n; + switch( enc ){ case 0: pMem->flags |= MEM_Blob; @@ -352,7 +367,7 @@ int sqlite3VdbeMemSetStr( default: assert(0); } - if( eCopy ){ + if( xDel==SQLITE_TRANSIENT ){ return sqlite3VdbeMemMakeWriteable(pMem); } return SQLITE_OK; @@ -510,6 +525,7 @@ int sqlite3VdbeMemFromBtree( return SQLITE_NOMEM; } pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; + pMem->xDel = 0; }else{ zData = &(pMem->zShort[0]); pMem->flags = MEM_Blob|MEM_Short|MEM_Term; @@ -611,24 +627,7 @@ sqlite3_value* sqlite3ValueNew(){ } void sqlite3ValueSetStr(sqlite3_value *v, int n, const void *z, u8 enc){ - Mem *p = (Mem *)v; - if( p->z && p->flags&MEM_Dyn ){ - sqliteFree(p->z); - } - p->z = (char *)z; - p->n = n; - p->enc = enc; - p->type = SQLITE_TEXT; - p->flags = (MEM_Str|MEM_Static); - - if( p->n<0 ){ - if( enc==SQLITE_UTF8 ){ - p->n = strlen(p->z); - }else{ - p->n = sqlite3utf16ByteLen(p->z, -1); - } - } - return; + sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, SQLITE_STATIC); } void sqlite3ValueFree(sqlite3_value *v){ |