From: drh Date: Wed, 19 Sep 2012 21:15:46 +0000 (+0000) Subject: Tighter VDBE code for the WHERE_DISTINCT_ORDERED case of DISTINCT keyword X-Git-Tag: version-3.7.15~123 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=053a128f5534a1c55032b9c13df40342b5323fb0;p=thirdparty%2Fsqlite.git Tighter VDBE code for the WHERE_DISTINCT_ORDERED case of DISTINCT keyword handling. FossilOrigin-Name: 94b48064db3cbb43e911fdf7183218b08146ec10 --- diff --git a/manifest b/manifest index 2ccfddd78b..4afd96e7ed 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 47d3161ee7..1ae05cab56 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82320501904f65030622a67836ba30f412169056 \ No newline at end of file +94b48064db3cbb43e911fdf7183218b08146ec10 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 656f39d6e8..fdd9931e31 100644 --- a/src/select.c +++ b/src/select.c @@ -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; iExprnExpr; iExpr++){ + iJump = sqlite3VdbeCurrentAddr(v) + pEList->nExpr; + for(iExpr=0; iExpra[iExpr].pExpr); - sqlite3VdbeAddOp3(v, OP_Ne, iBase+iExpr, iJump, iBase2+iExpr); + if( iExpriContinue, + 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{ diff --git a/src/vdbe.c b/src/vdbe.c index 68b0ebb93e..b1772c3f42 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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. diff --git a/src/vdbeInt.h b/src/vdbeInt.h index e559bc2bd2..aecada6038 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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 diff --git a/test/distinct.test b/test/distinct.test index 1e87246cf4..0d32628ef3 100644 --- a/test/distinct.test +++ b/test/distinct.test @@ -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