diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 6 | ||||
-rw-r--r-- | src/func.c | 28 | ||||
-rw-r--r-- | src/resolve.c | 14 | ||||
-rw-r--r-- | src/select.c | 126 | ||||
-rw-r--r-- | src/sqliteInt.h | 13 | ||||
-rw-r--r-- | src/window.c | 16 |
6 files changed, 129 insertions, 74 deletions
diff --git a/src/expr.c b/src/expr.c index faaca6c86..c93ce3f44 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1286,7 +1286,11 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ *pzBuffer = zAlloc; } }else{ - pNew->pWin = winDup(db, p->pWin); + if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){ + pNew->pWin = 0; + }else{ + pNew->pWin = winDup(db, p->pWin); + } if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; diff --git a/src/func.c b/src/func.c index f5a839d39..ea1fffaf0 100644 --- a/src/func.c +++ b/src/func.c @@ -1675,6 +1675,20 @@ static void groupConcatFinalize(sqlite3_context *context){ } } } +static void groupConcatValue(sqlite3_context *context){ + sqlite3_str *pAccum; + pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0); + if( pAccum ){ + if( pAccum->accError==SQLITE_TOOBIG ){ + sqlite3_result_error_toobig(context); + }else if( pAccum->accError==SQLITE_NOMEM ){ + sqlite3_result_error_nomem(context); + }else{ + const char *zText = sqlite3_str_value(pAccum); + sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); + } + } +} /* ** This routine does per-connection function registration. Most @@ -1859,14 +1873,16 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), - WFUNCTION(sum, 1, 0, sumStep, sumFinalize, sumFinalize, 0), - AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), - AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), + WAGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize), + WAGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), + WAGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ), AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, SQLITE_FUNC_COUNT ), - AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), - AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), - AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), + WAGGREGATE(count, 1, 0, 0, countStep, countFinalize ), + AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize, + groupConcatValue), + AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize, + groupConcatValue), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE diff --git a/src/resolve.c b/src/resolve.c index 073fdf193..99472272f 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -776,13 +776,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ sqlite3WalkExprList(pWalker, pList); if( is_agg ){ if( pExpr->pWin ){ - pExpr->pWin->pNextWin = pNC->pWin; - pNC->pWin = pExpr->pWin; + if( 0==pNC->pWin + || 0==sqlite3WindowCompare(pParse, pNC->pWin, pExpr->pWin) + ){ + pExpr->pWin->pNextWin = pNC->pWin; + pNC->pWin = pExpr->pWin; + } pExpr->pWin->pFunc = pDef; - pExpr->pWin->nArg = pExpr->x.pList->nExpr; - } - else - { + pExpr->pWin->nArg = (pExpr->x.pList ? pExpr->x.pList->nExpr : 0); + }else{ NameContext *pNC2 = pNC; pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; diff --git a/src/select.c b/src/select.c index 93e55b680..1b0bbe40e 100644 --- a/src/select.c +++ b/src/select.c @@ -5415,17 +5415,20 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ struct WindowRewrite *p = pWalker->u.pRewrite; Parse *pParse = pWalker->pParse; - int rc = WRC_Continue; switch( pExpr->op ){ case TK_FUNCTION: if( pExpr->pWin==0 ){ break; - }else if( pExpr->pWin==p->pWin ){ - rc = WRC_Prune; - pExpr->pWin->pOwner = pExpr; - break; + }else{ + Window *pWin; + for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ + if( pExpr->pWin==pWin ){ + pExpr->pWin->pOwner = pExpr; + return WRC_Prune; + } + } } /* Fall through. */ @@ -5451,7 +5454,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ break; } - return rc; + return WRC_Continue; } static int selectWindowRewriteEList( @@ -5532,41 +5535,46 @@ static int selectWindowRewrite(Parse *pParse, Select *p){ ExprList *pSort = 0; ExprList *pSublist = 0; /* Expression list for sub-query */ - Window *pWin = p->pWin; + Window *pMWin = p->pWin; /* Master window object */ + Window *pWin; /* Window object iterator */ p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; - pWin->regAccum = ++pParse->nMem; - pWin->regResult = ++pParse->nMem; - /* Assign a cursor number for the ephemeral table used to buffer rows. ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ - pWin->iEphCsr = pParse->nTab++; + pMWin->iEphCsr = pParse->nTab++; - rc = selectWindowRewriteEList(pParse, pWin, p->pEList, &pSublist); + rc = selectWindowRewriteEList(pParse, pMWin, p->pEList, &pSublist); if( rc ) return rc; - rc = selectWindowRewriteEList(pParse, pWin, p->pOrderBy, &pSublist); + rc = selectWindowRewriteEList(pParse, pMWin, p->pOrderBy, &pSublist); if( rc ) return rc; - pWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); + pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Create the ORDER BY clause for the sub-select. This is the concatenation ** of the window PARTITION and ORDER BY clauses. Append the same ** expressions to the sub-select expression list. They are required to ** figure out where boundaries for partitions and sets of peer rows. */ - pSort = sqlite3ExprListDup(db, pWin->pPartition, 0); - if( pWin->pOrderBy ){ - pSort = exprListAppendList(pParse, pSort, pWin->pOrderBy); + pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0); + if( pMWin->pOrderBy ){ + pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy); } pSublist = exprListAppendList(pParse, pSublist, pSort); - /* Also append the arguments passed to the window function to the - ** sub-select expression list. */ - pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); - pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); + /* Append the arguments passed to each window function to the + ** sub-select expression list. Also allocate two registers for each + ** window function - one for the accumulator, another for interim + ** results. */ + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); + pWin->regAccum = ++pParse->nMem; + pWin->regResult = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + } pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 @@ -5582,7 +5590,6 @@ static int selectWindowRewrite(Parse *pParse, Select *p){ }else{ pSub->selFlags |= SF_Expanded; } - pWin->pNextWin = 0; } #if SELECTTRACE_ENABLED @@ -5592,8 +5599,7 @@ static int selectWindowRewrite(Parse *pParse, Select *p){ } #endif - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->iEphCsr, pWin->nBufferCol); - sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pMWin->nBufferCol); } return rc; @@ -6061,7 +6067,7 @@ int sqlite3Select( } if( !isAgg && pGroupBy==0 ){ - Window *pWin = p->pWin; + Window *pMWin = p->pWin; /* Master window object (or NULL) */ int regPart = 0; /* No aggregate functions and no GROUP BY clause */ @@ -6069,9 +6075,9 @@ int sqlite3Select( assert( WHERE_USE_LIMIT==SF_FixedLimit ); wctrlFlags |= p->selFlags & SF_FixedLimit; - if( pWin ){ - int nPart = (pWin->pPartition ? pWin->pPartition->nExpr : 0); - nPart += (pWin->pOrderBy ? pWin->pOrderBy->nExpr : 0); + if( pMWin ){ + int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0); + nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); if( nPart ){ regPart = pParse->nMem+1; pParse->nMem += nPart; @@ -6107,7 +6113,8 @@ int sqlite3Select( } assert( p->pEList==pEList ); - if( p->pWin ){ + if( pMWin ){ + Window *pWin; int k; int iSubCsr = p->pSrc->a[0].iCursor; int nSub = p->pSrc->a[0].pTab->nCol; @@ -6128,29 +6135,31 @@ int sqlite3Select( /* Check if this is the start of a new partition or peer group. */ if( regPart ){ - ExprList *pPart = pWin->pPartition; + ExprList *pPart = pMWin->pPartition; int nPart = (pPart ? pPart->nExpr : 0); - ExprList *pOrderBy = pWin->pOrderBy; + ExprList *pOrderBy = pMWin->pOrderBy; int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); int addrGoto = 0; int addrJump = 0; if( pPart ){ - int regNewPart = reg + pWin->nBufferCol; + int regNewPart = reg + pMWin->nBufferCol; KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pPart, 0, 0); addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, regPart, nPart); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); - sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + } if( pOrderBy ){ addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); } } if( pOrderBy ){ - int regNewPeer = reg + pWin->nBufferCol + nPart; + int regNewPeer = reg + pMWin->nBufferCol + nPart; int regPeer = regPart + nPart; KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0, 0); @@ -6158,51 +6167,58 @@ int sqlite3Select( addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer); sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - sqlite3VdbeAddOp3(v, - OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult - ); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); - + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp3(v, + OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult + ); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + } if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); } addrGosub = sqlite3VdbeAddOp1(v, OP_Gosub, regGosub); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->iEphCsr); - sqlite3VdbeAddOp3(v,OP_Copy,reg+pWin->nBufferCol,regPart,nPart+nPeer-1); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); + sqlite3VdbeAddOp3( + v, OP_Copy, reg+pMWin->nBufferCol, regPart, nPart+nPeer-1 + ); sqlite3VdbeJumpHere(v, addrJump); } /* Invoke step function for window functions */ - sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, (u8)pWin->nArg); + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeChangeP5(v, (u8)pWin->nArg); + } /* Buffer the current row in the ephemeral table. */ - if( pWin->nBufferCol>0 ){ - sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pWin->nBufferCol, regRecord); + if( pMWin->nBufferCol>0 ){ + sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord); }else{ sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord); sqlite3VdbeAppendP4(v, (void*)"", 0); } - sqlite3VdbeAddOp2(v, OP_NewRowid, pWin->iEphCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pWin->iEphCsr, regRecord, regRowid); + sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); - sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); - sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg); + sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); + } sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp0(v, OP_Goto); if( regPart ){ sqlite3VdbeJumpHere(v, addrGosub); } - addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr); + addr = sqlite3VdbeAddOp1(v, OP_Rewind, pMWin->iEphCsr); selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addr+1, 0); - sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1); + sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr+1); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp1(v, OP_Return, regGosub); sqlite3VdbeJumpHere(v, addr-1); /* OP_Goto jumps here */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8a1376fd2..7f3d37ba4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1716,16 +1716,16 @@ struct FuncDestructor { #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } -#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ +#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,0,0,#zName, {0}} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}} #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,0,0,#zName, {0}} + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}} -#define WFUNCTION(zName, nArg, arg, xStep, xFinal, xValue, xInverse) \ - {nArg, SQLITE_UTF8, \ - SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}} +#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ + {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}} /* ** All current savepoints are stored in a linked list starting at @@ -3493,6 +3493,7 @@ struct Window { void sqlite3WindowDelete(sqlite3*, Window*); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*); void sqlite3WindowAttach(Parse*, Expr*, Window*); +int sqlite3WindowCompare(Parse*, Window*, Window*); /* ** Assuming zIn points to the first byte of a UTF-8 character, diff --git a/src/window.c b/src/window.c index 57d467424..d2d6f4766 100644 --- a/src/window.c +++ b/src/window.c @@ -51,3 +51,19 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ sqlite3WindowDelete(pParse->db, pWin); } } + +/* +** Return 0 if the two window objects are identical, or non-zero otherwise. +*/ +int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ + if( p1->eType!=p2->eType ) return 1; + if( p1->eStart!=p2->eStart ) return 1; + if( p1->eEnd!=p2->eEnd ) return 1; + if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; + if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; + if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; + if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1; + return 0; +} + + |