diff options
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/src/expr.c b/src/expr.c index 3f040309a..67c97930d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4001,7 +4001,6 @@ static void sqlite3ExprCodeIN( int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */ int eType; /* Type of the RHS */ int rLhs; /* Register(s) holding the LHS values */ - int rLhsOrig; /* LHS values prior to reordering by aiMap[] */ Vdbe *v; /* Statement under construction */ int *aiMap = 0; /* Map from vector field to index column */ char *zAff = 0; /* Affinity string for comparisons */ @@ -4064,19 +4063,8 @@ static void sqlite3ExprCodeIN( ** by code generated below. */ assert( pParse->okConstFactor==okConstFactor ); pParse->okConstFactor = 0; - rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); + rLhs = exprCodeVector(pParse, pLeft, &iDummy); pParse->okConstFactor = okConstFactor; - for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */ - if( i==nVector ){ - /* LHS fields are not reordered */ - rLhs = rLhsOrig; - }else{ - /* Need to reorder the LHS fields according to aiMap */ - rLhs = sqlite3GetTempRange(pParse, nVector); - for(i=0; i<nVector; i++){ - sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0); - } - } /* If sqlite3FindInIndex() did not find or create an index that is ** suitable for evaluating the IN operator, then evaluate using a @@ -4091,6 +4079,7 @@ static void sqlite3ExprCodeIN( int r2, regToFree; int regCkNull = 0; int ii; + assert( nVector==1 ); assert( ExprUseXList(pExpr) ); pList = pExpr->x.pList; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); @@ -4132,6 +4121,26 @@ static void sqlite3ExprCodeIN( goto sqlite3ExprCodeIN_finished; } + if( eType!=IN_INDEX_ROWID ){ + /* If this IN operator will use an index, then the order of columns in the + ** vector might be different from the order in the index. In that case, + ** we need to reorder the LHS values to be in index order. Run Affinity + ** before reordering the columns, so that the affinity is correct. + */ + sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); + for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */ + if( i!=nVector ){ + /* Need to reorder the LHS fields according to aiMap */ + int rLhsOrig = rLhs; + rLhs = sqlite3GetTempRange(pParse, nVector); + for(i=0; i<nVector; i++){ + sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0); + } + sqlite3ReleaseTempReg(pParse, rLhsOrig); + } + } + + /* Step 2: Check to see if the LHS contains any NULL columns. If the ** LHS does contain NULLs then the result must be either FALSE or NULL. ** We will then skip the binary search of the RHS. @@ -4158,11 +4167,11 @@ static void sqlite3ExprCodeIN( /* In this case, the RHS is the ROWID of table b-tree and so we also ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4 ** into a single opcode. */ + assert( nVector==1 ); sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs); VdbeCoverage(v); addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */ }else{ - sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector); if( destIfFalse==destIfNull ){ /* Combine Step 3 and Step 5 into a single opcode */ if( ExprHasProperty(pExpr, EP_Subrtn) ){ @@ -4240,7 +4249,6 @@ static void sqlite3ExprCodeIN( sqlite3VdbeJumpHere(v, addrTruthOp); sqlite3ExprCodeIN_finished: - if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); VdbeComment((v, "end IN expr")); sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); @@ -4989,6 +4997,12 @@ expr_code_doover: sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } + case TK_NULLS: { + /* Set a range of registers to NULL. pExpr->y.nReg registers starting + ** with target */ + sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1); + return target; + } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled @@ -5699,6 +5713,25 @@ int sqlite3ExprCodeRunJustOnce( } /* +** Make arrangements to invoke OP_Null on a range of registers +** during initialization. +*/ +SQLITE_NOINLINE void sqlite3ExprNullRegisterRange( + Parse *pParse, /* Parsing context */ + int iReg, /* First register to set to NULL */ + int nReg /* Number of sequential registers to NULL out */ +){ + u8 okConstFactor = pParse->okConstFactor; + Expr t; + memset(&t, 0, sizeof(t)); + t.op = TK_NULLS; + t.y.nReg = nReg; + pParse->okConstFactor = 1; + sqlite3ExprCodeRunJustOnce(pParse, &t, iReg); + pParse->okConstFactor = okConstFactor; +} + +/* ** Generate code to evaluate an expression and store the results ** into a register. Return the register number where the results ** are stored. |