]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rework the fix to ticket #461 so that we do not have to do redundant tests
authordrh <drh@noemail.net>
Wed, 7 Jan 2004 20:37:52 +0000 (20:37 +0000)
committerdrh <drh@noemail.net>
Wed, 7 Jan 2004 20:37:52 +0000 (20:37 +0000)
of WHERE clause terms looking for NULLs.  See also check-in (1103). (CVS 1167)

FossilOrigin-Name: 5fd581787e88173f0303f870fc956ec9285cca4e

manifest
manifest.uuid
src/vdbe.c
src/where.c

index d485735a1dc7cfef9dbe65895c868cf950f13b83..80558853f079d9b846de2476af8df37068b7d078 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Permit\ssqlite_exec()\sto\sbe\scalled\sfrom\swithin\suser-defined\sfunctions.\s(CVS\s1166)
-D 2004-01-07T19:24:48
+C Rework\sthe\sfix\sto\sticket\s#461\sso\sthat\swe\sdo\snot\shave\sto\sdo\sredundant\stests\nof\sWHERE\sclause\sterms\slooking\sfor\sNULLs.\s\sSee\salso\scheck-in\s(1103).\s(CVS\s1167)
+D 2004-01-07T20:37:52
 F Makefile.in 0515ff9218ad8d5a8f6220f0494b8ef94c67013b
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -63,11 +63,11 @@ F src/trigger.c ce83e017b407d046e909d05373d7f8ee70f9f7f9
 F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397
 F src/util.c 64995b5949a5d377629ffd2598747bc771cade1e
 F src/vacuum.c 77485a64a6e4e358170f150fff681c1624a092b0
-F src/vdbe.c 651fcdac5c865711169d5046836b31bd81e0cb8a
+F src/vdbe.c ff3551cbe96d31ec50e6a0fef654d69c8cd9ab91
 F src/vdbe.h 3957844e46fea71fd030e78f6a3bd2f7e320fb43
 F src/vdbeInt.h eab39bc209b267271bc4afbcf4991d6c229bae9a
 F src/vdbeaux.c 6f2d43643f83656b2555b7ee320397805db11d4c
-F src/where.c 724c7b82938b2b52602e583c1c3a719eec17003c
+F src/where.c 5b149c9851954156679741ea25b058c09f91bbfa
 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d
 F test/attach2.test d0105f4e8b1debf0ac25ed7df986b5854620e172
@@ -179,7 +179,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3
 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
-P d3e96da20d269a068188915b3cc0eb02d330d316
-R ed517c12ad32df3998805d703dfd3733
+P 03636c94a542b1f90a3acfbe65a9c2976872073f
+R 747698ac4eca9128ab63b6b98ff5a6c2
 U drh
