@@ -951,6 +951,72 @@ static ExprList *sqlite3ExpandReturning(
951
951
return pNew ;
952
952
}
953
953
954
+ /* If the Expr node is a subquery or an EXISTS operator or an IN operator that
955
+ ** uses a subquery, and if the subquery is SF_Correlated, then mark the
956
+ ** expression as EP_VarSelect.
957
+ */
958
+ static int sqlite3ReturningSubqueryVarSelect (Walker * NotUsed , Expr * pExpr ){
959
+ UNUSED_PARAMETER (NotUsed );
960
+ if ( ExprUseXSelect (pExpr )
961
+ && (pExpr -> x .pSelect -> selFlags & SF_Correlated )!= 0
962
+ ){
963
+ testcase ( ExprHasProperty (pExpr , EP_VarSelect ) );
964
+ ExprSetProperty (pExpr , EP_VarSelect );
965
+ }
966
+ return WRC_Continue ;
967
+ }
968
+
969
+
970
+ /*
971
+ ** If the SELECT references the table pWalker->u.pTab, then do two things:
972
+ **
973
+ ** (1) Mark the SELECT as as SF_Correlated.
974
+ ** (2) Set pWalker->eCode to non-zero so that the caller will know
975
+ ** that (1) has happened.
976
+ */
977
+ static int sqlite3ReturningSubqueryCorrelated (Walker * pWalker , Select * pSelect ){
978
+ int i ;
979
+ SrcList * pSrc ;
980
+ assert ( pSelect != 0 );
981
+ pSrc = pSelect -> pSrc ;
982
+ assert ( pSrc != 0 );
983
+ for (i = 0 ; i < pSrc -> nSrc ; i ++ ){
984
+ if ( pSrc -> a [i ].pTab == pWalker -> u .pTab ){
985
+ testcase ( pSelect -> selFlags & SF_Correlated );
986
+ pSelect -> selFlags |= SF_Correlated ;
987
+ pWalker -> eCode = 1 ;
988
+ break ;
989
+ }
990
+ }
991
+ return WRC_Continue ;
992
+ }
993
+
994
+ /*
995
+ ** Scan the expression list that is the argument to RETURNING looking
996
+ ** for subqueries that depend on the table which is being modified in the
997
+ ** statement that is hosting the RETURNING clause (pTab). Mark all such
998
+ ** subqueries as SF_Correlated. If the subqueries are part of an
999
+ ** expression, mark the expression as EP_VarSelect.
1000
+ **
1001
+ ** https://sqlite.org/forum/forumpost/2c83569ce8945d39
1002
+ */
1003
+ static void sqlite3ProcessReturningSubqueries (
1004
+ ExprList * pEList ,
1005
+ Table * pTab
1006
+ ){
1007
+ Walker w ;
1008
+ memset (& w , 0 , sizeof (w ));
1009
+ w .xExprCallback = sqlite3ExprWalkNoop ;
1010
+ w .xSelectCallback = sqlite3ReturningSubqueryCorrelated ;
1011
+ w .u .pTab = pTab ;
1012
+ sqlite3WalkExprList (& w , pEList );
1013
+ if ( w .eCode ){
1014
+ w .xExprCallback = sqlite3ReturningSubqueryVarSelect ;
1015
+ w .xSelectCallback = sqlite3SelectWalkNoop ;
1016
+ sqlite3WalkExprList (& w , pEList );
1017
+ }
1018
+ }
1019
+
954
1020
/*
955
1021
** Generate code for the RETURNING trigger. Unlike other triggers
956
1022
** that invoke a subprogram in the bytecode, the code for RETURNING
@@ -1014,6 +1080,7 @@ static void codeReturningTrigger(
1014
1080
int i ;
1015
1081
int nCol = pNew -> nExpr ;
1016
1082
int reg = pParse -> nMem + 1 ;
1083
+ sqlite3ProcessReturningSubqueries (pNew , pTab );
1017
1084
pParse -> nMem += nCol + 2 ;
1018
1085
pReturning -> iRetReg = reg ;
1019
1086
for (i = 0 ; i < nCol ; i ++ ){
0 commit comments