aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/alter.c14
-rw-r--r--src/build.c33
-rw-r--r--src/callback.c4
-rw-r--r--src/func.c30
-rw-r--r--src/insert.c14
-rw-r--r--src/main.c6
-rw-r--r--src/prepare.c4
-rw-r--r--src/select.c83
-rw-r--r--src/sqlite.h.in41
-rw-r--r--src/sqlite3ext.h4
-rw-r--r--src/sqliteInt.h28
-rw-r--r--src/tclsqlite.c19
-rw-r--r--src/trigger.c2
-rw-r--r--src/vacuum.c13
-rw-r--r--src/vdbe.c6
-rw-r--r--src/vdbeInt.h15
-rw-r--r--src/vdbeapi.c28
-rw-r--r--src/vdbemem.c54
-rw-r--r--src/wherecode.c2
-rw-r--r--src/whereexpr.c32
20 files changed, 246 insertions, 186 deletions
diff --git a/src/alter.c b/src/alter.c
index 8df06f064..51d4a4006 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -403,9 +403,9 @@ void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
- int savedDbFlags; /* Saved value of db->flags */
+ u32 savedDbFlags; /* Saved value of db->mDbFlags */
- savedDbFlags = db->flags;
+ savedDbFlags = db->mDbFlags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -414,7 +414,7 @@ void sqlite3AlterRenameTable(
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName;
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -579,7 +579,7 @@ void sqlite3AlterRenameTable(
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/*
@@ -680,11 +680,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
- int savedDbFlags = db->flags;
+ u32 savedDbFlags = db->mDbFlags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -693,7 +693,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zTab
);
sqlite3DbFree(db, zCol);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/* Make sure the schema version is at least 3. But do not upgrade
diff --git a/src/build.c b/src/build.c
index cc05bdfb9..8eab3823c 100644
--- a/src/build.c
+++ b/src/build.c
@@ -479,7 +479,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
}
freeIndex(db, pIndex);
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -551,7 +551,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
sqlite3SchemaClear(pDb->pSchema);
}
}
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
sqlite3CollapseDatabaseArray(db);
@@ -561,7 +561,7 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
** This routine is called when a commit occurs.
*/
void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
}
/*
@@ -665,7 +665,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -778,7 +778,8 @@ int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
+ assert( db->init.iDb==0 || db->init.busy
+ || (db->mDbFlags & DBFLAG_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -1738,15 +1739,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
- ** table entry. This is only required if currently generating VDBE
- ** code for a CREATE TABLE (not when parsing one as part of reading
- ** a database schema). */
- if( v ){
- assert( db->init.busy==0 );
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
- }
-
/*
** Remove all redundant columns from the PRIMARY KEY. For example, change
** "PRIMARY KEY(a,b,a,b,c,b,c,d)" into just "PRIMARY KEY(a,b,c,d)". Later
@@ -1766,6 +1758,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
nPk = pPk->nKeyCol;
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
+ ** table entry. This is only required if currently generating VDBE
+ ** code for a CREATE TABLE (not when parsing one as part of reading
+ ** a database schema). */
+ if( v && pPk->tnum>0 ){
+ assert( db->init.busy==0 );
+ sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
+ }
+
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -2055,7 +2056,7 @@ void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
@@ -3324,7 +3325,7 @@ void sqlite3CreateIndex(
sqlite3OomFault(db);
goto exit_create_index;
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
if( pTblName!=0 ){
pIndex->tnum = db->init.newTnum;
}
diff --git a/src/callback.c b/src/callback.c
index 5fe103686..10505414c 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -374,7 +374,7 @@ FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
- ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
@@ -384,7 +384,7 @@ FuncDef *sqlite3FindFunction(
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
- if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
+ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
diff --git a/src/func.c b/src/func.c
index fd5458ad3..2bb9a91de 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1706,9 +1706,14 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
/*
** pExpr points to an expression which implements a function. If
** it is appropriate to apply the LIKE optimization to that function
-** then set aWc[0] through aWc[2] to the wildcard characters and
-** return TRUE. If the function is not a LIKE-style function then
-** return FALSE.
+** then set aWc[0] through aWc[2] to the wildcard characters and the
+** escape character and then return TRUE. If the function is not a
+** LIKE-style function then return FALSE.
+**
+** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
+** operator if c is a string literal that is exactly one byte in length.
+** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
+** no ESCAPE clause.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
@@ -1717,17 +1722,26 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION
- || !pExpr->x.pList
- || pExpr->x.pList->nExpr!=2
- ){
+ int nExpr;
+ if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
+ nExpr = pExpr->x.pList->nExpr;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
+ if( nExpr<3 ){
+ aWc[3] = 0;
+ }else{
+ Expr *pEscape = pExpr->x.pList->a[2].pExpr;
+ char *zEscape;
+ if( pEscape->op!=TK_STRING ) return 0;
+ zEscape = pEscape->u.zToken;
+ if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
+ aWc[3] = zEscape[0];
+ }
/* The memcpy() statement assumes that the wildcard characters are
** the first three statements in the compareInfo structure. The
diff --git a/src/insert.c b/src/insert.c
index 20e3736d7..d51e64b8f 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -226,7 +226,7 @@ static int autoIncBegin(
){
int memId = 0; /* Register holding maximum rowid */
if( (pTab->tabFlags & TF_Autoincrement)!=0
- && (pParse->db->flags & SQLITE_Vacuum)==0
+ && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
@@ -2059,7 +2059,7 @@ static int xferOptimization(
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
- if( (db->flags & SQLITE_Vacuum)==0
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0; /* Neither table may have __hidden__ columns */
@@ -2135,15 +2135,15 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
- if( (db->flags & SQLITE_Vacuum)==0 && (
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
)){
/* In some circumstances, we are able to run the xfer optimization
** only if the destination table is initially empty. Unless the
- ** SQLITE_Vacuum flag is set, this block generates code to make
- ** that determination. If SQLITE_Vacuum is set, then the destination
+ ** DBFLAG_Vacuum flag is set, this block generates code to make
+ ** that determination. If DBFLAG_Vacuum is set, then the destination
** table is always empty.
**
** Conditions under which the destination must be empty:
@@ -2179,7 +2179,7 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
+ if( db->mDbFlags & DBFLAG_Vacuum ){
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
@@ -2211,7 +2211,7 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
- if( db->flags & SQLITE_Vacuum ){
+ if( db->mDbFlags & DBFLAG_Vacuum ){
/* This INSERT command is part of a VACUUM operation, which guarantees
** that the destination table is empty. If all indexed columns use
** collation sequence BINARY, then it can also be assumed that the
diff --git a/src/main.c b/src/main.c
index 747c25ea8..2d8135837 100644
--- a/src/main.c
+++ b/src/main.c
@@ -824,7 +824,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
- int oldFlags = db->flags;
+ u32 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
@@ -1259,7 +1259,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
- schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
+ schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -1273,7 +1273,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
+ if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
diff --git a/src/prepare.c b/src/prepare.c
index 17fbf66d3..cb3d5afee 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -85,7 +85,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
- assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
+ assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -354,7 +354,7 @@ error_out:
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int commit_internal = !(db->flags&SQLITE_InternChanges);
+ int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
diff --git a/src/select.c b/src/select.c
index a3ada4ef7..9af93dc9e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1438,13 +1438,10 @@ static const char *columnTypeImpl(
** of the SELECT statement. Return the declaration type and origin
** data for the result-set column of the sub-select.
*/
- if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
+ if( iCol>=0 && iCol<pS->pEList->nExpr ){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
** test case misc2.2.2) - it always evaluates to NULL.
- **
- ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
- ** caught already by name resolution.
*/
NameContext sNC;
Expr *p = pS->pEList->a[iCol].pExpr;
@@ -1554,18 +1551,6 @@ static void generateColumnTypes(
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
-/*
-** Return the Table objecct in the SrcList that has cursor iCursor.
-** Or return NULL if no such Table object exists in the SrcList.
-*/
-static Table *tableWithCursor(SrcList *pList, int iCursor){
- int j;
- for(j=0; j<pList->nSrc; j++){
- if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
- }
- return 0;
-}
-
/*
** Compute the column names for a SELECT statement.
@@ -1599,15 +1584,16 @@ static Table *tableWithCursor(SrcList *pList, int iCursor){
*/
static void generateColumnNames(
Parse *pParse, /* Parser context */
- SrcList *pTabList, /* The FROM clause of the SELECT */
- ExprList *pEList /* Expressions defining the result set */
+ Select *pSelect /* Generate column names for this SELECT statement */
){
Vdbe *v = pParse->pVdbe;
int i;
Table *pTab;
+ SrcList *pTabList;
+ ExprList *pEList;
sqlite3 *db = pParse->db;
- int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
- int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
+ int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
+ int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
#ifndef SQLITE_OMIT_EXPLAIN
/* If this is an EXPLAIN, skip this step */
@@ -1617,6 +1603,10 @@ static void generateColumnNames(
#endif
if( pParse->colNamesSet || db->mallocFailed ) return;
+ /* Column names are determined by the left-most term of a compound select */
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
+ pTabList = pSelect->pSrc;
+ pEList = pSelect->pEList;
assert( v!=0 );
assert( pTabList!=0 );
pParse->colNamesSet = 1;
@@ -1631,12 +1621,11 @@ static void generateColumnNames(
/* An AS clause always takes first priority */
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
- }else if( srcName
- && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
- && (pTab = tableWithCursor(pTabList, p->iTable))!=0
- ){
+ }else if( srcName && p->op==TK_COLUMN ){
char *zCol;
int iCol = p->iColumn;
+ pTab = p->pTab;
+ assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
@@ -2468,11 +2457,6 @@ static int multiSelect(
if( dest.eDest!=priorOp ){
int iCont, iBreak, iStart;
assert( p->pEList );
- if( dest.eDest==SRT_Output ){
- Select *pFirst = p;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
computeLimitRegisters(pParse, p, iBreak);
@@ -2543,11 +2527,6 @@ static int multiSelect(
** tables.
*/
assert( p->pEList );
- if( dest.eDest==SRT_Output ){
- Select *pFirst = p;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
iBreak = sqlite3VdbeMakeLabel(v);
iCont = sqlite3VdbeMakeLabel(v);
computeLimitRegisters(pParse, p, iBreak);
@@ -3155,14 +3134,6 @@ static int multiSelectOrderBy(
*/
sqlite3VdbeResolveLabel(v, labelEnd);
- /* Set the number of output columns
- */
- if( pDest->eDest==SRT_Output ){
- Select *pFirst = pPrior;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
-
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
if( p->pPrior ){
@@ -3457,7 +3428,6 @@ static int flattenSubquery(
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
SrcList *pSubSrc; /* The FROM clause of the subquery */
- ExprList *pList; /* The result set of the outer query */
int iParent; /* VDBE cursor number of the pSub result set temp table */
int iNewParent = -1;/* Replacement table for iParent */
int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
@@ -3782,14 +3752,6 @@ static int flattenSubquery(
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
- pList = pParent->pEList;
- for(i=0; i<pList->nExpr; i++){
- if( pList->a[i].zName==0 ){
- char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
- sqlite3Dequote(zName);
- pList->a[i].zName = zName;
- }
- }
if( pSub->pOrderBy ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
@@ -5219,6 +5181,14 @@ int sqlite3Select(
}
#endif
+ /* Get a pointer the VDBE under construction, allocating a new VDBE if one
+ ** does not already exist */
+ v = sqlite3GetVdbe(pParse);
+ if( v==0 ) goto select_end;
+ if( pDest->eDest==SRT_Output ){
+ generateColumnNames(pParse, p);
+ }
+
/* Try to flatten subqueries in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -5254,11 +5224,6 @@ int sqlite3Select(
}
#endif
- /* Get a pointer the VDBE under construction, allocating a new VDBE if one
- ** does not already exist */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto select_end;
-
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* Handle compound SELECT statements using the separate multiSelect()
** procedure.
@@ -6058,12 +6023,6 @@ int sqlite3Select(
select_end:
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
- /* Identify column names if results of the SELECT are to be output.
- */
- if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
- generateColumnNames(pParse, pTabList, pEList);
- }
-
sqlite3DbFree(db, sAggInfo.aCol);
sqlite3DbFree(db, sAggInfo.aFunc);
#if SELECTTRACE_ENABLED
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index ea002b720..e8f34e4ab 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -3883,19 +3883,14 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_blob_open | incremental BLOB I/O] routines.
** ^A negative value for the zeroblob results in a zero-length BLOB.
**
-** ^The sqlite3_bind_pointer(S,I,P,T) routine causes the I-th parameter in
+** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
** [prepared statement] S to have an SQL value of NULL, but to also be
-** associated with the pointer P of type T.
-** ^The sqlite3_bind_pointer() routine can be used to pass
-** host-language pointers into [application-defined SQL functions].
-** ^A parameter that is initialized using [sqlite3_bind_pointer()] appears
-** to be an ordinary SQL NULL value to everything other than
-** [sqlite3_value_pointer()]. The T parameter should be a static string,
-** preferably a string literal. The procedure that invokes
-** sqlite3_bind_pointer(S,I,P,T) continues to own the P and T pointers and
-** must guarantee that those pointers remain valid until after the last
-** access via [sqlite3_value_pointer()]. The sqlite3_bind_pointer() routine
-** is part of the [pointer passing interface] added for SQLite 3.20.0.
+** associated with the pointer P of type T. ^D is either a NULL pointer or
+** a pointer to a destructor function for P. ^SQLite will invoke the
+** destructor D with a single argument of P when it is finished using
+** P. The T parameter should be a static string, preferably a string
+** literal. The sqlite3_bind_pointer() routine is part of the
+** [pointer passing interface] added for SQLite 3.20.0.
**
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
** for the [prepared statement] or with a prepared statement for which
@@ -3930,7 +3925,7 @@ int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*);
+int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
@@ -4763,10 +4758,11 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** extract UTF-16 strings as big-endian and little-endian respectively.
**
** ^If [sqlite3_value] object V was initialized
-** using [sqlite3_bind_pointer(S,I,P,X)] or [sqlite3_result_pointer(C,P,X)]
+** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
** and if X and Y are strings that compare equal according to strcmp(X,Y),
** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
-** sqlite3_value_pointer(V,Y) returns a NULL.
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
**
** ^(The sqlite3_value_type(V) interface returns the
** [SQLITE_INTEGER | datatype code] for the initial datatype of the
@@ -5101,17 +5097,16 @@ typedef void (*sqlite3_destructor_type)(void*);
** [unprotected sqlite3_value] object is required, so either
** kind of [sqlite3_value] object can be used with this interface.
**
-** ^The sqlite3_result_pointer(C,P,T) interface sets the result to an
+** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
** SQL NULL value, just like [sqlite3_result_null(C)], except that it
** also associates the host-language pointer P or type T with that
** NULL value such that the pointer can be retrieved within an
** [application-defined SQL function] using [sqlite3_value_pointer()].
-** The T parameter should be a static string and preferably a string
-** literal. The procedure that invokes sqlite3_result_pointer(C,P,T)
-** continues to own the P and T pointers and must guarantee that
-** those pointers remain valid until after the last access via
-** [sqlite3_value_pointer()]. The sqlite3_result_pointer() routine
-** is part of the [pointer passing interface] added for SQLite 3.20.0.
+** ^If the D parameter is not NULL, then it is a pointer to a destructor
+** for the P parameter. ^SQLite invokes D with P as its only argument
+** when SQLite is finished with P. The T parameter should be a static
+** string and preferably a string literal. The sqlite3_result_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
**
** If these routines are called from within the different thread
** than the one containing the application-defined function that received
@@ -5136,7 +5131,7 @@ 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*);
-void sqlite3_result_pointer(sqlite3_context*, void*, const char*);
+void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
void sqlite3_result_zeroblob(sqlite3_context*, int n);
int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index c585f17f2..0f1712bee 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -289,8 +289,8 @@ struct sqlite3_api_routines {
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
- int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*);
- void (*result_pointer)(sqlite3_context*,void*,const char*);
+ int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
+ void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
};
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 2d19849da..724cd5312 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1316,7 +1316,8 @@ struct sqlite3 {
sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
int nDb; /* Number of backends currently in use */
- int flags; /* Miscellaneous flags. See below */
+ u32 mDbFlags; /* flags recording internal state */
+ u32 flags; /* flags settable by pragmas. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 szMmap; /* Default mmap_size setting */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
@@ -1470,18 +1471,13 @@ struct sqlite3 {
#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */
#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x00020000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x00040000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x00080000 /* Disable database changes */
-#define SQLITE_CellSizeCk 0x00100000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x00200000 /* Enable fts3_tokenizer(2) */
-#define SQLITE_EnableQPSG 0x00400000 /* Query Planner Stability Guarantee */
-/* The next four values are not used by PRAGMAs or by sqlite3_dbconfig() and
-** could be factored out into a separate bit vector of the sqlite3 object. */
-#define SQLITE_InternChanges 0x00800000 /* Uncommitted Hash table changes */
-#define SQLITE_LoadExtFunc 0x01000000 /* Enable load_extension() SQL func */
-#define SQLITE_PreferBuiltin 0x02000000 /* Preference to built-in funcs */
-#define SQLITE_Vacuum 0x04000000 /* Currently in a VACUUM */
+#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */
+#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */
+#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */
@@ -1491,6 +1487,12 @@ struct sqlite3 {
#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */
#endif
+/*
+** Allowed values for sqlite3.mDbFlags
+*/
+#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */
+#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */
+#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 341d3f0dc..1b9f91405 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3882,28 +3882,39 @@ static int SQLITE_TCLAPI md5file_cmd(
const char **argv
){
FILE *in;
+ int ofst;
+ int amt;
MD5Context ctx;
void (*converter)(unsigned char*, char*);
unsigned char digest[16];
char zBuf[10240];
- if( argc!=2 ){
+ if( argc!=2 && argc!=4 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
- " FILENAME\"", (char*)0);
+ " FILENAME [OFFSET AMT]\"", (char*)0);
return TCL_ERROR;
}
+ if( argc==4 ){
+ ofst = atoi(argv[2]);
+ amt = atoi(argv[3]);
+ }else{
+ ofst = 0;
+ amt = 2147483647;
+ }
in = fopen(argv[1],"rb");
if( in==0 ){
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
"\" for reading", (char*)0);
return TCL_ERROR;
}
+ fseek(in, ofst, SEEK_SET);
MD5Init(&ctx);
- for(;;){
+ while( amt>0 ){
int n;
- n = (int)fread(zBuf, 1, sizeof(zBuf), in);
+ n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
if( n<=0 ) break;
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
+ amt -= n;
}
fclose(in);
MD5Final(digest, &ctx);
diff --git a/src/trigger.c b/src/trigger.c
index dfa094141..2a4fdd8ed 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -585,7 +585,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
diff --git a/src/vacuum.c b/src/vacuum.c
index 841aa5200..fde08ddc2 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -130,7 +130,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- int saved_flags; /* Saved value of the db->flags */
+ u16 saved_mDbFlags; /* Saved value of db->mDbFlags */
+ u32 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
u8 saved_mTrace; /* Saved trace settings */
@@ -153,11 +154,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
+ saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
- | SQLITE_PreferBuiltin | SQLITE_Vacuum);
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
db->mTrace = 0;
@@ -268,8 +270,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
- assert( (db->flags & SQLITE_Vacuum)!=0 );
- db->flags &= ~SQLITE_Vacuum;
+ assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+ db->mDbFlags &= ~DBFLAG_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers, views, and virtual tables from the main database
@@ -337,6 +339,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
end_of_vacuum:
/* Restore the original value of db->flags */
db->init.iDb = 0;
+ db->mDbFlags = saved_mDbFlags;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
diff --git a/src/vdbe.c b/src/vdbe.c
index 3e6231e0d..d9900f383 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2950,7 +2950,7 @@ case OP_Savepoint: {
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
- isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
+ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
@@ -2969,7 +2969,7 @@ case OP_Savepoint: {
if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
- db->flags = (db->flags | SQLITE_InternChanges);
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -3249,7 +3249,7 @@ case OP_SetCookie: {
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
pDb->pSchema->schema_cookie = pOp->p3;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 599fe7041..d8e47be50 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -189,8 +189,8 @@ struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
- int nZero; /* Used when bit MEM_Zero is set in flags */
- void *pPtr; /* Pointer when flags=MEM_NULL and eSubtype='p' */
+ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
+ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
@@ -222,7 +222,8 @@ struct sqlite3_value {
** representations of the value stored in the Mem struct.
**
** If the MEM_Null flag is set, then the value is an SQL NULL value.
-** No other flags may be set in this case.
+** For a pointer type created using sqlite3_bind_pointer() or
+** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
**
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
@@ -230,7 +231,7 @@ struct sqlite3_value {
** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
*/
-#define MEM_Null 0x0001 /* Value is NULL */
+#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */
#define MEM_Str 0x0002 /* Value is a string */
#define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */
@@ -240,7 +241,7 @@ struct sqlite3_value {
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
-#define MEM_TypeMask 0x81ff /* Mask of type bits */
+#define MEM_TypeMask 0xc1ff /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
@@ -248,7 +249,7 @@ struct sqlite3_value {
** policy for Mem.z. The MEM_Term flag tells us whether or not the
** string is \000 or \u0000 terminated
*/
-#define MEM_Term 0x0200 /* String rep is nul terminated */
+#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */
#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
#define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
@@ -476,7 +477,7 @@ void sqlite3VdbeMemSetInt64(Mem*, i64);
#else
void sqlite3VdbeMemSetDouble(Mem*, double);
#endif
-void sqlite3VdbeMemSetPointer(Mem*, void*, const char*);
+void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 35b194fff..24545e4f1 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -201,12 +201,13 @@ unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
}
void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){
Mem *p = (Mem*)pVal;
- if( p->flags==(MEM_Null|MEM_Subtype|MEM_Term|MEM_Static)
+ if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
+ (MEM_Null|MEM_Term|MEM_Subtype)
&& zPType!=0
&& p->eSubtype=='p'
- && strcmp(p->z, zPType)==0
+ && strcmp(p->u.zPType, zPType)==0
){
- return p->u.pPtr;
+ return (void*)p->z;
}else{
return 0;
}
@@ -389,11 +390,16 @@ void sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
-void sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr, const char *zPT){
+void sqlite3_result_pointer(
+ sqlite3_context *pCtx,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
sqlite3VdbeMemSetNull(pOut);
- sqlite3VdbeMemSetPointer(pOut, pPtr, zPT);
+ sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
Mem *pOut = pCtx->pOut;
@@ -1398,13 +1404,21 @@ int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-int sqlite3_bind_pointer(sqlite3_stmt *pStmt, int i, void *pPtr,const char *zT){
+int sqlite3_bind_pointer(
+ sqlite3_stmt *pStmt,
+ int i,
+ void *pPtr,
+ const char *zPTtype,
+ void (*xDestructor)(void*)
+){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
- sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zT);
+ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
+ }else if( xDestructor ){
+ xDestructor(pPtr);
}
return rc;
}
diff --git a/src/vdbemem.c b/src/vdbemem.c
index eac3b9ed3..45b0b38c1 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -27,7 +27,7 @@
*/
int sqlite3VdbeCheckMemInvariants(Mem *p){
/* If MEM_Dyn is set then Mem.xDel!=0.
- ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
+ ** Mem.xDel might not be initialized if MEM_Dyn is clear.
*/
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
@@ -40,9 +40,34 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
/* Cannot be both MEM_Int and MEM_Real at the same time */
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
- /* Cannot be both MEM_Null and some other type */
- assert( (p->flags & MEM_Null)==0 ||
- (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 );
+ if( p->flags & MEM_Null ){
+ /* Cannot be both MEM_Null and some other type */
+ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
+ |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 );
+
+ /* If MEM_Null is set, then either the value is a pure NULL (the usual
+ ** case) or it is a pointer set using sqlite3_bind_pointer() or
+ ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be
+ ** set.
+ */
+ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
+ /* This is a pointer type. There may be a flag to indicate what to
+ ** do with the pointer. */
+ assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 );
+
+ /* No other bits set */
+ assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype
+ |MEM_Dyn|MEM_Ephem|MEM_Static))==0 );
+ }else{
+ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn,
+ ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */
+ }
+ }else{
+ /* The MEM_Cleared bit is only allowed on NULLs */
+ assert( (p->flags & MEM_Cleared)==0 );
+ }
/* The szMalloc field holds the correct memory allocation size */
assert( p->szMalloc==0
@@ -705,18 +730,25 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
+/* A no-op destructor */
+static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
+
/*
** Set the value stored in *pMem should already be a NULL.
** Also store a pointer to go with it.
*/
-void sqlite3VdbeMemSetPointer(Mem *pMem, void *pPtr, const char *zPType){
+void sqlite3VdbeMemSetPointer(
+ Mem *pMem,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
assert( pMem->flags==MEM_Null );
- if( zPType ){
- pMem->flags = MEM_Null|MEM_Subtype|MEM_Term|MEM_Static;
- pMem->u.pPtr = pPtr;
- pMem->eSubtype = 'p';
- pMem->z = (char*)zPType;
- }
+ pMem->u.zPType = zPType ? zPType : "";
+ pMem->z = pPtr;
+ pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;
+ pMem->eSubtype = 'p';
+ pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor;
}
#ifndef SQLITE_OMIT_FLOATING_POINT
diff --git a/src/wherecode.c b/src/wherecode.c
index d577f1d3f..528aeec2b 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -794,7 +794,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
- char d2[3];
+ char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
diff --git a/src/whereexpr.c b/src/whereexpr.c
index 461c14af1..7a70b5445 100644
--- a/src/whereexpr.c
+++ b/src/whereexpr.c
@@ -199,7 +199,7 @@ static int isLikeOrGlob(
ExprList *pList; /* List of operands to the LIKE operator */
int c; /* One character in z[] */
int cnt; /* Number of non-wildcard prefix characters */
- char wc[3]; /* Wildcard characters */
+ char wc[4]; /* Wildcard characters */
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
@@ -246,16 +246,44 @@ static int isLikeOrGlob(
return 0;
}
}
+
+ /* Count the number of prefix characters prior to the first wildcard */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
+ if( c==wc[3] && z[cnt]!=0 ){
+ if( z[cnt++]>0xc0 ) while( (z[cnt]&0xc0)==0x80 ){ cnt++; }
+ }
}
+
+ /* The optimization is possible only if (1) the pattern does not begin
+ ** with a wildcard and if (2) the non-wildcard prefix does not end with
+ ** an (illegal 0xff) character. The second condition is necessary so
+ ** that we can increment the prefix key to find an upper bound for the
+ ** range search.
+ */
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
+
+ /* A "complete" match if the pattern ends with "*" or "%" */
*pisComplete = c==wc[0] && z[cnt+1]==0;
+
+ /* Get the pattern prefix. Remove all escapes from the prefix. */
pPrefix = sqlite3Expr(db, TK_STRING, z);
- if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
+ if( pPrefix ){
+ int iFrom, iTo;
+ char *zNew = pPrefix->u.zToken;
+ zNew[cnt] = 0;
+ for(iFrom=iTo=0; iFrom<cnt; iFrom++){
+ if( zNew[iFrom]==wc[3] ) iFrom++;
+ zNew[iTo++] = zNew[iFrom];
+ }
+ zNew[iTo] = 0;
+ }
*ppPrefix = pPrefix;
+
+ /* If the RHS pattern is a bound parameter, make arrangements to
+ ** reprepare the statement when that parameter is rebound */
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
sqlite3VdbeSetVarmask(v, pRight->iColumn);