diff options
author | dan <dan@noemail.net> | 2016-08-01 16:37:43 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2016-08-01 16:37:43 +0000 |
commit | 870a0705feb00a9c60c3442431beeeff37ca0c6b (patch) | |
tree | 769f2050c38d2f74429f6e816bb21fd6525b9fab /src | |
parent | 5c288b929a80fb532c00e74853f097b267eff860 (diff) | |
download | sqlite-870a0705feb00a9c60c3442431beeeff37ca0c6b.tar.gz sqlite-870a0705feb00a9c60c3442431beeeff37ca0c6b.zip |
Fix a problem with IN(...) constraints where the LHS is a sub-select that is an aggregate query.
FossilOrigin-Name: 1f4dba87da4a44ad26223ad965731164c0d9bad9
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 86 | ||||
-rw-r--r-- | src/select.c | 41 | ||||
-rw-r--r-- | src/whereexpr.c | 24 |
3 files changed, 62 insertions, 89 deletions
diff --git a/src/expr.c b/src/expr.c index 5acce2f0c..3bbd015fd 100644 --- a/src/expr.c +++ b/src/expr.c @@ -310,6 +310,15 @@ static int codeCompare( } /* +** Return true if expression pExpr is a vector, or false otherwise. +*/ +int sqlite3ExprIsVector(Expr *pExpr){ + return ( (pExpr->op==TK_VECTOR) + || (pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1) + ); +} + +/* ** If the expression passed as the only argument is of type TK_VECTOR ** return the number of expressions in the vector. Or, if the expression ** is a sub-select, return the number of columns in the sub-select. For @@ -324,29 +333,22 @@ int sqlite3ExprVectorSize(Expr *pExpr){ } /* -** Return true if expression pExpr is a vector, or false otherwise. -*/ -int sqlite3ExprIsVector(Expr *pExpr){ - return ( - pExpr->op==TK_VECTOR - || (pExpr->op==TK_SELECT && pExpr->x.pSelect->pEList->nExpr>1) - ); -} - -/* ** 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, return a pointer to the i'th returned column -** value. Otherwise, return a copy of 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. */ static Expr *exprVectorField(Expr *pVector, int i){ - if( sqlite3ExprIsVector(pVector)==0 ){ - assert( i==0 ); - return pVector; - }else if( pVector->flags & EP_xIsSelect ){ - return pVector->x.pSelect->pEList->a[i].pExpr; + assert( i<sqlite3ExprVectorSize(pVector) ); + if( sqlite3ExprIsVector(pVector) ){ + if( pVector->op==TK_SELECT ){ + return pVector->x.pSelect->pEList->a[i].pExpr; + }else{ + return pVector->x.pList->a[i].pExpr; + } } - return pVector->x.pList->a[i].pExpr; + return pVector; } /* @@ -367,34 +369,37 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){ /* ** Argument pVector points to a vector expression - either a TK_VECTOR -** or TK_SELECT that returns more than one column. This function generates -** code to evaluate expression iElem of the vector. The number of the -** register containing the result is returned. +** or TK_SELECT that returns more than one column. This function returns +** the register number of a register that contains the value of +** element iField of the vector. ** -** Before returning, output parameter (*ppExpr) is set to point to the -** Expr object corresponding to element iElem of the vector. +** If pVector is a TK_SELECT expression, then code for it must have +** already been generated using the exprCodeSubselect() routine. In this +** case parameter regSelect should be the first in an array of registers +** containing the results of the sub-select. ** -** If pVector is a TK_SELECT expression, then argument regSelect is -** passed the first in an array of registers that contain the results -** of the sub-select. +** If pVector is of type TK_VECTOR, then code for the requested field +** is generated. In this case (*pRegFree) may be set to the number of +** a temporary register to be freed by the caller before returning. ** -** If output parameter (*pRegFree) is set to a non-zero value by this -** function, it is the value of a temporary register that should be -** freed by the caller. +** Before returning, output parameter (*ppExpr) is set to point to the +** Expr object corresponding to element iElem of the vector. */ static int exprVectorRegister( Parse *pParse, /* Parse context */ Expr *pVector, /* Vector to extract element from */ - int iElem, /* Element to extract from pVector */ + int iField, /* Field to extract from pVector */ int regSelect, /* First in array of registers */ Expr **ppExpr, /* OUT: Expression element */ int *pRegFree /* OUT: Temp register to free */ ){ + assert( pVector->op==TK_VECTOR || pVector->op==TK_SELECT ); + assert( (pVector->op==TK_VECTOR)==(regSelect==0) ); if( regSelect ){ - *ppExpr = pVector->x.pSelect->pEList->a[iElem].pExpr; - return regSelect+iElem; + *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; + return regSelect+iField; } - *ppExpr = pVector->x.pList->a[iElem].pExpr; + *ppExpr = pVector->x.pList->a[iField].pExpr; return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); } @@ -416,10 +421,7 @@ static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){ sqlite3ErrorMsg(pParse, "invalid use of row value"); }else{ int p5 = (pExpr->op==TK_IS || pExpr->op==TK_ISNOT) ? SQLITE_NULLEQ : 0; - int opCmp; int i; - int p3 = 0; - int p4 = 0; int regLeft = 0; int regRight = 0; int regTmp = 0; @@ -1777,13 +1779,6 @@ int sqlite3IsRowid(const char *z){ ** a pointer to the SELECT statement. If pX is not a SELECT statement, ** or if the SELECT statement needs to be manifested into a transient ** table, then return NULL. -** -** If parameter bNullSensitive is 0, then this operation will be -** used in a context in which there is no difference between a result -** of 0 and one of NULL. For example: -** -** ... WHERE (?,?) IN (SELECT ...) -** */ #ifndef SQLITE_OMIT_SUBQUERY static Select *isCandidateForInOpt(Expr *pX){ @@ -1957,10 +1952,9 @@ int sqlite3FindInIndex( /* If the RHS of this IN(...) operator is a SELECT, and if it matters ** whether or not the SELECT result contains NULL values, check whether - ** or not NULL is actuall possible (it may not be, for example, due + ** or not NULL is actually possible (it may not be, for example, due ** to NOT NULL constraints in the schema). If no NULL values are possible, - ** set prRhsHasNull to 0 before continuing. - */ + ** set prRhsHasNull to 0 before continuing. */ if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){ int i; ExprList *pEList = pX->x.pSelect->pEList; diff --git a/src/select.c b/src/select.c index f49a5c1fe..fb7217c1b 100644 --- a/src/select.c +++ b/src/select.c @@ -659,30 +659,6 @@ static void codeDistinct( sqlite3ReleaseTempReg(pParse, r1); } -#ifndef SQLITE_OMIT_SUBQUERY -/* -** Generate an error message when a SELECT is used within a subexpression -** (example: "a IN (SELECT * FROM table)") but it has more than 1 result -** column. We do this in a subroutine because the error used to occur -** in multiple places. (The error only occurs in one place now, but we -** retain the subroutine to minimize code disruption.) -*/ -static int checkForMultiColumnSelectError( - Parse *pParse, /* Parse context. */ - SelectDest *pDest, /* Destination of SELECT results */ - int nExpr /* Number of result columns returned by SELECT */ -){ - int eDest = pDest->eDest; - if( 0 && nExpr>1 && eDest==SRT_Set ){ - sqlite3ErrorMsg(pParse, "only a single result allowed for " - "a SELECT that is part of an expression"); - return 1; - }else{ - return 0; - } -} -#endif - /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. @@ -919,13 +895,14 @@ static void selectInnerLoop( } /* If this is a scalar select that is part of an expression, then - ** store the results in the appropriate memory cell and break out - ** of the scan loop. + ** store the results in the appropriate memory cell or array of + ** memory cells and break out of the scan loop. */ case SRT_Mem: { assert( nResultCol==pDest->nSdst ); if( pSort ){ - pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg); + pushOntoSorter( + pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg); }else{ assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ @@ -4894,16 +4871,6 @@ int sqlite3Select( } #endif - - /* If writing to memory or generating a set - ** only a single column may be output. - */ -#ifndef SQLITE_OMIT_SUBQUERY - if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){ - goto select_end; - } -#endif - /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) diff --git a/src/whereexpr.c b/src/whereexpr.c index 5997da1e3..33ce7edb3 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -872,13 +872,25 @@ static int exprMightBeIndexed( return 0; } -static Expr *exprVectorExpr(Parse *pParse, Expr *p, int iField){ +/* +** 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; - if( p->flags & EP_xIsSelect ){ - pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, p, 0, 0); + 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, p->x.pList->a[iField].pExpr, 0); + pRet = sqlite3ExprDup(pParse->db, pVector->x.pList->a[iField].pExpr, 0); } return pRet; } @@ -1194,8 +1206,8 @@ static void exprAnalyze( for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){ int idxNew; Expr *pNew; - Expr *pLeft = exprVectorExpr(pParse, pExpr->pLeft, i); - Expr *pRight = exprVectorExpr(pParse, pExpr->pRight, i); + Expr *pLeft = exprExtractVectorField(pParse, pExpr->pLeft, i); + Expr *pRight = exprExtractVectorField(pParse, pExpr->pRight, i); pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0); idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); |