pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selId = ++pParse->nSelect;
- pNew->addrOpenEphm[0] = -1;
- pNew->addrOpenEphm[1] = -1;
+ pNew->addrOpenEphm = -1;
pNew->nSelectRow = 0;
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
pNew->pSrc = pSrc;
}
switch( eDest ){
- /* In this mode, write each query result to the key of the temporary
- ** table iParm.
- */
-#ifndef SQLITE_OMIT_COMPOUND_SELECT
- case SRT_Union: {
- int r1;
- r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
- sqlite3ReleaseTempReg(pParse, r1);
- break;
- }
-
- /* Construct a record from the query result, but instead of
- ** saving that record, use it as a key to delete elements from
- ** the temporary table iParm.
- */
- case SRT_Except: {
- sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol);
- break;
- }
-#endif /* SQLITE_OMIT_COMPOUND_SELECT */
-
/* Store the result as data using a unique key.
*/
case SRT_Fifo:
}
VdbeComment((v, "Queue table"));
if( iDistinct ){
- p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0);
+ p->addrOpenEphm = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0);
p->selFlags |= SF_UsesEphemeral;
}
*/
if( p->pOrderBy ){
return multiSelectOrderBy(pParse, p, pDest);
- }else if( p->op!=TK_ALL && (p->selFlags & SF_NoMerge)==0 ){
+ }else if( p->op!=TK_ALL ){
Expr *pOne = sqlite3ExprInt32(db, 1);
p->pOrderBy = sqlite3ExprListAppend(pParse, 0, pOne);
if( pParse->nErr ) goto multi_select_end;
p->pOrderBy->a[0].u.x.iOrderByCol = 1;
return multiSelectOrderBy(pParse, p, pDest);
}else{
+ int addr = 0;
+ int nLimit = 0; /* Initialize to suppress harmless compiler warning */
#ifndef SQLITE_OMIT_EXPLAIN
if( pPrior->pPrior==0 ){
ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));
}
#endif
-
- /* Generate code for the left and right SELECT statements.
- */
- switch( p->op ){
- case TK_ALL: {
- int addr = 0;
- int nLimit = 0; /* Initialize to suppress harmless compiler warning */
- assert( !pPrior->pLimit );
- pPrior->iLimit = p->iLimit;
- pPrior->iOffset = p->iOffset;
- pPrior->pLimit = sqlite3ExprDup(db, p->pLimit, 0);
- TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n"));
- rc = sqlite3Select(pParse, pPrior, &dest);
- sqlite3ExprDelete(db, pPrior->pLimit);
- pPrior->pLimit = 0;
- if( rc ){
- goto multi_select_end;
- }
- p->pPrior = 0;
- p->iLimit = pPrior->iLimit;
- p->iOffset = pPrior->iOffset;
- if( p->iLimit ){
- addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
- VdbeComment((v, "Jump ahead if LIMIT reached"));
- if( p->iOffset ){
- sqlite3VdbeAddOp3(v, OP_OffsetLimit,
- p->iLimit, p->iOffset+1, p->iOffset);
- }
- }
- ExplainQueryPlan((pParse, 1, "UNION ALL"));
- TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n"));
- rc = sqlite3Select(pParse, p, &dest);
- testcase( rc!=SQLITE_OK );
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
- if( p->pLimit
- && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse)
- && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
- ){
- p->nSelectRow = sqlite3LogEst((u64)nLimit);
- }
- if( addr ){
- sqlite3VdbeJumpHere(v, addr);
- }
- break;
- }
- case TK_EXCEPT:
- case TK_UNION: {
- int unionTab; /* Cursor number of the temp table holding result */
- u8 op = 0; /* One of the SRT_ operations to apply to self */
- int priorOp; /* The SRT_ operation to apply to prior selects */
- Expr *pLimit; /* Saved values of p->nLimit */
- int addr;
- int emptyBypass = 0; /* IfEmpty opcode to bypass RHS */
- SelectDest uniondest;
-
-
- testcase( p->op==TK_EXCEPT );
- testcase( p->op==TK_UNION );
- priorOp = SRT_Union;
- if( dest.eDest==priorOp ){
- /* We can reuse a temporary table generated by a SELECT to our
- ** right.
- */
- assert( p->pLimit==0 ); /* Not allowed on leftward elements */
- unionTab = dest.iSDParm;
- }else{
- /* We will need to create our own temporary table to hold the
- ** intermediate results.
- */
- unionTab = pParse->nTab++;
- assert( p->pOrderBy==0 );
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
- assert( p->addrOpenEphm[0] == -1 );
- p->addrOpenEphm[0] = addr;
- findRightmost(p)->selFlags |= SF_UsesEphemeral;
- assert( p->pEList );
- }
-
-
- /* Code the SELECT statements to our left
- */
- assert( !pPrior->pOrderBy );
- sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
- TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
- rc = sqlite3Select(pParse, pPrior, &uniondest);
- if( rc ){
- goto multi_select_end;
- }
-
- /* Code the current SELECT statement
- */
- if( p->op==TK_EXCEPT ){
- op = SRT_Except;
- emptyBypass = sqlite3VdbeAddOp1(v, OP_IfEmpty, unionTab);
- VdbeCoverage(v);
- }else{
- assert( p->op==TK_UNION );
- op = SRT_Union;
- }
- p->pPrior = 0;
- pLimit = p->pLimit;
- p->pLimit = 0;
- uniondest.eDest = op;
- ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
- sqlite3SelectOpName(p->op)));
- TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
- rc = sqlite3Select(pParse, p, &uniondest);
- testcase( rc!=SQLITE_OK );
- assert( p->pOrderBy==0 );
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- p->pOrderBy = 0;
- if( p->op==TK_UNION ){
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
- }
- if( emptyBypass ) sqlite3VdbeJumpHere(v, emptyBypass);
- sqlite3ExprDelete(db, p->pLimit);
- p->pLimit = pLimit;
- p->iLimit = 0;
- p->iOffset = 0;
-
- /* Convert the data in the temporary table into whatever form
- ** it is that we currently need.
- */
- assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
- assert( p->pEList || db->mallocFailed );
- if( dest.eDest!=priorOp && db->mallocFailed==0 ){
- int iCont, iBreak, iStart;
- iBreak = sqlite3VdbeMakeLabel(pParse);
- iCont = sqlite3VdbeMakeLabel(pParse);
- computeLimitRegisters(pParse, p, iBreak);
- sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
- iStart = sqlite3VdbeCurrentAddr(v);
- selectInnerLoop(pParse, p, unionTab,
- 0, 0, &dest, iCont, iBreak);
- sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
- }
- break;
- }
- default: assert( p->op==TK_INTERSECT ); {
- int tab1, tab2;
- int iCont, iBreak, iStart;
- Expr *pLimit;
- int addr, iLimit, iOffset;
- SelectDest intersectdest;
- int r1;
- int emptyBypass;
-
- /* INTERSECT is different from the others since it requires
- ** two temporary tables. Hence it has its own case. Begin
- ** by allocating the tables we will need.
- */
- tab1 = pParse->nTab++;
- tab2 = pParse->nTab++;
- assert( p->pOrderBy==0 );
-
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
- assert( p->addrOpenEphm[0] == -1 );
- p->addrOpenEphm[0] = addr;
- findRightmost(p)->selFlags |= SF_UsesEphemeral;
- assert( p->pEList );
-
- /* Code the SELECTs to our left into temporary table "tab1".
- */
- sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
- TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n"));
- rc = sqlite3Select(pParse, pPrior, &intersectdest);
- if( rc ){
- goto multi_select_end;
- }
-
- /* Initialize LIMIT counters before checking to see if the LHS
- ** is empty, in case the jump is taken */
- iBreak = sqlite3VdbeMakeLabel(pParse);
- computeLimitRegisters(pParse, p, iBreak);
- emptyBypass = sqlite3VdbeAddOp1(v, OP_IfEmpty, tab1); VdbeCoverage(v);
-
- /* Code the current SELECT into temporary table "tab2"
- */
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
- assert( p->addrOpenEphm[1] == -1 );
- p->addrOpenEphm[1] = addr;
-
- /* Disable prior SELECTs and the LIMIT counters during the computation
- ** of the RHS select */
- pLimit = p->pLimit;
- iLimit = p->iLimit;
- iOffset = p->iOffset;
- p->pPrior = 0;
- p->pLimit = 0;
- p->iLimit = 0;
- p->iOffset = 0;
-
- intersectdest.iSDParm = tab2;
- ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
- sqlite3SelectOpName(p->op)));
- TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n"));
- rc = sqlite3Select(pParse, p, &intersectdest);
- testcase( rc!=SQLITE_OK );
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- if( p->nSelectRow>pPrior->nSelectRow ){
- p->nSelectRow = pPrior->nSelectRow;
- }
- sqlite3ExprDelete(db, p->pLimit);
-
- /* Reinstate the LIMIT counters prior to running the final intersect */
- p->pLimit = pLimit;
- p->iLimit = iLimit;
- p->iOffset = iOffset;
-
- /* Generate code to take the intersection of the two temporary
- ** tables.
- */
- if( rc ) break;
- assert( p->pEList );
- sqlite3VdbeAddOp1(v, OP_Rewind, tab1);
- r1 = sqlite3GetTempReg(pParse);
- iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
- iCont = sqlite3VdbeMakeLabel(pParse);
- sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
- VdbeCoverage(v);
- sqlite3ReleaseTempReg(pParse, r1);
- selectInnerLoop(pParse, p, tab1,
- 0, 0, &dest, iCont, iBreak);
- sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
- sqlite3VdbeJumpHere(v, emptyBypass);
- sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
- break;
- }
+ assert( !pPrior->pLimit );
+ pPrior->iLimit = p->iLimit;
+ pPrior->iOffset = p->iOffset;
+ pPrior->pLimit = sqlite3ExprDup(db, p->pLimit, 0);
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n"));
+ rc = sqlite3Select(pParse, pPrior, &dest);
+ sqlite3ExprDelete(db, pPrior->pLimit);
+ pPrior->pLimit = 0;
+ if( rc ){
+ goto multi_select_end;
}
-
- #ifndef SQLITE_OMIT_EXPLAIN
- if( p->pNext==0 ){
- ExplainQueryPlanPop(pParse);
+ p->pPrior = 0;
+ p->iLimit = pPrior->iLimit;
+ p->iOffset = pPrior->iOffset;
+ if( p->iLimit ){
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
+ VdbeComment((v, "Jump ahead if LIMIT reached"));
+ if( p->iOffset ){
+ sqlite3VdbeAddOp3(v, OP_OffsetLimit,
+ p->iLimit, p->iOffset+1, p->iOffset);
+ }
+ }
+ ExplainQueryPlan((pParse, 1, "UNION ALL"));
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n"));
+ rc = sqlite3Select(pParse, p, &dest);
+ testcase( rc!=SQLITE_OK );
+ pDelete = p->pPrior;
+ p->pPrior = pPrior;
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ if( p->pLimit
+ && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse)
+ && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
+ ){
+ p->nSelectRow = sqlite3LogEst((u64)nLimit);
+ }
+ if( addr ){
+ sqlite3VdbeJumpHere(v, addr);
}
- #endif
}
+#ifndef SQLITE_OMIT_EXPLAIN
+ if( p->pNext==0 ){
+ ExplainQueryPlanPop(pParse);
+ }
+#endif
if( pParse->nErr ) goto multi_select_end;
/* Compute collating sequences used by
}
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
- for(i=0; i<2; i++){
- int addr = pLoop->addrOpenEphm[i];
- if( addr<0 ){
- /* If [0] is unused then [1] is also unused. So we can
- ** always safely abort as soon as the first unused slot is found */
- assert( pLoop->addrOpenEphm[1]<0 );
- break;
- }
+ int addr = pLoop->addrOpenEphm;
+ if( addr>=0 ){
sqlite3VdbeChangeP2(v, addr, nCol);
sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo),
P4_KEYINFO);
- pLoop->addrOpenEphm[i] = -1;
+ pLoop->addrOpenEphm = -1;
}
}
sqlite3KeyInfoUnref(pKeyInfo);
r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3GetTempRange(pParse, nKey+2);
r3 = r2+nKey+1;
- if( pDest->eDest==SRT_DistQueue ){
+ if( NEVER(pDest->eDest==SRT_DistQueue) ){
/* If the destination is DistQueue, then cursor (iParm+1) is open
** on a second ephemeral index that holds all values every previously
** added to the queue. */
}
#endif /* SQLITE_OMIT_CTE */
- /*
- ** For SRT_Output, results are stored in a sequence of registers.
- ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
- ** return the next row of result.
- */
- case SRT_Output: {
- sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst);
+ /* Ignore the output */
+ case SRT_Discard: {
break;
}
-
/* If none of the above, then the result destination must be
- ** SRT_Discard. Ignore the results.
+ ** SRT_Output.
+ **
+ ** For SRT_Output, results are stored in a sequence of registers.
+ ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
+ ** return the next row of result.
*/
default: {
- assert( pDest->eDest==SRT_Discard );
+ assert( pDest->eDest==SRT_Output );
+ sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst);
break;
}
}
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
if( IgnorableDistinct(pDest) ){
- assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
- pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
+ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo );
/* All of these destinations are also able to ignore the ORDER BY clause */
if( p->pOrderBy ){
** See the header comment on the computeLimitRegisters() routine for a
** detailed description of the meaning of the iLimit and iOffset fields.
**
-** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes.
-** These addresses must be stored so that we can go back and fill in
+** addrOpenEphm entries contain the address of an OP_OpenEphemeral opcode.
+** This address must be stored so that we can go back and fill in
** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor
** the number of columns in P2 can be computed at the same time
** as the OP_OpenEphm instruction is coded because not
** enough information about the compound query is known at that point.
-** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences
-** for the result set. The KeyInfo for addrOpenEphm[2] contains collating
-** sequences for the ORDER BY clause.
*/
struct Select {
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u32 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
u32 selId; /* Unique identifier number for this SELECT */
- int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
+ int addrOpenEphm; /* OP_OpenEphem opcodes related to this select */
ExprList *pEList; /* The fields of the result */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
#define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */
#define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */
#define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */
-#define SF_NoMerge 0x0008000 /* Don't use merge to compute compounds */
+/* 0x0008000 // available for reuse */
#define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */
#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */
#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */
** by one of the following macros. The "SRT" prefix means "SELECT Result
** Type".
**
-** SRT_Union Store results as a key in a temporary index
-** identified by pDest->iSDParm.
-**
-** SRT_Except Remove results from the temporary index pDest->iSDParm.
-**
** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result
** set is not empty.
**
** table. (pDest->iSDParm) is the number of key columns in
** each index record in this case.
*/
-#define SRT_Union 1 /* Store result as keys in an index */
-#define SRT_Except 2 /* Remove result from a UNION index */
-#define SRT_Exists 3 /* Store 1 if the result is not empty */
-#define SRT_Discard 4 /* Do not save the results anywhere */
-#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */
-#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */
+#define SRT_Exists 1 /* Store 1 if the result is not empty */
+#define SRT_Discard 2 /* Do not save the results anywhere */
+#define SRT_DistFifo 3 /* Like SRT_Fifo, but unique results only */
+#define SRT_DistQueue 4 /* Like SRT_Queue, but unique results only */
/* The DISTINCT clause is ignored for all of the above. Not that
** IgnorableDistinct() implies IgnorableOrderby() */
#define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue)
-#define SRT_Queue 7 /* Store result in an queue */
-#define SRT_Fifo 8 /* Store result as data with an automatic rowid */
+#define SRT_Queue 5 /* Store result in an queue */
+#define SRT_Fifo 6 /* Store result as data with an automatic rowid */
/* The ORDER BY clause is ignored for all of the above */
#define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo)
-#define SRT_Output 9 /* Output each row of result */
-#define SRT_Mem 10 /* Store result in a memory cell */
-#define SRT_Set 11 /* Store results as keys in an index */
-#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
-#define SRT_Coroutine 13 /* Generate a single row of result */
-#define SRT_Table 14 /* Store result as data with an automatic rowid */
-#define SRT_Upfrom 15 /* Store result as data with rowid */
+#define SRT_Output 7 /* Output each row of result */
+#define SRT_Mem 8 /* Store result in a memory cell */
+#define SRT_Set 9 /* Store results as keys in an index */
+#define SRT_EphemTab 10 /* Create transient tab and store like SRT_Table */
+#define SRT_Coroutine 11 /* Generate a single row of result */
+#define SRT_Table 12 /* Store result as data with an automatic rowid */
+#define SRT_Upfrom 13 /* Store result as data with rowid */
/*
** An instance of this object describes where to put of the results of