Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Do not allow temporary registers to be in use across an OP_Yield within a co-routine. Fix for ticket [8c63ff0eca81a9132d8]. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
97a8c9733cba97c78e979dfd5c66610c |
User & Date: | drh 2014-02-25 21:55:16.402 |
Context
2014-02-26
| ||
02:26 | Improved handling of constants and especially constant functions in the ORDER BY clause of a query. Do not optimize out "ORDER BY random()". Fix for ticket [65bdeb9739605cc2296]. (check-in: dca1945aeb user: drh tags: trunk) | |
2014-02-25
| ||
21:55 | Do not allow temporary registers to be in use across an OP_Yield within a co-routine. Fix for ticket [8c63ff0eca81a9132d8]. (check-in: 97a8c9733c user: drh tags: trunk) | |
18:12 | Also adjust the order of files in the amalgamation to ensure that _FILE_OFFSET_BITS is defined before any #include, for QNX. (check-in: 23001a85cd user: drh tags: trunk) | |
Changes
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2354 2355 2356 2357 2358 2359 2360 | char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ | < | 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 | char *zErrMsg; /* An error message */ Vdbe *pVdbe; /* An engine for executing database bytecode */ int rc; /* Return code from execution */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 checkSchema; /* Causes schema cookie check after an error */ u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 nColCache; /* Number of entries in aColCache[] */ u8 iColCache; /* Next entry in aColCache[] to replace */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ int aTempReg[8]; /* Holding area for temporary registers */ |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
2849 2850 2851 2852 2853 2854 2855 | ){ /* Case 2: We can directly reference a single row using an ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); | < > > | 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 | ){ /* Case 2: We can directly reference a single row using an ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ assert( pLoop->u.btree.nEq==1 ); pTerm = pLoop->aLTerm[0]; assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); |
︙ | ︙ | |||
2944 2945 2946 2947 2948 2949 2950 | } start = sqlite3VdbeCurrentAddr(v); pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ | | | 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 | } start = sqlite3VdbeCurrentAddr(v); pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); VdbeCoverageIf(v, testOp==OP_Le); VdbeCoverageIf(v, testOp==OP_Lt); VdbeCoverageIf(v, testOp==OP_Ge); VdbeCoverageIf(v, testOp==OP_Gt); |
︙ | ︙ | |||
3177 3178 3179 3180 3181 3182 3183 | /* Seek the table cursor, if required */ disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ | | | 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 | /* Seek the table cursor, if required */ disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ }else{ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; j<pPk->nKeyCol; j++){ |
︙ | ︙ | |||
3525 3526 3527 3528 3529 3530 3531 | continue; } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } | < | 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 | continue; } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } return pLevel->notReady; } #if defined(WHERETRACE_ENABLED) && defined(SQLITE_ENABLE_TREE_EXPLAIN) /* ** Generate "Explanation" text for a WhereTerm. |
︙ | ︙ |
Added test/tkt-8c63ff0ec.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 | # 2014-02-25 # # 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. # #*********************************************************************** # # Test cases to show that ticket [8c63ff0eca81a9132d8d67b31cd6ae9712a2cc6f] # "Incorrect query result on a UNION ALL" which was caused by using the same # temporary register in concurrent co-routines, as been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix tkt-8c63ff0ec do_execsql_test 1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e); INSERT INTO t1 VALUES(1,20,30,40,50),(3,60,70,80,90); CREATE TABLE t2(x INTEGER PRIMARY KEY); INSERT INTO t2 VALUES(2); CREATE TABLE t3(z); INSERT INTO t3 VALUES(2),(2),(2),(2); SELECT a, b+c FROM t1 UNION ALL SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 ORDER BY a; } {1 50 2 5 2 5 2 5 2 5 3 130} do_execsql_test 1.2 { SELECT a, b+c+d FROM t1 UNION ALL SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 ORDER BY a; } {1 90 2 5 2 5 2 5 2 5 3 210} do_execsql_test 1.3 { SELECT a, b+c+d+e FROM t1 UNION ALL SELECT x, 5 FROM t2 JOIN t3 ON z=x WHERE x=2 ORDER BY a; } {1 140 2 5 2 5 2 5 2 5 3 300} finish_test |