aboutsummaryrefslogtreecommitdiff
path: root/src/trigger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trigger.c')
-rw-r--r--src/trigger.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/src/trigger.c b/src/trigger.c
index 97ca249be..ff2df82cb 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -152,8 +152,10 @@ void sqlite3BeginTrigger(
** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
- sqlite3DbFree(db, pTableName->a[0].zDatabase);
- pTableName->a[0].zDatabase = 0;
+ assert( pTableName->a[0].fg.fixedSchema==0 );
+ assert( pTableName->a[0].fg.isSubquery==0 );
+ sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
+ pTableName->a[0].u4.zDatabase = 0;
}
/* If the trigger name was unqualified, and the table is a temp table,
@@ -631,7 +633,8 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
}
assert( pName->nSrc==1 );
- zDb = pName->a[0].zDatabase;
+ assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
+ zDb = pName->a[0].u4.zDatabase;
zName = pName->a[0].zName;
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
@@ -868,7 +871,9 @@ SrcList *sqlite3TriggerStepSrc(
Schema *pSchema = pStep->pTrig->pSchema;
pSrc->a[0].zName = zName;
if( pSchema!=db->aDb[1].pSchema ){
- pSrc->a[0].pSchema = pSchema;
+ assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
+ pSrc->a[0].u4.pSchema = pSchema;
+ pSrc->a[0].fg.fixedSchema = 1;
}
if( pStep->pFrom ){
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
@@ -951,6 +956,72 @@ static ExprList *sqlite3ExpandReturning(
return pNew;
}
+/* If the Expr node is a subquery or an EXISTS operator or an IN operator that
+** uses a subquery, and if the subquery is SF_Correlated, then mark the
+** expression as EP_VarSelect.
+*/
+static int sqlite3ReturningSubqueryVarSelect(Walker *NotUsed, Expr *pExpr){
+ UNUSED_PARAMETER(NotUsed);
+ if( ExprUseXSelect(pExpr)
+ && (pExpr->x.pSelect->selFlags & SF_Correlated)!=0
+ ){
+ testcase( ExprHasProperty(pExpr, EP_VarSelect) );
+ ExprSetProperty(pExpr, EP_VarSelect);
+ }
+ return WRC_Continue;
+}
+
+
+/*
+** If the SELECT references the table pWalker->u.pTab, then do two things:
+**
+** (1) Mark the SELECT as as SF_Correlated.
+** (2) Set pWalker->eCode to non-zero so that the caller will know
+** that (1) has happened.
+*/
+static int sqlite3ReturningSubqueryCorrelated(Walker *pWalker, Select *pSelect){
+ int i;
+ SrcList *pSrc;
+ assert( pSelect!=0 );
+ pSrc = pSelect->pSrc;
+ assert( pSrc!=0 );
+ for(i=0; i<pSrc->nSrc; i++){
+ if( pSrc->a[i].pSTab==pWalker->u.pTab ){
+ testcase( pSelect->selFlags & SF_Correlated );
+ pSelect->selFlags |= SF_Correlated;
+ pWalker->eCode = 1;
+ break;
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Scan the expression list that is the argument to RETURNING looking
+** for subqueries that depend on the table which is being modified in the
+** statement that is hosting the RETURNING clause (pTab). Mark all such
+** subqueries as SF_Correlated. If the subqueries are part of an
+** expression, mark the expression as EP_VarSelect.
+**
+** https://sqlite.org/forum/forumpost/2c83569ce8945d39
+*/
+static void sqlite3ProcessReturningSubqueries(
+ ExprList *pEList,
+ Table *pTab
+){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3ExprWalkNoop;
+ w.xSelectCallback = sqlite3ReturningSubqueryCorrelated;
+ w.u.pTab = pTab;
+ sqlite3WalkExprList(&w, pEList);
+ if( w.eCode ){
+ w.xExprCallback = sqlite3ReturningSubqueryVarSelect;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ sqlite3WalkExprList(&w, pEList);
+ }
+}
+
/*
** Generate code for the RETURNING trigger. Unlike other triggers
** that invoke a subprogram in the bytecode, the code for RETURNING
@@ -986,7 +1057,8 @@ static void codeReturningTrigger(
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = &sFrom;
sFrom.nSrc = 1;
- sFrom.a[0].pTab = pTab;
+ sFrom.a[0].pSTab = pTab;
+ sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
sFrom.a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
@@ -1013,6 +1085,7 @@ static void codeReturningTrigger(
int i;
int nCol = pNew->nExpr;
int reg = pParse->nMem+1;
+ sqlite3ProcessReturningSubqueries(pNew, pTab);
pParse->nMem += nCol+2;
pReturning->iRetReg = reg;
for(i=0; i<nCol; i++){