mirror of
https://github.com/php/php-src.git
synced 2025-08-18 23:18:56 +02:00
Update bundled library to version 2.8.2.
Make OnUpdateInt compatible with ZE2. Fix the makefile fragment for non-gnu makes
This commit is contained in:
parent
82a1818fde
commit
80e7f7001d
42 changed files with 11143 additions and 7558 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1466,37 +1472,11 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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;
|
||||
|
||||
/* If we reach this point, it means flattening is permitted for the
|
||||
** i-th entry of the FROM clause in the outer query.
|
||||
/* 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.
|
||||
*/
|
||||
iParent = p->base + iFrom;
|
||||
iSub = pSub->base;
|
||||
substExprList(p->pEList, iParent, pSub->pEList, iSub);
|
||||
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
|
||||
** 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".
|
||||
*/
|
||||
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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue