aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2016-08-20 00:07:01 +0000
committerdrh <drh@noemail.net>2016-08-20 00:07:01 +0000
commitfc7f27b9d2e4083faba332a9a15d182549f68cb2 (patch)
treedd3863898d7a12319063c734cb3d79567e0cdb3d /src
parent8d25cb90cdc01b79eb368299c24846388c4e7866 (diff)
downloadsqlite-fc7f27b9d2e4083faba332a9a15d182549f68cb2.tar.gz
sqlite-fc7f27b9d2e4083faba332a9a15d182549f68cb2.zip
Change the way TK_SELECT_COLUMN is handled so that the subquery is only
generated once even if part of the vector comparison is used for indexing and the other part is now. This change also is a pathway to vector assignment in UPDATE statements. FossilOrigin-Name: d8feea7dcde83179bff303072426561cfe825e58
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;
}
}