aboutsummaryrefslogtreecommitdiff
path: root/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/select.c')
-rw-r--r--src/select.c120
1 files changed, 83 insertions, 37 deletions
diff --git a/src/select.c b/src/select.c
index 529df0f94..cf1034bb6 100644
--- a/src/select.c
+++ b/src/select.c
@@ -162,6 +162,7 @@ Select *sqlite3SelectNew(
pNew->pNext = 0;
pNew->pLimit = pLimit;
pNew->pWith = 0;
+ pNew->pWin = 0;
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
pNew = 0;
@@ -529,14 +530,6 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
return 0;
}
-/* Forward reference */
-static KeyInfo *keyInfoFromExprList(
- Parse *pParse, /* Parsing context */
- ExprList *pList, /* Form the KeyInfo object from this ExprList */
- int iStart, /* Begin with this column of pList */
- int nExtra /* Add this many extra columns to the end */
-);
-
/*
** An instance of this object holds information (beyond pParse and pSelect)
** needed to load the next result row that is to be added to the sorter.
@@ -678,7 +671,7 @@ static void pushOntoSorter(
memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
testcase( pKI->nAllField > pKI->nKeyField+2 );
- pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
+ pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
@@ -1348,7 +1341,7 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
** function is responsible for seeing that this structure is eventually
** freed.
*/
-static KeyInfo *keyInfoFromExprList(
+KeyInfo *sqlite3KeyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
@@ -3719,6 +3712,8 @@ static int flattenSubquery(
pSub = pSubitem->pSelect;
assert( pSub!=0 );
+ if( p->pWin ) return 0;
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
@@ -4588,6 +4583,27 @@ static void selectPopWith(Walker *pWalker, Select *p){
#define selectPopWith 0
#endif
+int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
+ Select *pSel = pFrom->pSelect;
+ Table *pTab;
+
+ pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
+ if( pTab==0 ) return WRC_Abort;
+ pTab->nTabRef = 1;
+ if( pFrom->zAlias ){
+ pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
+ }else{
+ pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%p", (void*)pTab);
+ }
+ while( pSel->pPrior ){ pSel = pSel->pPrior; }
+ sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
+ pTab->iPKey = -1;
+ pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
+ pTab->tabFlags |= TF_Ephemeral;
+
+ return WRC_Continue;
+}
+
/*
** This routine is a Walker callback for "expanding" a SELECT statement.
** "Expanding" means to do the following:
@@ -4660,19 +4676,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( pSel!=0 );
assert( pFrom->pTab==0 );
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
- pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
- if( pTab==0 ) return WRC_Abort;
- pTab->nTabRef = 1;
- if( pFrom->zAlias ){
- pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
- }else{
- pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
- }
- while( pSel->pPrior ){ pSel = pSel->pPrior; }
- sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
- pTab->iPKey = -1;
- pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
- pTab->tabFlags |= TF_Ephemeral;
+ if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
#endif
}else{
/* An ordinary table or view name in the FROM clause */
@@ -5076,7 +5080,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
"argument");
pFunc->iDistinct = -1;
}else{
- KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO);
}
@@ -5443,7 +5447,6 @@ int sqlite3Select(
sqlite3SelectPrep(pParse, p, 0);
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
- pTabList = p->pSrc;
if( pParse->nErr || db->mallocFailed ){
goto select_end;
}
@@ -5460,6 +5463,17 @@ int sqlite3Select(
generateColumnNames(pParse, p);
}
+ if( (rc = sqlite3WindowRewrite(pParse, p)) ){
+ goto select_end;
+ }
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x108 ){
+ SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+ pTabList = p->pSrc;
+
/* Try to various optimizations (flattening subqueries, and strength
** reduction of join operators) in the FROM clause up into the main query
*/
@@ -5789,7 +5803,8 @@ int sqlite3Select(
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
- pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
+ pKeyInfo = sqlite3KeyInfoFromExprList(
+ pParse, sSort.pOrderBy, 0, pEList->nExpr);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
@@ -5823,9 +5838,9 @@ int sqlite3Select(
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
- sDistinct.tabTnct, 0, 0,
- (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
- P4_KEYINFO);
+ sDistinct.tabTnct, 0, 0,
+ (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0),
+ P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
@@ -5833,11 +5848,17 @@ int sqlite3Select(
}
if( !isAgg && pGroupBy==0 ){
+ Window *pWin = p->pWin; /* Master window object (or NULL) */
+
/* No aggregate functions and no GROUP BY clause */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
assert( WHERE_USE_LIMIT==SF_FixedLimit );
wctrlFlags |= p->selFlags & SF_FixedLimit;
+ if( pWin ){
+ sqlite3WindowCodeInit(pParse, pWin);
+ }
+
/* Begin the database scan. */
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
@@ -5865,15 +5886,40 @@ int sqlite3Select(
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
}
- /* Use the standard inner loop. */
assert( p->pEList==pEList );
- selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
- sqlite3WhereContinueLabel(pWInfo),
- sqlite3WhereBreakLabel(pWInfo));
+ if( pWin ){
+ int addrGosub = sqlite3VdbeMakeLabel(v);
+ int regGosub = ++pParse->nMem;
+ int addr = 0;
+ int bLoop = 0;
+
+ sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub, &bLoop);
+
+ sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeResolveLabel(v, addrGosub);
+ if( bLoop ){
+ addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr);
+ }else{
+ addr = sqlite3VdbeCurrentAddr(v);
+ }
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addr+1, 0);
+ if( bLoop ){
+ sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1);
+ sqlite3VdbeJumpHere(v, addr);
+ }
+ sqlite3VdbeAddOp1(v, OP_Return, regGosub);
+ sqlite3VdbeJumpHere(v, addr-1); /* OP_Goto jumps here */
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
+ }else{
+ /* Use the standard inner loop. */
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
+ sqlite3WhereContinueLabel(pWInfo),
+ sqlite3WhereBreakLabel(pWInfo));
+
+ /* End the database scan loop.
+ */
+ sqlite3WhereEnd(pWInfo);
+ }
}else{
/* This case when there exist aggregate functions or a GROUP BY clause
** or both */
@@ -6002,7 +6048,7 @@ int sqlite3Select(
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);