Upgrade SQLite to 3.40 (#699)

This commit is contained in:
Paul Kulchenko 2022-11-28 12:54:48 -08:00 committed by GitHub
parent bcae817215
commit 0dc0758574
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 27917 additions and 22169 deletions

View file

@ -10,8 +10,7 @@
*************************************************************************
** This file contains the implementation for TRIGGERs
*/
#include "third_party/sqlite3/sqliteInt.inc"
/* clang-format off */
#include "third_party/sqlite3/sqliteInt.h"
#ifndef SQLITE_OMIT_TRIGGER
/*
@ -53,34 +52,43 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
Trigger *pList; /* List of triggers to return */
HashElem *p; /* Loop variable for TEMP triggers */
if( pParse->disableTriggers ){
return 0;
}
assert( pParse->disableTriggers==0 );
pTmpSchema = pParse->db->aDb[1].pSchema;
p = sqliteHashFirst(&pTmpSchema->trigHash);
if( p==0 ){
return pTab->pTrigger;
}
pList = pTab->pTrigger;
if( pTmpSchema!=pTab->pSchema ){
while( p ){
Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
){
pTrig->pNext = pList;
pList = pTrig;
}else if( pTrig->op==TK_RETURNING ){
assert( pParse->bReturning );
assert( &(pParse->u1.pReturning->retTrig) == pTrig );
pTrig->table = pTab->zName;
pTrig->pTabSchema = pTab->pSchema;
pTrig->pNext = pList;
pList = pTrig;
}
p = sqliteHashNext(p);
}
while( p ){
Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema
&& pTrig->table
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
&& pTrig->pTabSchema!=pTmpSchema
){
pTrig->pNext = pList;
pList = pTrig;
}else if( pTrig->op==TK_RETURNING ){
#ifndef SQLITE_OMIT_VIRTUALTABLE
assert( pParse->db->pVtabCtx==0 );
#endif
assert( pParse->bReturning );
assert( &(pParse->u1.pReturning->retTrig) == pTrig );
pTrig->table = pTab->zName;
pTrig->pTabSchema = pTab->pSchema;
pTrig->pNext = pList;
pList = pTrig;
}
p = sqliteHashNext(p);
}
#if 0
if( pList ){
Trigger *pX;
printf("Triggers for %s:", pTab->zName);
for(pX=pList; pX; pX=pX->pNext){
printf(" %s", pX->zName);
}
printf("\n");
fflush(stdout);
}
#endif
return pList;
}
@ -208,14 +216,14 @@ void sqlite3BeginTrigger(
/* INSTEAD of triggers are only for views and views only support INSTEAD
** of triggers.
*/
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
if( IsView(pTab) && tr_tm!=TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a);
goto trigger_orphan_error;
}
if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
if( !IsView(pTab) && tr_tm==TK_INSTEAD ){
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
" trigger on table: %S", pTableName, 0);
" trigger on table: %S", pTableName->a);
goto trigger_orphan_error;
}
@ -343,6 +351,23 @@ void sqlite3FinishTrigger(
Vdbe *v;
char *z;
/* If this is a new CREATE TABLE statement, and if shadow tables
** are read-only, and the trigger makes a change to a shadow table,
** then raise an error - do not allow the trigger to be created. */
if( sqlite3ReadOnlyShadowTables(db) ){
TriggerStep *pStep;
for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
if( pStep->zTarget!=0
&& sqlite3ShadowTableName(db, pStep->zTarget)
){
sqlite3ErrorMsg(pParse,
"trigger \"%s\" may not write to shadow table \"%s\"",
pTrig->zName, pStep->zTarget);
goto triggerfinish_cleanup;
}
}
}
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
@ -350,7 +375,7 @@ void sqlite3FinishTrigger(
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
testcase( z==0 );
sqlite3NestedParse(pParse,
"INSERT INTO %Q." DFLT_SCHEMA_TABLE
"INSERT INTO %Q." LEGACY_SCHEMA_TABLE
" VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zDbSName, zName,
pTrig->table, z);
@ -435,6 +460,7 @@ static TriggerStep *triggerStepAllocate(
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
if( pParse->nErr ) return 0;
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
if( pTriggerStep ){
char *z = (char*)&pTriggerStep[1];
@ -505,7 +531,7 @@ TriggerStep *sqlite3TriggerInsertStep(
TriggerStep *sqlite3TriggerUpdateStep(
Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table to be updated */
SrcList *pFrom,
SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
@ -612,7 +638,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
}
if( !pTrigger ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a);
}else{
sqlite3CodeVerifyNamedSchema(pParse, zDb);
}
@ -664,7 +690,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
*/
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
"DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
db->aDb[iDb].zDbSName, pTrigger->zName
);
sqlite3ChangeCookie(pParse, iDb);
@ -718,13 +744,22 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
return 0;
}
/*
** Return true if any TEMP triggers exist
*/
static int tempTriggersExist(sqlite3 *db){
if( NEVER(db->aDb[1].pSchema==0) ) return 0;
if( sqliteHashFirst(&db->aDb[1].pSchema->trigHash)==0 ) return 0;
return 1;
}
/*
** Return a list of all triggers on table pTab if there exists at least
** one trigger that must be fired when an operation of type 'op' is
** performed on the table, and, if that operation is an UPDATE, if at
** least one of the columns in pChanges is being modified.
*/
Trigger *sqlite3TriggersExist(
static SQLITE_NOINLINE Trigger *triggersReallyExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
@ -787,6 +822,22 @@ exit_triggers_exist:
}
return (mask ? pList : 0);
}
Trigger *sqlite3TriggersExist(
Parse *pParse, /* Parse context */
Table *pTab, /* The table the contains the triggers */
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
ExprList *pChanges, /* Columns that change in an UPDATE statement */
int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
){
assert( pTab!=0 );
if( (pTab->pTrigger==0 && !tempTriggersExist(pParse->db))
|| pParse->disableTriggers
){
if( pMask ) *pMask = 0;
return 0;
}
return triggersReallyExist(pParse,pTab,op,pChanges,pMask);
}
/*
** Convert the pStep->zTarget string into a SrcList and return a pointer
@ -816,6 +867,14 @@ SrcList *sqlite3TriggerStepSrc(
}
if( pStep->pFrom ){
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
Select *pSubquery;
Token as;
pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0);
as.n = 0;
as.z = 0;
pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
}
pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
}
}else{
@ -866,12 +925,12 @@ static ExprList *sqlite3ExpandReturning(
for(jj=0; jj<pTab->nCol; jj++){
Expr *pNewExpr;
if( IsHiddenColumn(pTab->aCol+jj) ) continue;
pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zName);
pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName);
pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr);
if( !db->mallocFailed ){
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zName);
pItem->eEName = ENAME_NAME;
pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName);
pItem->fg.eEName = ENAME_NAME;
}
}
}else{
@ -880,19 +939,10 @@ static ExprList *sqlite3ExpandReturning(
if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){
struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName);
pItem->eEName = pList->a[i].eEName;
pItem->fg.eEName = pList->a[i].fg.eEName;
}
}
}
if( !db->mallocFailed ){
Vdbe *v = pParse->pVdbe;
assert( v!=0 );
sqlite3VdbeSetNumCols(v, pNew->nExpr);
for(i=0; i<pNew->nExpr; i++){
sqlite3VdbeSetColName(v, i, COLNAME_NAME, pNew->a[i].zEName,
SQLITE_TRANSIENT);
}
}
return pNew;
}
@ -908,15 +958,32 @@ static void codeReturningTrigger(
int regIn /* The first in an array of registers */
){
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
ExprList *pNew;
Returning *pReturning;
Select sSelect;
SrcList sFrom;
assert( v!=0 );
assert( pParse->bReturning );
assert( db->pParse==pParse );
pReturning = pParse->u1.pReturning;
assert( pTrigger == &(pReturning->retTrig) );
memset(&sSelect, 0, sizeof(sSelect));
memset(&sFrom, 0, sizeof(sFrom));
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = &sFrom;
sFrom.nSrc = 1;
sFrom.a[0].pTab = pTab;
sFrom.a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
assert( db->mallocFailed==0 );
sqlite3GenerateColumnNames(pParse, &sSelect);
}
sqlite3ExprListDelete(db, sSelect.pEList);
pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
if( pNew ){
if( !db->mallocFailed ){
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
if( pReturning->nRetCol==0 ){
@ -928,23 +995,30 @@ static void codeReturningTrigger(
sNC.ncFlags = NC_UBaseReg;
pParse->eTriggerOp = pTrigger->op;
pParse->pTriggerTab = pTab;
if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK ){
if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK
&& ALWAYS(!db->mallocFailed)
){
int i;
int nCol = pNew->nExpr;
int reg = pParse->nMem+1;
pParse->nMem += nCol+2;
pReturning->iRetReg = reg;
for(i=0; i<nCol; i++){
sqlite3ExprCodeFactorable(pParse, pNew->a[i].pExpr, reg+i);
Expr *pCol = pNew->a[i].pExpr;
assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */
sqlite3ExprCodeFactorable(pParse, pCol, reg+i);
if( sqlite3ExprAffinity(pCol)==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, reg+i);
}
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i);
sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1);
sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1);
}
sqlite3ExprListDelete(pParse->db, pNew);
pParse->eTriggerOp = 0;
pParse->pTriggerTab = 0;
}
sqlite3ExprListDelete(db, pNew);
pParse->eTriggerOp = 0;
pParse->pTriggerTab = 0;
}
@ -1086,8 +1160,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 );
@ -1109,19 +1183,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.prepFlags = pParse->prepFlags;
v = sqlite3GetVdbe(pSubParse);
v = sqlite3GetVdbe(&sSubParse);
if( v ){
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
pTrigger->zName, onErrorText(orconf),
@ -1144,17 +1216,17 @@ static TriggerPrg *codeRowTrigger(
** OP_Halt inserted at the end of the program. */
if( pTrigger->pWhen ){
pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
&& db->mallocFailed==0
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);
codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf);
/* Insert an OP_Halt at the end of the sub-program. */
if( iEndTrigger ){
@ -1162,23 +1234,24 @@ static TriggerPrg *codeRowTrigger(
}
sqlite3VdbeAddOp0(v, OP_Halt);
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
transferParseError(pParse, &sSubParse);
transferParseError(pParse, pSubParse);
if( db->mallocFailed==0 && pParse->nErr==0 ){
if( pParse->nErr==0 ){
assert( db->mallocFailed==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);
}else{
transferParseError(pParse, &sSubParse);
}
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
sqlite3ParserReset(pSubParse);
sqlite3StackFree(db, pSubParse);
assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg );
sqlite3ParseObjectReset(&sSubParse);
return pPrg;
}
@ -1211,6 +1284,7 @@ static TriggerPrg *getRowTrigger(
/* If an existing TriggerPrg could not be located, create a new one. */
if( !pPrg ){
pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf);
pParse->db->errByteOffset = -1;
}
return pPrg;
@ -1233,7 +1307,7 @@ void sqlite3CodeRowTriggerDirect(
Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
TriggerPrg *pPrg;
pPrg = getRowTrigger(pParse, p, pTab, orconf);
assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
assert( pPrg || pParse->nErr );
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
** is a pointer to the sub-vdbe containing the trigger program. */