]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Tighter VDBE code for the WHERE_DISTINCT_ORDERED case of DISTINCT keyword
authordrh <drh@noemail.net>
Wed, 19 Sep 2012 21:15:46 +0000 (21:15 +0000)
committerdrh <drh@noemail.net>
Wed, 19 Sep 2012 21:15:46 +0000 (21:15 +0000)
handling.

FossilOrigin-Name: 94b48064db3cbb43e911fdf7183218b08146ec10

manifest
manifest.uuid
src/select.c
src/vdbe.c
src/vdbeInt.h
test/distinct.test

index 2ccfddd78bee9351c394c0803b68022f2fd83925..4afd96e7ed49971a41f065fdb23196b26b0ef1cc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\scomments\sto\sthe\sWHERE_DISTINCT_*\smacros.\s\sNo\schanges\sto\scode.
-D 2012-09-19T17:31:15.874
+C Tighter\sVDBE\scode\sfor\sthe\sWHERE_DISTINCT_ORDERED\scase\sof\sDISTINCT\skeyword\nhandling.
+D 2012-09-19T21:15:46.053
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -174,7 +174,7 @@ F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
 F src/resolve.c 9e28280ec98035f31900fdd1db01f86f68ca6c32
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c 1278b07a8c9a7f2f65b8efa8565993a56c4a58a3
+F src/select.c 63206bbfd19e0f85e609307041db9276ddf9f2c2
 F src/shell.c 87953c5d9c73d9494db97d1607e2e2280418f261
 F src/sqlite.h.in c76c38f9635590ff5844684a7976843878327137
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
@@ -236,9 +236,9 @@ F src/update.c 28d2d098b43a2c70dae399896ea8a02f622410ef
 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
 F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
 F src/vacuum.c 587a52bb8833d7ac15af8916f25437e2575028bd
-F src/vdbe.c 16e894bd59d11c4a2c184627906c794a6bdc6eff
+F src/vdbe.c b0ac98789b74dfd58106578aee425c094ecb5c53
 F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
-F src/vdbeInt.h a668b303644377433e31a18d3d9efb87eefb6332
+F src/vdbeInt.h 573a43ab5697b648a1e8f3dfc7d8667d5ca55729
 F src/vdbeapi.c 4c2418161cf45392ba76a7ca92f9a5f06b96f89c
 F src/vdbeaux.c fac025c798ad19070451b41eddc5dcd4696fdd1e
 F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
@@ -374,7 +374,7 @@ F test/descidx1.test 533dcbda614b0463b0ea029527fd27e5a9ab2d66
 F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
 F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
 F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
-F test/distinct.test 328c3930fc00da96147351aa48f91bd085ed226a
+F test/distinct.test c239558222e5ae357aade535bfe61aaabcb00bbf
 F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
 F test/e_createtable.test 0a2465736199cb5e084645a8714ee04299b81721
 F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5
@@ -1016,7 +1016,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
-P ddd5d789e7ae4a66cd7b7fa79e48d2777f95350b
-R e46138ca39f138f4ac7a97431cbdd838
+P 82320501904f65030622a67836ba30f412169056
+R 9541e63a94fc58e6e6ac938d40479670
 U drh
