Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Initialize all constants at the very beginning of a prepared statement. Do not allow constant initialization to occur once control flow has a chance to diverge, to avoid the possibility of having uninitialized registers. Ticket [80ba201079ea60807]. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c5c53152d68218bb5e7f922271dd7c50 |
User & Date: | drh 2010-12-06 18:50:32.000 |
Context
2010-12-06
| ||
18:59 | Back out part of the previous change that was not really necessary in order to fix [80ba201079ea60], and which in fact serves no useful purpose. (check-in: fa9eef865f user: drh tags: trunk) | |
18:50 | Initialize all constants at the very beginning of a prepared statement. Do not allow constant initialization to occur once control flow has a chance to diverge, to avoid the possibility of having uninitialized registers. Ticket [80ba201079ea60807]. (check-in: c5c53152d6 user: drh tags: trunk) | |
17:11 | Have sqlite3_blob_bytes() return 0 following a failed call to sqlite3_reopen_blob(). (check-in: 476a8b4921 user: dan tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 | SelectDest dest; ExprList *pEList; assert( !isRowid ); sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ return 0; } pEList = pExpr->x.pSelect->pEList; if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pEList->a[0].pExpr); | > | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 | SelectDest dest; ExprList *pEList; assert( !isRowid ); sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pExpr->x.pSelect->iLimit = 0; if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ return 0; } pEList = pExpr->x.pSelect->pEList; if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pEList->a[0].pExpr); |
︙ | ︙ | |||
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[1]); if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } rReg = dest.iParm; ExprSetIrreducible(pExpr); break; } | > | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 | dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[1]); pSel->iLimit = 0; if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } rReg = dest.iParm; ExprSetIrreducible(pExpr); break; } |
︙ | ︙ | |||
3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 | pExpr->op2 = pExpr->op; pExpr->op = TK_REGISTER; pExpr->iTable = r2; return WRC_Prune; } return WRC_Continue; } /* ** Preevaluate constant subexpressions within pExpr and store the ** results in registers. Modify pExpr so that the constant subexpresions ** are TK_REGISTER opcodes that refer to the precomputed values. */ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; w.xExprCallback = evalConstExpr; | > > > > > > > > > > > > | | 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 | pExpr->op2 = pExpr->op; pExpr->op = TK_REGISTER; pExpr->iTable = r2; return WRC_Prune; } return WRC_Continue; } /* This routine is part of the parse-tree walker for ** sqlite3ExprCodeConstants(). Simply return WRC_Continue so that ** tree walker logic will extend constant extraction and precoding ** into subqueires. */ static int evalConstSelect(Walker *pNotUsed1, Select *pNotUsed2){ UNUSED_PARAMETER(pNotUsed1); UNUSED_PARAMETER(pNotUsed2); return WRC_Continue; } /* ** Preevaluate constant subexpressions within pExpr and store the ** results in registers. Modify pExpr so that the constant subexpresions ** are TK_REGISTER opcodes that refer to the precomputed values. */ void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){ Walker w; if( pParse->cookieGoto ) return; w.xExprCallback = evalConstExpr; w.xSelectCallback = evalConstSelect; w.pParse = pParse; sqlite3WalkExpr(&w, pExpr); } /* ** Generate code that pushes the value of every element of the given |
︙ | ︙ |
Added test/tkt-80ba201079.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | # 2010 December 6 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. Specifically, # it tests that ticket [80ba201079ea608071d22a57856b940ea3ac53ce] is # resolved. That ticket is about an incorrect result that appears when # an index is added. The root cause is that a constant is being used # without initialization when the OR optimization applies in the WHERE clause. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-80ba2-100 { db eval { CREATE TABLE t1(a); INSERT INTO t1 VALUES('A'); CREATE TABLE t2(b); INSERT INTO t2 VALUES('B'); CREATE TABLE t3(c); INSERT INTO t3 VALUES('C'); SELECT * FROM t1, t2 WHERE (a='A' AND b='X') OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C')); } } {A B} do_test tkt-80ba2-101 { db eval { CREATE INDEX i1 ON t1(a); SELECT * FROM t1, t2 WHERE (a='A' AND b='X') OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C')); } } {A B} do_test tkt-80ba2-200 { db eval { CREATE TABLE entry_types ( id integer primary key, name text ); INSERT INTO "entry_types" VALUES(100,'cli_command'); INSERT INTO "entry_types" VALUES(300,'object_change'); CREATE TABLE object_changes ( change_id integer primary key, system_id int, obj_id int, obj_context text, change_type int, command_id int ); INSERT INTO "object_changes" VALUES(1551,1,114608,'exported_pools',1,2114); INSERT INTO "object_changes" VALUES(2048,1,114608,'exported_pools',2,2319); CREATE TABLE timeline ( rowid integer primary key, timestamp text, system_id int, entry_type int, entry_id int ); INSERT INTO "timeline" VALUES(6735,'2010-11-21 17:08:27.000',1,300,2048); INSERT INTO "timeline" VALUES(6825,'2010-11-21 17:09:21.000',1,300,2114); SELECT entry_type, entry_types.name, entry_id FROM timeline JOIN entry_types ON entry_type = entry_types.id WHERE (entry_types.name = 'cli_command' AND entry_id=2114) OR (entry_types.name = 'object_change' AND entry_id IN (SELECT change_id FROM object_changes WHERE obj_context = 'exported_pools')); } } {300 object_change 2048} do_test tkt-80ba2-201 { db eval { CREATE INDEX timeline_entry_id_idx on timeline(entry_id); SELECT entry_type, entry_types.name, entry_id FROM timeline JOIN entry_types ON entry_type = entry_types.id WHERE (entry_types.name = 'cli_command' AND entry_id=2114) OR (entry_types.name = 'object_change' AND entry_id IN (SELECT change_id FROM object_changes WHERE obj_context = 'exported_pools')); } } {300 object_change 2048} finish_test |