aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c131
-rw-r--r--src/date.c14
-rw-r--r--src/expr.c87
-rw-r--r--src/func.c133
-rw-r--r--src/main.c60
-rw-r--r--src/md5.c5
-rw-r--r--src/select.c5
-rw-r--r--src/sqlite.h.in33
-rw-r--r--src/sqliteInt.h7
-rw-r--r--src/tclsqlite.c8
-rw-r--r--src/test1.c33
-rw-r--r--src/trigger.c9
-rw-r--r--src/vdbe.c14
-rw-r--r--src/vdbeInt.h4
-rw-r--r--src/vdbeapi.c54
-rw-r--r--src/vdbeaux.c96
-rw-r--r--src/vdbemem.c65
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,
diff --git a/src/md5.c b/src/md5.c
index 72f9ef492..91d1051c8 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -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){