Tighter VDBE code for the WHERE_DISTINCT_ORDERED case of DISTINCT keyword
handling. FossilOrigin-Name: 94b48064db3cbb43e911fdf7183218b08146ec10
This commit is contained in:
parent
ae651d614e
commit
053a128f55
18
manifest
18
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
|
||||
|
@ -1 +1 @@
|
||||
82320501904f65030622a67836ba30f412169056
|
||||
94b48064db3cbb43e911fdf7183218b08146ec10
|
32
src/select.c
32
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; 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{
|
||||
|
29
src/vdbe.c
29
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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user