aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c95
-rw-r--r--src/sqliteInt.h9
-rw-r--r--src/vdbemem.c2
-rw-r--r--src/wherecode.c35
-rw-r--r--src/whereexpr.c32
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;
}
}