aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c6
-rw-r--r--src/func.c28
-rw-r--r--src/resolve.c14
-rw-r--r--src/select.c126
-rw-r--r--src/sqliteInt.h13
-rw-r--r--src/window.c16
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;
+}
+
+