aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2020-06-07 17:33:18 +0000
committerdrh <drh@noemail.net>2020-06-07 17:33:18 +0000
commit896366282dae3789fb277c2dad8660784a0895a3 (patch)
treeab2a2f656f0c46a8e021d349324b7f8303721e43 /src/expr.c
parenta0365c487c1267af6d3ab101399c6fa35f5184a3 (diff)
downloadsqlite-896366282dae3789fb277c2dad8660784a0895a3.tar.gz
sqlite-896366282dae3789fb277c2dad8660784a0895a3.zip
Alternative fix to ticket [c8d3b9f0a750a529]: Prior to deleting or modifying
an Expr not that is referenced by an AggInfo, modify the AggInfo to get its own copy of the original Expr. FossilOrigin-Name: 7682d8a768fbccfe0cc956e9f6481637146e1ab9763b248ff11052761ce32e32
Diffstat (limited to 'src/expr.c')
-rw-r--r--src/expr.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/src/expr.c b/src/expr.c
index 496177a5c..631d71568 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -5710,6 +5710,66 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
}
/*
+** This is a Walker expression node callback.
+**
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
+** object that is referenced does not refer directly to the Expr. If
+** it does, make a copy. This is done because the pExpr argument is
+** subject to change.
+**
+** The copy is stored on pParse->pConstExpr with a register number of 0.
+** This will cause the expression to be deleted automatically when the
+** Parse object is destroyed, but the zero register number means that it
+** will not generate any code in the preamble.
+*/
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
+ if( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced)
+ && pExpr->pAggInfo!=0
+ ){
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ int iAgg = pExpr->iAgg;
+ Parse *pParse = pWalker->pParse;
+ sqlite3 *db = pParse->db;
+ assert( pAggInfo->iAggMagic==AggInfoMagic );
+ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN
+ || pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION );
+ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
+ assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
+ if( pAggInfo->aCol[iAgg].pExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aCol[iAgg].pExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }else{
+ assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
+ if( pAggInfo->aFunc[iAgg].pExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aFunc[iAgg].pExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Initialize a Walker object so that will persist AggInfo entries referenced
+** by the tree that is walked.
+*/
+void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
+ memset(pWalker, 0, sizeof(*pWalker));
+ pWalker->pParse = pParse;
+ pWalker->xExprCallback = agginfoPersistExprCb;
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
+}
+
+/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
@@ -5739,7 +5799,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
&i
);
return i;
-}
+}
/*
** This is the xExprCallback for a tree walker. It is used to