diff options
Diffstat (limited to 'ext/sqlite/libsqlite/src/select.c')
-rw-r--r-- | ext/sqlite/libsqlite/src/select.c | 394 |
1 files changed, 205 insertions, 189 deletions
diff --git a/ext/sqlite/libsqlite/src/select.c b/ext/sqlite/libsqlite/src/select.c index 03eb861c9e..9bed641be7 100644 --- a/ext/sqlite/libsqlite/src/select.c +++ b/ext/sqlite/libsqlite/src/select.c @@ -120,9 +120,8 @@ int sqliteJoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ pParse->nErr++; jointype = JT_INNER; }else if( jointype & JT_RIGHT ){ - sqliteSetString(&pParse->zErrMsg, - "RIGHT and FULL OUTER JOINs are not currently supported", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, + "RIGHT and FULL OUTER JOINs are not currently supported"); jointype = JT_INNER; } return jointype; @@ -218,9 +217,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ if( pTerm->jointype & JT_NATURAL ){ Table *pTab; if( pTerm->pOn || pTerm->pUsing ){ - sqliteSetString(&pParse->zErrMsg, "a NATURAL join may not have " + sqliteErrorMsg(pParse, "a NATURAL join may not have " "an ON or USING clause", 0); - pParse->nErr++; return 1; } pTab = pTerm->pTab; @@ -234,9 +232,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ /* Disallow both ON and USING clauses in the same join */ if( pTerm->pOn && pTerm->pUsing ){ - sqliteSetString(&pParse->zErrMsg, "cannot have both ON and USING " - "clauses in the same join", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, "cannot have both ON and USING " + "clauses in the same join"); return 1; } @@ -268,9 +265,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ for(j=0; j<pList->nId; j++){ if( columnIndex(pTerm->pTab, pList->a[j].zName)<0 || columnIndex(pOther->pTab, pList->a[j].zName)<0 ){ - sqliteSetString(&pParse->zErrMsg, "cannot join using column ", - pList->a[j].zName, " - column not present in both tables", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, "cannot join using column %s - column " + "not present in both tables", pList->a[j].zName); return 1; } addWhereTerm(pList->a[j].zName, pTerm->pTab, pOther->pTab, &p->pWhere); @@ -300,13 +296,15 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ ** will work correctly for both SQLite and Oracle8. */ static int sqliteOracle8JoinFixup( - int base, /* VDBE cursor number for first table in pSrc */ SrcList *pSrc, /* List of tables being joined */ Expr *pWhere /* The WHERE clause of the SELECT statement */ ){ int rc = 0; if( ExprHasProperty(pWhere, EP_Oracle8Join) && pWhere->op==TK_COLUMN ){ - int idx = pWhere->iTable - base; + int idx; + for(idx=0; idx<pSrc->nSrc; idx++){ + if( pSrc->a[idx].iCursor==pWhere->iTable ) break; + } assert( idx>=0 && idx<pSrc->nSrc ); if( idx>0 ){ pSrc->a[idx-1].jointype &= ~JT_INNER; @@ -315,16 +313,16 @@ static int sqliteOracle8JoinFixup( } } if( pWhere->pRight ){ - rc = sqliteOracle8JoinFixup(base, pSrc, pWhere->pRight); + rc = sqliteOracle8JoinFixup(pSrc, pWhere->pRight); } if( pWhere->pLeft ){ - rc |= sqliteOracle8JoinFixup(base, pSrc, pWhere->pLeft); + rc |= sqliteOracle8JoinFixup(pSrc, pWhere->pLeft); } if( pWhere->pList ){ int i; ExprList *pList = pWhere->pList; for(i=0; i<pList->nExpr && rc==0; i++){ - rc |= sqliteOracle8JoinFixup(base, pSrc, pList->a[i].pExpr); + rc |= sqliteOracle8JoinFixup(pSrc, pList->a[i].pExpr); } } if( rc==1 && (pWhere->op==TK_AND || pWhere->op==TK_EQ) ){ @@ -691,12 +689,11 @@ static void generateSortTail( */ static void generateColumnTypes( Parse *pParse, /* Parser context */ - int base, /* VDBE cursor corresponding to first entry in pTabList */ SrcList *pTabList, /* List of tables */ ExprList *pEList /* Expressions defining the result set */ ){ Vdbe *v = pParse->pVdbe; - int i; + int i, j; if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){ return; } @@ -705,8 +702,11 @@ static void generateColumnTypes( char *zType = 0; if( p==0 ) continue; if( p->op==TK_COLUMN && pTabList ){ - Table *pTab = pTabList->a[p->iTable - base].pTab; + Table *pTab; int iCol = p->iColumn; + for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( j<pTabList->nSrc ); + pTab = pTabList->a[j].pTab; if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ @@ -733,12 +733,11 @@ static void generateColumnTypes( */ static void generateColumnNames( Parse *pParse, /* Parser context */ - int base, /* VDBE cursor corresponding to first entry in pTabList */ SrcList *pTabList, /* List of tables */ ExprList *pEList /* Expressions defining the result set */ ){ Vdbe *v = pParse->pVdbe; - int i; + int i, j; if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return; pParse->colNamesSet = 1; for(i=0; i<pEList->nExpr; i++){ @@ -755,9 +754,12 @@ static void generateColumnNames( } showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0; if( p->op==TK_COLUMN && pTabList ){ - Table *pTab = pTabList->a[p->iTable - base].pTab; + Table *pTab; char *zCol; int iCol = p->iColumn; + for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( j<pTabList->nSrc ); + pTab = pTabList->a[j].pTab; if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ @@ -775,7 +777,7 @@ static void generateColumnNames( char *zName = 0; char *zTab; - zTab = pTabList->a[p->iTable - base].zAlias; + zTab = pTabList->a[j].zAlias; if( showFullNames || zTab==0 ) zTab = pTab->zName; sqliteSetString(&zName, zTab, ".", zCol, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0); @@ -863,7 +865,12 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ ** For the given SELECT statement, do three things. ** ** (1) Fill in the pTabList->a[].pTab fields in the SrcList that -** defines the set of tables that should be scanned. +** defines the set of tables that should be scanned. For views, +** fill pTabList->a[].pSelect with a copy of the SELECT statement +** that implements the view. A copy is made of the view's SELECT +** statement so that we can freely modify or delete that statement +** without worrying about messing up the presistent representation +** of the view. ** ** (2) Add terms to the WHERE clause to accomodate the NATURAL keyword ** on joins and the ON and USING clause of joins. @@ -908,23 +915,31 @@ static int fillInColumnList(Parse *pParse, Select *p){ if( pTab==0 ){ return 1; } + /* The isTransient flag indicates that the Table structure has been + ** dynamically allocated and may be freed at any time. In other words, + ** pTab is not pointing to a persistent table structure that defines + ** part of the schema. */ pTab->isTransient = 1; }else{ /* An ordinary table or view name in the FROM clause */ pTabList->a[i].pTab = pTab = - sqliteFindTable(pParse->db, pTabList->a[i].zName); + sqliteLocateTable(pParse,pTabList->a[i].zName,pTabList->a[i].zDatabase); if( pTab==0 ){ - sqliteSetString(&pParse->zErrMsg, "no such table: ", - pTabList->a[i].zName, 0); - pParse->nErr++; return 1; } if( pTab->pSelect ){ + /* We reach here if the named table is a really a view */ if( sqliteViewGetColumnNames(pParse, pTab) ){ return 1; } - sqliteSelectDelete(pTabList->a[i].pSelect); - pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); + /* If pTabList->a[i].pSelect!=0 it means we are dealing with a + ** view within a view. The SELECT structure has already been + ** copied by the outer view so we can skip the copy step here + ** in the inner view. + */ + if( pTabList->a[i].pSelect==0 ){ + pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect); + } } } } @@ -1032,10 +1047,9 @@ static int fillInColumnList(Parse *pParse, Select *p){ } if( !tableSeen ){ if( pName ){ - sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, - pName->z, pName->n, 0); + sqliteErrorMsg(pParse, "no such table: %T", pName); }else{ - sqliteSetString(&pParse->zErrMsg, "no tables specified", 0); + sqliteErrorMsg(pParse, "no tables specified"); } rc = 1; } @@ -1056,6 +1070,9 @@ static int fillInColumnList(Parse *pParse, Select *p){ ** This routine is called on the Select structure that defines a ** VIEW in order to undo any bindings to tables. This is necessary ** because those tables might be DROPed by a subsequent SQL command. +** If the bindings are not removed, then the Select.pSrc->a[].pTab field +** will be left pointing to a deallocated Table structure after the +** DROP and a coredump will occur the next time the VIEW is used. */ void sqliteSelectUnbind(Select *p){ int i; @@ -1066,10 +1083,6 @@ void sqliteSelectUnbind(Select *p){ if( (pTab = pSrc->a[i].pTab)!=0 ){ if( pTab->isTransient ){ sqliteDeleteTable(0, pTab); -#if 0 - sqliteSelectDelete(pSrc->a[i].pSelect); - pSrc->a[i].pSelect = 0; -#endif } pSrc->a[i].pTab = 0; if( pSrc->a[i].pSelect ){ @@ -1129,11 +1142,9 @@ static int matchOrderbyToColumn( if( pOrderBy->a[i].done ) continue; if( sqliteExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ - char zBuf[200]; - sprintf(zBuf,"ORDER BY position %d should be between 1 and %d", - iCol, pEList->nExpr); - sqliteSetString(&pParse->zErrMsg, zBuf, 0); - pParse->nErr++; + sqliteErrorMsg(pParse, + "ORDER BY position %d should be between 1 and %d", + iCol, pEList->nExpr); nErr++; break; } @@ -1163,11 +1174,8 @@ static int matchOrderbyToColumn( pOrderBy->a[i].done = 1; } if( iCol<0 && mustComplete ){ - char zBuf[30]; - sprintf(zBuf,"%d",i+1); - sqliteSetString(&pParse->zErrMsg, "ORDER BY term number ", zBuf, - " does not match any result column", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, + "ORDER BY term number %d does not match any result column", i+1); nErr++; break; } @@ -1277,9 +1285,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ if( p==0 || p->pPrior==0 ) return 1; pPrior = p->pPrior; if( pPrior->pOrderBy ){ - sqliteSetString(&pParse->zErrMsg,"ORDER BY clause should come after ", - selectOpName(p->op), " not before", 0); - pParse->nErr++; + sqliteErrorMsg(pParse,"ORDER BY clause should come after %s not before", + selectOpName(p->op)); return 1; } @@ -1367,8 +1374,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ int iCont, iBreak, iStart; assert( p->pEList ); if( eDest==SRT_Callback ){ - generateColumnNames(pParse, p->base, 0, p->pEList); - generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); + generateColumnNames(pParse, 0, p->pEList); + generateColumnTypes(pParse, p->pSrc, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); @@ -1424,8 +1431,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ */ assert( p->pEList ); if( eDest==SRT_Callback ){ - generateColumnNames(pParse, p->base, 0, p->pEList); - generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); + generateColumnNames(pParse, 0, p->pEList); + generateColumnTypes(pParse, p->pSrc, p->pEList); } iBreak = sqliteVdbeMakeLabel(v); iCont = sqliteVdbeMakeLabel(v); @@ -1450,9 +1457,8 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ } assert( p->pEList && pPrior->pEList ); if( p->pEList->nExpr!=pPrior->pEList->nExpr ){ - sqliteSetString(&pParse->zErrMsg, "SELECTs to the left and right of ", - selectOpName(p->op), " do not have the same number of result columns", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, "SELECTs to the left and right of %s" + " do not have the same number of result columns", selectOpName(p->op)); return 1; } @@ -1467,36 +1473,10 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){ } /* -** Recursively scan through an expression tree. For every reference -** to a column in table number iFrom, change that reference to the -** same column in table number iTo. -*/ -static void changeTablesInList(ExprList*, int, int); /* Forward Declaration */ -static void changeTables(Expr *pExpr, int iFrom, int iTo){ - if( pExpr==0 ) return; - if( pExpr->op==TK_COLUMN && pExpr->iTable==iFrom ){ - pExpr->iTable = iTo; - }else{ - changeTables(pExpr->pLeft, iFrom, iTo); - changeTables(pExpr->pRight, iFrom, iTo); - changeTablesInList(pExpr->pList, iFrom, iTo); - } -} -static void changeTablesInList(ExprList *pList, int iFrom, int iTo){ - if( pList ){ - int i; - for(i=0; i<pList->nExpr; i++){ - changeTables(pList->a[i].pExpr, iFrom, iTo); - } - } -} - -/* ** Scan through the expression pExpr. Replace every reference to -** a column in table number iTable with a copy of the corresponding +** a column in table number iTable with a copy of the iColumn-th ** entry in pEList. (But leave references to the ROWID column -** unchanged.) When making a copy of an expression in pEList, change -** references to columns in table iSub into references to table iTable. +** unchanged.) ** ** This routine is part of the flattening procedure. A subquery ** whose result set is defined by pEList appears as entry in the @@ -1505,8 +1485,8 @@ static void changeTablesInList(ExprList *pList, int iFrom, int iTo){ ** changes to pExpr so that it refers directly to the source table ** of the subquery rather the result set of the subquery. */ -static void substExprList(ExprList*,int,ExprList*,int); /* Forward Decl */ -static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){ +static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */ +static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){ if( pExpr==0 ) return; if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){ Expr *pNew; @@ -1527,21 +1507,18 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){ pExpr->iAgg = pNew->iAgg; sqliteTokenCopy(&pExpr->token, &pNew->token); sqliteTokenCopy(&pExpr->span, &pNew->span); - if( iSub!=iTable ){ - changeTables(pExpr, iSub, iTable); - } }else{ - substExpr(pExpr->pLeft, iTable, pEList, iSub); - substExpr(pExpr->pRight, iTable, pEList, iSub); - substExprList(pExpr->pList, iTable, pEList, iSub); + substExpr(pExpr->pLeft, iTable, pEList); + substExpr(pExpr->pRight, iTable, pEList); + substExprList(pExpr->pList, iTable, pEList); } } static void -substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){ +substExprList(ExprList *pList, int iTable, ExprList *pEList){ int i; if( pList==0 ) return; for(i=0; i<pList->nExpr; i++){ - substExpr(pList->a[i].pExpr, iTable, pEList, iSub); + substExpr(pList->a[i].pExpr, iTable, pEList); } } @@ -1578,7 +1555,8 @@ substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){ ** ** (2) The subquery is not an aggregate or the outer query is not a join. ** -** (3) The subquery is not a join. +** (3) The subquery is not the right operand of a left outer join, or +** the subquery is not itself a join. (Ticket #306) ** ** (4) The subquery is not DISTINCT or the outer query is not a join. ** @@ -1604,7 +1582,7 @@ substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){ ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates. ** -** If flattening is not attempted, this routine is a no-op and return 0. +** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. ** ** All of the expression analysis must occur on both the outer query and @@ -1621,8 +1599,8 @@ static int flattenSubquery( SrcList *pSrc; /* The FROM clause of the outer query */ SrcList *pSubSrc; /* The FROM clause of the subquery */ ExprList *pList; /* The result set of the outer query */ + int iParent; /* VDBE cursor number of the pSub result set temp table */ int i; - int iParent, iSub; Expr *pWhere; /* Check to see if flattening is permitted. Return 0 if not. @@ -1636,19 +1614,81 @@ static int flattenSubquery( if( subqueryIsAgg && pSrc->nSrc>1 ) return 0; pSubSrc = pSub->pSrc; assert( pSubSrc ); - if( pSubSrc->nSrc!=1 ) return 0; + if( pSubSrc->nSrc==0 ) return 0; if( (pSub->isDistinct || pSub->nLimit>=0) && (pSrc->nSrc>1 || isAgg) ){ return 0; } if( (p->isDistinct || p->nLimit>=0) && subqueryIsAgg ) return 0; if( p->pOrderBy && pSub->pOrderBy ) return 0; + /* Restriction 3: If the subquery is a join, make sure the subquery is + ** not used as the right operand of an outer join. Examples of why this + ** is not allowed: + ** + ** t1 LEFT OUTER JOIN (t2 JOIN t3) + ** + ** If we flatten the above, we would get + ** + ** (t1 LEFT OUTER JOIN t2) JOIN t3 + ** + ** which is not at all the same thing. + */ + if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){ + return 0; + } + /* If we reach this point, it means flattening is permitted for the - ** i-th entry of the FROM clause in the outer query. + ** iFrom-th entry of the FROM clause in the outer query. + */ + + /* Move all of the FROM elements of the subquery into the + ** the FROM clause of the outer query. Before doing this, remember + ** the cursor number for the original outer query FROM element in + ** iParent. The iParent cursor will never be used. Subsequent code + ** will scan expressions looking for iParent references and replace + ** those references with expressions that resolve to the subquery FROM + ** elements we are now copying in. + */ + iParent = pSrc->a[iFrom].iCursor; + { + int nSubSrc = pSubSrc->nSrc; + int jointype = pSrc->a[iFrom].jointype; + + if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ + sqliteDeleteTable(0, pSrc->a[iFrom].pTab); + } + sqliteFree(pSrc->a[iFrom].zName); + sqliteFree(pSrc->a[iFrom].zAlias); + if( nSubSrc>1 ){ + int extra = nSubSrc - 1; + for(i=1; i<nSubSrc; i++){ + pSrc = sqliteSrcListAppend(pSrc, 0, 0); + } + p->pSrc = pSrc; + for(i=pSrc->nSrc-1; i-extra>=iFrom; i--){ + pSrc->a[i] = pSrc->a[i-extra]; + } + } + for(i=0; i<nSubSrc; i++){ + pSrc->a[i+iFrom] = pSubSrc->a[i]; + memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); + } + pSrc->a[iFrom+nSubSrc-1].jointype = jointype; + } + + /* Now begin substituting subquery result set expressions for + ** references to the iParent in the outer query. + ** + ** Example: + ** + ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; + ** \ \_____________ subquery __________/ / + ** \_____________________ outer query ______________________________/ + ** + ** We look at every expression in the outer query and every place we see + ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - iParent = p->base + iFrom; - iSub = pSub->base; - substExprList(p->pEList, iParent, pSub->pEList, iSub); + substExprList(p->pEList, iParent, pSub->pEList); pList = p->pEList; for(i=0; i<pList->nExpr; i++){ Expr *pExpr; @@ -1657,22 +1697,18 @@ static int flattenSubquery( } } if( isAgg ){ - substExprList(p->pGroupBy, iParent, pSub->pEList, iSub); - substExpr(p->pHaving, iParent, pSub->pEList, iSub); + substExprList(p->pGroupBy, iParent, pSub->pEList); + substExpr(p->pHaving, iParent, pSub->pEList); } if( pSub->pOrderBy ){ assert( p->pOrderBy==0 ); p->pOrderBy = pSub->pOrderBy; pSub->pOrderBy = 0; - changeTablesInList(p->pOrderBy, iSub, iParent); }else if( p->pOrderBy ){ - substExprList(p->pOrderBy, iParent, pSub->pEList, iSub); + substExprList(p->pOrderBy, iParent, pSub->pEList); } if( pSub->pWhere ){ pWhere = sqliteExprDup(pSub->pWhere); - if( iParent!=iSub ){ - changeTables(pWhere, iSub, iParent); - } }else{ pWhere = 0; } @@ -1680,12 +1716,9 @@ static int flattenSubquery( assert( p->pHaving==0 ); p->pHaving = p->pWhere; p->pWhere = pWhere; - substExpr(p->pHaving, iParent, pSub->pEList, iSub); + substExpr(p->pHaving, iParent, pSub->pEList); if( pSub->pHaving ){ Expr *pHaving = sqliteExprDup(pSub->pHaving); - if( iParent!=iSub ){ - changeTables(pHaving, iSub, iParent); - } if( p->pHaving ){ p->pHaving = sqliteExpr(TK_AND, p->pHaving, pHaving, 0); }else{ @@ -1694,19 +1727,23 @@ static int flattenSubquery( } assert( p->pGroupBy==0 ); p->pGroupBy = sqliteExprListDup(pSub->pGroupBy); - if( iParent!=iSub ){ - changeTablesInList(p->pGroupBy, iSub, iParent); - } }else if( p->pWhere==0 ){ p->pWhere = pWhere; }else{ - substExpr(p->pWhere, iParent, pSub->pEList, iSub); + substExpr(p->pWhere, iParent, pSub->pEList); if( pWhere ){ p->pWhere = sqliteExpr(TK_AND, p->pWhere, pWhere, 0); } } + + /* The flattened query is distinct if either the inner or the + ** outer query is distinct. + */ p->isDistinct = p->isDistinct || pSub->isDistinct; + /* Transfer the limit expression from the subquery to the outer + ** query. + */ if( pSub->nLimit>=0 ){ if( p->nLimit<0 ){ p->nLimit = pSub->nLimit; @@ -1716,27 +1753,9 @@ static int flattenSubquery( } p->nOffset += pSub->nOffset; - /* If the subquery contains subqueries of its own, that were not - ** flattened, then code will have already been generated to put - ** the results of those sub-subqueries into VDBE cursors relative - ** to the subquery. We must translate the cursor number into values - ** suitable for use by the outer query. + /* Finially, delete what is left of the subquery and return + ** success. */ - for(i=0; i<pSubSrc->nSrc; i++){ - Vdbe *v; - if( pSubSrc->a[i].pSelect==0 ) continue; - v = sqliteGetVdbe(pParse); - sqliteVdbeAddOp(v, OP_RenameCursor, pSub->base+i, p->base+i); - } - - if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){ - sqliteDeleteTable(0, pSrc->a[iFrom].pTab); - } - pSrc->a[iFrom].pTab = pSubSrc->a[0].pTab; - pSubSrc->a[0].pTab = 0; - assert( pSrc->a[iFrom].pSelect==pSub ); - pSrc->a[iFrom].pSelect = pSubSrc->a[0].pSelect; - pSubSrc->a[0].pSelect = 0; sqliteSelectDelete(pSub); return 1; } @@ -1768,7 +1787,6 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ Index *pIdx; int base; Vdbe *v; - int openOp; int seekOp; int cont; ExprList eList; @@ -1818,8 +1836,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ v = sqliteGetVdbe(pParse); if( v==0 ) return 0; if( eDest==SRT_Callback ){ - generateColumnNames(pParse, p->base, p->pSrc, p->pEList); - generateColumnTypes(pParse, p->base, p->pSrc, p->pEList); + generateColumnNames(pParse, p->pSrc, p->pEList); + generateColumnTypes(pParse, p->pSrc, p->pEList); } /* Generating code to find the min or the max. Basically all we have @@ -1827,18 +1845,17 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first ** or last entry in the main table. */ - if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){ - sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0); - pParse->schemaVerified = 1; - } - openOp = pTab->isTemp ? OP_OpenAux : OP_Open; - base = p->base; - sqliteVdbeAddOp(v, openOp, base, pTab->tnum); + sqliteCodeVerifySchema(pParse, pTab->iDb); + base = p->pSrc->a[0].iCursor; + sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + cont = sqliteVdbeMakeLabel(v); if( pIdx==0 ){ sqliteVdbeAddOp(v, seekOp, base, 0); }else{ - sqliteVdbeAddOp(v, openOp, base+1, pIdx->tnum); + sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum); sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); sqliteVdbeAddOp(v, seekOp, base+1, 0); sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0); @@ -1849,7 +1866,6 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; - cont = sqliteVdbeMakeLabel(v); selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont); sqliteVdbeResolveLabel(v, cont); sqliteVdbeAddOp(v, OP_Close, base, 0); @@ -1929,11 +1945,10 @@ int sqliteSelect( Expr *pHaving; /* The HAVING clause. May be NULL */ int isDistinct; /* True if the DISTINCT keyword is present */ int distinct; /* Table to use for the distinct set */ - int base; /* First cursor available for use */ int rc = 1; /* Value to return from this function */ if( sqlite_malloc_failed || pParse->nErr || p==0 ) return 1; - if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0) ) return 1; + if( sqliteAuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; /* If there is are a sequence of queries, do the earlier ones first. */ @@ -1950,12 +1965,9 @@ int sqliteSelect( pHaving = p->pHaving; isDistinct = p->isDistinct; - /* Allocate a block of VDBE cursors, one for each table in the FROM clause. - ** The WHERE processing requires that the cursors for the tables in the - ** FROM clause be consecutive. + /* Allocate VDBE cursors for each table in the FROM clause */ - base = p->base = pParse->nTab; - pParse->nTab += pTabList->nSrc; + sqliteSrcListAssignCursors(pParse, pTabList); /* ** Do not even attempt to generate any code if we have already seen @@ -1978,9 +1990,8 @@ int sqliteSelect( ** only a single column may be output. */ if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ - sqliteSetString(&pParse->zErrMsg, "only a single result allowed for " - "a SELECT that is part of an expression", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, "only a single result allowed for " + "a SELECT that is part of an expression"); goto select_end; } @@ -2002,7 +2013,7 @@ int sqliteSelect( ** Resolve the column names and do a semantics check on all the expressions. */ for(i=0; i<pEList->nExpr; i++){ - if( sqliteExprResolveIds(pParse, base, pTabList, 0, pEList->a[i].pExpr) ){ + if( sqliteExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){ goto select_end; } if( sqliteExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){ @@ -2010,22 +2021,20 @@ int sqliteSelect( } } if( pWhere ){ - if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pWhere) ){ + if( sqliteExprResolveIds(pParse, pTabList, pEList, pWhere) ){ goto select_end; } if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ goto select_end; } - sqliteOracle8JoinFixup(base, pTabList, pWhere); + sqliteOracle8JoinFixup(pTabList, pWhere); } if( pHaving ){ if( pGroupBy==0 ){ - sqliteSetString(&pParse->zErrMsg, "a GROUP BY clause is required " - "before HAVING", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); goto select_end; } - if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pHaving) ){ + if( sqliteExprResolveIds(pParse, pTabList, pEList, pHaving) ){ goto select_end; } if( sqliteExprCheck(pParse, pHaving, 1, &isAgg) ){ @@ -2040,7 +2049,7 @@ int sqliteSelect( sqliteExprDelete(pE); pE = pOrderBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); } - if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){ + if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){ goto select_end; } if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ @@ -2048,16 +2057,13 @@ int sqliteSelect( } if( sqliteExprIsConstant(pE) ){ if( sqliteExprIsInteger(pE, &iCol)==0 ){ - sqliteSetString(&pParse->zErrMsg, - "ORDER BY terms must not be non-integer constants", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, + "ORDER BY terms must not be non-integer constants"); goto select_end; }else if( iCol<=0 || iCol>pEList->nExpr ){ - char zBuf[2000]; - sprintf(zBuf,"ORDER BY column number %d out of range - should be " + sqliteErrorMsg(pParse, + "ORDER BY column number %d out of range - should be " "between 1 and %d", iCol, pEList->nExpr); - sqliteSetString(&pParse->zErrMsg, zBuf, 0); - pParse->nErr++; goto select_end; } } @@ -2071,7 +2077,7 @@ int sqliteSelect( sqliteExprDelete(pE); pE = pGroupBy->a[i].pExpr = sqliteExprDup(pEList->a[iCol-1].pExpr); } - if( sqliteExprResolveIds(pParse, base, pTabList, pEList, pE) ){ + if( sqliteExprResolveIds(pParse, pTabList, pEList, pE) ){ goto select_end; } if( sqliteExprCheck(pParse, pE, isAgg, 0) ){ @@ -2079,16 +2085,13 @@ int sqliteSelect( } if( sqliteExprIsConstant(pE) ){ if( sqliteExprIsInteger(pE, &iCol)==0 ){ - sqliteSetString(&pParse->zErrMsg, - "GROUP BY terms must not be non-integer constants", 0); - pParse->nErr++; + sqliteErrorMsg(pParse, + "GROUP BY terms must not be non-integer constants"); goto select_end; }else if( iCol<=0 || iCol>pEList->nExpr ){ - char zBuf[2000]; - sprintf(zBuf,"GROUP BY column number %d out of range - should be " + sqliteErrorMsg(pParse, + "GROUP BY column number %d out of range - should be " "between 1 and %d", iCol, pEList->nExpr); - sqliteSetString(&pParse->zErrMsg, zBuf, 0); - pParse->nErr++; goto select_end; } } @@ -2112,7 +2115,7 @@ int sqliteSelect( ** step is skipped if the output is going to some other destination. */ if( eDest==SRT_Callback ){ - generateColumnNames(pParse, p->base, pTabList, pEList); + generateColumnNames(pParse, pTabList, pEList); } /* Set the limiter @@ -2138,12 +2141,25 @@ int sqliteSelect( /* Generate code for all sub-queries in the FROM clause */ for(i=0; i<pTabList->nSrc; i++){ + const char *zSavedAuthContext; + int needRestoreContext; + if( pTabList->a[i].pSelect==0 ) continue; - sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i, - p, i, &isAgg); + if( pTabList->a[i].zName!=0 ){ + zSavedAuthContext = pParse->zAuthContext; + pParse->zAuthContext = pTabList->a[i].zName; + needRestoreContext = 1; + }else{ + needRestoreContext = 0; + } + sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, + pTabList->a[i].iCursor, p, i, &isAgg); + if( needRestoreContext ){ + pParse->zAuthContext = zSavedAuthContext; + } pTabList = p->pSrc; pWhere = p->pWhere; - if( eDest==SRT_Callback ){ + if( eDest!=SRT_Union && eDest!=SRT_Except && eDest!=SRT_Discard ){ pOrderBy = p->pOrderBy; } pGroupBy = p->pGroupBy; @@ -2165,7 +2181,7 @@ int sqliteSelect( ** than a callback. */ if( eDest==SRT_Callback ){ - generateColumnTypes(pParse, p->base, pTabList, pEList); + generateColumnTypes(pParse, pTabList, pEList); } /* If the output is destined for a temporary table, open that table. @@ -2239,7 +2255,7 @@ int sqliteSelect( /* Begin the database scan */ - pWInfo = sqliteWhereBegin(pParse, p->base, pTabList, pWhere, 0, + pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0, pGroupBy ? 0 : &pOrderBy); if( pWInfo==0 ) goto select_end; |