| Index: third_party/sqlite/src/src/select.c
|
| diff --git a/third_party/sqlite/src/src/select.c b/third_party/sqlite/src/src/select.c
|
| index 85f8518cf1c38f0cc49dc159a726dfef1a204540..d817ebd074f39c616d5287af89cd2397655dc061 100644
|
| --- a/third_party/sqlite/src/src/select.c
|
| +++ b/third_party/sqlite/src/src/select.c
|
| @@ -56,6 +56,7 @@ struct SortCtx {
|
| int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
|
| int labelDone; /* Jump here when done, ex: LIMIT reached */
|
| u8 sortFlags; /* Zero or more SORTFLAG_* bits */
|
| + u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
|
| };
|
| #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
|
|
| @@ -74,7 +75,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
| sqlite3ExprListDelete(db, p->pOrderBy);
|
| sqlite3ExprDelete(db, p->pLimit);
|
| sqlite3ExprDelete(db, p->pOffset);
|
| - sqlite3WithDelete(db, p->pWith);
|
| + if( p->pWith ) sqlite3WithDelete(db, p->pWith);
|
| if( bFree ) sqlite3DbFree(db, p);
|
| p = pPrior;
|
| bFree = 1;
|
| @@ -87,7 +88,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
| void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
| pDest->eDest = (u8)eDest;
|
| pDest->iSDParm = iParm;
|
| - pDest->affSdst = 0;
|
| + pDest->zAffSdst = 0;
|
| pDest->iSdst = 0;
|
| pDest->nSdst = 0;
|
| }
|
| @@ -105,36 +106,44 @@ Select *sqlite3SelectNew(
|
| ExprList *pGroupBy, /* the GROUP BY clause */
|
| Expr *pHaving, /* the HAVING clause */
|
| ExprList *pOrderBy, /* the ORDER BY clause */
|
| - u16 selFlags, /* Flag parameters, such as SF_Distinct */
|
| + u32 selFlags, /* Flag parameters, such as SF_Distinct */
|
| Expr *pLimit, /* LIMIT value. NULL means not used */
|
| Expr *pOffset /* OFFSET value. NULL means no offset */
|
| ){
|
| Select *pNew;
|
| Select standin;
|
| sqlite3 *db = pParse->db;
|
| - pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
| + pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
| if( pNew==0 ){
|
| assert( db->mallocFailed );
|
| pNew = &standin;
|
| - memset(pNew, 0, sizeof(*pNew));
|
| }
|
| if( pEList==0 ){
|
| pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
|
| }
|
| pNew->pEList = pEList;
|
| + pNew->op = TK_SELECT;
|
| + pNew->selFlags = selFlags;
|
| + pNew->iLimit = 0;
|
| + pNew->iOffset = 0;
|
| +#if SELECTTRACE_ENABLED
|
| + pNew->zSelName[0] = 0;
|
| +#endif
|
| + pNew->addrOpenEphm[0] = -1;
|
| + pNew->addrOpenEphm[1] = -1;
|
| + pNew->nSelectRow = 0;
|
| if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
|
| pNew->pSrc = pSrc;
|
| pNew->pWhere = pWhere;
|
| pNew->pGroupBy = pGroupBy;
|
| pNew->pHaving = pHaving;
|
| pNew->pOrderBy = pOrderBy;
|
| - pNew->selFlags = selFlags;
|
| - pNew->op = TK_SELECT;
|
| + pNew->pPrior = 0;
|
| + pNew->pNext = 0;
|
| pNew->pLimit = pLimit;
|
| pNew->pOffset = pOffset;
|
| + pNew->pWith = 0;
|
| assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
|
| - pNew->addrOpenEphm[0] = -1;
|
| - pNew->addrOpenEphm[1] = -1;
|
| if( db->mallocFailed ) {
|
| clearSelect(db, pNew, pNew!=&standin);
|
| pNew = 0;
|
| @@ -161,7 +170,7 @@ void sqlite3SelectSetName(Select *p, const char *zName){
|
| ** Delete the given Select structure and all of its substructures.
|
| */
|
| void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
| - clearSelect(db, p, 1);
|
| + if( p ) clearSelect(db, p, 1);
|
| }
|
|
|
| /*
|
| @@ -325,7 +334,7 @@ static void addWhereTerm(
|
| pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
|
| pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
|
|
|
| - pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
|
| + pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
|
| if( pEq && isOuterJoin ){
|
| ExprSetProperty(pEq, EP_FromJoin);
|
| assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
| @@ -512,7 +521,7 @@ static void pushOntoSorter(
|
| int iLimit; /* LIMIT counter */
|
|
|
| assert( bSeq==0 || bSeq==1 );
|
| - assert( nData==1 || regData==regOrigData );
|
| + assert( nData==1 || regData==regOrigData || regOrigData==0 );
|
| if( nPrefixReg ){
|
| assert( nPrefixReg==nExpr+bSeq );
|
| regBase = regData - nExpr - bSeq;
|
| @@ -524,11 +533,11 @@ static void pushOntoSorter(
|
| iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
|
| pSort->labelDone = sqlite3VdbeMakeLabel(v);
|
| sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
|
| - SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
|
| + SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
|
| if( bSeq ){
|
| sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
|
| }
|
| - if( nPrefixReg==0 ){
|
| + if( nPrefixReg==0 && nData>0 ){
|
| sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
|
| }
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
|
| @@ -578,12 +587,34 @@ static void pushOntoSorter(
|
| }else{
|
| op = OP_IdxInsert;
|
| }
|
| - sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
| + sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
|
| + regBase+nOBSat, nBase-nOBSat);
|
| if( iLimit ){
|
| int addr;
|
| - addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
|
| + int r1 = 0;
|
| + /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit
|
| + ** register is initialized with value of LIMIT+OFFSET.) After the sorter
|
| + ** fills up, delete the least entry in the sorter after each insert.
|
| + ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
|
| + addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v);
|
| sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
|
| + if( pSort->bOrderedInnerLoop ){
|
| + r1 = ++pParse->nMem;
|
| + sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
|
| + VdbeComment((v, "seq"));
|
| + }
|
| sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
|
| + if( pSort->bOrderedInnerLoop ){
|
| + /* If the inner loop is driven by an index such that values from
|
| + ** the same iteration of the inner loop are in sorted order, then
|
| + ** immediately jump to the next iteration of an inner loop if the
|
| + ** entry from the current iteration does not fit into the top
|
| + ** LIMIT+OFFSET entries of the sorter. */
|
| + int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
|
| + sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
|
| + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
| + VdbeCoverage(v);
|
| + }
|
| sqlite3VdbeJumpHere(v, addr);
|
| }
|
| }
|
| @@ -625,34 +656,11 @@ static void codeDistinct(
|
| r1 = sqlite3GetTempReg(pParse);
|
| sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| }
|
|
|
| -#ifndef SQLITE_OMIT_SUBQUERY
|
| -/*
|
| -** Generate an error message when a SELECT is used within a subexpression
|
| -** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
|
| -** column. We do this in a subroutine because the error used to occur
|
| -** in multiple places. (The error only occurs in one place now, but we
|
| -** retain the subroutine to minimize code disruption.)
|
| -*/
|
| -static int checkForMultiColumnSelectError(
|
| - Parse *pParse, /* Parse context. */
|
| - SelectDest *pDest, /* Destination of SELECT results */
|
| - int nExpr /* Number of result columns returned by SELECT */
|
| -){
|
| - int eDest = pDest->eDest;
|
| - if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
|
| - sqlite3ErrorMsg(pParse, "only a single result allowed for "
|
| - "a SELECT that is part of an expression");
|
| - return 1;
|
| - }else{
|
| - return 0;
|
| - }
|
| -}
|
| -#endif
|
| -
|
| /*
|
| ** This routine generates the code for the inside of the inner loop
|
| ** of a SELECT.
|
| @@ -660,7 +668,7 @@ static int checkForMultiColumnSelectError(
|
| ** If srcTab is negative, then the pEList expressions
|
| ** are evaluated in order to get the data for this row. If srcTab is
|
| ** zero or more, then data is pulled from srcTab and pEList is used only
|
| -** to get number columns and the datatype for each column.
|
| +** to get the number of columns and the collation sequence for each column.
|
| */
|
| static void selectInnerLoop(
|
| Parse *pParse, /* The parser context */
|
| @@ -675,13 +683,20 @@ static void selectInnerLoop(
|
| ){
|
| Vdbe *v = pParse->pVdbe;
|
| int i;
|
| - int hasDistinct; /* True if the DISTINCT keyword is present */
|
| - int regResult; /* Start of memory holding result set */
|
| + int hasDistinct; /* True if the DISTINCT keyword is present */
|
| int eDest = pDest->eDest; /* How to dispose of results */
|
| int iParm = pDest->iSDParm; /* First argument to disposal method */
|
| int nResultCol; /* Number of result columns */
|
| int nPrefixReg = 0; /* Number of extra registers before regResult */
|
|
|
| + /* Usually, regResult is the first cell in an array of memory cells
|
| + ** containing the current result row. In this case regOrig is set to the
|
| + ** same value. However, if the results are being sent to the sorter, the
|
| + ** values for any expressions that are also part of the sort-key are omitted
|
| + ** from this array. In this case regOrig is set to zero. */
|
| + int regResult; /* Start of memory holding current results */
|
| + int regOrig; /* Start of memory holding full result (or 0) */
|
| +
|
| assert( v );
|
| assert( pEList!=0 );
|
| hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
|
| @@ -712,7 +727,7 @@ static void selectInnerLoop(
|
| pParse->nMem += nResultCol;
|
| }
|
| pDest->nSdst = nResultCol;
|
| - regResult = pDest->iSdst;
|
| + regOrig = regResult = pDest->iSdst;
|
| if( srcTab>=0 ){
|
| for(i=0; i<nResultCol; i++){
|
| sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
|
| @@ -728,7 +743,25 @@ static void selectInnerLoop(
|
| }else{
|
| ecelFlags = 0;
|
| }
|
| - sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
|
| + if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
|
| + /* For each expression in pEList that is a copy of an expression in
|
| + ** the ORDER BY clause (pSort->pOrderBy), set the associated
|
| + ** iOrderByCol value to one more than the index of the ORDER BY
|
| + ** expression within the sort-key that pushOntoSorter() will generate.
|
| + ** This allows the pEList field to be omitted from the sorted record,
|
| + ** saving space and CPU cycles. */
|
| + ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
|
| + for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
|
| + int j;
|
| + if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
|
| + pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
|
| + }
|
| + }
|
| + regOrig = 0;
|
| + assert( eDest==SRT_Set || eDest==SRT_Mem
|
| + || eDest==SRT_Coroutine || eDest==SRT_Output );
|
| + }
|
| + nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags);
|
| }
|
|
|
| /* If the DISTINCT keyword was present on the SELECT statement
|
| @@ -802,7 +835,7 @@ static void selectInnerLoop(
|
| int r1;
|
| r1 = sqlite3GetTempReg(pParse);
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| break;
|
| }
|
| @@ -839,7 +872,7 @@ static void selectInnerLoop(
|
| int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
| sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
|
| VdbeCoverage(v);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
|
| assert( pSort==0 );
|
| }
|
| #endif
|
| @@ -862,20 +895,20 @@ static void selectInnerLoop(
|
| ** item into the set table with bogus data.
|
| */
|
| case SRT_Set: {
|
| - assert( nResultCol==1 );
|
| - pDest->affSdst =
|
| - sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
|
| if( pSort ){
|
| /* At first glance you would think we could optimize out the
|
| ** ORDER BY in this case since the order of entries in the set
|
| ** does not matter. But there might be a LIMIT clause, in which
|
| ** case the order does matter */
|
| - pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
|
| + pushOntoSorter(
|
| + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
|
| }else{
|
| int r1 = sqlite3GetTempReg(pParse);
|
| - sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
|
| - sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
|
| + r1, pDest->zAffSdst, nResultCol);
|
| + sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| }
|
| break;
|
| @@ -890,14 +923,16 @@ static void selectInnerLoop(
|
| }
|
|
|
| /* If this is a scalar select that is part of an expression, then
|
| - ** store the results in the appropriate memory cell and break out
|
| - ** of the scan loop.
|
| + ** store the results in the appropriate memory cell or array of
|
| + ** memory cells and break out of the scan loop.
|
| */
|
| case SRT_Mem: {
|
| - assert( nResultCol==1 );
|
| if( pSort ){
|
| - pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
|
| + assert( nResultCol<=pDest->nSdst );
|
| + pushOntoSorter(
|
| + pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
|
| }else{
|
| + assert( nResultCol==pDest->nSdst );
|
| assert( regResult==iParm );
|
| /* The LIMIT clause will jump out of the loop for us */
|
| }
|
| @@ -910,7 +945,7 @@ static void selectInnerLoop(
|
| testcase( eDest==SRT_Coroutine );
|
| testcase( eDest==SRT_Output );
|
| if( pSort ){
|
| - pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
|
| + pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
|
| nPrefixReg);
|
| }else if( eDest==SRT_Coroutine ){
|
| sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
|
| @@ -960,7 +995,7 @@ static void selectInnerLoop(
|
| }
|
| sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
|
| if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| sqlite3ReleaseTempRange(pParse, r2, nKey+2);
|
| @@ -997,8 +1032,8 @@ static void selectInnerLoop(
|
| ** X extra columns.
|
| */
|
| KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
| - KeyInfo *p = sqlite3DbMallocZero(0,
|
| - sizeof(KeyInfo) + (N+X)*(sizeof(CollSeq*)+1));
|
| + int nExtra = (N+X)*(sizeof(CollSeq*)+1);
|
| + KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
|
| if( p ){
|
| p->aSortOrder = (u8*)&p->aColl[N+X];
|
| p->nField = (u16)N;
|
| @@ -1006,8 +1041,9 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
| p->enc = ENC(db);
|
| p->db = db;
|
| p->nRef = 1;
|
| + memset(&p[1], 0, nExtra);
|
| }else{
|
| - db->mallocFailed = 1;
|
| + sqlite3OomFault(db);
|
| }
|
| return p;
|
| }
|
| @@ -1019,7 +1055,7 @@ void sqlite3KeyInfoUnref(KeyInfo *p){
|
| if( p ){
|
| assert( p->nRef>0 );
|
| p->nRef--;
|
| - if( p->nRef==0 ) sqlite3DbFree(0, p);
|
| + if( p->nRef==0 ) sqlite3DbFree(p->db, p);
|
| }
|
| }
|
|
|
| @@ -1194,14 +1230,13 @@ static void generateSortTail(
|
| int iParm = pDest->iSDParm;
|
| int regRow;
|
| int regRowid;
|
| + int iCol;
|
| int nKey;
|
| int iSortTab; /* Sorter cursor to read from */
|
| int nSortData; /* Trailing values to read from sorter */
|
| int i;
|
| int bSeq; /* True if sorter record includes seq. no. */
|
| -#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
| struct ExprList_item *aOutEx = p->pEList->a;
|
| -#endif
|
|
|
| assert( addrBreak<0 );
|
| if( pSort->labelBkOut ){
|
| @@ -1210,21 +1245,21 @@ static void generateSortTail(
|
| sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
|
| }
|
| iTab = pSort->iECursor;
|
| - if( eDest==SRT_Output || eDest==SRT_Coroutine ){
|
| + if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
|
| regRowid = 0;
|
| regRow = pDest->iSdst;
|
| nSortData = nColumn;
|
| }else{
|
| regRowid = sqlite3GetTempReg(pParse);
|
| - regRow = sqlite3GetTempReg(pParse);
|
| - nSortData = 1;
|
| + regRow = sqlite3GetTempRange(pParse, nColumn);
|
| + nSortData = nColumn;
|
| }
|
| nKey = pOrderBy->nExpr - pSort->nOBSat;
|
| if( pSort->sortFlags & SORTFLAG_UseSorter ){
|
| int regSortOut = ++pParse->nMem;
|
| iSortTab = pParse->nTab++;
|
| if( pSort->labelBkOut ){
|
| - addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
| }
|
| sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
|
| if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
| @@ -1239,11 +1274,18 @@ static void generateSortTail(
|
| iSortTab = iTab;
|
| bSeq = 1;
|
| }
|
| - for(i=0; i<nSortData; i++){
|
| - sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
|
| + for(i=0, iCol=nKey+bSeq; i<nSortData; i++){
|
| + int iRead;
|
| + if( aOutEx[i].u.x.iOrderByCol ){
|
| + iRead = aOutEx[i].u.x.iOrderByCol-1;
|
| + }else{
|
| + iRead = iCol++;
|
| + }
|
| + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
|
| VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
|
| }
|
| switch( eDest ){
|
| + case SRT_Table:
|
| case SRT_EphemTab: {
|
| sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
|
| sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
|
| @@ -1252,16 +1294,14 @@ static void generateSortTail(
|
| }
|
| #ifndef SQLITE_OMIT_SUBQUERY
|
| case SRT_Set: {
|
| - assert( nColumn==1 );
|
| - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
|
| - &pDest->affSdst, 1);
|
| - sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
|
| + assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
|
| + pDest->zAffSdst, nColumn);
|
| + sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
|
| break;
|
| }
|
| case SRT_Mem: {
|
| - assert( nColumn==1 );
|
| - sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
|
| /* The LIMIT clause will terminate the loop for us */
|
| break;
|
| }
|
| @@ -1280,7 +1320,11 @@ static void generateSortTail(
|
| }
|
| }
|
| if( regRowid ){
|
| - sqlite3ReleaseTempReg(pParse, regRow);
|
| + if( eDest==SRT_Set ){
|
| + sqlite3ReleaseTempRange(pParse, regRow, nColumn);
|
| + }else{
|
| + sqlite3ReleaseTempReg(pParse, regRow);
|
| + }
|
| sqlite3ReleaseTempReg(pParse, regRowid);
|
| }
|
| /* The bottom of the loop
|
| @@ -1420,20 +1464,20 @@ static const char *columnTypeImpl(
|
| zType = "INTEGER";
|
| zOrigCol = "rowid";
|
| }else{
|
| - zType = pTab->aCol[iCol].zType;
|
| zOrigCol = pTab->aCol[iCol].zName;
|
| + zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
|
| estWidth = pTab->aCol[iCol].szEst;
|
| }
|
| zOrigTab = pTab->zName;
|
| if( pNC->pParse ){
|
| int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
|
| - zOrigDb = pNC->pParse->db->aDb[iDb].zName;
|
| + zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
|
| }
|
| #else
|
| if( iCol<0 ){
|
| zType = "INTEGER";
|
| }else{
|
| - zType = pTab->aCol[iCol].zType;
|
| + zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
|
| estWidth = pTab->aCol[iCol].szEst;
|
| }
|
| #endif
|
| @@ -1668,7 +1712,7 @@ int sqlite3ColumnsFromExprList(
|
| pCol->zName = zName;
|
| sqlite3ColumnPropertiesFromName(0, pCol);
|
| if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
|
| - db->mallocFailed = 1;
|
| + sqlite3OomFault(db);
|
| }
|
| }
|
| sqlite3HashClear(&ht);
|
| @@ -1679,7 +1723,7 @@ int sqlite3ColumnsFromExprList(
|
| sqlite3DbFree(db, aCol);
|
| *paCol = 0;
|
| *pnCol = 0;
|
| - return SQLITE_NOMEM;
|
| + return SQLITE_NOMEM_BKPT;
|
| }
|
| return SQLITE_OK;
|
| }
|
| @@ -1695,7 +1739,7 @@ int sqlite3ColumnsFromExprList(
|
| ** This routine requires that all identifiers in the SELECT
|
| ** statement be resolved.
|
| */
|
| -static void selectAddColumnTypeAndCollation(
|
| +void sqlite3SelectAddColumnTypeAndCollation(
|
| Parse *pParse, /* Parsing contexts */
|
| Table *pTab, /* Add column type information to this table */
|
| Select *pSelect /* SELECT used to determine types and collations */
|
| @@ -1717,13 +1761,20 @@ static void selectAddColumnTypeAndCollation(
|
| sNC.pSrcList = pSelect->pSrc;
|
| a = pSelect->pEList->a;
|
| for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
| + const char *zType;
|
| + int n, m;
|
| p = a[i].pExpr;
|
| - if( pCol->zType==0 ){
|
| - pCol->zType = sqlite3DbStrDup(db,
|
| - columnType(&sNC, p,0,0,0, &pCol->szEst));
|
| - }
|
| + zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
| szAll += pCol->szEst;
|
| pCol->affinity = sqlite3ExprAffinity(p);
|
| + if( zType && (m = sqlite3Strlen30(zType))>0 ){
|
| + n = sqlite3Strlen30(pCol->zName);
|
| + pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
|
| + if( pCol->zName ){
|
| + memcpy(&pCol->zName[n+1], zType, m+1);
|
| + pCol->colFlags |= COLFLAG_HASTYPE;
|
| + }
|
| + }
|
| if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
| pColl = sqlite3ExprCollSeq(pParse, p);
|
| if( pColl && pCol->zColl==0 ){
|
| @@ -1755,12 +1806,12 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
| }
|
| /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
|
| ** is disabled */
|
| - assert( db->lookaside.bEnabled==0 );
|
| - pTab->nRef = 1;
|
| + assert( db->lookaside.bDisable );
|
| + pTab->nTabRef = 1;
|
| pTab->zName = 0;
|
| pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
| - selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
| + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
|
| pTab->iPKey = -1;
|
| if( db->mallocFailed ){
|
| sqlite3DeleteTable(db, pTab);
|
| @@ -1773,20 +1824,20 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
| ** Get a VDBE for the given parser context. Create a new one if necessary.
|
| ** If an error occurs, return NULL and leave a message in pParse.
|
| */
|
| -Vdbe *sqlite3GetVdbe(Parse *pParse){
|
| - Vdbe *v = pParse->pVdbe;
|
| - if( v==0 ){
|
| - v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
|
| - if( v ) sqlite3VdbeAddOp0(v, OP_Init);
|
| - if( pParse->pToplevel==0
|
| - && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
|
| - ){
|
| - pParse->okConstFactor = 1;
|
| - }
|
| -
|
| +static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
|
| + Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
|
| + if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
|
| + if( pParse->pToplevel==0
|
| + && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
|
| + ){
|
| + pParse->okConstFactor = 1;
|
| }
|
| return v;
|
| }
|
| +Vdbe *sqlite3GetVdbe(Parse *pParse){
|
| + Vdbe *v = pParse->pVdbe;
|
| + return v ? v : allocVdbe(pParse);
|
| +}
|
|
|
|
|
| /*
|
| @@ -1836,8 +1887,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
| VdbeComment((v, "LIMIT counter"));
|
| if( n==0 ){
|
| sqlite3VdbeGoto(v, iBreak);
|
| - }else if( n>=0 && p->nSelectRow>(u64)n ){
|
| - p->nSelectRow = n;
|
| + }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
|
| + p->nSelectRow = sqlite3LogEst((u64)n);
|
| + p->selFlags |= SF_FixedLimit;
|
| }
|
| }else{
|
| sqlite3ExprCode(pParse, p->pLimit, iLimit);
|
| @@ -1851,10 +1903,8 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
| sqlite3ExprCode(pParse, p->pOffset, iOffset);
|
| sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
|
| VdbeComment((v, "OFFSET counter"));
|
| - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
|
| - sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
|
| + sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
|
| VdbeComment((v, "LIMIT+OFFSET"));
|
| - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
|
| }
|
| }
|
| }
|
| @@ -1988,6 +2038,7 @@ static void generateWithRecursiveQuery(
|
|
|
| /* Process the LIMIT and OFFSET clauses, if they exist */
|
| addrBreak = sqlite3VdbeMakeLabel(v);
|
| + p->nSelectRow = 320; /* 4 billion rows */
|
| computeLimitRegisters(pParse, p, addrBreak);
|
| pLimit = p->pLimit;
|
| pOffset = p->pOffset;
|
| @@ -2217,7 +2268,6 @@ static int multiSelect(
|
| if( dest.eDest==SRT_EphemTab ){
|
| assert( p->pEList );
|
| sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
|
| - sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
| dest.eDest = SRT_Table;
|
| }
|
|
|
| @@ -2271,9 +2321,8 @@ static int multiSelect(
|
| addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
|
| VdbeComment((v, "Jump ahead if LIMIT reached"));
|
| if( p->iOffset ){
|
| - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
|
| - sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
|
| - sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
|
| + sqlite3VdbeAddOp3(v, OP_OffsetLimit,
|
| + p->iLimit, p->iOffset+1, p->iOffset);
|
| }
|
| }
|
| explainSetInteger(iSub2, pParse->iNextSelectId);
|
| @@ -2281,12 +2330,12 @@ static int multiSelect(
|
| testcase( rc!=SQLITE_OK );
|
| pDelete = p->pPrior;
|
| p->pPrior = pPrior;
|
| - p->nSelectRow += pPrior->nSelectRow;
|
| + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
| if( pPrior->pLimit
|
| && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
|
| - && nLimit>0 && p->nSelectRow > (u64)nLimit
|
| + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
| ){
|
| - p->nSelectRow = nLimit;
|
| + p->nSelectRow = sqlite3LogEst((u64)nLimit);
|
| }
|
| if( addr ){
|
| sqlite3VdbeJumpHere(v, addr);
|
| @@ -2358,7 +2407,9 @@ static int multiSelect(
|
| pDelete = p->pPrior;
|
| p->pPrior = pPrior;
|
| p->pOrderBy = 0;
|
| - if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
|
| + if( p->op==TK_UNION ){
|
| + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
| + }
|
| sqlite3ExprDelete(db, p->pLimit);
|
| p->pLimit = pLimit;
|
| p->pOffset = pOffset;
|
| @@ -2457,7 +2508,7 @@ static int multiSelect(
|
| computeLimitRegisters(pParse, p, iBreak);
|
| sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
|
| r1 = sqlite3GetTempReg(pParse);
|
| - iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
|
| + iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
|
| sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| selectInnerLoop(pParse, p, p->pEList, tab1,
|
| @@ -2493,7 +2544,7 @@ static int multiSelect(
|
| nCol = p->pEList->nExpr;
|
| pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
|
| if( !pKeyInfo ){
|
| - rc = SQLITE_NOMEM;
|
| + rc = SQLITE_NOMEM_BKPT;
|
| goto multi_select_end;
|
| }
|
| for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
|
| @@ -2615,19 +2666,17 @@ static int generateOutputSubroutine(
|
| }
|
|
|
| #ifndef SQLITE_OMIT_SUBQUERY
|
| - /* If we are creating a set for an "expr IN (SELECT ...)" construct,
|
| - ** then there should be a single item on the stack. Write this
|
| - ** item into the set table with bogus data.
|
| + /* If we are creating a set for an "expr IN (SELECT ...)".
|
| */
|
| case SRT_Set: {
|
| int r1;
|
| - assert( pIn->nSdst==1 || pParse->nErr>0 );
|
| - pDest->affSdst =
|
| - sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
|
| + testcase( pIn->nSdst>1 );
|
| r1 = sqlite3GetTempReg(pParse);
|
| - sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
|
| - sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
|
| + sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
|
| + r1, pDest->zAffSdst, pIn->nSdst);
|
| + sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
|
| + pIn->iSdst, pIn->nSdst);
|
| sqlite3ReleaseTempReg(pParse, r1);
|
| break;
|
| }
|
| @@ -2848,7 +2897,7 @@ static int multiSelectOrderBy(
|
| }
|
| if( j==nOrderBy ){
|
| Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
|
| - if( pNew==0 ) return SQLITE_NOMEM;
|
| + if( pNew==0 ) return SQLITE_NOMEM_BKPT;
|
| pNew->flags |= EP_IntValue;
|
| pNew->u.iValue = i;
|
| pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
| @@ -2864,10 +2913,11 @@ static int multiSelectOrderBy(
|
| ** to the right and the left are evaluated, they use the correct
|
| ** collation.
|
| */
|
| - aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
|
| + aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
|
| if( aPermute ){
|
| struct ExprList_item *pItem;
|
| - for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
| + aPermute[0] = nOrderBy;
|
| + for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
|
| assert( pItem->u.x.iOrderByCol>0 );
|
| assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
| aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
| @@ -2945,7 +2995,7 @@ static int multiSelectOrderBy(
|
| pPrior->iLimit = regLimitA;
|
| explainSetInteger(iSub1, pParse->iNextSelectId);
|
| sqlite3Select(pParse, pPrior, &destA);
|
| - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
|
| + sqlite3VdbeEndCoroutine(v, regAddrA);
|
| sqlite3VdbeJumpHere(v, addr1);
|
|
|
| /* Generate a coroutine to evaluate the SELECT statement on
|
| @@ -2962,7 +3012,7 @@ static int multiSelectOrderBy(
|
| sqlite3Select(pParse, p, &destB);
|
| p->iLimit = savedLimit;
|
| p->iOffset = savedOffset;
|
| - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
|
| + sqlite3VdbeEndCoroutine(v, regAddrB);
|
|
|
| /* Generate a subroutine that outputs the current row of the A
|
| ** select as the next output row of the compound select.
|
| @@ -2994,7 +3044,7 @@ static int multiSelectOrderBy(
|
| addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
| VdbeCoverage(v);
|
| sqlite3VdbeGoto(v, addrEofA);
|
| - p->nSelectRow += pPrior->nSelectRow;
|
| + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
| }
|
|
|
| /* Generate a subroutine to run when the results from select B
|
| @@ -3085,8 +3135,8 @@ static int multiSelectOrderBy(
|
|
|
| #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| /* Forward Declarations */
|
| -static void substExprList(sqlite3*, ExprList*, int, ExprList*);
|
| -static void substSelect(sqlite3*, Select *, int, ExprList*, int);
|
| +static void substExprList(Parse*, ExprList*, int, ExprList*);
|
| +static void substSelect(Parse*, Select *, int, ExprList*, int);
|
|
|
| /*
|
| ** Scan through the expression pExpr. Replace every reference to
|
| @@ -3102,36 +3152,46 @@ static void substSelect(sqlite3*, Select *, int, ExprList*, int);
|
| ** of the subquery rather the result set of the subquery.
|
| */
|
| static Expr *substExpr(
|
| - sqlite3 *db, /* Report malloc errors to this connection */
|
| + Parse *pParse, /* Report errors here */
|
| Expr *pExpr, /* Expr in which substitution occurs */
|
| int iTable, /* Table to be substituted */
|
| ExprList *pEList /* Substitute expressions */
|
| ){
|
| + sqlite3 *db = pParse->db;
|
| if( pExpr==0 ) return 0;
|
| if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
|
| if( pExpr->iColumn<0 ){
|
| pExpr->op = TK_NULL;
|
| }else{
|
| Expr *pNew;
|
| + Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
|
| assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
| assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
| - pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
|
| - sqlite3ExprDelete(db, pExpr);
|
| - pExpr = pNew;
|
| + if( sqlite3ExprIsVector(pCopy) ){
|
| + sqlite3VectorErrorMsg(pParse, pCopy);
|
| + }else{
|
| + pNew = sqlite3ExprDup(db, pCopy, 0);
|
| + if( pNew && (pExpr->flags & EP_FromJoin) ){
|
| + pNew->iRightJoinTable = pExpr->iRightJoinTable;
|
| + pNew->flags |= EP_FromJoin;
|
| + }
|
| + sqlite3ExprDelete(db, pExpr);
|
| + pExpr = pNew;
|
| + }
|
| }
|
| }else{
|
| - pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
|
| - pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
|
| + pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
|
| + pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
|
| if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
| - substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
|
| + substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
|
| }else{
|
| - substExprList(db, pExpr->x.pList, iTable, pEList);
|
| + substExprList(pParse, pExpr->x.pList, iTable, pEList);
|
| }
|
| }
|
| return pExpr;
|
| }
|
| static void substExprList(
|
| - sqlite3 *db, /* Report malloc errors here */
|
| + Parse *pParse, /* Report errors here */
|
| ExprList *pList, /* List to scan and in which to make substitutes */
|
| int iTable, /* Table to be substituted */
|
| ExprList *pEList /* Substitute values */
|
| @@ -3139,11 +3199,11 @@ static void substExprList(
|
| int i;
|
| if( pList==0 ) return;
|
| for(i=0; i<pList->nExpr; i++){
|
| - pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
|
| + pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
|
| }
|
| }
|
| static void substSelect(
|
| - sqlite3 *db, /* Report malloc errors here */
|
| + Parse *pParse, /* Report errors here */
|
| Select *p, /* SELECT statement in which to make substitutions */
|
| int iTable, /* Table to be replaced */
|
| ExprList *pEList, /* Substitute values */
|
| @@ -3154,17 +3214,17 @@ static void substSelect(
|
| int i;
|
| if( !p ) return;
|
| do{
|
| - substExprList(db, p->pEList, iTable, pEList);
|
| - substExprList(db, p->pGroupBy, iTable, pEList);
|
| - substExprList(db, p->pOrderBy, iTable, pEList);
|
| - p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
|
| - p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
|
| + substExprList(pParse, p->pEList, iTable, pEList);
|
| + substExprList(pParse, p->pGroupBy, iTable, pEList);
|
| + substExprList(pParse, p->pOrderBy, iTable, pEList);
|
| + p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
|
| + p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
|
| pSrc = p->pSrc;
|
| assert( pSrc!=0 );
|
| for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
| - substSelect(db, pItem->pSelect, iTable, pEList, 1);
|
| + substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
|
| if( pItem->fg.isTabFunc ){
|
| - substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
|
| + substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
|
| }
|
| }
|
| }while( doPrior && (p = p->pPrior)!=0 );
|
| @@ -3561,12 +3621,12 @@ static int flattenSubquery(
|
| */
|
| if( ALWAYS(pSubitem->pTab!=0) ){
|
| Table *pTabToDel = pSubitem->pTab;
|
| - if( pTabToDel->nRef==1 ){
|
| + if( pTabToDel->nTabRef==1 ){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| pTabToDel->pNextZombie = pToplevel->pZombieTab;
|
| pToplevel->pZombieTab = pTabToDel;
|
| }else{
|
| - pTabToDel->nRef--;
|
| + pTabToDel->nTabRef--;
|
| }
|
| pSubitem->pTab = 0;
|
| }
|
| @@ -3681,14 +3741,15 @@ static int flattenSubquery(
|
| assert( pParent->pHaving==0 );
|
| pParent->pHaving = pParent->pWhere;
|
| pParent->pWhere = pWhere;
|
| - pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
|
| - sqlite3ExprDup(db, pSub->pHaving, 0));
|
| + pParent->pHaving = sqlite3ExprAnd(db,
|
| + sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
|
| + );
|
| assert( pParent->pGroupBy==0 );
|
| pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
|
| }else{
|
| - pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
|
| + pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
| }
|
| - substSelect(db, pParent, iParent, pSub->pEList, 0);
|
| + substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
|
|
| /* The flattened query is distinct if either the inner or the
|
| ** outer query is distinct.
|
| @@ -3762,31 +3823,37 @@ static int flattenSubquery(
|
| ** terms are duplicated into the subquery.
|
| */
|
| static int pushDownWhereTerms(
|
| - sqlite3 *db, /* The database connection (for malloc()) */
|
| + Parse *pParse, /* Parse context (for malloc() and error reporting) */
|
| Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
|
| Expr *pWhere, /* The WHERE clause of the outer query */
|
| int iCursor /* Cursor number of the subquery */
|
| ){
|
| Expr *pNew;
|
| int nChng = 0;
|
| + Select *pX; /* For looping over compound SELECTs in pSubq */
|
| if( pWhere==0 ) return 0;
|
| - if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
| - return 0; /* restrictions (1) and (2) */
|
| + for(pX=pSubq; pX; pX=pX->pPrior){
|
| + if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
|
| + testcase( pX->selFlags & SF_Aggregate );
|
| + testcase( pX->selFlags & SF_Recursive );
|
| + testcase( pX!=pSubq );
|
| + return 0; /* restrictions (1) and (2) */
|
| + }
|
| }
|
| if( pSubq->pLimit!=0 ){
|
| - return 0; /* restriction (3) */
|
| + return 0; /* restriction (3) */
|
| }
|
| while( pWhere->op==TK_AND ){
|
| - nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
|
| + nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
|
| pWhere = pWhere->pLeft;
|
| }
|
| if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
|
| if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
| nChng++;
|
| while( pSubq ){
|
| - pNew = sqlite3ExprDup(db, pWhere, 0);
|
| - pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
|
| - pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
|
| + pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
| + pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
|
| + pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
| pSubq = pSubq->pPrior;
|
| }
|
| }
|
| @@ -4078,13 +4145,13 @@ static int withExpand(
|
| assert( pFrom->pTab==0 );
|
| pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
| if( pTab==0 ) return WRC_Abort;
|
| - pTab->nRef = 1;
|
| + pTab->nTabRef = 1;
|
| pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
| pTab->iPKey = -1;
|
| pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
| pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
| pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
| - if( db->mallocFailed ) return SQLITE_NOMEM;
|
| + if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
|
| assert( pFrom->pSelect );
|
|
|
| /* Check if this is a recursive CTE. */
|
| @@ -4101,25 +4168,33 @@ static int withExpand(
|
| ){
|
| pItem->pTab = pTab;
|
| pItem->fg.isRecursive = 1;
|
| - pTab->nRef++;
|
| + pTab->nTabRef++;
|
| pSel->selFlags |= SF_Recursive;
|
| }
|
| }
|
| }
|
|
|
| /* Only one recursive reference is permitted. */
|
| - if( pTab->nRef>2 ){
|
| + if( pTab->nTabRef>2 ){
|
| sqlite3ErrorMsg(
|
| pParse, "multiple references to recursive table: %s", pCte->zName
|
| );
|
| return SQLITE_ERROR;
|
| }
|
| - assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
|
| + assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
|
|
|
| pCte->zCteErr = "circular reference: %s";
|
| pSavedWith = pParse->pWith;
|
| pParse->pWith = pWith;
|
| - sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
|
| + if( bMayRecursive ){
|
| + Select *pPrior = pSel->pPrior;
|
| + assert( pPrior->pWith==0 );
|
| + pPrior->pWith = pSel->pWith;
|
| + sqlite3WalkSelect(pWalker, pPrior);
|
| + pPrior->pWith = 0;
|
| + }else{
|
| + sqlite3WalkSelect(pWalker, pSel);
|
| + }
|
| pParse->pWith = pWith;
|
|
|
| for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
| @@ -4163,10 +4238,12 @@ static int withExpand(
|
| */
|
| static void selectPopWith(Walker *pWalker, Select *p){
|
| Parse *pParse = pWalker->pParse;
|
| - With *pWith = findRightmost(p)->pWith;
|
| - if( pWith!=0 ){
|
| - assert( pParse->pWith==pWith );
|
| - pParse->pWith = pWith->pOuter;
|
| + if( pParse->pWith && p->pPrior==0 ){
|
| + With *pWith = findRightmost(p)->pWith;
|
| + if( pWith!=0 ){
|
| + assert( pParse->pWith==pWith );
|
| + pParse->pWith = pWith->pOuter;
|
| + }
|
| }
|
| }
|
| #else
|
| @@ -4216,8 +4293,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| }
|
| pTabList = p->pSrc;
|
| pEList = p->pEList;
|
| - if( pWalker->xSelectCallback2==selectPopWith ){
|
| - sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
|
| + if( p->pWith ){
|
| + sqlite3WithPush(pParse, p->pWith, 0);
|
| }
|
|
|
| /* Make sure cursor numbers have been assigned to all entries in
|
| @@ -4247,7 +4324,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
| pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
| if( pTab==0 ) return WRC_Abort;
|
| - pTab->nRef = 1;
|
| + pTab->nTabRef = 1;
|
| pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
|
| while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
| sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
|
| @@ -4260,13 +4337,13 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| assert( pFrom->pTab==0 );
|
| pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
|
| if( pTab==0 ) return WRC_Abort;
|
| - if( pTab->nRef==0xffff ){
|
| + if( pTab->nTabRef>=0xffff ){
|
| sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
|
| pTab->zName);
|
| pFrom->pTab = 0;
|
| return WRC_Abort;
|
| }
|
| - pTab->nRef++;
|
| + pTab->nTabRef++;
|
| if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
|
| return WRC_Abort;
|
| }
|
| @@ -4370,7 +4447,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| continue;
|
| }
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| - zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
|
| + zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
|
| }
|
| for(j=0; j<pTab->nCol; j++){
|
| char *zName = pTab->aCol[j].zName;
|
| @@ -4416,10 +4493,10 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| if( longNames || pTabList->nSrc>1 ){
|
| Expr *pLeft;
|
| pLeft = sqlite3Expr(db, TK_ID, zTabName);
|
| - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
|
| + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
|
| if( zSchemaName ){
|
| pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
|
| - pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
|
| + pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
|
| }
|
| if( longNames ){
|
| zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
|
| @@ -4429,8 +4506,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
| pExpr = pRight;
|
| }
|
| pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
|
| - sColname.z = zColname;
|
| - sColname.n = sqlite3Strlen30(zColname);
|
| + sqlite3TokenInit(&sColname, zColname);
|
| sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
|
| if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
|
| struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
|
| @@ -4505,9 +4581,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
| sqlite3WalkSelect(&w, pSelect);
|
| }
|
| w.xSelectCallback = selectExpander;
|
| - if( (pSelect->selFlags & SF_MultiValue)==0 ){
|
| - w.xSelectCallback2 = selectPopWith;
|
| - }
|
| + w.xSelectCallback2 = selectPopWith;
|
| sqlite3WalkSelect(&w, pSelect);
|
| }
|
|
|
| @@ -4545,7 +4619,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
| Select *pSel = pFrom->pSelect;
|
| if( pSel ){
|
| while( pSel->pPrior ) pSel = pSel->pPrior;
|
| - selectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
| + sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
|
| }
|
| }
|
| }
|
| @@ -4657,8 +4731,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
| for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
| ExprList *pList = pF->pExpr->x.pList;
|
| assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
| - sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
|
| - (void*)pF->pFunc, P4_FUNCDEF);
|
| + sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
|
| + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
| }
|
| }
|
|
|
| @@ -4709,8 +4783,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
| if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
|
| sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
|
| }
|
| - sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
|
| - (void*)pF->pFunc, P4_FUNCDEF);
|
| + sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
|
| + sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
| sqlite3VdbeChangeP5(v, (u8)nArg);
|
| sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
| sqlite3ReleaseTempRange(pParse, regAgg, nArg);
|
| @@ -4854,16 +4928,6 @@ int sqlite3Select(
|
| }
|
| #endif
|
|
|
| -
|
| - /* If writing to memory or generating a set
|
| - ** only a single column may be output.
|
| - */
|
| -#ifndef SQLITE_OMIT_SUBQUERY
|
| - if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
|
| - goto select_end;
|
| - }
|
| -#endif
|
| -
|
| /* Try to flatten subqueries in the FROM clause up into the main query
|
| */
|
| #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
| @@ -4954,7 +5018,7 @@ int sqlite3Select(
|
| ** inside the subquery. This can help the subquery to run more efficiently.
|
| */
|
| if( (pItem->fg.jointype & JT_OUTER)==0
|
| - && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
|
| + && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor)
|
| ){
|
| #if SELECTTRACE_ENABLED
|
| if( sqlite3SelectTrace & 0x100 ){
|
| @@ -4965,10 +5029,24 @@ int sqlite3Select(
|
| }
|
|
|
| /* Generate code to implement the subquery
|
| + **
|
| + ** The subquery is implemented as a co-routine if all of these are true:
|
| + ** (1) The subquery is guaranteed to be the outer loop (so that it
|
| + ** does not need to be computed more than once)
|
| + ** (2) The ALL keyword after SELECT is omitted. (Applications are
|
| + ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
|
| + ** the use of co-routines.)
|
| + ** (3) Co-routines are not disabled using sqlite3_test_control()
|
| + ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
|
| + **
|
| + ** TODO: Are there other reasons beside (1) to use a co-routine
|
| + ** implementation?
|
| */
|
| - if( pTabList->nSrc==1
|
| - && (p->selFlags & SF_All)==0
|
| - && OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
| + if( i==0
|
| + && (pTabList->nSrc==1
|
| + || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
|
| + && (p->selFlags & SF_All)==0 /* (2) */
|
| + && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
|
| ){
|
| /* Implement a co-routine that will return a single row of the result
|
| ** set on each invocation.
|
| @@ -4981,10 +5059,10 @@ int sqlite3Select(
|
| sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
| explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
| sqlite3Select(pParse, pSub, &dest);
|
| - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
| + pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
| pItem->fg.viaCoroutine = 1;
|
| pItem->regResult = dest.iSdst;
|
| - sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
| + sqlite3VdbeEndCoroutine(v, pItem->regReturn);
|
| sqlite3VdbeJumpHere(v, addrTop-1);
|
| sqlite3ClearTempRegCache(pParse);
|
| }else{
|
| @@ -5004,7 +5082,7 @@ int sqlite3Select(
|
| /* If the subquery is not correlated and if we are not inside of
|
| ** a trigger, then we only need to compute the value of the subquery
|
| ** once. */
|
| - onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
| + onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
| VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
| }else{
|
| VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
| @@ -5012,7 +5090,7 @@ int sqlite3Select(
|
| sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
| explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
| sqlite3Select(pParse, pSub, &dest);
|
| - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
|
| + pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
| if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
| retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
| VdbeComment((v, "end %s", pItem->pTab->zName));
|
| @@ -5063,6 +5141,13 @@ int sqlite3Select(
|
| ** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
| ** original setting of the SF_Distinct flag, not the current setting */
|
| assert( sDistinct.isTnct );
|
| +
|
| +#if SELECTTRACE_ENABLED
|
| + if( sqlite3SelectTrace & 0x400 ){
|
| + SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
|
| + sqlite3TreeViewSelect(0, p, 0);
|
| + }
|
| +#endif
|
| }
|
|
|
| /* If there is an ORDER BY clause, then create an ephemeral index to
|
| @@ -5095,7 +5180,9 @@ int sqlite3Select(
|
| /* Set the limiter.
|
| */
|
| iEnd = sqlite3VdbeMakeLabel(v);
|
| - p->nSelectRow = LARGEST_INT64;
|
| + if( (p->selFlags & SF_FixedLimit)==0 ){
|
| + p->nSelectRow = 320; /* 4 billion rows */
|
| + }
|
| computeLimitRegisters(pParse, p, iEnd);
|
| if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
|
| sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
|
| @@ -5119,10 +5206,12 @@ int sqlite3Select(
|
| if( !isAgg && pGroupBy==0 ){
|
| /* 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;
|
|
|
| /* Begin the database scan. */
|
| pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
| - p->pEList, wctrlFlags, 0);
|
| + p->pEList, wctrlFlags, p->nSelectRow);
|
| if( pWInfo==0 ) goto select_end;
|
| if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
| p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
| @@ -5132,6 +5221,7 @@ int sqlite3Select(
|
| }
|
| if( sSort.pOrderBy ){
|
| sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
|
| + sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
|
| if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
|
| sSort.pOrderBy = 0;
|
| }
|
| @@ -5182,9 +5272,11 @@ int sqlite3Select(
|
| for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
|
| pItem->u.x.iAlias = 0;
|
| }
|
| - if( p->nSelectRow>100 ) p->nSelectRow = 100;
|
| + assert( 66==sqlite3LogEst(100) );
|
| + if( p->nSelectRow>66 ) p->nSelectRow = 66;
|
| }else{
|
| - p->nSelectRow = 1;
|
| + assert( 0==sqlite3LogEst(1) );
|
| + p->nSelectRow = 0;
|
| }
|
|
|
| /* If there is both a GROUP BY and an ORDER BY clause and they are
|
| @@ -5556,7 +5648,8 @@ int sqlite3Select(
|
| if( flag ){
|
| pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
|
| pDel = pMinMax;
|
| - if( pMinMax && !db->mallocFailed ){
|
| + assert( db->mallocFailed || pMinMax!=0 );
|
| + if( !db->mallocFailed ){
|
| pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
|
| pMinMax->a[0].pExpr->op = TK_COLUMN;
|
| }
|
| @@ -5567,7 +5660,7 @@ int sqlite3Select(
|
| ** of output.
|
| */
|
| resetAccumulator(pParse, &sAggInfo);
|
| - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
|
| + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax, 0,flag,0);
|
| if( pWInfo==0 ){
|
| sqlite3ExprListDelete(db, pDel);
|
| goto select_end;
|
|
|