Make it so that any Parse object is always linked into the database conenction
while it is active. Hence, an OOM will cause Parse.nErr to be set. FossilOrigin-Name: 6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec
This commit is contained in:
+2
-2
@@ -1132,7 +1132,7 @@ static int renameParseSql(
|
||||
/* Parse the SQL statement passed as the first argument. If no error
|
||||
** occurs and the parse does not result in a new table, index or
|
||||
** trigger object, the database must be corrupt. */
|
||||
memset(p, 0, sizeof(Parse));
|
||||
sqlite3ParseObjectInit(p, db);
|
||||
p->eParseMode = PARSE_MODE_RENAME;
|
||||
p->db = db;
|
||||
p->nQueryLoop = 1;
|
||||
@@ -1417,7 +1417,7 @@ static void renameParseCleanup(Parse *pParse){
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
sqlite3DbFree(db, pParse->zErrMsg);
|
||||
renameTokenFree(db, pParse->pRename);
|
||||
sqlite3ParserReset(pParse);
|
||||
sqlite3ParseObjectReset(pParse);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+2
-3
@@ -85,14 +85,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
||||
if( i==1 ){
|
||||
Parse sParse;
|
||||
int rc = 0;
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sParse.db = pDb;
|
||||
sqlite3ParseObjectInit(&sParse,pErrorDb);
|
||||
if( sqlite3OpenTempDatabase(&sParse) ){
|
||||
sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
sqlite3DbFree(pErrorDb, sParse.zErrMsg);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
if( rc ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
+29
-5
@@ -568,7 +568,7 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
||||
/*
|
||||
** Free all memory allocations in the pParse object
|
||||
*/
|
||||
void sqlite3ParserReset(Parse *pParse){
|
||||
void sqlite3ParseObjectReset(Parse *pParse){
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( pParse->nested==0 );
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
@@ -588,6 +588,9 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
||||
db->lookaside.bDisable -= pParse->disableLookaside;
|
||||
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
|
||||
assert( pParse->db->pParse==pParse );
|
||||
pParse->db->pParse = pParse->pOuterParse;
|
||||
pParse->db = 0;
|
||||
}
|
||||
pParse->disableLookaside = 0;
|
||||
}
|
||||
@@ -601,7 +604,7 @@ void sqlite3ParserReset(Parse *pParse){
|
||||
** cost for this mechansim (an extra malloc), so it should not be used
|
||||
** for common cleanups that happen on most calls. But for less
|
||||
** common cleanups, we save a single NULL-pointer comparison in
|
||||
** sqlite3ParserReset(), which reduces the total CPU cycle count.
|
||||
** sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
|
||||
**
|
||||
** If a memory allocation error occurs, then the cleanup happens immediately.
|
||||
** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
||||
@@ -641,6 +644,24 @@ void *sqlite3ParserAddCleanup(
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Turn bulk memory into a valid Parse object and link that Parse object
|
||||
** into database connection db.
|
||||
**
|
||||
** Call sqlite3ParseObjectReset() to undo this operation.
|
||||
**
|
||||
** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which
|
||||
** is generated by Lemon.
|
||||
*/
|
||||
void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){
|
||||
memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ);
|
||||
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
|
||||
assert( db->pParse!=pParse );
|
||||
pParse->pOuterParse = db->pParse;
|
||||
db->pParse = pParse;
|
||||
pParse->db = db;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
||||
*/
|
||||
@@ -657,8 +678,12 @@ static int sqlite3Prepare(
|
||||
int i; /* Loop counter */
|
||||
Parse sParse; /* Parsing context */
|
||||
|
||||
memset(&sParse, 0, PARSE_HDR_SZ);
|
||||
/* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */
|
||||
memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ);
|
||||
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
|
||||
sParse.pOuterParse = db->pParse;
|
||||
db->pParse = &sParse;
|
||||
sParse.db = db;
|
||||
sParse.pReprepare = pReprepare;
|
||||
assert( ppStmt && *ppStmt==0 );
|
||||
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
|
||||
@@ -714,7 +739,6 @@ static int sqlite3Prepare(
|
||||
|
||||
sqlite3VtabUnlockList(db);
|
||||
|
||||
sParse.db = db;
|
||||
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
||||
char *zSqlCopy;
|
||||
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
||||
@@ -781,7 +805,7 @@ static int sqlite3Prepare(
|
||||
|
||||
end_prepare:
|
||||
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
return rc;
|
||||
}
|
||||
static int sqlite3LockAndPrepare(
|
||||
|
||||
+5
-2
@@ -3585,6 +3585,7 @@ struct Parse {
|
||||
**************************************************************************/
|
||||
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
Parse *pOuterParse; /* Outer Parse object when nested */
|
||||
Token sNameToken; /* Token with unqualified schema object name */
|
||||
|
||||
/************************************************************************
|
||||
@@ -3635,7 +3636,8 @@ struct Parse {
|
||||
/*
|
||||
** Sizes and pointers of various parts of the Parse object.
|
||||
*/
|
||||
#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
|
||||
#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg))
|
||||
#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/
|
||||
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
|
||||
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
|
||||
#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
|
||||
@@ -5096,7 +5098,8 @@ FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
||||
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
void sqlite3ParseObjectInit(Parse*,sqlite3*);
|
||||
void sqlite3ParseObjectReset(Parse*);
|
||||
void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *sqlite3Normalize(Vdbe*, const char*);
|
||||
|
||||
+20
-24
@@ -1110,8 +1110,8 @@ static TriggerPrg *codeRowTrigger(
|
||||
Vdbe *v; /* Temporary VM */
|
||||
NameContext sNC; /* Name context for sub-vdbe */
|
||||
SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */
|
||||
Parse *pSubParse; /* Parse context for sub-vdbe */
|
||||
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
||||
Parse sSubParse; /* Parse context for sub-vdbe */
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTop->pVdbe );
|
||||
@@ -1133,19 +1133,17 @@ static TriggerPrg *codeRowTrigger(
|
||||
|
||||
/* Allocate and populate a new Parse context to use for coding the
|
||||
** trigger sub-program. */
|
||||
pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
|
||||
if( !pSubParse ) return 0;
|
||||
sqlite3ParseObjectInit(&sSubParse, db);
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pSubParse;
|
||||
pSubParse->db = db;
|
||||
pSubParse->pTriggerTab = pTab;
|
||||
pSubParse->pToplevel = pTop;
|
||||
pSubParse->zAuthContext = pTrigger->zName;
|
||||
pSubParse->eTriggerOp = pTrigger->op;
|
||||
pSubParse->nQueryLoop = pParse->nQueryLoop;
|
||||
pSubParse->disableVtab = pParse->disableVtab;
|
||||
sNC.pParse = &sSubParse;
|
||||
sSubParse.pTriggerTab = pTab;
|
||||
sSubParse.pToplevel = pTop;
|
||||
sSubParse.zAuthContext = pTrigger->zName;
|
||||
sSubParse.eTriggerOp = pTrigger->op;
|
||||
sSubParse.nQueryLoop = pParse->nQueryLoop;
|
||||
sSubParse.disableVtab = pParse->disableVtab;
|
||||
|
||||
v = sqlite3GetVdbe(pSubParse);
|
||||
v = sqlite3GetVdbe(&sSubParse);
|
||||
if( v ){
|
||||
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
|
||||
pTrigger->zName, onErrorText(orconf),
|
||||
@@ -1171,15 +1169,14 @@ static TriggerPrg *codeRowTrigger(
|
||||
if( db->mallocFailed==0
|
||||
&& SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
|
||||
){
|
||||
iEndTrigger = sqlite3VdbeMakeLabel(pSubParse);
|
||||
sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
||||
iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse);
|
||||
sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3ExprDelete(db, pWhen);
|
||||
}
|
||||
|
||||
/* Code the trigger program into the sub-vdbe. */
|
||||
codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
|
||||
transferParseError(pParse, pSubParse);
|
||||
codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf);
|
||||
|
||||
/* Insert an OP_Halt at the end of the sub-program. */
|
||||
if( iEndTrigger ){
|
||||
@@ -1187,22 +1184,21 @@ static TriggerPrg *codeRowTrigger(
|
||||
}
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
|
||||
transferParseError(pParse, &sSubParse);
|
||||
|
||||
if( db->mallocFailed==0 && pParse->nErr==0 ){
|
||||
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
pProgram->nCsr = pSubParse->nTab;
|
||||
pProgram->nMem = sSubParse.nMem;
|
||||
pProgram->nCsr = sSubParse.nTab;
|
||||
pProgram->token = (void *)pTrigger;
|
||||
pPrg->aColmask[0] = pSubParse->oldmask;
|
||||
pPrg->aColmask[1] = pSubParse->newmask;
|
||||
pPrg->aColmask[0] = sSubParse.oldmask;
|
||||
pPrg->aColmask[1] = sSubParse.newmask;
|
||||
sqlite3VdbeDelete(v);
|
||||
}
|
||||
|
||||
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
|
||||
sqlite3ParserReset(pSubParse);
|
||||
sqlite3StackFree(db, pSubParse);
|
||||
|
||||
assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg );
|
||||
sqlite3ParseObjectReset(&sSubParse);
|
||||
return pPrg;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,8 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
||||
char *zMsg;
|
||||
va_list ap;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( db!=0 );
|
||||
assert( db->pParse==pParse );
|
||||
db->errByteOffset = -2;
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3VMPrintf(db, zFormat, ap);
|
||||
|
||||
+6
-5
@@ -152,10 +152,9 @@ int sqlite3_blob_open(
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
||||
do {
|
||||
memset(&sParse, 0, sizeof(Parse));
|
||||
while(1){
|
||||
sqlite3ParseObjectInit(&sParse,db);
|
||||
if( !pBlob ) goto blob_open_out;
|
||||
sParse.db = db;
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = 0;
|
||||
|
||||
@@ -332,7 +331,9 @@ int sqlite3_blob_open(
|
||||
goto blob_open_out;
|
||||
}
|
||||
rc = blobSeekToRow(pBlob, iRow, &zErr);
|
||||
} while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
|
||||
if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break;
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
}
|
||||
|
||||
blob_open_out:
|
||||
if( rc==SQLITE_OK && db->mallocFailed==0 ){
|
||||
@@ -343,7 +344,7 @@ blob_open_out:
|
||||
}
|
||||
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
|
||||
+2
-3
@@ -825,9 +825,8 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pTab = pCtx->pTab;
|
||||
assert( IsVirtual(pTab) );
|
||||
|
||||
memset(&sParse, 0, sizeof(sParse));
|
||||
sqlite3ParseObjectInit(&sParse, db);
|
||||
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
|
||||
sParse.db = db;
|
||||
/* We should never be able to reach this point while loading the
|
||||
** schema. Nevertheless, defend against that (turn off db->init.busy)
|
||||
** in case a bug arises. */
|
||||
@@ -881,7 +880,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
sqlite3VdbeFinalize(sParse.pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(db, sParse.pNewTable);
|
||||
sqlite3ParserReset(&sParse);
|
||||
sqlite3ParseObjectReset(&sParse);
|
||||
db->init.busy = initBusy;
|
||||
|
||||
assert( (rc&0xff)==rc );
|
||||
|
||||
Reference in New Issue
Block a user