diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 95 | ||||
-rw-r--r-- | src/sqliteInt.h | 9 | ||||
-rw-r--r-- | src/vdbemem.c | 2 | ||||
-rw-r--r-- | src/wherecode.c | 35 | ||||
-rw-r--r-- | src/whereexpr.c | 32 |
5 files changed, 95 insertions, 78 deletions
diff --git a/src/expr.c b/src/expr.c index 1949be50a..de2c7a6a2 100644 --- a/src/expr.c +++ b/src/expr.c @@ -334,13 +334,21 @@ int sqlite3ExprVectorSize(Expr *pExpr){ #ifndef SQLITE_OMIT_SUBQUERY /* -** If the expression passed as the first argument is a TK_VECTOR, return -** a pointer to the i'th field of the vector. Or, if the first argument -** points to a sub-select that returns more than one column, return a -** pointer to the i'th returned column value. Otherwise, return a copy -** of the first argument. +** Interpret the pVector input as a vector expression. If pVector is +** an ordinary scalar expression, treat it as a vector of size 1. +** +** Return a pointer to a subexpression of pVector that is the i-th +** column of the vector (numbered starting with 0). The caller must +** ensure that i is within range. +** +** pVector retains ownership of the returned subexpression. +** +** If the vector is a (SELECT ...) then the expression returned is +** just the expression for the i-th term of the result set, and is +** necessarily ready to be evaluated because the table cursor might +** not have been positioned yet. */ -Expr *sqlite3ExprVectorField(Expr *pVector, int i){ +Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){ assert( i<sqlite3ExprVectorSize(pVector) ); if( sqlite3ExprIsVector(pVector) ){ if( pVector->op==TK_SELECT ){ @@ -351,7 +359,57 @@ Expr *sqlite3ExprVectorField(Expr *pVector, int i){ } return pVector; } -#endif +#endif /* !defined(SQLITE_OMIT_SUBQUERY) */ + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** Compute and return a new Expr object which when passed to +** sqlite3ExprCode() will generate all necessary code to compute +** the iField-th column of the vector expression pVector. +** +** The caller owns the returned Expr object and is responsible for +** ensuring that the returned value eventually gets freed. +** +** Ownership of pVector is controlled by the takeOwnership parameter. If +** takeOwnership is true, this routine takes responsibility for freeing +** pVector, and may do so before returning, hence the caller must not reference +** pVector again. If takeOwnership is false, then the caller takes +** responsibility for freeing pVector and must ensure the pVector remains +** valid as long as the returned value remains in use. +*/ +Expr *sqlite3ExprForVectorField( + Parse *pParse, /* Parsing context */ + Expr *pVector, /* The vector. List of expressions or a sub-SELECT */ + int iField, /* Which column of the vector to return */ + int takeOwnership /* True to take ownership of pVector before returning */ +){ + Expr *pRet; + assert( sqlite3ExprIsVector(pVector) ); + /* FIXME: Add support for takeOwnership!=0 */ assert( takeOwnership==0 ); + if( pVector->flags & EP_xIsSelect ){ + /* The TK_SELECT_COLUMN Expr node: + ** + ** pLeft: pVector containing TK_SELECT + ** pRight: pVector if ownership taken + ** iColumn: Index of a column in pVector + ** pLeft->iTable: First in an array of register holding result, or 0 + ** if the result is not yet computed. + ** + ** sqlite3ExprDelete() specifically skips the recursive delete of + ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector + ** is included on pRight if ownership is taken. Typically there will + ** be multiple TK_SELECT_COLUMN nodes with the same pLeft pointer to + ** the pVector, but only one of them will own the pVector. + */ + pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, pVector, 0, 0); + if( pRet ) pRet->iColumn = iField; + assert( pRet==0 || pRet->iTable==0 ); + }else{ + pRet = sqlite3ExprDup(pParse->db, pVector->x.pList->a[iField].pExpr, 0); + } + return pRet; +} +#endif /* !define(SQLITE_OMIT_SUBQUERY) */ /* ** If expression pExpr is of type TK_SELECT, generate code to evaluate @@ -2025,7 +2083,7 @@ int sqlite3FindInIndex( ** comparison is the same as the affinity of each column. If ** it not, it is not possible to use any index. */ for(i=0; i<nExpr && affinity_ok; i++){ - Expr *pLhs = sqlite3ExprVectorField(pX->pLeft, i); + Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i); int iCol = pEList->a[i].pExpr->iColumn; char idxaff = pTab->aCol[iCol].affinity; char cmpaff = sqlite3CompareAffinity(pLhs, idxaff); @@ -2051,7 +2109,7 @@ int sqlite3FindInIndex( } for(i=0; i<nExpr; i++){ - Expr *pLhs = sqlite3ExprVectorField(pX->pLeft, i); + Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; @@ -2159,7 +2217,7 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){ if( zRet ){ int i; for(i=0; i<nVal; i++){ - Expr *pA = sqlite3ExprVectorField(pLeft, i); + Expr *pA = sqlite3VectorFieldSubexpr(pLeft, i); char a = sqlite3ExprAffinity(pA); if( pSelect ){ zRet[i] = sqlite3CompareAffinity(pSelect->pEList->a[i].pExpr, a); @@ -2313,7 +2371,7 @@ int sqlite3CodeSubselect( assert( pEList->nExpr>0 ); assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); for(i=0; i<nVal; i++){ - Expr *p = (nVal>1) ? sqlite3ExprVectorField(pLeft, i) : pLeft; + Expr *p = (nVal>1) ? sqlite3VectorFieldSubexpr(pLeft, i) : pLeft; pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq( pParse, p, pEList->a[i].pExpr ); @@ -2553,7 +2611,7 @@ static void sqlite3ExprCodeIN( } }else{ for(i=0; i<nVector; i++){ - Expr *pLhs = sqlite3ExprVectorField(pLeft, i); + Expr *pLhs = sqlite3VectorFieldSubexpr(pLeft, i); sqlite3ExprCode(pParse, pLhs, r1+aiMap[i]); } } @@ -2612,7 +2670,7 @@ static void sqlite3ExprCodeIN( ** completely empty, or NULL otherwise. */ if( destIfNull==destIfFalse ){ for(i=0; i<nVector; i++){ - Expr *p = sqlite3ExprVectorField(pExpr->pLeft, i); + Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull); VdbeCoverage(v); @@ -2654,7 +2712,7 @@ static void sqlite3ExprCodeIN( Expr *p; CollSeq *pColl; int r2 = sqlite3GetTempReg(pParse); - p = sqlite3ExprVectorField(pLeft, i); + p = sqlite3VectorFieldSubexpr(pLeft, i); pColl = sqlite3ExprCollSeq(pParse, p); sqlite3VdbeAddOp3(v, OP_Column, iIdx, i, r2); @@ -2674,7 +2732,7 @@ static void sqlite3ExprCodeIN( ** result is 1. */ sqlite3VdbeJumpHere(v, addr); for(i=0; i<nVector; i++){ - Expr *p = sqlite3ExprVectorField(pExpr->pLeft, i); + Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull); VdbeCoverage(v); @@ -3510,6 +3568,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ } break; } + case TK_SELECT_COLUMN: { + if( pExpr->pLeft->iTable==0 ){ + pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0); + } + inReg = pExpr->pLeft->iTable + pExpr->iColumn; + break; + } case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel(v); int destIfNull = sqlite3VdbeMakeLabel(v); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7b37b030c..7651ff69e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2298,9 +2298,11 @@ struct Expr { int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old - ** EP_Unlikely: 134217728 times likelihood */ + ** EP_Unlikely: 134217728 times likelihood + ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. - ** TK_VARIABLE: variable number (always >= 1). */ + ** TK_VARIABLE: variable number (always >= 1). + ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 op2; /* TK_REGISTER: original value of Expr.op @@ -4273,6 +4275,7 @@ int sqlite3DbstatRegister(sqlite3*); int sqlite3ExprVectorSize(Expr *pExpr); int sqlite3ExprIsVector(Expr *pExpr); -Expr *sqlite3ExprVectorField(Expr*, int); +Expr *sqlite3VectorFieldSubexpr(Expr*, int); +Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int); #endif /* SQLITEINT_H */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 070952763..bc0804200 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1571,7 +1571,7 @@ int sqlite3Stat4ProbeSetValue( for(i=0; i<nElem; i++){ sqlite3_value *pVal = 0; - Expr *pElem = (pExpr ? sqlite3ExprVectorField(pExpr, i) : 0); + Expr *pElem = (pExpr ? sqlite3VectorFieldSubexpr(pExpr, i) : 0); u8 aff = sqlite3IndexColumnAffinity(pParse->db, pIdx, iVal+i); alloc.iVal = iVal+i; rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); diff --git a/src/wherecode.c b/src/wherecode.c index dd15b5893..2ef9a46b5 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -377,34 +377,7 @@ static int codeEqualityTerm( assert( pLevel->pWLoop->aLTerm[iEq]==pTerm ); assert( iTarget>0 ); if( pX->op==TK_EQ || pX->op==TK_IS ){ - Expr *pRight = pX->pRight; -#ifndef SQLITE_OMIT_SUBQUERY - if( pRight->op==TK_SELECT_COLUMN ){ - /* This case occurs for expressions like "(a, b) == (SELECT ...)". */ - WhereLoop *pLoop = pLevel->pWLoop; - int i; - Expr *pSub = pRight->pLeft; - assert( pSub->op==TK_SELECT ); - for(i=pLoop->nSkip; i<iEq; i++){ - Expr *pExpr = pLoop->aLTerm[i]->pExpr->pRight; - if( pExpr && pExpr->op==TK_SELECT_COLUMN && pExpr->pLeft==pSub ) break; - } - - if( i==iEq ){ - iReg = sqlite3CodeSubselect(pParse, pSub, 0, 0); - for(/*no-op*/; i<pLoop->nLTerm; i++){ - Expr *pExpr = pLoop->aLTerm[i]->pExpr->pRight; - if( pExpr && pExpr->op==TK_SELECT_COLUMN && pExpr->pLeft==pSub ){ - sqlite3VdbeAddOp2(v, OP_Copy, iReg+pExpr->iColumn, iTarget-iEq+i); - } - } - } - iReg = iTarget; - }else -#endif - { - iReg = sqlite3ExprCodeTarget(pParse, pRight, iTarget); - } + iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); @@ -1101,11 +1074,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( addrNotFound = pLevel->addrNxt; }else{ Expr *pRight = pTerm->pExpr->pRight; - if( pRight->op==TK_SELECT_COLUMN ){ - codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); - }else{ - codeExprOrVector(pParse, pRight, iTarget, 1); - } + codeExprOrVector(pParse, pRight, iTarget, 1); } } sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); diff --git a/src/whereexpr.c b/src/whereexpr.c index 2fc903ce6..55a4cf568 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -874,29 +874,6 @@ static int exprMightBeIndexed( } /* -** The expression passed as the second argument is a vector (either a -** TK_VECTOR node or a TK_SELECT that returns more than one column). This -** function returns a pointer to a new expression object representing -** field iField of the vector. -** -** If pVector is of type TK_VECTOR, the returned object is just a copy of -** the iField'th element of the vector. Or, if pVector is of type TK_SELECT, -** the return value points to a new expression object of type -** TK_SELECT_COLUMN. -*/ -static Expr *exprExtractVectorField(Parse *pParse, Expr *pVector, int iField){ - Expr *pRet; - assert( sqlite3ExprIsVector(pVector) ); - if( pVector->flags & EP_xIsSelect ){ - pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, pVector, 0, 0); - if( pRet ) pRet->iColumn = iField; - }else{ - pRet = sqlite3ExprDup(pParse->db, pVector->x.pList->a[iField].pExpr, 0); - } - return pRet; -} - -/* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm @@ -1211,14 +1188,17 @@ static void exprAnalyze( for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){ int idxNew; Expr *pNew; - Expr *pLeft = exprExtractVectorField(pParse, pExpr->pLeft, i); - Expr *pRight = exprExtractVectorField(pParse, pExpr->pRight, i); + Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i, 0); + Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, 0); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0); - idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); + idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags = TERM_CODED; + pTerm->eOperator = 0; } } |