707 lines
26 KiB
Diff
707 lines
26 KiB
Diff
From 896366282dae3789fb277c2dad8660784a0895a3 Mon Sep 17 00:00:00 2001
|
|
From: drh <drh@noemail.net>
|
|
Date: Sun, 7 Jun 2020 17:33:18 +0000
|
|
Subject: [PATCH 1/3] 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.
|
|
|
|
patch reference:
|
|
https://www.sqlite.org/src/info/6e6b3729e0549de0
|
|
|
|
FossilOrigin-Name: 7682d8a768fbccfe0cc956e9f6481637146e1ab9763b248ff11052761ce32e32
|
|
---
|
|
src/build.c | 12 +++-
|
|
src/expr.c | 61 ++++++++++++++++++-
|
|
src/prepare.c | 15 +++++
|
|
src/select.c | 128 ++++++++++++++++++++++++----------------
|
|
src/sqliteInt.h | 12 +++-
|
|
src/window.c | 4 ++
|
|
test/window1.test | 146 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
7 files changed, 324 insertions(+), 54 deletions(-)
|
|
|
|
diff --git a/src/build.c b/src/build.c
|
|
index f1d078f..5846215 100644
|
|
--- a/src/build.c
|
|
+++ b/src/build.c
|
|
@@ -208,11 +208,21 @@ void sqlite3FinishCoding(Parse *pParse){
|
|
sqlite3AutoincrementBegin(pParse);
|
|
|
|
/* Code constant expressions that where factored out of inner loops */
|
|
+ /* Code constant expressions that where factored out of inner loops.
|
|
+ **
|
|
+ ** The pConstExpr list might also contain expressions that we simply
|
|
+ ** want to keep around until the Parse object is deleted. Such
|
|
+ ** expressions have iConstExprReg==0. Do not generate code for
|
|
+ ** those expressions, of course.
|
|
+ */
|
|
if( pParse->pConstExpr ){
|
|
ExprList *pEL = pParse->pConstExpr;
|
|
pParse->okConstFactor = 0;
|
|
for(i=0; i<pEL->nExpr; i++){
|
|
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
|
+ int iReg = pEL->a[i].u.iConstExprReg;
|
|
+ if( iReg>0 ){
|
|
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
diff --git a/src/expr.c b/src/expr.c
|
|
index af779d3..07e1612 100644
|
|
--- a/src/expr.c
|
|
+++ b/src/expr.c
|
|
@@ -52,7 +52,12 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
|
op = pExpr->op;
|
|
if( op==TK_SELECT ){
|
|
assert( pExpr->flags&EP_xIsSelect );
|
|
- return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
|
+ if( ALWAYS(pExpr->x.pSelect)
|
|
+ && pExpr->x.pSelect->pEList
|
|
+ && ALWAYS(pExpr->x.pSelect->pEList->a[0].pExpr)
|
|
+ ){
|
|
+ return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
|
+ }
|
|
}
|
|
if( op==TK_REGISTER ) op = pExpr->op2;
|
|
#ifndef SQLITE_OMIT_CAST
|
|
@@ -5658,6 +5663,60 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
|
#endif
|
|
return cnt.nThis>0 || cnt.nOther==0;
|
|
}
|
|
+/*
|
|
+** 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( ALWAYS(!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( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
|
|
+ if( 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
|
|
diff --git a/src/prepare.c b/src/prepare.c
|
|
index 2d928f1..e012ad4 100644
|
|
--- a/src/prepare.c
|
|
+++ b/src/prepare.c
|
|
@@ -530,11 +530,26 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
|
return i;
|
|
}
|
|
|
|
+/*
|
|
+** Deallocate a single AggInfo object
|
|
+*/
|
|
+static void agginfoFree(sqlite3 *db, AggInfo *p){
|
|
+ sqlite3DbFree(db, p->aCol);
|
|
+ sqlite3DbFree(db, p->aFunc);
|
|
+ sqlite3DbFree(db, p);
|
|
+}
|
|
+
|
|
/*
|
|
** Free all memory allocations in the pParse object
|
|
*/
|
|
void sqlite3ParserReset(Parse *pParse){
|
|
sqlite3 *db = pParse->db;
|
|
+ AggInfo *pThis = pParse->pAggList;
|
|
+ while( pThis ){
|
|
+ AggInfo *pNext = pThis->pNext;
|
|
+ agginfoFree(db, pThis);
|
|
+ pThis = pNext;
|
|
+ }
|
|
sqlite3DbFree(db, pParse->aLabel);
|
|
sqlite3ExprListDelete(db, pParse->pConstExpr);
|
|
if( db ){
|
|
diff --git a/src/select.c b/src/select.c
|
|
index 9a16e8e..f117cd1 100644
|
|
--- a/src/select.c
|
|
+++ b/src/select.c
|
|
@@ -3752,6 +3752,7 @@ static int flattenSubquery(
|
|
Expr *pWhere; /* The WHERE clause */
|
|
struct SrcList_item *pSubitem; /* The subquery */
|
|
sqlite3 *db = pParse->db;
|
|
+ Walker w; /* Walker to persist agginfo data */
|
|
|
|
/* Check to see if flattening is permitted. Return 0 if not.
|
|
*/
|
|
@@ -4120,6 +4121,8 @@ static int flattenSubquery(
|
|
/* Finially, delete what is left of the subquery and return
|
|
** success.
|
|
*/
|
|
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
|
+ sqlite3WalkSelect(&w,pSub1);
|
|
sqlite3SelectDelete(db, pSub1);
|
|
|
|
#if SELECTTRACE_ENABLED
|
|
@@ -5729,10 +5732,10 @@ int sqlite3Select(
|
|
Expr *pWhere; /* The WHERE clause. May be NULL */
|
|
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
|
Expr *pHaving; /* The HAVING clause. May be NULL */
|
|
+ AggInfo *pAggInfo = 0; /* Aggregate information */
|
|
int rc = 1; /* Value to return from this function */
|
|
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
|
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
|
- AggInfo sAggInfo; /* Information used by aggregate queries */
|
|
int iEnd; /* Address of the end of the query */
|
|
sqlite3 *db; /* The database connection */
|
|
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
|
|
@@ -5744,7 +5747,6 @@ int sqlite3Select(
|
|
return 1;
|
|
}
|
|
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
|
- memset(&sAggInfo, 0, sizeof(sAggInfo));
|
|
#if SELECTTRACE_ENABLED
|
|
SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
|
if( sqlite3SelectTrace & 0x100 ){
|
|
@@ -6335,14 +6337,20 @@ int sqlite3Select(
|
|
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
|
|
** SELECT statement.
|
|
*/
|
|
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
|
+ if( pAggInfo==0 ){
|
|
+ goto select_end;
|
|
+ }
|
|
+ pAggInfo->pNext = pParse->pAggList;
|
|
+ pParse->pAggList = pAggInfo;
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = pParse;
|
|
sNC.pSrcList = pTabList;
|
|
- sNC.uNC.pAggInfo = &sAggInfo;
|
|
+ sNC.uNC.pAggInfo = pAggInfo;
|
|
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
|
|
- sAggInfo.mnReg = pParse->nMem+1;
|
|
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
|
- sAggInfo.pGroupBy = pGroupBy;
|
|
+ pAggInfo->mnReg = pParse->nMem+1;
|
|
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
|
+ pAggInfo->pGroupBy = pGroupBy;
|
|
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
|
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
|
if( pHaving ){
|
|
@@ -6355,14 +6363,14 @@ int sqlite3Select(
|
|
}
|
|
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
|
}
|
|
- sAggInfo.nAccumulator = sAggInfo.nColumn;
|
|
- if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
|
|
- minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
|
|
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
|
|
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
|
|
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pExpr, &pMinMaxOrderBy);
|
|
}else{
|
|
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
|
}
|
|
- for(i=0; i<sAggInfo.nFunc; i++){
|
|
- Expr *pExpr = sAggInfo.aFunc[i].pExpr;
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
sNC.ncFlags |= NC_InAggFunc;
|
|
sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
|
@@ -6374,22 +6382,22 @@ int sqlite3Select(
|
|
#endif
|
|
sNC.ncFlags &= ~NC_InAggFunc;
|
|
}
|
|
- sAggInfo.mxReg = pParse->nMem;
|
|
+ pAggInfo->mxReg = pParse->nMem;
|
|
if( db->mallocFailed ) goto select_end;
|
|
#if SELECTTRACE_ENABLED
|
|
if( sqlite3SelectTrace & 0x400 ){
|
|
int ii;
|
|
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", &sAggInfo));
|
|
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
- for(ii=0; ii<sAggInfo.nColumn; ii++){
|
|
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
|
|
sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
|
- ii, sAggInfo.aCol[ii].iMem);
|
|
- sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
|
|
+ ii,pAggInfo->aCol[ii].iMem);
|
|
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pExpr, 0);
|
|
}
|
|
- for(ii=0; ii<sAggInfo.nFunc; ii++){
|
|
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
|
|
sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
|
- ii, sAggInfo.aFunc[ii].iMem);
|
|
- sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
|
|
+ ii, pAggInfo->aFunc[ii].iMem);
|
|
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pExpr, 0);
|
|
}
|
|
}
|
|
#endif
|
|
@@ -6414,10 +6422,11 @@ int sqlite3Select(
|
|
** that we do not need it after all, the OP_SorterOpen instruction
|
|
** will be converted into a Noop.
|
|
*/
|
|
- sAggInfo.sortingIdx = pParse->nTab++;
|
|
- pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
|
|
- addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
|
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
|
+ pAggInfo->sortingIdx = pParse->nTab++;
|
|
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
|
|
+ 0, pAggInfo->nColumn);
|
|
+ addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
|
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
|
|
0, (char*)pKeyInfo, P4_KEYINFO);
|
|
|
|
/* Initialize memory locations used by GROUP BY aggregate processing
|
|
@@ -6472,8 +6481,8 @@ int sqlite3Select(
|
|
nGroupBy = pGroupBy->nExpr;
|
|
nCol = nGroupBy;
|
|
j = nGroupBy;
|
|
- for(i=0; i<sAggInfo.nColumn; i++){
|
|
- if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
|
|
nCol++;
|
|
j++;
|
|
}
|
|
@@ -6481,8 +6490,8 @@ int sqlite3Select(
|
|
regBase = sqlite3GetTempRange(pParse, nCol);
|
|
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
|
|
j = nGroupBy;
|
|
- for(i=0; i<sAggInfo.nColumn; i++){
|
|
- struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
|
|
if( pCol->iSorterColumn>=j ){
|
|
int r1 = j + regBase;
|
|
sqlite3ExprCodeGetColumnOfTable(v,
|
|
@@ -6492,16 +6501,16 @@ int sqlite3Select(
|
|
}
|
|
regRecord = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
|
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
|
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
|
sqlite3WhereEnd(pWInfo);
|
|
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
|
|
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
|
sortOut = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
|
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
|
|
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
|
- sAggInfo.useSortingIdx = 1;
|
|
+ pAggInfo->useSortingIdx = 1;
|
|
}
|
|
|
|
/* If the index or temporary table used by the GROUP BY sort
|
|
@@ -6525,14 +6534,14 @@ int sqlite3Select(
|
|
*/
|
|
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
|
if( groupBySort ){
|
|
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
|
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
|
|
sortOut, sortPTab);
|
|
}
|
|
for(j=0; j<pGroupBy->nExpr; j++){
|
|
if( groupBySort ){
|
|
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
|
|
}else{
|
|
- sAggInfo.directMode = 1;
|
|
+ pAggInfo->directMode = 1;
|
|
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
|
}
|
|
}
|
|
@@ -6562,14 +6571,14 @@ int sqlite3Select(
|
|
** the current row
|
|
*/
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
- updateAccumulator(pParse, iUseFlag, &sAggInfo);
|
|
+ updateAccumulator(pParse, iUseFlag, pAggInfo);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
|
VdbeComment((v, "indicate data in accumulator"));
|
|
|
|
/* End of the loop
|
|
*/
|
|
if( groupBySort ){
|
|
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
|
|
VdbeCoverage(v);
|
|
}else{
|
|
sqlite3WhereEnd(pWInfo);
|
|
@@ -6602,7 +6611,7 @@ int sqlite3Select(
|
|
VdbeCoverage(v);
|
|
VdbeComment((v, "Groupby result generator entry point"));
|
|
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
|
- finalizeAggFunctions(pParse, &sAggInfo);
|
|
+ finalizeAggFunctions(pParse, pAggInfo);
|
|
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
|
selectInnerLoop(pParse, p, -1, &sSort,
|
|
&sDistinct, pDest,
|
|
@@ -6613,7 +6622,7 @@ int sqlite3Select(
|
|
/* Generate a subroutine that will reset the group-by accumulator
|
|
*/
|
|
sqlite3VdbeResolveLabel(v, addrReset);
|
|
- resetAccumulator(pParse, &sAggInfo);
|
|
+ resetAccumulator(pParse, pAggInfo);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
|
VdbeComment((v, "indicate accumulator empty"));
|
|
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
|
@@ -6621,7 +6630,7 @@ int sqlite3Select(
|
|
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
|
else {
|
|
Table *pTab;
|
|
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
|
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
|
|
/* If isSimpleCount() returns a pointer to a Table structure, then
|
|
** the SQL statement is of the form:
|
|
**
|
|
@@ -6674,7 +6683,7 @@ int sqlite3Select(
|
|
if( pKeyInfo ){
|
|
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
|
}
|
|
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
|
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
|
|
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
|
explainSimpleCount(pParse, pTab, pBest);
|
|
}else{
|
|
@@ -6689,12 +6698,16 @@ int sqlite3Select(
|
|
** first row visited by the aggregate, so that they are updated at
|
|
** least once even if the FILTER clause means the min() or max()
|
|
** function visits zero rows. */
|
|
- if( sAggInfo.nAccumulator ){
|
|
- for(i=0; i<sAggInfo.nFunc; i++){
|
|
- if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
|
|
- if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
|
+ if( pAggInfo->nAccumulator ){
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ if( ExprHasProperty(pAggInfo->aFunc[i].pExpr, EP_WinFunc) ){
|
|
+ continue;
|
|
+ }
|
|
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
|
|
+ break;
|
|
+ }
|
|
}
|
|
- if( i==sAggInfo.nFunc ){
|
|
+ if( i==pAggInfo->nFunc ){
|
|
regAcc = ++pParse->nMem;
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
|
|
}
|
|
@@ -6705,7 +6718,7 @@ int sqlite3Select(
|
|
** of output.
|
|
*/
|
|
assert( p->pGroupBy==0 );
|
|
- resetAccumulator(pParse, &sAggInfo);
|
|
+ resetAccumulator(pParse, pAggInfo);
|
|
|
|
/* If this query is a candidate for the min/max optimization, then
|
|
** minMaxFlag will have been previously set to either
|
|
@@ -6721,7 +6734,7 @@ int sqlite3Select(
|
|
if( pWInfo==0 ){
|
|
goto select_end;
|
|
}
|
|
- updateAccumulator(pParse, regAcc, &sAggInfo);
|
|
+ updateAccumulator(pParse, regAcc, pAggInfo);
|
|
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
|
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
|
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
|
@@ -6729,7 +6742,7 @@ int sqlite3Select(
|
|
(minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
|
|
}
|
|
sqlite3WhereEnd(pWInfo);
|
|
- finalizeAggFunctions(pParse, &sAggInfo);
|
|
+ finalizeAggFunctions(pParse, pAggInfo);
|
|
}
|
|
|
|
sSort.pOrderBy = 0;
|
|
@@ -6768,8 +6781,25 @@ int sqlite3Select(
|
|
*/
|
|
select_end:
|
|
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
|
- sqlite3DbFree(db, sAggInfo.aCol);
|
|
- sqlite3DbFree(db, sAggInfo.aFunc);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( pAggInfo ){
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ Expr *pExpr = pAggInfo->aCol[i].pExpr;
|
|
+ assert( pExpr!=0 || db->mallocFailed );
|
|
+ if( pExpr==0 ) continue;
|
|
+ assert( pExpr->pAggInfo==pAggInfo );
|
|
+ assert( pExpr->iAgg==i );
|
|
+ }
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ Expr *pExpr = pAggInfo->aFunc[i].pExpr;
|
|
+ assert( pExpr!=0 || db->mallocFailed );
|
|
+ if( pExpr==0 ) continue;
|
|
+ assert( pExpr->pAggInfo==pAggInfo );
|
|
+ assert( pExpr->iAgg==i );
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
#if SELECTTRACE_ENABLED
|
|
SELECTTRACE(0x1,pParse,p,("end processing\n"));
|
|
if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
|
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
|
|
index 514df18..fe24c3a 100644
|
|
--- a/src/sqliteInt.h
|
|
+++ b/src/sqliteInt.h
|
|
@@ -2489,11 +2489,11 @@ struct AggInfo {
|
|
ExprList *pGroupBy; /* The group by clause */
|
|
struct AggInfo_col { /* For each column used in source tables */
|
|
Table *pTab; /* Source table */
|
|
+ Expr *pExpr; /* The original expression */
|
|
int iTable; /* Cursor number of the source table */
|
|
- int iColumn; /* Column number within the source table */
|
|
- int iSorterColumn; /* Column number in the sorting index */
|
|
int iMem; /* Memory location that acts as accumulator */
|
|
- Expr *pExpr; /* The original expression */
|
|
+ i16 iColumn; /* Column number within the source table */
|
|
+ i16 iSorterColumn; /* Column number in the sorting index */
|
|
} *aCol;
|
|
int nColumn; /* Number of used entries in aCol[] */
|
|
int nAccumulator; /* Number of columns that show through to the output.
|
|
@@ -2506,6 +2506,10 @@ struct AggInfo {
|
|
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
|
|
} *aFunc;
|
|
int nFunc; /* Number of entries in aFunc[] */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ int iAggMagic; /* Magic number when valid */
|
|
+#endif
|
|
+ AggInfo *pNext; /* Next in list of them all */
|
|
};
|
|
|
|
/*
|
|
@@ -3291,6 +3295,7 @@ struct Parse {
|
|
Parse *pToplevel; /* Parse structure for main program (or NULL) */
|
|
Table *pTriggerTab; /* Table triggers are being coded for */
|
|
Parse *pParentParse; /* Parent parser if this parser is nested */
|
|
+ AggInfo *pAggList; /* List of all AggInfo objects */
|
|
int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
|
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
|
|
u32 oldmask; /* Mask of old.* columns referenced */
|
|
@@ -4254,6 +4259,7 @@ int sqlite3ExprCompareSkip(Expr*, Expr*, int);
|
|
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
|
int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
|
|
int sqlite3ExprImpliesNonNullRow(Expr*,int);
|
|
+void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
|
|
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
|
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
|
int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
|
|
diff --git a/src/window.c b/src/window.c
|
|
index 9bb3217..f4919d6 100644
|
|
--- a/src/window.c
|
|
+++ b/src/window.c
|
|
@@ -933,12 +933,16 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
Window *pMWin = p->pWin; /* Master window object */
|
|
Window *pWin; /* Window object iterator */
|
|
Table *pTab;
|
|
+ Walker w;
|
|
+
|
|
u32 selFlags = p->selFlags;
|
|
|
|
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
|
if( pTab==0 ){
|
|
return sqlite3ErrorToParser(db, SQLITE_NOMEM);
|
|
}
|
|
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
|
+ sqlite3WalkSelect(&w, p);
|
|
|
|
p->pSrc = 0;
|
|
p->pWhere = 0;
|
|
diff --git a/test/window1.test b/test/window1.test
|
|
index 18b9bdc..1d554f9 100644
|
|
--- a/test/window1.test
|
|
+++ b/test/window1.test
|
|
@@ -1603,4 +1603,150 @@ do_catchsql_test 51.1 {
|
|
sum(b) OVER(PARTITION BY min(DISTINCT c), c ORDER BY b)));
|
|
} {1 {row value misused}}
|
|
|
|
+#-------------------------------------------------------------------------
|
|
+reset_db
|
|
+do_execsql_test 54.1 {
|
|
+ CREATE TABLE t1(a VARCHAR(20), b FLOAT);
|
|
+ INSERT INTO t1 VALUES('1',10.0);
|
|
+}
|
|
+
|
|
+do_catchsql_test 54.2 {
|
|
+ SELECT * FROM (
|
|
+ SELECT sum(b) OVER() AS c FROM t1
|
|
+ UNION
|
|
+ SELECT b AS c FROM t1
|
|
+ ) WHERE c>10;
|
|
+} {1 {misuse of window function sum()}}
|
|
+
|
|
+do_execsql_test 54.3 {
|
|
+ INSERT INTO t1 VALUES('2',5.0);
|
|
+ INSERT INTO t1 VALUES('3',15.0);
|
|
+}
|
|
+
|
|
+do_catchsql_test 54.4 {
|
|
+ SELECT * FROM (
|
|
+ SELECT sum(b) OVER() AS c FROM t1
|
|
+ UNION
|
|
+ SELECT b AS c FROM t1
|
|
+ ) WHERE c>10;
|
|
+} {1 {misuse of window function sum()}}
|
|
+
|
|
+# 2020-06-05 ticket c8d3b9f0a750a529
|
|
+reset_db
|
|
+do_execsql_test 55.1 {
|
|
+ CREATE TABLE a(b);
|
|
+ SELECT
|
|
+ (SELECT b FROM a
|
|
+ GROUP BY b
|
|
+ HAVING (SELECT COUNT()OVER() + lead(b)OVER(ORDER BY SUM(DISTINCT b) + b))
|
|
+ )
|
|
+ FROM a
|
|
+ UNION
|
|
+ SELECT 99
|
|
+ ORDER BY 1;
|
|
+} {99}
|
|
+
|
|
+#------------------------------------------------------------------------
|
|
+reset_db
|
|
+do_execsql_test 56.1 {
|
|
+ CREATE TABLE t1(a, b INTEGER);
|
|
+ CREATE TABLE t2(c, d);
|
|
+}
|
|
+do_catchsql_test 56.2 {
|
|
+ SELECT avg(b) FROM t1
|
|
+ UNION ALL
|
|
+ SELECT min(c) OVER () FROM t2
|
|
+ ORDER BY nosuchcolumn;
|
|
+} {1 {1st ORDER BY term does not match any column in the result set}}
|
|
+
|
|
+reset_db
|
|
+do_execsql_test 57.1 {
|
|
+ CREATE TABLE t4(a, b, c, d, e);
|
|
+}
|
|
+
|
|
+do_catchsql_test 57.2 {
|
|
+ SELECT b FROM t4
|
|
+ UNION
|
|
+ SELECT a FROM t4
|
|
+ ORDER BY (
|
|
+ SELECT sum(x) OVER() FROM (
|
|
+ SELECT c AS x FROM t4
|
|
+ UNION
|
|
+ SELECT d FROM t4
|
|
+ ORDER BY (SELECT e FROM t4)
|
|
+ )
|
|
+ );
|
|
+} {1 {1st ORDER BY term does not match any column in the result set}}
|
|
+
|
|
+# 2020-06-06 various dbsqlfuzz finds and
|
|
+# ticket 0899cf62f597d7e7
|
|
+#
|
|
+reset_db
|
|
+do_execsql_test 57.1 {
|
|
+ CREATE TABLE t1(a, b, c);
|
|
+ INSERT INTO t1 VALUES(NULL,NULL,NULL);
|
|
+ SELECT
|
|
+ sum(a),
|
|
+ min(b) OVER (),
|
|
+ count(c) OVER (ORDER BY b)
|
|
+ FROM t1;
|
|
+} {{} {} 0}
|
|
+do_execsql_test 57.2 {
|
|
+ CREATE TABLE v0 ( v1 INTEGER PRIMARY KEY ) ;
|
|
+ INSERT INTO v0 VALUES ( 10 ) ;
|
|
+ SELECT DISTINCT v1, lead(v1) OVER() FROM v0 GROUP BY v1 ORDER BY 2;
|
|
+} {10 {}}
|
|
+do_catchsql_test 57.3 {
|
|
+ DROP TABLE t1;
|
|
+ CREATE TABLE t1(a);
|
|
+ INSERT INTO t1(a) VALUES(22);
|
|
+ CREATE TABLE t3(y);
|
|
+ INSERT INTO t3(y) VALUES(5),(11),(-9);
|
|
+ SELECT (
|
|
+ SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
|
|
+ )
|
|
+ FROM t3;
|
|
+} {1 {misuse of aggregate: sum()}}
|
|
+
|
|
+# 2020-06-06 ticket 1f6f353b684fc708
|
|
+reset_db
|
|
+do_execsql_test 58.1 {
|
|
+ CREATE TABLE a(a, b, c);
|
|
+ INSERT INTO a VALUES(1, 2, 3);
|
|
+ INSERT INTO a VALUES(4, 5, 6);
|
|
+ SELECT sum(345+b) OVER (ORDER BY b),
|
|
+ sum(avg(678)) OVER (ORDER BY c) FROM a;
|
|
+} {347 678.0}
|
|
+
|
|
+# 2020-06-06 ticket e5504e987e419fb0
|
|
+do_catchsql_test 59.1 {
|
|
+ DROP TABLE IF EXISTS t1;
|
|
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
|
|
+ INSERT INTO t1 VALUES (123);
|
|
+ SELECT
|
|
+ ntile( (SELECT sum(x)) ) OVER(ORDER BY x),
|
|
+ min(x) OVER(ORDER BY x)
|
|
+ FROM t1;
|
|
+} {1 {misuse of aggregate: sum()}}
|
|
+
|
|
+# 2020-06-07 ticket f7d890858f361402
|
|
+do_execsql_test 60.1 {
|
|
+ DROP TABLE IF EXISTS t1;
|
|
+ CREATE TABLE t1 (x INTEGER PRIMARY KEY);
|
|
+ INSERT INTO t1 VALUES (99);
|
|
+ SELECT EXISTS(SELECT count(*) OVER() FROM t1 ORDER BY sum(x) OVER());
|
|
+} {1}
|
|
+
|
|
+# 2020-06-07 test case generated by dbsqlfuzz showing how an AggInfo
|
|
+# object might be referenced after the sqlite3Select() call that created
|
|
+# it returns. This proves the need to persist all AggInfo objects until
|
|
+# the Parse object is destroyed.
|
|
+#
|
|
+reset_db
|
|
+do_execsql_test 61.1 {
|
|
+CREATE TABLE t1(a);
|
|
+INSERT INTO t1 VALUES(5),(NULL),('seventeen');
|
|
+SELECT (SELECT max(x)OVER(ORDER BY x) % min(x)OVER(ORDER BY CASE x WHEN 889 THEN x WHEN x THEN x END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST((SELECT (SELECT max(x)OVER(ORDER BY x) / min(x)OVER(ORDER BY CASE x WHEN 889 THEN 299 WHEN -true THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a IN(SELECT (SELECT max(x) & sum ( a )OVER(ORDER BY CASE x WHEN -8 THEN 299 WHEN 863 THEN 863 END)) FROM (SELECT (SELECT sum(CAST(a AS )) FROM t1) AS x FROM t1)) AS t1 )) FROM t1) AS x FROM t1)) AS x )) FROM t1) AS x FROM t1)) AS real)) FROM t1) AS x FROM t1);
|
|
+} {{} {} {}}
|
|
+
|
|
finish_test
|
|
--
|
|
2.23.0
|
|
|