aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr.c')
-rw-r--r--src/expr.c591
1 files changed, 469 insertions, 122 deletions
diff --git a/src/expr.c b/src/expr.c
index ea52d6625..3c95136c5 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -309,6 +309,134 @@ static int codeCompare(
return addr;
}
+/*
+** 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
+** any other type of expression, return 1.
+*/
+int sqlite3ExprVectorSize(Expr *pExpr){
+ if( (pExpr->flags & EP_Vector)==0 ) return 1;
+ if( pExpr->flags & EP_xIsSelect ){
+ return pExpr->x.pSelect->pEList->nExpr;
+ }
+ return pExpr->x.pList->nExpr;
+}
+
+/*
+** 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.
+*/
+static Expr *exprVectorField(Expr *pVector, int i){
+ if( (pVector->flags & EP_Vector)==0 ){
+ assert( i==0 );
+ return pVector;
+ }else if( pVector->flags & EP_xIsSelect ){
+ return pVector->x.pSelect->pEList->a[i].pExpr;
+ }
+ return pVector->x.pList->a[i].pExpr;
+}
+
+static int exprVectorSubselect(Parse *pParse, Expr *pExpr){
+ int reg = 0;
+ if( pExpr->flags & EP_xIsSelect ){
+ assert( pExpr->op==TK_REGISTER || pExpr->op==TK_SELECT );
+ if( pExpr->op==TK_REGISTER ){
+ reg = pExpr->iTable;
+ }else{
+ reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ }
+ }
+ return reg;
+}
+
+static void codeVectorCompare(Parse *pParse, Expr *pExpr, int dest){
+ Vdbe *v = pParse->pVdbe;
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ int nLeft = sqlite3ExprVectorSize(pLeft);
+ int nRight = sqlite3ExprVectorSize(pRight);
+ int addr = sqlite3VdbeMakeLabel(v);
+
+ /* Check that both sides of the comparison are vectors, and that
+ ** both are the same length. */
+ if( nLeft!=nRight ){
+ sqlite3ErrorMsg(pParse, "invalid use of row value");
+ }else{
+ int p5 = (pExpr->op==TK_IS || pExpr->op==TK_ISNOT) ? SQLITE_NULLEQ : 0;
+ int opCmp;
+ int opTest;
+ int i;
+ int p3 = 1;
+ int regLeft = 0;
+ int regRight = 0;
+
+ assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
+ || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
+ || pExpr->op==TK_LT || pExpr->op==TK_GT
+ || pExpr->op==TK_LE || pExpr->op==TK_GE
+ );
+
+ switch( pExpr->op ){
+ case TK_EQ:
+ case TK_IS:
+ opTest = OP_IfNot;
+ opCmp = OP_Eq;
+ break;
+
+ case TK_NE:
+ case TK_ISNOT:
+ opTest = OP_If;
+ opCmp = OP_Ne;
+ break;
+
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE:
+ opCmp = OP_Cmp;
+ opTest = OP_CmpTest;
+ p3 = pExpr->op;
+ break;
+ }
+
+ regLeft = exprVectorSubselect(pParse, pLeft);
+ regRight = exprVectorSubselect(pParse, pRight);
+ if( pParse->nErr ) return;
+
+ for(i=0; i<nLeft; i++){
+ int regFree1 = 0, regFree2 = 0;
+ Expr *pL, *pR;
+ int r1, r2;
+
+ if( regLeft ){
+ pL = pLeft->x.pSelect->pEList->a[i].pExpr;
+ r1 = regLeft+i;
+ }else{
+ pL = pLeft->x.pList->a[i].pExpr;
+ r1 = sqlite3ExprCodeTemp(pParse, pL, &regFree1);
+ }
+
+ if( regRight ){
+ pR = pRight->x.pSelect->pEList->a[i].pExpr;
+ r2 = regRight+i;
+ }else{
+ pR = pRight->x.pList->a[i].pExpr;
+ r2 = sqlite3ExprCodeTemp(pParse, pR, &regFree1);
+ }
+
+ codeCompare(pParse, pL, pR, opCmp, r1, r2, dest, SQLITE_STOREP2 | p5);
+ sqlite3VdbeAddOp3(v, opTest, dest, addr, p3);
+ sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ReleaseTempReg(pParse, regFree2);
+ }
+ }
+
+ sqlite3VdbeResolveLabel(v, addr);
+}
+
#if SQLITE_MAX_EXPR_DEPTH>0
/*
** Check that argument nHeight is less than or equal to the maximum
@@ -743,7 +871,7 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
if( !ExprHasProperty(p, EP_TokenOnly) ){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
- sqlite3ExprDelete(db, p->pLeft);
+ if( p->op!=TK_SELECT_COLUMN ) sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( ExprHasProperty(p, EP_xIsSelect) ){
@@ -1593,14 +1721,21 @@ 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){
+static Select *isCandidateForInOpt(Expr *pX, int bNullSensitive){
Select *p;
SrcList *pSrc;
ExprList *pEList;
- Expr *pRes;
Table *pTab;
+ int i;
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
p = pX->x.pSelect;
@@ -1623,10 +1758,18 @@ static Select *isCandidateForInOpt(Expr *pX){
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
- if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
- pRes = pEList->a[0].pExpr;
- if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
- assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
+
+ /* All SELECT results must be columns. If the SELECT returns more than
+ ** one column and the bNullSensitive flag is set, all returned columns
+ ** must be declared NOT NULL. */
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *pRes = pEList->a[i].pExpr;
+ if( pRes->op!=TK_COLUMN ) return 0;
+ assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
+ if( pEList->nExpr>1 && bNullSensitive ){
+ if( pTab->aCol[pRes->iColumn].notNull==0 ) return 0;
+ }
+ }
return p;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -1745,7 +1888,13 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** NULL values.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
+int sqlite3FindInIndex(
+ Parse *pParse,
+ Expr *pX,
+ u32 inFlags,
+ int *prRhsHasNull,
+ int *aiMap
+){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */
@@ -1759,20 +1908,18 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
** satisfy the query. This is preferable to generating a new
** ephemeral table.
*/
- if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
+ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX, prRhsHasNull!=0))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
- Expr *pExpr; /* Expression <column> */
- i16 iCol; /* Index of column <column> */
i16 iDb; /* Database idx for pTab */
+ ExprList *pEList = p->pEList;
+ int nExpr = pEList->nExpr;
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
pTab = p->pSrc->a[0].pTab;
- pExpr = p->pEList->a[0].pExpr;
- iCol = (i16)pExpr->iColumn;
-
+
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3CodeVerifySchema(pParse, iDb);
@@ -1783,7 +1930,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
** successful here.
*/
assert(v);
- if( iCol<0 ){
+ if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
int iAddr = sqlite3CodeOnce(pParse);
VdbeCoverage(v);
@@ -1793,23 +1940,55 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */
+ int affinity_ok = 1;
+ int i;
+
+ /* Check that the affinity that will be used to perform each
+ ** 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 = exprVectorField(pX->pLeft, i);
+ int iCol = pEList->a[i].pExpr->iColumn;
+ char idxaff = pTab->aCol[iCol].affinity;
+ char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
+ switch( cmpaff ){
+ case SQLITE_AFF_BLOB:
+ break;
+ case SQLITE_AFF_TEXT:
+ affinity_ok = (idxaff==SQLITE_AFF_TEXT);
+ break;
+ default:
+ affinity_ok = sqlite3IsNumericAffinity(idxaff);
+ }
+ }
/* The collation sequence used by the comparison. If an index is to
** be used in place of a temp-table, it must be ordered according
** to this collation sequence. */
- CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
-
- /* Check that the affinity that will be used to perform the
- ** comparison is the same as the affinity of the column. If
- ** it is not, it is not possible to use any index.
- */
- int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
- if( (pIdx->aiColumn[0]==iCol)
- && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
- && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
- ){
+ if( pIdx->nKeyCol<nExpr ) continue;
+ if( mustBeUnique && (pIdx->nKeyCol!=nExpr || !IsUniqueIndex(pIdx)) ){
+ continue;
+ }
+
+ for(i=0; i<nExpr; i++){
+ Expr *pLhs = exprVectorField(pX->pLeft, i);
+ Expr *pRhs = pEList->a[i].pExpr;
+ CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
+ int j;
+
+ for(j=0; j<nExpr; j++){
+ if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
+ assert( pIdx->azColl[j] );
+ if( sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ) continue;
+ break;
+ }
+ if( j==nExpr ) break;
+ if( aiMap ) aiMap[i] = j;
+ }
+
+ if( i==nExpr ){
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
@@ -1817,11 +1996,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
- if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
+ if( prRhsHasNull && nExpr==1
+ && !pTab->aCol[pEList->a[0].pExpr->iColumn].notNull
+ ){
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- const i64 sOne = 1;
+ i64 mask = (1<<nExpr)-1;
sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
- iTab, 0, 0, (u8*)&sOne, P4_INT64);
+ iTab, 0, 0, (u8*)&mask, P4_INT64);
#endif
*prRhsHasNull = ++pParse->nMem;
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
@@ -1846,7 +2027,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
){
eType = IN_INDEX_NOOP;
}
-
if( eType==0 ){
/* Could not find an existing table or index to use as the RHS b-tree.
@@ -1868,10 +2048,53 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
}else{
pX->iTable = iTab;
}
+
+ if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
+ int i, n;
+ n = sqlite3ExprVectorSize(pX->pLeft);
+ for(i=0; i<n; i++) aiMap[i] = i;
+ }
return eType;
}
#endif
+static char *exprINAffinity(Parse *pParse, Expr *pExpr){
+ Expr *pLeft = pExpr->pLeft;
+ int nVal = sqlite3ExprVectorSize(pLeft);
+ char *zRet;
+
+ zRet = sqlite3DbMallocZero(pParse->db, nVal+1);
+ if( zRet ){
+ int i;
+ for(i=0; i<nVal; i++){
+ Expr *pA;
+ char a;
+ if( nVal==1 && 0 ){
+ pA = pLeft;
+ }else{
+ pA = exprVectorField(pLeft, i);
+ }
+ a = sqlite3ExprAffinity(pA);
+ zRet[i] = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[i].pExpr, a);
+ }
+ zRet[nVal] = '\0';
+ }
+ return zRet;
+}
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Load the Parse object passed as the first argument with an error
+** message of the form:
+**
+** "sub-select returns N columns - expected M"
+*/
+void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
+ const char *zFmt = "sub-select returns %d columns - expected %d";
+ sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+}
+#endif
+
/*
** Generate code for scalar subqueries used as a subquery expression, EXISTS,
** or IN operators. Examples:
@@ -1939,12 +2162,12 @@ int sqlite3CodeSubselect(
switch( pExpr->op ){
case TK_IN: {
- char affinity; /* Affinity of the LHS of the IN */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
-
- affinity = sqlite3ExprAffinity(pLeft);
+ int nVal; /* Size of vector pLeft */
+
+ nVal = sqlite3ExprVectorSize(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
** expression it is handled the same way. An ephemeral table is
@@ -1960,8 +2183,9 @@ int sqlite3CodeSubselect(
** is used.
*/
pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
- pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
+ pExpr->iTable, (isRowid?0:nVal));
+ pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@@ -1970,27 +2194,37 @@ int sqlite3CodeSubselect(
** table allocated and opened above.
*/
Select *pSelect = pExpr->x.pSelect;
- SelectDest dest;
- ExprList *pEList;
+ ExprList *pEList = pSelect->pEList;
assert( !isRowid );
- sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
- dest.affSdst = (u8)affinity;
- assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- pSelect->iLimit = 0;
- testcase( pSelect->selFlags & SF_Distinct );
- testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
- if( sqlite3Select(pParse, pSelect, &dest) ){
- sqlite3KeyInfoUnref(pKeyInfo);
- return 0;
+ if( pEList->nExpr!=nVal ){
+ sqlite3SubselectError(pParse, pEList->nExpr, nVal);
+ }else{
+ SelectDest dest;
+ int i;
+ sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
+ dest.zAffSdst = exprINAffinity(pParse, pExpr);
+ assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
+ pSelect->iLimit = 0;
+ testcase( pSelect->selFlags & SF_Distinct );
+ testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
+ if( sqlite3Select(pParse, pSelect, &dest) ){
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ sqlite3KeyInfoUnref(pKeyInfo);
+ return 0;
+ }
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
+ assert( pEList!=0 );
+ assert( pEList->nExpr>0 );
+ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
+ for(i=0; i<nVal; i++){
+ Expr *p = (nVal>1) ? exprVectorField(pLeft, i) : pLeft;
+ pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
+ pParse, p, pEList->a[i].pExpr
+ );
+ }
}
- pEList = pSelect->pEList;
- assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
- assert( pEList!=0 );
- assert( pEList->nExpr>0 );
- assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
- pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
- pEList->a[0].pExpr);
}else if( ALWAYS(pExpr->x.pList!=0) ){
/* Case 2: expr IN (exprlist)
**
@@ -1999,11 +2233,13 @@ int sqlite3CodeSubselect(
** that columns affinity when building index keys. If <expr> is not
** a column, use numeric affinity.
*/
+ char affinity; /* Affinity of the LHS of the IN */
int i;
ExprList *pList = pExpr->x.pList;
struct ExprList_item *pItem;
int r1, r2, r3;
+ affinity = sqlite3ExprAffinity(pLeft);
if( !affinity ){
affinity = SQLITE_AFF_BLOB;
}
@@ -2067,18 +2303,22 @@ int sqlite3CodeSubselect(
*/
Select *pSel; /* SELECT statement to encode */
SelectDest dest; /* How to deal with SELECt result */
+ int nReg; /* Registers to allocate */
testcase( pExpr->op==TK_EXISTS );
testcase( pExpr->op==TK_SELECT );
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
-
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+
pSel = pExpr->x.pSelect;
- sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
+ nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
+ sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
+ pParse->nMem += nReg;
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
dest.iSdst = dest.iSDParm;
- sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
+ dest.nSdst = nReg;
+ sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
VdbeComment((v, "Init subquery result"));
}else{
dest.eDest = SRT_Exists;
@@ -2137,32 +2377,64 @@ static void sqlite3ExprCodeIN(
int destIfNull /* Jump here if the results are unknown due to NULLs */
){
int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */
- char affinity; /* Comparison affinity to use */
int eType; /* Type of the RHS */
int r1; /* Temporary use register */
Vdbe *v; /* Statement under construction */
+ int *aiMap = 0; /* Map from vector field to index column */
+ char *zAff = 0; /* Affinity string for comparisons */
+ int nVector; /* Size of vectors for this IN(...) op */
+ int regSelect = 0;
+ Expr *pLeft = pExpr->pLeft;
+ int i;
- /* Compute the RHS. After this step, the table with cursor
- ** pExpr->iTable will contains the values that make up the RHS.
- */
+ nVector = sqlite3ExprVectorSize(pExpr->pLeft);
+ aiMap = (int*)sqlite3DbMallocZero(
+ pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
+ );
+ if( !aiMap ) return;
+ zAff = (char*)&aiMap[nVector];
+
+ /* Attempt to compute the RHS. After this step, if anything other than
+ ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable
+ ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
+ ** the RHS has not yet been coded. */
v = pParse->pVdbe;
assert( v!=0 ); /* OOM detected prior to this routine */
VdbeNoopComment((v, "begin IN expr"));
eType = sqlite3FindInIndex(pParse, pExpr,
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
- destIfFalse==destIfNull ? 0 : &rRhsHasNull);
+ destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
- /* Figure out the affinity to use to create a key from the results
- ** of the expression. affinityStr stores a static string suitable for
- ** P4 of OP_MakeRecord.
- */
- affinity = comparisonAffinity(pExpr);
+ assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
+ || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
+ );
- /* Code the LHS, the <expr> from "<expr> IN (...)".
+ /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
+ ** vector, then it is stored in an array of nVector registers starting
+ ** at r1.
*/
+ r1 = sqlite3GetTempRange(pParse, nVector);
sqlite3ExprCachePush(pParse);
- r1 = sqlite3GetTempReg(pParse);
- sqlite3ExprCode(pParse, pExpr->pLeft, r1);
+ if( nVector>1 && (pLeft->flags & EP_xIsSelect) ){
+ regSelect = sqlite3CodeSubselect(pParse, pLeft, 0, 0);
+ }
+ for(i=0; i<nVector; i++){
+ int iCol = aiMap[i];
+ Expr *pLhs = exprVectorField(pLeft, i);
+
+ if( regSelect ){
+ sqlite3VdbeAddOp3(v, OP_Copy, regSelect+i, r1+iCol, 0);
+ }else{
+ sqlite3ExprCode(pParse, pLhs, r1+iCol);
+ }
+
+ zAff[iCol] = sqlite3ExprAffinity(pLhs);
+ if( pExpr->flags & EP_xIsSelect ){
+ zAff[iCol] = sqlite3CompareAffinity(
+ pExpr->x.pSelect->pEList->a[iCol].pExpr, zAff[iCol]
+ );
+ }
+ }
/* If sqlite3FindInIndex() did not find or create an index that is
** suitable for evaluating the IN operator, then evaluate using a
@@ -2190,12 +2462,12 @@ static void sqlite3ExprCodeIN(
(void*)pColl, P4_COLLSEQ);
VdbeCoverageIf(v, ii<pList->nExpr-1);
VdbeCoverageIf(v, ii==pList->nExpr-1);
- sqlite3VdbeChangeP5(v, affinity);
+ sqlite3VdbeChangeP5(v, zAff[0]);
}else{
assert( destIfNull==destIfFalse );
sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
(void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
- sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
+ sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
}
sqlite3ReleaseTempReg(pParse, regToFree);
}
@@ -2208,20 +2480,20 @@ static void sqlite3ExprCodeIN(
}else{
/* If the LHS is NULL, then the result is either false or NULL depending
- ** on whether the RHS is empty or not, respectively.
- */
- if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
- if( destIfNull==destIfFalse ){
- /* Shortcut for the common case where the false and NULL outcomes are
- ** the same. */
- sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
- }else{
- int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
- VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfNull);
- sqlite3VdbeJumpHere(v, addr1);
+ ** on whether the RHS is empty or not, respectively. */
+ if( destIfNull==destIfFalse ){
+ for(i=0; i<nVector; i++){
+ Expr *p = exprVectorField(pExpr->pLeft, i);
+ if( sqlite3ExprCanBeNull(p) ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull);
+ }
}
+ }else if( nVector==1 && sqlite3ExprCanBeNull(pExpr->pLeft) ){
+ int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ VdbeCoverage(v);
+ sqlite3VdbeGoto(v, destIfNull);
+ sqlite3VdbeJumpHere(v, addr1);
}
if( eType==IN_INDEX_ROWID ){
@@ -2229,10 +2501,50 @@ static void sqlite3ExprCodeIN(
*/
sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1);
VdbeCoverage(v);
+ }else if( nVector>1 && eType==IN_INDEX_EPH && destIfNull!=destIfFalse ){
+ int regNull = sqlite3GetTempReg(pParse);
+ int r2 = sqlite3GetTempReg(pParse);
+ int r3 = sqlite3GetTempReg(pParse);
+ int r4 = sqlite3GetTempReg(pParse);
+ int addrNext;
+ int addrIf;
+
+ if( destIfFalse!=destIfNull ){
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regNull);
+ }
+ addrNext = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ for(i=0; i<nVector; i++){
+ Expr *p;
+ CollSeq *pColl;
+ p = exprVectorField(pLeft, i);
+ pColl = sqlite3ExprCollSeq(pParse, p);
+
+ sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r2);
+ sqlite3VdbeAddOp4(v, OP_Eq, r1+i, i?r3:r4, r2, (void*)pColl,P4_COLLSEQ);
+ sqlite3VdbeChangeP5(v, SQLITE_STOREP2);
+ if( i!=0 ){
+ sqlite3VdbeAddOp3(v, OP_And, r3, r4, r4);
+ }
+ }
+ addrIf = sqlite3VdbeAddOp1(v, OP_If, r4);
+ if( destIfNull!=destIfFalse ){
+ sqlite3VdbeAddOp2(v, OP_IfNot, r4, sqlite3VdbeCurrentAddr(v)+2);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regNull);
+ }
+ sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrNext+1);
+ if( destIfNull!=destIfFalse ){
+ sqlite3VdbeAddOp2(v, OP_If, regNull, destIfNull);
+ }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
+ sqlite3VdbeChangeP2(v, addrIf, sqlite3VdbeCurrentAddr(v));
+ sqlite3ReleaseTempReg(pParse, regNull);
+ sqlite3ReleaseTempReg(pParse, r2);
+ sqlite3ReleaseTempReg(pParse, r3);
+ sqlite3ReleaseTempReg(pParse, r4);
}else{
/* In this case, the RHS is an index b-tree.
*/
- sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
+ sqlite3VdbeAddOp4(v, OP_Affinity, r1, nVector, 0, zAff, nVector);
/* If the set membership test fails, then the result of the
** "x IN (...)" expression must be either 0 or NULL. If the set
@@ -2249,7 +2561,9 @@ static void sqlite3ExprCodeIN(
** Also run this branch if NULL is equivalent to FALSE
** for this particular IN operator.
*/
- sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
+ sqlite3VdbeAddOp4Int(
+ v, OP_NotFound, pExpr->iTable, destIfFalse, r1, nVector
+ );
VdbeCoverage(v);
}else{
/* In this branch, the RHS of the IN might contain a NULL and
@@ -2275,6 +2589,7 @@ static void sqlite3ExprCodeIN(
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ExprCachePop(pParse);
+ sqlite3DbFree(pParse->db, aiMap);
VdbeComment((v, "end IN expr"));
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -2669,6 +2984,8 @@ static void exprToRegister(Expr *p, int iReg){
ExprClearProperty(p, EP_Skip);
}
+static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
+
/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
@@ -2689,6 +3006,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int r1, r2, r3, r4; /* Various register numbers */
sqlite3 *db = pParse->db; /* The database connection */
Expr tempX; /* Temporary expression node */
+ int p5 = 0;
assert( target>0 && target<=pParse->nMem );
if( v==0 ){
@@ -2801,39 +3119,34 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
#endif /* SQLITE_OMIT_CAST */
+ case TK_IS:
+ case TK_ISNOT:
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ p5 = SQLITE_NULLEQ;
+ /* fall-through */
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2);
- assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
- assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
- assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
- assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
- break;
- }
- case TK_IS:
- case TK_ISNOT: {
- testcase( op==TK_IS );
- testcase( op==TK_ISNOT );
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- op = (op==TK_IS) ? TK_EQ : TK_NE;
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==TK_EQ);
- VdbeCoverageIf(v, op==TK_NE);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
+ Expr *pLeft = pExpr->pLeft;
+ if( (pLeft->flags & EP_Vector) ){
+ codeVectorCompare(pParse, pExpr, target);
+ }else{
+ r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ codeCompare(pParse, pLeft, pExpr->pRight, op,
+ r1, r2, inReg, SQLITE_STOREP2 | p5);
+ assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
+ assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
+ assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
+ assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ }
break;
}
case TK_AND:
@@ -3054,9 +3367,14 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS:
case TK_SELECT: {
+ int nCol;
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
- inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
+ sqlite3SubselectError(pParse, nCol, 1);
+ }else{
+ inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ }
break;
}
case TK_IN: {
@@ -3085,6 +3403,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** Z is stored in pExpr->pList->a[1].pExpr.
*/
case TK_BETWEEN: {
+ exprCodeBetween(pParse, pExpr, target, 0, 0);
+#if 0
Expr *pLeft = pExpr->pLeft;
struct ExprList_item *pLItem = pExpr->x.pList->a;
Expr *pRight = pLItem->pExpr;
@@ -3107,6 +3427,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
sqlite3ReleaseTempReg(pParse, r3);
sqlite3ReleaseTempReg(pParse, r4);
+#endif
break;
}
case TK_SPAN:
@@ -3172,6 +3493,22 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
+ case TK_VECTOR: {
+ sqlite3ErrorMsg(pParse, "invalid use of row value");
+ break;
+ }
+
+ case TK_SELECT_COLUMN: {
+ Expr *pLeft = pExpr->pLeft;
+ assert( pLeft );
+ assert( pLeft->op==TK_SELECT || pLeft->op==TK_REGISTER );
+ if( pLeft->op==TK_SELECT ){
+ pLeft->iTable = sqlite3CodeSubselect(pParse, pLeft, 0, 0);
+ pLeft->op = TK_REGISTER;
+ }
+ inReg = pLeft->iTable + pExpr->iColumn;
+ break;
+ }
/*
** Form A:
@@ -3500,7 +3837,7 @@ static void exprCodeBetween(
Parse *pParse, /* Parsing and code generating context */
Expr *pExpr, /* The BETWEEN expression */
int dest, /* Jump here if the jump is taken */
- int jumpIfTrue, /* Take the jump if the BETWEEN is true */
+ void (*xJumpIf)(Parse*,Expr*,int,int),
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
){
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
@@ -3509,6 +3846,10 @@ static void exprCodeBetween(
Expr exprX; /* The x subexpression */
int regFree1 = 0; /* Temporary use register */
+ memset(&compLeft, 0, sizeof(Expr));
+ memset(&compRight, 0, sizeof(Expr));
+ memset(&exprAnd, 0, sizeof(Expr));
+
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
@@ -3520,11 +3861,14 @@ static void exprCodeBetween(
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, &regFree1));
- if( jumpIfTrue ){
- sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
+ if( (exprX.flags & EP_Vector)==0 ){
+ exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, &regFree1));
+ }
+ if( xJumpIf ){
+ xJumpIf(pParse, &exprAnd, dest, jumpIfNull);
}else{
- sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
+ exprX.flags |= EP_FromJoin;
+ sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
}
sqlite3ReleaseTempReg(pParse, regFree1);
@@ -3564,7 +3908,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
if( NEVER(pExpr==0) ) return; /* No way this can happen */
op = pExpr->op;
- switch( op ){
+ switch( op | (pExpr->pLeft ? (pExpr->pLeft->flags & EP_Vector) : 0)){
case TK_AND: {
int d2 = sqlite3VdbeMakeLabel(v);
testcase( jumpIfNull==0 );
@@ -3633,7 +3977,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
}
case TK_BETWEEN: {
testcase( jumpIfNull==0 );
- exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull);
+ exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -3753,6 +4097,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
case TK_GE:
case TK_NE:
case TK_EQ: {
+ if( pExpr->pLeft->flags & EP_Vector ) goto default_expr;
+
testcase( jumpIfNull==0 );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
@@ -3783,7 +4129,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
}
case TK_BETWEEN: {
testcase( jumpIfNull==0 );
- exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull);
+ exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -3799,6 +4145,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
}
#endif
default: {
+ default_expr:
if( exprAlwaysFalse(pExpr) ){
sqlite3VdbeGoto(v, dest);
}else if( exprAlwaysTrue(pExpr) ){