printf "#define TK_%-29s %4d\n", "TO_NUMERIC", ++max
printf "#define TK_%-29s %4d\n", "TO_INT", ++max
printf "#define TK_%-29s %4d\n", "TO_REAL", ++max
+ printf "#define TK_%-29s %4d\n", "ISNOT", ++max
printf "#define TK_%-29s %4d\n", "END_OF_FILE", ++max
printf "#define TK_%-29s %4d\n", "ILLEGAL", ++max
printf "#define TK_%-29s %4d\n", "SPACE", ++max
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
-C Factor\sthe\sUMINUS\sand\sUPLUS\stokens\sout\sof\sthe\sparser\sso\sthat\sthe\sparser\ntables\scan\sgo\sback\sto\susing\s8-bit\svalues\sinstead\sof\s16-bit\svalues.
-D 2009-09-22T20:08:35
+C Generalize\sthe\sIS\sand\sIS\sNOT\soperators\sso\sthat\stheir\sright-hand\sside\scan\sbe\nan\sarbitrary\sexpression\sand\snot\ssimple\sthe\sconstant\sNULL.\s\sThey\swork\slike\n=\sand\s<>\sexcept\sthat\sNULL\svalues\scompare\sequal\sto\sone\sanother\san\sunequal\sto\neverything\selse.
+D 2009-09-23T02:29:37
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 7260e7baf934051dee42458206e915b75570f41d
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
-F addopcodes.awk 08eb3bdfef10a131530e3ad7fa1a6902a52dad15
+F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
F art/SQLite.eps 9b43cc99cfd2be687d386faea6862ea68d6a72b2
F art/SQLite.gif 1bbb94484963f1382e27e1c5e86dd0c1061eba2b
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638
F src/delete.c 15499f5d10047d38e68ce991b3f88cbddb6e0931
-F src/expr.c 638b599adad562d41c3bf90f542f9419664aa7b8
+F src/expr.c 8a663240f374a5326ee157df3d27751f58b7676a
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/fkey.c fa1ad144926a8536e23cbbf64c0e51b8f2fdd4bf
F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
F src/os_win.c 49a360be4f42d5a63d00be9aa44449ed4d6717e0
F src/pager.c ebd0a8f2421e8f0ad5b78201440004bf3e1c96d8
F src/pager.h 11852d044c86cf5a9d6e34171fb0c4fcf1f6265f
-F src/parse.y 749f39fa218418a19c46970336c2343214e2fe05
+F src/parse.y 563ecc9e633bbb465383667380aff1646ecd96f7
F src/pcache.c c92ffd4f3e1279b3766854c6d18b5bf4aac0d1fa
F src/pcache.h 435ef324197f79391f9c92b71d7f92b548ad7a36
F src/pcache1.c 211295a9ff6a5b30f1ca50516731a5cf3e9bf82c
F src/shell.c d0171721c7402b368e257ddfc09ed54d0c74070c
F src/sqlite.h.in 5af8181f815831a8672c3834c60e6b4418448bcc
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 6a949ccf79ae441ac37f0d3033204895aa2a9e6a
+F src/sqliteInt.h 35f0d4203924272b5ae849c88b7b857eda3bb272
F src/sqliteLimit.h 504a3161886d2938cbd163054ad620b8356df758
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30
F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35
F src/vacuum.c 869d08eaab64e2a4eaf4ef9ea34b851892b65a75
-F src/vdbe.c 03857c07b8d159eb86ff559138d2eb5317cbfe32
+F src/vdbe.c 4946e2ac1124b0cb0ee882ed7628d2d8b339b8ef
F src/vdbe.h 7d5075e3fa4e5587a9be8d5e503857c825490cef
F src/vdbeInt.h 546ed25cad488c053819e19d09751d71d3ce3601
F src/vdbeapi.c 524d79eb17bbcbe31c37c908b8e01edc5c684a90
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 55b263fa2b2fed8c721154e3c48f4226be95065c
-R eef40f23e9c60a6f8dbfd20ac239494a
+P 3fc938c961fd7810594224b91a2d6e1ac9e48084
+R d99ab25244fa05bd56d10d71bb3bee44
U drh
-Z a26ff37b38b185f4ba103e5a00635dcb
+Z 4608482892179163853473e1fbf42a31
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
-iD8DBQFKuS7GoxKgR168RlERArmIAJ9Zh9EPcETkJ903DGxflMeqs+sSrQCfRsQh
-N09u5KCVOpvUNYJvUIHJJug=
-=Nr38
+iD8DBQFKuYgUoxKgR168RlERApeHAJ48L4oeCXw8ZV6ov3G5+bjNMfQIewCfX/Rc
+qXj8iamFDJ6JXwF0VP/iAOI=
+=lSDQ
-----END PGP SIGNATURE-----
-3fc938c961fd7810594224b91a2d6e1ac9e48084
\ No newline at end of file
+98853f6104076c50ea92175e17a3254bfbbd4619
\ No newline at end of file
char aff;
assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
- pExpr->op==TK_NE );
+ pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT );
assert( pExpr->pLeft );
aff = sqlite3ExprAffinity(pExpr->pLeft);
if( pExpr->pRight ){
testcase( regFree2==0 );
break;
}
+ case TK_IS:
+ case TK_ISNOT: {
+ testcase( op==TK_IS );
+ testcase( op==TK_ISNOT );
+ codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
+ pExpr->pRight, &r2, ®Free2);
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ break;
+ }
case TK_AND:
case TK_OR:
case TK_PLUS:
testcase( regFree2==0 );
break;
}
+ case TK_IS:
+ case TK_ISNOT: {
+ testcase( op==TK_IS );
+ testcase( op==TK_ISNOT );
+ codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
+ pExpr->pRight, &r2, ®Free2);
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, SQLITE_NULLEQ);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ break;
+ }
case TK_ISNULL:
case TK_NOTNULL: {
assert( TK_ISNULL==OP_IsNull );
testcase( regFree2==0 );
break;
}
+ case TK_IS:
+ case TK_ISNOT: {
+ testcase( op==TK_IS );
+ testcase( op==TK_ISNOT );
+ codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1,
+ pExpr->pRight, &r2, ®Free2);
+ op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
+ codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
+ r1, r2, dest, SQLITE_NULLEQ);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ break;
+ }
case TK_ISNULL:
case TK_NOTNULL: {
testcase( op==TK_ISNULL );
}
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);}
-expr(A) ::= expr(X) IS NULL(E). {spanUnaryPostfix(&A,pParse,TK_ISNULL,&X,&E);}
expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
-expr(A) ::= expr(X) IS NOT NULL(E).
- {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
+
+// expr1 IS expr2
+// expr1 IS NOT expr2
+//
+// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2
+// is any other expression, code as TK_IS or TK_ISNOT.
+//
+expr(A) ::= expr(X) IS expr(Y). {
+ spanBinaryExpr(&A,pParse,TK_IS,&X,&Y);
+ if( pParse->db->mallocFailed==0 && Y.pExpr->op==TK_NULL ){
+ A.pExpr->op = TK_ISNULL;
+ }
+}
+expr(A) ::= expr(X) IS NOT expr(Y). {
+ spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y);
+ if( pParse->db->mallocFailed==0 && Y.pExpr->op==TK_NULL ){
+ A.pExpr->op = TK_NOTNULL;
+ }
+}
%include {
/* Construct an expression node for a unary prefix operator
*/
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
+#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
/*
** An object of this type is created for each virtual table present in
** This works just like the Lt opcode except that the jump is taken if
** the operands in registers P1 and P3 are not equal. See the Lt opcode for
** additional information.
+**
+** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
+** true or false and is never NULL. If both operands are NULL then the result
+** of comparison is false. If either operand is NULL then the result is true.
+** If neither operand is NULL the the result is the same as it would be if
+** the SQLITE_NULLEQ flag were omitted from P5.
*/
/* Opcode: Eq P1 P2 P3 P4 P5
**
** This works just like the Lt opcode except that the jump is taken if
** the operands in registers P1 and P3 are equal.
** See the Lt opcode for additional information.
+**
+** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
+** true or false and is never NULL. If both operands are NULL then the result
+** of comparison is true. If either operand is NULL then the result is false.
+** If neither operand is NULL the the result is the same as it would be if
+** the SQLITE_NULLEQ flag were omitted from P5.
*/
/* Opcode: Le P1 P2 P3 P4 P5
**
case OP_Le: /* same as TK_LE, jump, in1, in3 */
case OP_Gt: /* same as TK_GT, jump, in1, in3 */
case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
- int flags;
- int res;
- char affinity;
-
- flags = pIn1->flags|pIn3->flags;
-
- if( flags&MEM_Null ){
- /* If either operand is NULL then the result is always NULL.
- ** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
- */
- if( pOp->p5 & SQLITE_STOREP2 ){
- pOut = &p->aMem[pOp->p2];
- MemSetTypeFlag(pOut, MEM_Null);
- REGISTER_TRACE(pOp->p2, pOut);
- }else if( pOp->p5 & SQLITE_JUMPIFNULL ){
- pc = pOp->p2-1;
+ int res; /* Result of the comparison of pIn1 against pIn3 */
+ char affinity; /* Affinity to use for comparison */
+
+ if( (pIn1->flags | pIn3->flags)&MEM_Null ){
+ /* One or both operands are NULL */
+ if( pOp->p5 & SQLITE_NULLEQ ){
+ /* If SQLITE_NULLEQ is set (which will only happen if the operator is
+ ** OP_Eq or OP_Ne) then take the jump or not depending on whether
+ ** or not both operands are null.
+ */
+ assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
+ res = (pIn1->flags & pIn3->flags & MEM_Null)==0;
+ }else{
+ /* SQLITE_NULLEQ is clear and at least one operand is NULL,
+ ** then the result is always NULL.
+ ** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
+ */
+ if( pOp->p5 & SQLITE_STOREP2 ){
+ pOut = &p->aMem[pOp->p2];
+ MemSetTypeFlag(pOut, MEM_Null);
+ REGISTER_TRACE(pOp->p2, pOut);
+ }else if( pOp->p5 & SQLITE_JUMPIFNULL ){
+ pc = pOp->p2-1;
+ }
+ break;
+ }
+ }else{
+ /* Neither operand is NULL. Do a comparison. */
+ affinity = pOp->p5 & SQLITE_AFF_MASK;
+ if( affinity ){
+ applyAffinity(pIn1, affinity, encoding);
+ applyAffinity(pIn3, affinity, encoding);
+ if( db->mallocFailed ) goto no_mem;
}
- break;
- }
- affinity = pOp->p5 & SQLITE_AFF_MASK;
- if( affinity ){
- applyAffinity(pIn1, affinity, encoding);
- applyAffinity(pIn3, affinity, encoding);
- if( db->mallocFailed ) goto no_mem;
+ assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
+ ExpandBlob(pIn1);
+ ExpandBlob(pIn3);
+ res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
-
- assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
- ExpandBlob(pIn1);
- ExpandBlob(pIn3);
- res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
switch( pOp->opcode ){
case OP_Eq: res = res==0; break;
case OP_Ne: res = res!=0; break;
assert( n>0 );
assert( pKeyInfo!=0 );
p1 = pOp->p1;
- assert( p1>0 && p1+n<=p->nMem+1 );
p2 = pOp->p2;
- assert( p2>0 && p2+n<=p->nMem+1 );
+#if SQLITE_DEBUG
+ if( aPermute ){
+ int k, mx = 0;
+ for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
+ assert( p1>0 && p1+mx<=p->nMem+1 );
+ assert( p2>0 && p2+mx<=p->nMem+1 );
+ }else{
+ assert( p1>0 && p1+n<=p->nMem+1 );
+ assert( p2>0 && p2+n<=p->nMem+1 );
+ }
+#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
idx = aPermute ? aPermute[i] : i;
REGISTER_TRACE(p1+idx, &p->aMem[p1+idx]);