-Z 26ec9a3d31b656e70959884bbce24366
+Z 981d7e657532e16949d872fc02730646
index 47d3161ee701095bbba5e0808a8d9e3d9936b14c..1ae05cab56c845082fbd219b6e339b886068f13d 100644 (file)
@@ -1 +1 @@
-82320501904f65030622a67836ba30f412169056
\ No newline at end of file
+94b48064db3cbb43e911fdf7183218b08146ec10
\ No newline at end of file
index 656f39d6e8b8e7cc225069af5eb277e4a82b0df4..fdd9931e31540d35b926dbcde66efd767cd21eeb 100644 (file)
@@ -4059,29 +4059,35 @@ int sqlite3Select(
       if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED ){
         int iJump;
         int iExpr;
-        int iFlag = ++pParse->nMem;
+        int nExpr = pEList->nExpr;
         int iBase = pParse->nMem+1;
-        int iBase2 = iBase + pEList->nExpr;
+        int iBase2 = iBase + nExpr;
         pParse->nMem += (pEList->nExpr*2);
 
-        /* Change the OP_OpenEphemeral coded earlier to an OP_Integer. The
-        ** OP_Integer initializes the "first row" flag.  */
-        pOp->opcode = OP_Integer;
+        /* Change the OP_OpenEphemeral coded earlier to an OP_Null
+        ** sets the MEM_Cleared bit on the first register of the
+        ** previous value.  This will cause the OP_Ne below to always
+        ** fail on the first iteration of the loop even if the first
+        ** row is all NULLs.
+        */
+        pOp->opcode = OP_Null;
         pOp->p1 = 1;
-        pOp->p2 = iFlag;
+        pOp->p2 = iBase2;
+        pOp->p3 = iBase2 + nExpr - 1;
 
         sqlite3ExprCodeExprList(pParse, pEList, iBase, 1);
-        iJump = sqlite3VdbeCurrentAddr(v) + 1 + pEList->nExpr + 1 + 1;
-        sqlite3VdbeAddOp2(v, OP_If, iFlag, iJump-1);
-        for(iExpr=0; iExpr<pEList->nExpr; iExpr++){
+        iJump = sqlite3VdbeCurrentAddr(v) + pEList->nExpr;
+        for(iExpr=0; iExpr<nExpr; iExpr++){
           CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[iExpr].pExpr);
-          sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
+          if( iExpr<nExpr-1 ){
+            sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr);
+          }else{
+            sqlite3VdbeAddOp3(v, OP_Eq, iBase+iExpr, pWInfo->iContinue,
+                              iBase2+iExpr);
+          }
           sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
           sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
         }
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iContinue);
-
-        sqlite3VdbeAddOp2(v, OP_Integer, 0, iFlag);
         assert( sqlite3VdbeCurrentAddr(v)==iJump );
         sqlite3VdbeAddOp3(v, OP_Move, iBase, iBase2, pEList->nExpr);
       }else{
index 68b0ebb93efaaf8c234311e6ccffad55ec58bf31..b1772c3f42223741661b23917bdcc0d93df97bb6 100644 (file)
@@ -956,23 +956,28 @@ case OP_String: {          /* out2-prerelease */
   break;
 }
 
-/* Opcode: Null * P2 P3 * *
+/* Opcode: Null P1 P2 P3 * *
 **
 ** Write a NULL into registers P2.  If P3 greater than P2, then also write
-** NULL into register P3 and ever register in between P2 and P3.  If P3
+** NULL into register P3 and every register in between P2 and P3.  If P3
 ** is less than P2 (typically P3 is zero) then only register P2 is
-** set to NULL
+** set to NULL.
+**
+** If the P1 value is non-zero, then also set the MEM_Cleared flag so that
+** NULL values will not compare equal even if SQLITE_NULLEQ is set on
+** OP_Ne or OP_Eq.
 */
 case OP_Null: {           /* out2-prerelease */
   int cnt;
+  u16 nullFlag;
   cnt = pOp->p3-pOp->p2;
   assert( pOp->p3<=p->nMem );
-  pOut->flags = MEM_Null;
+  pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
   while( cnt>0 ){
     pOut++;
     memAboutToChange(p, pOut);
     VdbeMemRelease(pOut);
-    pOut->flags = MEM_Null;
+    pOut->flags = nullFlag;
     cnt--;
   }
   break;
@@ -1737,6 +1742,10 @@ case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
 **
 ** If the SQLITE_STOREP2 bit of P5 is set, then do not jump.  Instead,
 ** store a boolean result (either 0, or 1, or NULL) in register P2.
+**
+** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
+** equal to one another, provided that they do not have their MEM_Cleared
+** bit set.
 */
 /* Opcode: Ne P1 P2 P3 P4 P5
 **
@@ -1803,7 +1812,15 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
       ** or not both operands are null.
       */
       assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
-      res = (flags1 & flags3 & MEM_Null)==0;
+      assert( (flags1 & MEM_Cleared)==0 );
+      if( (flags1&MEM_Null)!=0
+       && (flags3&MEM_Null)!=0
+       && (flags3&MEM_Cleared)==0
+      ){
+        res = 0;  /* Results are equal */
+      }else{
+        res = 1;  /* Results are not equal */
+      }
     }else{
       /* SQLITE_NULLEQ is clear and at least one operand is NULL,
       ** then the result is always NULL.
index e559bc2bd286fe888a1989876b3393fec2c6d1f7..aecada60383e7621cb4edaae5505fa6985e47c82 100644 (file)
@@ -187,7 +187,9 @@ struct Mem {
 #define MEM_RowSet    0x0020   /* Value is a RowSet object */
 #define MEM_Frame     0x0040   /* Value is a VdbeFrame object */
 #define MEM_Invalid   0x0080   /* Value is undefined */
-#define MEM_TypeMask  0x00ff   /* Mask of type bits */
+#define MEM_Cleared   0x0100   /* NULL set by OP_Null, not from data */
+#define MEM_TypeMask  0x01ff   /* Mask of type bits */
+
 
 /* Whenever Mem contains a valid string or blob representation, one of
 ** the following flags must be set to determine the memory management
index 1e87246cf43708a0dd0e1ba1ce62d57a73893d6c..0d32628ef3ca7069cd5087a17e3793490329da75 100644 (file)
@@ -178,7 +178,23 @@ do_execsql_test 2.A {
   SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o ORDER BY rowid;
 } {a A a A}
 
-
-
+do_test 3.0 {
+  db eval {
+    CREATE TABLE t3(a INTEGER, b INTEGER, c, UNIQUE(a,b));
+    INSERT INTO t3 VALUES
+        (null, null, 1),
+        (null, null, 2),
+        (null, 3, 4),
+        (null, 3, 5),
+        (6, null, 7),
+        (6, null, 8);
+    SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
+  }
+} {{} {} {} 3 6 {}}
+do_test 3.1 {
+  regexp {OpenEphemeral} [db eval {
+    EXPLAIN SELECT DISTINCT a, b FROM t3 ORDER BY +a, +b;
+  }]
+} {0}
 
 finish_test