-Z 9db3a07230e97c9741564f07ae589d3e
+Z af269badac40ad362e9b5738b29d6b42
index 03c751170c3077f47fa859917cfa36df4485b577..42d2dbe1b5403ca3de8b9600307c33224183374e 100644 (file)
@@ -1 +1 @@
-03636c94a542b1f90a3acfbe65a9c2976872073f
\ No newline at end of file
+5fd581787e88173f0303f870fc956ec9285cca4e
\ No newline at end of file
index 667591e22b14b4a526bb83ec295b97781edae8c9..8e01614ddac01159a77c578355a5d48ef771a2a9 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.248 2004/01/07 19:24:48 drh Exp $
+** $Id: vdbe.c,v 1.249 2004/01/07 20:37:52 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1797,8 +1797,8 @@ case OP_IfNot: {
 /* Opcode: IsNull P1 P2 *
 **
 ** If any of the top abs(P1) values on the stack are NULL, then jump
-** to P2.  The stack is popped P1 times if P1>0.  If P1<0 then all values
-** are left unchanged on the stack.
+** to P2.  Pop the stack P1 times if P1>0.   If P1<0 leave the stack
+** unchanged.
 */
 case OP_IsNull: {
   int i, cnt;
@@ -1817,14 +1817,18 @@ case OP_IsNull: {
 
 /* Opcode: NotNull P1 P2 *
 **
-** Jump to P2 if the top value on the stack is not NULL.  Pop the
-** stack if P1 is greater than zero.  If P1 is less than or equal to
-** zero then leave the value on the stack.
+** Jump to P2 if the top P1 values on the stack are all not NULL.  Pop the
+** stack if P1 times if P1 is greater than zero.  If P1 is less than
+** zero then leave the stack unchanged.
 */
 case OP_NotNull: {
-  VERIFY( if( p->tos<0 ) goto not_enough_stack; )
-  if( (aStack[p->tos].flags & STK_Null)==0 ) pc = pOp->p2-1;
-  if( pOp->p1>0 ){ POPSTACK; }
+  int i, cnt;
+  cnt = pOp->p1;
+  if( cnt<0 ) cnt = -cnt;
+  VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; )
+  for(i=0; i<cnt && (aStack[p->tos-i].flags & STK_Null)==0; i++){}
+  if( i>=cnt ) pc = pOp->p2-1;
+  if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt);
   break;
 }
 
@@ -3027,6 +3031,16 @@ case OP_KeyAsData: {
 ** If the cursor is not pointing to a valid row, a NULL is pushed
 ** onto the stack.
 */
+/* Opcode: RowKey P1 * *
+**
+** Push onto the stack the complete row key for cursor P1.
+** There is no interpretation of the key.  It is just copied
+** onto the stack exactly as it is found in the database file.
+**
+** If the cursor is not pointing to a valid row, a NULL is pushed
+** onto the stack.
+*/
+case OP_RowKey:
 case OP_RowData: {
   int i = pOp->p1;
   int tos = ++p->tos;
@@ -3043,7 +3057,7 @@ case OP_RowData: {
     if( pC->nullRow ){
       aStack[tos].flags = STK_Null;
       break;
-    }else if( pC->keyAsData ){
+    }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){
       sqliteBtreeKeySize(pCrsr, &n);
     }else{
       sqliteBtreeDataSize(pCrsr, &n);
@@ -3058,7 +3072,7 @@ case OP_RowData: {
       aStack[tos].flags = STK_Str | STK_Dyn;
       zStack[tos] = z;
     }
-    if( pC->keyAsData ){
+    if( pC->keyAsData || pOp->opcode==OP_RowKey ){
       sqliteBtreeKey(pCrsr, 0, n, zStack[tos]);
     }else{
       sqliteBtreeData(pCrsr, 0, n, zStack[tos]);
@@ -3557,6 +3571,37 @@ case OP_IdxGE: {
   break;
 }
 
+/* Opcode: IdxIsNull P1 P2 *
+**
+** The top of the stack contains an index entry such as might be generated
+** by the MakeIdxKey opcode.  This routine looks at the first P1 fields of
+** that key.  If any of the first P1 fields are NULL, then a jump is made
+** to address P2.  Otherwise we fall straight through.
+**
+** The index entry is always popped from the stack.
+*/
+case OP_IdxIsNull: {
+  int i = pOp->p1;
+  int tos = p->tos;
+  int k, n;
+  const char *z;
+
+  assert( tos>=0 );
+  assert( aStack[tos].flags & STK_Str );
+  z = zStack[tos];
+  n = aStack[tos].n;
+  for(k=0; k<n && i>0; i--){
+    if( z[k]=='a' ){
+      pc = pOp->p2-1;
+      break;
+    }
+    while( k<n && z[k] ){ k++; }
+    k++;
+  }
+  POPSTACK;
+  break;
+}
+
 /* Opcode: Destroy P1 P2 *
 **
 ** Delete an entire database table or index whose root page in the database
index e05783b2549afc4b0f14af2c9883a4d51485cbf9..b93e2ceb21ca1c7bcff4bc812a6738809c1e74c4 100644 (file)
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** the WHERE clause of SQL statements.
 **
-** $Id: where.c,v 1.85 2003/12/10 01:31:21 drh Exp $
+** $Id: where.c,v 1.86 2004/01/07 20:37:52 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -764,7 +764,7 @@ WhereInfo *sqliteWhereBegin(
           ){
             if( pX->op==TK_EQ ){
               sqliteExprCode(pParse, pX->pRight);
-              /* aExpr[k].p = 0; // See ticket #461 */
+              aExpr[k].p = 0;
               break;
             }
             if( pX->op==TK_IN && nColumn==1 ){
@@ -781,7 +781,7 @@ WhereInfo *sqliteWhereBegin(
                 pLevel->inOp = OP_Next;
                 pLevel->inP1 = pX->iTable;
               }
-              /* aExpr[k].p = 0; // See ticket #461 */
+              aExpr[k].p = 0;
               break;
             }
           }
@@ -791,13 +791,16 @@ WhereInfo *sqliteWhereBegin(
              && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
           ){
             sqliteExprCode(pParse, aExpr[k].p->pLeft);
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
         }
       }
       pLevel->iMem = pParse->nMem++;
       cont = pLevel->cont = sqliteVdbeMakeLabel(v);
+      sqliteVdbeAddOp(v, OP_NotNull, -nColumn, sqliteVdbeCurrentAddr(v)+3);
+      sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
+      sqliteVdbeAddOp(v, OP_Goto, 0, brk);
       sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
       sqliteAddIdxKeyType(v, pIdx);
       if( nColumn==pIdx->nColumn || pLevel->bRev ){
@@ -815,16 +818,17 @@ WhereInfo *sqliteWhereBegin(
         sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
         start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqliteVdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
-        sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
         pLevel->op = OP_Prev;
       }else{
         /* Scan in the forward order */
         sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
         start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
-        sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
         pLevel->op = OP_Next;
       }
+      sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
+      sqliteVdbeAddOp(v, OP_IdxIsNull, nColumn, cont);
+      sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
       if( i==pTabList->nSrc-1 && pushKey ){
         haveKey = 1;
       }else{
@@ -933,7 +937,7 @@ WhereInfo *sqliteWhereBegin(
              && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
           ){
             sqliteExprCode(pParse, aExpr[k].p->pRight);
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
           if( aExpr[k].idxRight==iCur
@@ -942,7 +946,7 @@ WhereInfo *sqliteWhereBegin(
              && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
           ){
             sqliteExprCode(pParse, aExpr[k].p->pLeft);
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
         }
@@ -979,7 +983,7 @@ WhereInfo *sqliteWhereBegin(
           ){
             sqliteExprCode(pParse, pExpr->pRight);
             leFlag = pExpr->op==TK_LE;
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
           if( aExpr[k].idxRight==iCur
@@ -989,7 +993,7 @@ WhereInfo *sqliteWhereBegin(
           ){
             sqliteExprCode(pParse, pExpr->pLeft);
             leFlag = pExpr->op==TK_GE;
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
         }
@@ -999,8 +1003,12 @@ WhereInfo *sqliteWhereBegin(
         leFlag = 1;
       }
       if( testOp!=OP_Noop ){
+        int nCol = nEqColumn + (score & 1);
         pLevel->iMem = pParse->nMem++;
-        sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + (score & 1), 0);
+        sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
+        sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
+        sqliteVdbeAddOp(v, OP_Goto, 0, brk);
+        sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
         sqliteAddIdxKeyType(v, pIdx);
         if( leFlag ){
           sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
@@ -1034,7 +1042,7 @@ WhereInfo *sqliteWhereBegin(
           ){
             sqliteExprCode(pParse, pExpr->pRight);
             geFlag = pExpr->op==TK_GE;
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
           if( aExpr[k].idxRight==iCur
@@ -1044,7 +1052,7 @@ WhereInfo *sqliteWhereBegin(
           ){
             sqliteExprCode(pParse, pExpr->pLeft);
             geFlag = pExpr->op==TK_LE;
-            /* aExpr[k].p = 0; // See ticket #461 */
+            aExpr[k].p = 0;
             break;
           }
         }
@@ -1052,7 +1060,11 @@ WhereInfo *sqliteWhereBegin(
         geFlag = 1;
       }
       if( nEqColumn>0 || (score&2)!=0 ){
-        sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + ((score&2)!=0), 0);
+        int nCol = nEqColumn + ((score&2)!=0);
+        sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
+        sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
+        sqliteVdbeAddOp(v, OP_Goto, 0, brk);
+        sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
         sqliteAddIdxKeyType(v, pIdx);
         if( !geFlag ){
           sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
@@ -1079,6 +1091,8 @@ WhereInfo *sqliteWhereBegin(
         sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
         sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
       }
+      sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
+      sqliteVdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
       sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
       if( i==pTabList->nSrc-1 && pushKey ){
         haveKey = 1;