/ Check-in [c5c53152]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c5c53152d68218bb5e7f922271dd7c50da2361c1
User & Date: drh 2010-12-06 18:50:32
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: fa9eef86 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: c5c53152 user: drh tags: trunk
17:11
Have sqlite3_blob_bytes() return 0 following a failed call to sqlite3_reopen_blob(). check-in: 476a8b49 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/expr.c.

  1651   1651           SelectDest dest;
  1652   1652           ExprList *pEList;
  1653   1653   
  1654   1654           assert( !isRowid );
  1655   1655           sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
  1656   1656           dest.affinity = (u8)affinity;
  1657   1657           assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
         1658  +        pExpr->x.pSelect->iLimit = 0;
  1658   1659           if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
  1659   1660             return 0;
  1660   1661           }
  1661   1662           pEList = pExpr->x.pSelect->pEList;
  1662   1663           if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ 
  1663   1664             keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
  1664   1665                 pEList->a[0].pExpr);
................................................................................
  1751   1752           dest.eDest = SRT_Exists;
  1752   1753           sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
  1753   1754           VdbeComment((v, "Init EXISTS result"));
  1754   1755         }
  1755   1756         sqlite3ExprDelete(pParse->db, pSel->pLimit);
  1756   1757         pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
  1757   1758                                     &sqlite3IntTokens[1]);
         1759  +      pSel->iLimit = 0;
  1758   1760         if( sqlite3Select(pParse, pSel, &dest) ){
  1759   1761           return 0;
  1760   1762         }
  1761   1763         rReg = dest.iParm;
  1762   1764         ExprSetIrreducible(pExpr);
  1763   1765         break;
  1764   1766       }
................................................................................
  3029   3031       pExpr->op2 = pExpr->op;
  3030   3032       pExpr->op = TK_REGISTER;
  3031   3033       pExpr->iTable = r2;
  3032   3034       return WRC_Prune;
  3033   3035     }
  3034   3036     return WRC_Continue;
  3035   3037   }
         3038  +
         3039  +/* This routine is part of the parse-tree walker for
         3040  +** sqlite3ExprCodeConstants().  Simply return WRC_Continue so that
         3041  +** tree walker logic will extend constant extraction and precoding
         3042  +** into subqueires.
         3043  +*/
         3044  +static int evalConstSelect(Walker *pNotUsed1, Select *pNotUsed2){
         3045  +  UNUSED_PARAMETER(pNotUsed1);
         3046  +  UNUSED_PARAMETER(pNotUsed2);
         3047  +  return WRC_Continue;
         3048  +}
  3036   3049   
  3037   3050   /*
  3038   3051   ** Preevaluate constant subexpressions within pExpr and store the
  3039   3052   ** results in registers.  Modify pExpr so that the constant subexpresions
  3040   3053   ** are TK_REGISTER opcodes that refer to the precomputed values.
  3041   3054   */
  3042   3055   void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
  3043   3056     Walker w;
         3057  +  if( pParse->cookieGoto ) return;
  3044   3058     w.xExprCallback = evalConstExpr;
  3045         -  w.xSelectCallback = 0;
         3059  +  w.xSelectCallback = evalConstSelect;
  3046   3060     w.pParse = pParse;
  3047   3061     sqlite3WalkExpr(&w, pExpr);
  3048   3062   }
  3049   3063   
  3050   3064   
  3051   3065   /*
  3052   3066   ** Generate code that pushes the value of every element of the given

Added test/tkt-80ba201079.test.

            1  +# 2010 December 6
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library. Specifically,
           12  +# it tests that ticket [80ba201079ea608071d22a57856b940ea3ac53ce] is
           13  +# resolved.  That ticket is about an incorrect result that appears when
           14  +# an index is added.  The root cause is that a constant is being used
           15  +# without initialization when the OR optimization applies in the WHERE clause.
           16  +#
           17  +
           18  +set testdir [file dirname $argv0]
           19  +source $testdir/tester.tcl
           20  +
           21  +do_test tkt-80ba2-100 {
           22  +  db eval {
           23  +    CREATE TABLE t1(a);
           24  +    INSERT INTO t1 VALUES('A');
           25  +    CREATE TABLE t2(b);
           26  +    INSERT INTO t2 VALUES('B');
           27  +    CREATE TABLE t3(c);
           28  +    INSERT INTO t3 VALUES('C');
           29  +    SELECT * FROM t1, t2
           30  +     WHERE (a='A' AND b='X')
           31  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
           32  +  }
           33  +} {A B}
           34  +do_test tkt-80ba2-101 {
           35  +  db eval {
           36  +    CREATE INDEX i1 ON t1(a);
           37  +    SELECT * FROM t1, t2
           38  +     WHERE (a='A' AND b='X')
           39  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
           40  +  }
           41  +} {A B}
           42  +
           43  +do_test tkt-80ba2-200 {
           44  +  db eval {
           45  +    CREATE TABLE entry_types (
           46  +                        id     integer primary key,
           47  +                        name   text
           48  +                    );
           49  +    INSERT INTO "entry_types" VALUES(100,'cli_command');
           50  +    INSERT INTO "entry_types" VALUES(300,'object_change');
           51  +    CREATE TABLE object_changes (
           52  +                        change_id    integer primary key,
           53  +                        system_id    int,
           54  +                        obj_id       int,
           55  +                        obj_context  text,
           56  +                        change_type  int,
           57  +                        command_id   int
           58  +                    );
           59  +    INSERT INTO "object_changes" VALUES(1551,1,114608,'exported_pools',1,2114);
           60  +    INSERT INTO "object_changes" VALUES(2048,1,114608,'exported_pools',2,2319);
           61  +    CREATE TABLE timeline (
           62  +                        rowid        integer primary key,
           63  +                        timestamp    text,
           64  +                        system_id    int,
           65  +                        entry_type   int,
           66  +                        entry_id     int
           67  +                    );
           68  +    INSERT INTO "timeline" VALUES(6735,'2010-11-21 17:08:27.000',1,300,2048);
           69  +    INSERT INTO "timeline" VALUES(6825,'2010-11-21 17:09:21.000',1,300,2114);
           70  +    SELECT entry_type,
           71  +           entry_types.name,
           72  +           entry_id
           73  +      FROM timeline JOIN entry_types ON entry_type = entry_types.id
           74  +     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
           75  +        OR (entry_types.name = 'object_change'
           76  +             AND entry_id IN (SELECT change_id
           77  +                              FROM object_changes
           78  +                               WHERE obj_context = 'exported_pools'));
           79  +  }
           80  +} {300 object_change 2048}
           81  +do_test tkt-80ba2-201 {
           82  +  db eval {
           83  +    CREATE INDEX timeline_entry_id_idx on timeline(entry_id);
           84  +    SELECT entry_type,
           85  +           entry_types.name,
           86  +           entry_id
           87  +      FROM timeline JOIN entry_types ON entry_type = entry_types.id
           88  +     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
           89  +        OR (entry_types.name = 'object_change'
           90  +             AND entry_id IN (SELECT change_id
           91  +                              FROM object_changes
           92  +                               WHERE obj_context = 'exported_pools'));
           93  +  }
           94  +} {300 object_change 2048}
           95  +
           96  +finish_test