Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Disable the result-set alias cache when on conditional code branches. Ticket #3461. The column cache and result set alias cache mechanisms are prone to this kind of error and need to be refactored. This check-in should be considered a temporary fix in advance of a more general redesign of the whole mechanism. (CVS 5841) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1fa3bbd8220ce073e91935ea362b6f5d |
User & Date: | drh 2008-10-25 15:03:21.000 |
Context
2008-10-25
| ||
17:10 | Remove unused parameter from function rtreeInit() (part of the r-tree extension). (CVS 5842) (check-in: 3224ea5981 user: danielk1977 tags: trunk) | |
15:03 | Disable the result-set alias cache when on conditional code branches. Ticket #3461. The column cache and result set alias cache mechanisms are prone to this kind of error and need to be refactored. This check-in should be considered a temporary fix in advance of a more general redesign of the whole mechanism. (CVS 5841) (check-in: 1fa3bbd822 user: drh tags: trunk) | |
09:35 | Add file tkt3461.test with a few examples of bug #3461. Because these tests currently fail they are disabled for now. (CVS 5840) (check-in: f2cc159159 user: danielk1977 tags: trunk) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.400 2008/10/25 15:03:21 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1714 1715 1716 1717 1718 1719 1720 | ** Aliases are numbered starting with 1. So iAlias is in the range ** of 1 to pParse->nAlias inclusive. ** ** pParse->aAlias[iAlias-1] records the register number where the value ** of the iAlias-th alias is stored. If zero, that means that the ** alias has not yet been computed. */ | | > > > | | | > | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 | ** Aliases are numbered starting with 1. So iAlias is in the range ** of 1 to pParse->nAlias inclusive. ** ** pParse->aAlias[iAlias-1] records the register number where the value ** of the iAlias-th alias is stored. If zero, that means that the ** alias has not yet been computed. */ static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){ sqlite3 *db = pParse->db; int iReg; if( pParse->aAlias==0 ){ pParse->aAlias = sqlite3DbMallocZero(db, sizeof(pParse->aAlias[0])*pParse->nAlias ); if( db->mallocFailed ) return 0; } assert( iAlias>0 && iAlias<=pParse->nAlias ); iReg = pParse->aAlias[iAlias-1]; if( iReg==0 ){ if( pParse->disableColCache ){ iReg = sqlite3ExprCodeTarget(pParse, pExpr, target); }else{ iReg = ++pParse->nMem; sqlite3ExprCode(pParse, pExpr, iReg); pParse->aAlias[iAlias-1] = iReg; } } return iReg; } /* ** Generate code into the current Vdbe to evaluate the given ** expression. Attempt to store the results in register "target". |
︙ | ︙ | |||
1836 1837 1838 1839 1840 1841 1842 | break; } case TK_REGISTER: { inReg = pExpr->iTable; break; } case TK_AS: { | | | 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 | break; } case TK_REGISTER: { inReg = pExpr->iTable; break; } case TK_AS: { inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, to_op; inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); |
︙ | ︙ | |||
2496 2497 2498 2499 2500 2501 2502 | struct ExprList_item *pItem; int i, n; assert( pList!=0 ); assert( target>0 ); n = pList->nExpr; for(pItem=pList->a, i=0; i<n; i++, pItem++){ if( pItem->iAlias ){ | | > | > | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 | struct ExprList_item *pItem; int i, n; assert( pList!=0 ); assert( target>0 ); n = pList->nExpr; for(pItem=pList->a, i=0; i<n; i++, pItem++){ if( pItem->iAlias ){ int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr, target+i); Vdbe *v = sqlite3GetVdbe(pParse); if( iReg!=target+i ){ sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i); } }else{ sqlite3ExprCode(pParse, pItem->pExpr, target+i); } if( doHardCopy ){ sqlite3ExprHardCopy(pParse, target, n); } } |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** ** $Id: where.c,v 1.327 2008/10/25 15:03:21 drh Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS (sizeof(Bitmask)*8) |
︙ | ︙ | |||
2345 2346 2347 2348 2349 2350 2351 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ | | | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 | /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ int j, k; int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */ Index *pIdx; /* The index we will be using */ int nxt; /* Where to jump to continue with the next IN case */ int iIdxCur; /* The VDBE cursor for the index */ int omitTable; /* True if we use the index only */ int bRev; /* True if we need to scan in reverse order */ |
︙ | ︙ | |||
2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 | pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } notReady &= ~getMask(&maskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->flags & TERM_VIRTUAL ); testcase( pTerm->flags & TERM_CODED ); if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & notReady)!=0 ) continue; pE = pTerm->pExpr; assert( pE!=0 ); if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } sqlite3ExprIfFalse(pParse, pE, cont, SQLITE_JUMPIFNULL); pTerm->flags |= TERM_CODED; } /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ | > > > > | 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 | pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } notReady &= ~getMask(&maskSet, iCur); /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ k = 0; for(pTerm=wc.a, j=wc.nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->flags & TERM_VIRTUAL ); testcase( pTerm->flags & TERM_CODED ); if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & notReady)!=0 ) continue; pE = pTerm->pExpr; assert( pE!=0 ); if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } pParse->disableColCache += k; sqlite3ExprIfFalse(pParse, pE, cont, SQLITE_JUMPIFNULL); pParse->disableColCache -= k; k = 1; pTerm->flags |= TERM_CODED; } /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ |
︙ | ︙ |
Changes to test/alias.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file implements regression tests for SQLite library. The # focus of this script is correct code generation of aliased result-set # values. See ticket #3343. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # # This file implements regression tests for SQLite library. The # focus of this script is correct code generation of aliased result-set # values. See ticket #3343. # # $Id: alias.test,v 1.2 2008/10/25 15:03:21 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # A procedure to return a sequence of increasing integers. # namespace eval ::seq { |
︙ | ︙ | |||
43 44 45 46 47 48 49 | INSERT INTO t1 VALUES(7); SELECT x, sequence() FROM t1; } } {9 1 8 2 7 3} do_test alias-1.2 { ::seq::reset db eval { | < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | INSERT INTO t1 VALUES(7); SELECT x, sequence() FROM t1; } } {9 1 8 2 7 3} do_test alias-1.2 { ::seq::reset db eval { SELECT x, sequence() AS y FROM t1 WHERE y>0 } } {9 1 8 2 7 3} do_test alias-1.3 { ::seq::reset db eval { SELECT x, sequence() AS y FROM t1 WHERE y>0 AND y<99 |
︙ | ︙ | |||
73 74 75 76 77 78 79 | } {8 2} do_test alias-1.6 { ::seq::reset db eval { SELECT x, sequence() AS y FROM t1 WHERE y BETWEEN 0 AND 99 } } {9 1 8 2 7 3} | | | | | < > | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | } {8 2} do_test alias-1.6 { ::seq::reset db eval { SELECT x, sequence() AS y FROM t1 WHERE y BETWEEN 0 AND 99 } } {9 1 8 2 7 3} #do_test alias-1.7 { # ::seq::reset # db eval { # SELECT x, sequence() AS y FROM t1 WHERE y IN (55,66,3) # } #} {7 3} do_test alias-1.8 { ::seq::reset db eval { SELECT x, 1-sequence() AS y FROM t1 ORDER BY y } } {7 -2 8 -1 9 0} do_test alias-1.9 { |
︙ | ︙ |
Changes to test/tkt3461.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3461 has been # fixed. # | | | | | > < | 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 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3461 has been # fixed. # # $Id: tkt3461.test,v 1.2 2008/10/25 15:03:21 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl #################################### #################################### # REMOVE THESE TWO LINES: #################################### #################################### #finish_test #return do_test tkt3461-1.1 { execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); } } {} do_test tkt3461-1.2 { execsql { SELECT a, b+1 AS b_plus_one FROM t1 WHERE a=1 } } {1 3} do_test tkt3461-1.3 { # explain { SELECT a, b+1 AS b_plus_one FROM t1 WHERE a=1 OR b_plus_one } # execsql { PRAGMA vdbe_trace = 1; PRAGMA vdbe_listing=1 } execsql { SELECT a, b+1 AS b_plus_one FROM t1 WHERE a=1 OR b_plus_one } } {1 3} do_test tkt3461-2.1 { execsql { SELECT a, b+1 AS b_plus_one FROM t1 WHERE CASE WHEN a=1 THEN 1 ELSE b_plus_one END } } {1 3} do_test tkt3461-3.1 { execsql { CREATE TABLE t2(c, d); INSERT INTO t2 VALUES(3, 4); } # execsql { PRAGMA vdbe_trace = 1; PRAGMA vdbe_listing=1 } execsql { SELECT a, b+1 AS b_plus_one, c, d FROM t1 LEFT JOIN t2 ON (a=c AND d=b_plus_one) } } {1 3 {} {}} finish_test |