diff options
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 591 |
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, ®Free1); + } + + 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, ®Free1); + } + + 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, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - 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, ®Free1); - r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); - 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, ®Free1); + r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); + 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, ®Free1)); - if( jumpIfTrue ){ - sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull); + if( (exprX.flags & EP_Vector)==0 ){ + exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, ®Free1)); + } + 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, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2); @@ -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) ){ |