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:
drh
2022-01-24 15:34:55 +00:00
parent b5d4473221
commit c692df2784
10 changed files with 83 additions and 59 deletions
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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 );