mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Rework the column-cache mechanism to be more robust (and more correct).
The column-alias cache is currently disabled, (CVS 6538) FossilOrigin-Name: dd4d67a67454a3ff13c286a2a8360c5f0432c91d
This commit is contained in:
26
manifest
26
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Eliminate\sthe\sOP_VRowid\sopcode.\s\sThe\sregular\sOP_Rowid\snow\swork\sfor\sboth\nregular\sand\svirtual\stables.\s(CVS\s6537)
|
C Rework\sthe\scolumn-cache\smechanism\sto\sbe\smore\srobust\s(and\smore\scorrect).\nThe\scolumn-alias\scache\sis\scurrently\sdisabled,\s(CVS\s6538)
|
||||||
D 2009-04-22T17:15:03
|
D 2009-04-23T13:22:43
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
|
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -106,12 +106,12 @@ F src/btmutex.c 9b899c0d8df3bd68f527b0afe03088321b696d3c
|
|||||||
F src/btree.c b4ec46b3adc3e2d82704c949d4b654b031a64ad6
|
F src/btree.c b4ec46b3adc3e2d82704c949d4b654b031a64ad6
|
||||||
F src/btree.h 99fcc7e8c4a1e35afe271bcb38de1a698dfc904e
|
F src/btree.h 99fcc7e8c4a1e35afe271bcb38de1a698dfc904e
|
||||||
F src/btreeInt.h df64030d632f8c8ac217ed52e8b6b3eacacb33a5
|
F src/btreeInt.h df64030d632f8c8ac217ed52e8b6b3eacacb33a5
|
||||||
F src/build.c 18c5e51c2cbaab95b1d90d38f5a15005a430d047
|
F src/build.c d4c6d22636607aa3c937e619de6781e83db48b6f
|
||||||
F src/callback.c 73016376d6848ba987709e8c9048d4f0e0776036
|
F src/callback.c 73016376d6848ba987709e8c9048d4f0e0776036
|
||||||
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
|
||||||
F src/date.c d327ec7bb2f64b08d32b1035de82b9ba8675de91
|
F src/date.c d327ec7bb2f64b08d32b1035de82b9ba8675de91
|
||||||
F src/delete.c eb1066b2f35489fee46ad765d2b66386fc7d8adf
|
F src/delete.c eb1066b2f35489fee46ad765d2b66386fc7d8adf
|
||||||
F src/expr.c 51ec16f86855a0a6ba44ba9d219abb72f06fd1c8
|
F src/expr.c 015bdfc73af9d867558761cd8dc8652aa6c8cc04
|
||||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||||
F src/func.c f667fe886309707c7178542073bb0ced00a9fae7
|
F src/func.c f667fe886309707c7178542073bb0ced00a9fae7
|
||||||
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
||||||
@@ -155,11 +155,11 @@ F src/printf.c ea2d76000cc5f4579d7e9cb2f5460433eec0d384
|
|||||||
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
||||||
F src/resolve.c 094e44450371fb27869eb8bf679aacbe51fdc56d
|
F src/resolve.c 094e44450371fb27869eb8bf679aacbe51fdc56d
|
||||||
F src/rowset.c 14d12b5e81b5907b87d511f6f4219805f96a4b55
|
F src/rowset.c 14d12b5e81b5907b87d511f6f4219805f96a4b55
|
||||||
F src/select.c 35225756c247484f473678e5bd191d70a6e4dba0
|
F src/select.c b3d9b7a56e08ec007286aad55cc46f36b13b63dd
|
||||||
F src/shell.c 0a11f831603f17fea20ca97133c0f64e716af4a7
|
F src/shell.c 0a11f831603f17fea20ca97133c0f64e716af4a7
|
||||||
F src/sqlite.h.in 8e0e256079bac2319380bdfebf403fcbe630510f
|
F src/sqlite.h.in 8e0e256079bac2319380bdfebf403fcbe630510f
|
||||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||||
F src/sqliteInt.h b663bb04bc2d71d8f156f559ff267045de64787a
|
F src/sqliteInt.h 2ce7f412fbc5a56e35befea0625f05c786ddad83
|
||||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||||
@@ -195,7 +195,7 @@ F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
|
|||||||
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
|
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
|
||||||
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
||||||
F src/tokenize.c 7bd3b6dd56566604ad24ed4aa017e6618166b500
|
F src/tokenize.c 7bd3b6dd56566604ad24ed4aa017e6618166b500
|
||||||
F src/trigger.c 21f39db410cdc32166a94900ac1b3df98ea560e6
|
F src/trigger.c c029d5262768faa43962080a170bb707afa0b9d7
|
||||||
F src/update.c 9617202877aa55c585b55937e0097bf050970c67
|
F src/update.c 9617202877aa55c585b55937e0097bf050970c67
|
||||||
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
|
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
|
||||||
F src/util.c 828c552a22a1d5b650b8a5ea0009546715c45d93
|
F src/util.c 828c552a22a1d5b650b8a5ea0009546715c45d93
|
||||||
@@ -209,9 +209,9 @@ F src/vdbeblob.c e67757450ae8581a8b354d9d7e467e41502dfe38
|
|||||||
F src/vdbemem.c 111d8193859d16aefd5d3cb57472808584ea5503
|
F src/vdbemem.c 111d8193859d16aefd5d3cb57472808584ea5503
|
||||||
F src/vtab.c 6118d71c5137e20a7ac51fb5d9beb0361fbedb89
|
F src/vtab.c 6118d71c5137e20a7ac51fb5d9beb0361fbedb89
|
||||||
F src/walker.c 7cdf63223c953d4343c6833e940f110281a378ee
|
F src/walker.c 7cdf63223c953d4343c6833e940f110281a378ee
|
||||||
F src/where.c 423ed1dab78a8a62bfc4f349e7d53756b31deeaa
|
F src/where.c 6f7199cff0f05934bdadd6c67a0c14c0cbf5bcb4
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
|
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||||
F test/alter.test 645b2e8d23c9936f9494af9d2fa7f8351a248c6e
|
F test/alter.test 645b2e8d23c9936f9494af9d2fa7f8351a248c6e
|
||||||
F test/alter2.test d0133bfa7a0a24aa84c034051410b95217d24a35
|
F test/alter2.test d0133bfa7a0a24aa84c034051410b95217d24a35
|
||||||
@@ -621,7 +621,7 @@ F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
|||||||
F test/tkt3424.test 3171193ce340cff6b7ea81c03b8fa1cbc34ec36e
|
F test/tkt3424.test 3171193ce340cff6b7ea81c03b8fa1cbc34ec36e
|
||||||
F test/tkt3442.test 33722a3fa4bdc0614448044eb5e28765aea28eb7
|
F test/tkt3442.test 33722a3fa4bdc0614448044eb5e28765aea28eb7
|
||||||
F test/tkt3457.test e9ca2b90f0eb1fb8be73a30d29aacb2e3abedeb9
|
F test/tkt3457.test e9ca2b90f0eb1fb8be73a30d29aacb2e3abedeb9
|
||||||
F test/tkt3461.test 5a63e8d8ee5ce00f076b1e2f82aba5480a0f14ed
|
F test/tkt3461.test f79d027198b7e2bcf3d2d1a5501b6efef52096ee
|
||||||
F test/tkt3472.test 98c7e54b8fef2b1266a552a66c8e5d88a6908d1d
|
F test/tkt3472.test 98c7e54b8fef2b1266a552a66c8e5d88a6908d1d
|
||||||
F test/tkt3493.test 8472b3464e49a27ff7271308eec46154209e667b
|
F test/tkt3493.test 8472b3464e49a27ff7271308eec46154209e667b
|
||||||
F test/tkt3508.test d9e285ff91731247d4673f9252fe5934639d7f0d
|
F test/tkt3508.test d9e285ff91731247d4673f9252fe5934639d7f0d
|
||||||
@@ -720,7 +720,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P 1c508a99822caa383e7e24b5d09a9bddd2ee3a00
|
P ecbef45011f1f98d940b2d3492941213d9f04172
|
||||||
R 999e0378f327461c6dde395dd11ca7e1
|
R 809b7ccefbb8e27249a22441796f79d9
|
||||||
U drh
|
U drh
|
||||||
Z 6d0b2cfca513b61db3f6e2221f153ea3
|
Z 84c7a808c7a31870885d027c8c29d439
|
||||||
|
@@ -1 +1 @@
|
|||||||
ecbef45011f1f98d940b2d3492941213d9f04172
|
dd4d67a67454a3ff13c286a2a8360c5f0432c91d
|
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.529 2009/04/20 17:43:03 drh Exp $
|
** $Id: build.c,v 1.530 2009/04/23 13:22:43 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||||
sqlite3VdbeTrace(v, trace);
|
sqlite3VdbeTrace(v, trace);
|
||||||
#endif
|
#endif
|
||||||
assert( pParse->disableColCache==0 ); /* Disables and re-enables match */
|
assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
||||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
||||||
pParse->nTab, pParse->explain);
|
pParse->nTab, pParse->explain);
|
||||||
pParse->rc = SQLITE_DONE;
|
pParse->rc = SQLITE_DONE;
|
||||||
|
262
src/expr.c
262
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.427 2009/04/22 17:15:03 drh Exp $
|
** $Id: expr.c,v 1.428 2009/04/23 13:22:43 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -1463,7 +1463,7 @@ void sqlite3CodeSubselect(
|
|||||||
int testAddr = 0; /* One-time test address */
|
int testAddr = 0; /* One-time test address */
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
if( v==0 ) return;
|
if( v==0 ) return;
|
||||||
|
sqlite3ExprCachePush(pParse);
|
||||||
|
|
||||||
/* This code must be run in its entirety every time it is encountered
|
/* This code must be run in its entirety every time it is encountered
|
||||||
** if any of the following is true:
|
** if any of the following is true:
|
||||||
@@ -1570,11 +1570,7 @@ void sqlite3CodeSubselect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the expression and insert it into the temp table */
|
/* Evaluate the expression and insert it into the temp table */
|
||||||
pParse->disableColCache++;
|
|
||||||
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
|
|
||||||
if( isRowid ){
|
if( isRowid ){
|
||||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2);
|
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2);
|
||||||
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
|
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
|
||||||
@@ -1628,6 +1624,7 @@ void sqlite3CodeSubselect(
|
|||||||
if( testAddr ){
|
if( testAddr ){
|
||||||
sqlite3VdbeJumpHere(v, testAddr-1);
|
sqlite3VdbeJumpHere(v, testAddr-1);
|
||||||
}
|
}
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1705,6 +1702,120 @@ static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Clear a cache entry.
|
||||||
|
*/
|
||||||
|
static void cacheEntryClear(Parse *pParse, struct yColCache *p){
|
||||||
|
if( p->tempReg ){
|
||||||
|
if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||||
|
pParse->aTempReg[pParse->nTempReg++] = p->iReg;
|
||||||
|
}
|
||||||
|
p->tempReg = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Record in the column cache that a particular column from a
|
||||||
|
** particular table is stored in a particular register.
|
||||||
|
*/
|
||||||
|
void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
|
||||||
|
int i;
|
||||||
|
int minLru;
|
||||||
|
int idxLru;
|
||||||
|
struct yColCache *p;
|
||||||
|
|
||||||
|
/* First replace any existing entry */
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->iReg && p->iTable==iTab && p->iColumn==iCol ){
|
||||||
|
cacheEntryClear(pParse, p);
|
||||||
|
p->iLevel = pParse->iCacheLevel;
|
||||||
|
p->iReg = iReg;
|
||||||
|
p->affChange = 0;
|
||||||
|
p->lru = pParse->iCacheCnt++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( iReg<=0 ) return;
|
||||||
|
|
||||||
|
/* Find an empty slot and replace it */
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->iReg==0 ){
|
||||||
|
p->iLevel = pParse->iCacheLevel;
|
||||||
|
p->iTable = iTab;
|
||||||
|
p->iColumn = iCol;
|
||||||
|
p->iReg = iReg;
|
||||||
|
p->affChange = 0;
|
||||||
|
p->tempReg = 0;
|
||||||
|
p->lru = pParse->iCacheCnt++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace the last recently used */
|
||||||
|
minLru = 0x7fffffff;
|
||||||
|
idxLru = -1;
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->lru<minLru ){
|
||||||
|
idxLru = i;
|
||||||
|
minLru = p->lru;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( idxLru>=0 ){
|
||||||
|
p = &pParse->aColCache[idxLru];
|
||||||
|
p->iLevel = pParse->iCacheLevel;
|
||||||
|
p->iTable = iTab;
|
||||||
|
p->iColumn = iCol;
|
||||||
|
p->iReg = iReg;
|
||||||
|
p->affChange = 0;
|
||||||
|
p->tempReg = 0;
|
||||||
|
p->lru = pParse->iCacheCnt++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Indicate that a register is being overwritten. Purge the register
|
||||||
|
** from the column cache.
|
||||||
|
*/
|
||||||
|
void sqlite3ExprCacheRemove(Parse *pParse, int iReg){
|
||||||
|
int i;
|
||||||
|
struct yColCache *p;
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->iReg==iReg ){
|
||||||
|
cacheEntryClear(pParse, p);
|
||||||
|
p->iReg = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remember the current column cache context. Any new entries added
|
||||||
|
** added to the column cache after this call are removed when the
|
||||||
|
** corresponding pop occurs.
|
||||||
|
*/
|
||||||
|
void sqlite3ExprCachePush(Parse *pParse){
|
||||||
|
pParse->iCacheLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Remove from the column cache any entries that were added since the
|
||||||
|
** the previous N Push operations. In other words, restore the cache
|
||||||
|
** to the state it was in N Pushes ago.
|
||||||
|
*/
|
||||||
|
void sqlite3ExprCachePop(Parse *pParse, int N){
|
||||||
|
int i;
|
||||||
|
struct yColCache *p;
|
||||||
|
assert( N>0 );
|
||||||
|
assert( pParse->iCacheLevel>=N );
|
||||||
|
pParse->iCacheLevel -= N;
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
|
||||||
|
cacheEntryClear(pParse, p);
|
||||||
|
p->iReg = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code that will extract the iColumn-th column from
|
** Generate code that will extract the iColumn-th column from
|
||||||
@@ -1733,13 +1844,15 @@ int sqlite3ExprCodeGetColumn(
|
|||||||
int i;
|
int i;
|
||||||
struct yColCache *p;
|
struct yColCache *p;
|
||||||
|
|
||||||
for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
if( p->iTable==iTable && p->iColumn==iColumn
|
if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn
|
||||||
&& (!p->affChange || allowAffChng) ){
|
&& (!p->affChange || allowAffChng) ){
|
||||||
#if 0
|
#if 0
|
||||||
sqlite3VdbeAddOp0(v, OP_Noop);
|
sqlite3VdbeAddOp0(v, OP_Noop);
|
||||||
VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));
|
VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));
|
||||||
#endif
|
#endif
|
||||||
|
p->lru = pParse->iCacheCnt++;
|
||||||
|
p->tempReg = 0; /* This pins the register, but also leaks it */
|
||||||
return p->iReg;
|
return p->iReg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1758,37 +1871,21 @@ int sqlite3ExprCodeGetColumn(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if( pParse->disableColCache==0 ){
|
sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
|
||||||
i = pParse->iColCache;
|
|
||||||
p = &pParse->aColCache[i];
|
|
||||||
p->iTable = iTable;
|
|
||||||
p->iColumn = iColumn;
|
|
||||||
p->iReg = iReg;
|
|
||||||
p->affChange = 0;
|
|
||||||
i++;
|
|
||||||
if( i>=ArraySize(pParse->aColCache) ) i = 0;
|
|
||||||
if( i>pParse->nColCache ) pParse->nColCache = i;
|
|
||||||
pParse->iColCache = i;
|
|
||||||
}
|
|
||||||
return iReg;
|
return iReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Clear all column cache entries associated with the vdbe
|
** Clear all column cache entries.
|
||||||
** cursor with cursor number iTable.
|
|
||||||
*/
|
*/
|
||||||
void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){
|
void sqlite3ExprCacheClear(Parse *pParse){
|
||||||
if( iTable<0 ){
|
int i;
|
||||||
pParse->nColCache = 0;
|
struct yColCache *p;
|
||||||
pParse->iColCache = 0;
|
|
||||||
}else{
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
int i;
|
if( p->iReg ){
|
||||||
for(i=0; i<pParse->nColCache; i++){
|
cacheEntryClear(pParse, p);
|
||||||
if( pParse->aColCache[i].iTable==iTable ){
|
p->iReg = 0;
|
||||||
testcase( i==pParse->nColCache-1 );
|
|
||||||
pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache];
|
|
||||||
pParse->iColCache = pParse->nColCache;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1800,10 +1897,11 @@ void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){
|
|||||||
void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
|
void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
|
||||||
int iEnd = iStart + iCount - 1;
|
int iEnd = iStart + iCount - 1;
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<pParse->nColCache; i++){
|
struct yColCache *p;
|
||||||
int r = pParse->aColCache[i].iReg;
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
int r = p->iReg;
|
||||||
if( r>=iStart && r<=iEnd ){
|
if( r>=iStart && r<=iEnd ){
|
||||||
pParse->aColCache[i].affChange = 1;
|
p->affChange = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1814,12 +1912,13 @@ void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
|
|||||||
*/
|
*/
|
||||||
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||||
int i;
|
int i;
|
||||||
|
struct yColCache *p;
|
||||||
if( iFrom==iTo ) return;
|
if( iFrom==iTo ) return;
|
||||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
|
||||||
for(i=0; i<pParse->nColCache; i++){
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
int x = pParse->aColCache[i].iReg;
|
int x = p->iReg;
|
||||||
if( x>=iFrom && x<iFrom+nReg ){
|
if( x>=iFrom && x<iFrom+nReg ){
|
||||||
pParse->aColCache[i].iReg += iTo-iFrom;
|
p->iReg += iTo-iFrom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1842,32 +1941,14 @@ void sqlite3ExprCodeCopy(Parse *pParse, int iFrom, int iTo, int nReg){
|
|||||||
*/
|
*/
|
||||||
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
|
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<pParse->nColCache; i++){
|
struct yColCache *p;
|
||||||
int r = pParse->aColCache[i].iReg;
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
int r = p->iReg;
|
||||||
if( r>=iFrom && r<=iTo ) return 1;
|
if( r>=iFrom && r<=iTo ) return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** There is a value in register iReg.
|
|
||||||
**
|
|
||||||
** We are going to modify the value, so we need to make sure it
|
|
||||||
** is not a cached register. If iReg is a cached register,
|
|
||||||
** then clear the corresponding cache line.
|
|
||||||
*/
|
|
||||||
void sqlite3ExprWritableRegister(Parse *pParse, int iReg){
|
|
||||||
int i;
|
|
||||||
if( usedAsColumnCache(pParse, iReg, iReg) ){
|
|
||||||
for(i=0; i<pParse->nColCache; i++){
|
|
||||||
if( pParse->aColCache[i].iReg==iReg ){
|
|
||||||
pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache];
|
|
||||||
pParse->iColCache = pParse->nColCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If the last instruction coded is an ephemeral copy of any of
|
** If the last instruction coded is an ephemeral copy of any of
|
||||||
** the registers in the nReg registers beginning with iReg, then
|
** the registers in the nReg registers beginning with iReg, then
|
||||||
@@ -1905,6 +1986,7 @@ void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
|
|||||||
** alias has not yet been computed.
|
** alias has not yet been computed.
|
||||||
*/
|
*/
|
||||||
static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
|
static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
|
||||||
|
#if 0
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
int iReg;
|
int iReg;
|
||||||
if( pParse->nAliasAlloc<pParse->nAlias ){
|
if( pParse->nAliasAlloc<pParse->nAlias ){
|
||||||
@@ -1919,7 +2001,7 @@ static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
|
|||||||
assert( iAlias>0 && iAlias<=pParse->nAlias );
|
assert( iAlias>0 && iAlias<=pParse->nAlias );
|
||||||
iReg = pParse->aAlias[iAlias-1];
|
iReg = pParse->aAlias[iAlias-1];
|
||||||
if( iReg==0 ){
|
if( iReg==0 ){
|
||||||
if( pParse->disableColCache ){
|
if( pParse->iCacheLevel>0 ){
|
||||||
iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||||
}else{
|
}else{
|
||||||
iReg = ++pParse->nMem;
|
iReg = ++pParse->nMem;
|
||||||
@@ -1928,6 +2010,9 @@ static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return iReg;
|
return iReg;
|
||||||
|
#else
|
||||||
|
return sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2307,9 +2392,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
||||||
** pExpr->iTable contains the values that make up the (...) set.
|
** pExpr->iTable contains the values that make up the (...) set.
|
||||||
*/
|
*/
|
||||||
pParse->disableColCache++;
|
sqlite3ExprCachePush(pParse);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft, target);
|
sqlite3ExprCode(pParse, pExpr->pLeft, target);
|
||||||
pParse->disableColCache--;
|
|
||||||
j2 = sqlite3VdbeAddOp1(v, OP_IsNull, target);
|
j2 = sqlite3VdbeAddOp1(v, OP_IsNull, target);
|
||||||
if( eType==IN_INDEX_ROWID ){
|
if( eType==IN_INDEX_ROWID ){
|
||||||
j3 = sqlite3VdbeAddOp1(v, OP_MustBeInt, target);
|
j3 = sqlite3VdbeAddOp1(v, OP_MustBeInt, target);
|
||||||
@@ -2370,6 +2454,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, j2);
|
sqlite3VdbeJumpHere(v, j2);
|
||||||
sqlite3VdbeJumpHere(v, j5);
|
sqlite3VdbeJumpHere(v, j5);
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
VdbeComment((v, "end IN expr r%d", target));
|
VdbeComment((v, "end IN expr r%d", target));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2446,6 +2531,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
Expr cacheX; /* Cached expression X */
|
Expr cacheX; /* Cached expression X */
|
||||||
Expr *pX; /* The X expression */
|
Expr *pX; /* The X expression */
|
||||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||||
|
VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
|
||||||
|
|
||||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||||
assert((pExpr->x.pList->nExpr % 2) == 0);
|
assert((pExpr->x.pList->nExpr % 2) == 0);
|
||||||
@@ -2464,8 +2550,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
opCompare.pLeft = &cacheX;
|
opCompare.pLeft = &cacheX;
|
||||||
pTest = &opCompare;
|
pTest = &opCompare;
|
||||||
}
|
}
|
||||||
pParse->disableColCache++;
|
|
||||||
for(i=0; i<nExpr; i=i+2){
|
for(i=0; i<nExpr; i=i+2){
|
||||||
|
sqlite3ExprCachePush(pParse);
|
||||||
if( pX ){
|
if( pX ){
|
||||||
assert( pTest!=0 );
|
assert( pTest!=0 );
|
||||||
opCompare.pRight = aListelem[i].pExpr;
|
opCompare.pRight = aListelem[i].pExpr;
|
||||||
@@ -2479,16 +2565,18 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
|||||||
testcase( aListelem[i+1].pExpr->op==TK_REGISTER );
|
testcase( aListelem[i+1].pExpr->op==TK_REGISTER );
|
||||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
sqlite3VdbeResolveLabel(v, nextCase);
|
sqlite3VdbeResolveLabel(v, nextCase);
|
||||||
}
|
}
|
||||||
if( pExpr->pRight ){
|
if( pExpr->pRight ){
|
||||||
|
sqlite3ExprCachePush(pParse);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight, target);
|
sqlite3ExprCode(pParse, pExpr->pRight, target);
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||||
}
|
}
|
||||||
|
assert( pParse->iCacheLevel==iCacheLevel );
|
||||||
sqlite3VdbeResolveLabel(v, endLabel);
|
sqlite3VdbeResolveLabel(v, endLabel);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
@@ -2763,23 +2851,17 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
case TK_AND: {
|
case TK_AND: {
|
||||||
int d2 = sqlite3VdbeMakeLabel(v);
|
int d2 = sqlite3VdbeMakeLabel(v);
|
||||||
testcase( jumpIfNull==0 );
|
testcase( jumpIfNull==0 );
|
||||||
testcase( pParse->disableColCache==0 );
|
sqlite3ExprCachePush(pParse);
|
||||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
|
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
|
||||||
pParse->disableColCache++;
|
|
||||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
sqlite3VdbeResolveLabel(v, d2);
|
sqlite3VdbeResolveLabel(v, d2);
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_OR: {
|
case TK_OR: {
|
||||||
testcase( jumpIfNull==0 );
|
testcase( jumpIfNull==0 );
|
||||||
testcase( pParse->disableColCache==0 );
|
|
||||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||||
pParse->disableColCache++;
|
|
||||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_NOT: {
|
case TK_NOT: {
|
||||||
@@ -2923,24 +3005,18 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
case TK_AND: {
|
case TK_AND: {
|
||||||
testcase( jumpIfNull==0 );
|
testcase( jumpIfNull==0 );
|
||||||
testcase( pParse->disableColCache==0 );
|
|
||||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||||
pParse->disableColCache++;
|
|
||||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_OR: {
|
case TK_OR: {
|
||||||
int d2 = sqlite3VdbeMakeLabel(v);
|
int d2 = sqlite3VdbeMakeLabel(v);
|
||||||
testcase( jumpIfNull==0 );
|
testcase( jumpIfNull==0 );
|
||||||
testcase( pParse->disableColCache==0 );
|
sqlite3ExprCachePush(pParse);
|
||||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
|
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
|
||||||
pParse->disableColCache++;
|
|
||||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||||
assert( pParse->disableColCache>0 );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
sqlite3VdbeResolveLabel(v, d2);
|
sqlite3VdbeResolveLabel(v, d2);
|
||||||
|
sqlite3ExprCachePop(pParse, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_NOT: {
|
case TK_NOT: {
|
||||||
@@ -3276,7 +3352,7 @@ void sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Allocate or deallocate temporary use registers during code generation.
|
** Allocate a single new register for use to hold some intermediate result.
|
||||||
*/
|
*/
|
||||||
int sqlite3GetTempReg(Parse *pParse){
|
int sqlite3GetTempReg(Parse *pParse){
|
||||||
if( pParse->nTempReg==0 ){
|
if( pParse->nTempReg==0 ){
|
||||||
@@ -3284,9 +3360,25 @@ int sqlite3GetTempReg(Parse *pParse){
|
|||||||
}
|
}
|
||||||
return pParse->aTempReg[--pParse->nTempReg];
|
return pParse->aTempReg[--pParse->nTempReg];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Deallocate a register, making available for reuse for some other
|
||||||
|
** purpose.
|
||||||
|
**
|
||||||
|
** If a register is currently being used by the column cache, then
|
||||||
|
** the dallocation is deferred until the column cache line that uses
|
||||||
|
** the register becomes stale.
|
||||||
|
*/
|
||||||
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
||||||
if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||||
sqlite3ExprWritableRegister(pParse, iReg);
|
int i;
|
||||||
|
struct yColCache *p;
|
||||||
|
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
|
||||||
|
if( p->iReg==iReg ){
|
||||||
|
p->tempReg = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/select.c
11
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.508 2009/04/16 00:24:24 drh Exp $
|
** $Id: select.c,v 1.509 2009/04/23 13:22:43 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -421,6 +421,7 @@ static void pushOntoSorter(
|
|||||||
int nExpr = pOrderBy->nExpr;
|
int nExpr = pOrderBy->nExpr;
|
||||||
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
|
||||||
int regRecord = sqlite3GetTempReg(pParse);
|
int regRecord = sqlite3GetTempReg(pParse);
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
|
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
|
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
|
||||||
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
|
||||||
@@ -573,6 +574,7 @@ static void selectInnerLoop(
|
|||||||
/* If the destination is an EXISTS(...) expression, the actual
|
/* If the destination is an EXISTS(...) expression, the actual
|
||||||
** values returned by the SELECT are not required.
|
** values returned by the SELECT are not required.
|
||||||
*/
|
*/
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Output);
|
sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Output);
|
||||||
}
|
}
|
||||||
nColumn = nResultCol;
|
nColumn = nResultCol;
|
||||||
@@ -1346,6 +1348,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
|||||||
** The current implementation interprets "LIMIT 0" to mean
|
** The current implementation interprets "LIMIT 0" to mean
|
||||||
** no rows.
|
** no rows.
|
||||||
*/
|
*/
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
if( p->pLimit ){
|
if( p->pLimit ){
|
||||||
p->iLimit = iLimit = ++pParse->nMem;
|
p->iLimit = iLimit = ++pParse->nMem;
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
@@ -3456,6 +3459,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
struct AggInfo_col *pC;
|
struct AggInfo_col *pC;
|
||||||
|
|
||||||
pAggInfo->directMode = 1;
|
pAggInfo->directMode = 1;
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
||||||
int nArg;
|
int nArg;
|
||||||
int addrNext = 0;
|
int addrNext = 0;
|
||||||
@@ -3495,12 +3499,14 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
|
||||||
if( addrNext ){
|
if( addrNext ){
|
||||||
sqlite3VdbeResolveLabel(v, addrNext);
|
sqlite3VdbeResolveLabel(v, addrNext);
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
||||||
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
||||||
}
|
}
|
||||||
pAggInfo->directMode = 0;
|
pAggInfo->directMode = 0;
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3918,6 +3924,7 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
regBase = sqlite3GetTempRange(pParse, nCol);
|
regBase = sqlite3GetTempRange(pParse, nCol);
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
|
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
|
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
|
||||||
j = nGroupBy+1;
|
j = nGroupBy+1;
|
||||||
@@ -3944,6 +3951,7 @@ int sqlite3Select(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
|
sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd);
|
||||||
VdbeComment((v, "GROUP BY sort"));
|
VdbeComment((v, "GROUP BY sort"));
|
||||||
sAggInfo.useSortingIdx = 1;
|
sAggInfo.useSortingIdx = 1;
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
|
/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
|
||||||
@@ -3952,6 +3960,7 @@ int sqlite3Select(
|
|||||||
** from the previous row currently stored in a0, a1, a2...
|
** from the previous row currently stored in a0, a1, a2...
|
||||||
*/
|
*/
|
||||||
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||||
|
sqlite3ExprCacheClear(pParse);
|
||||||
for(j=0; j<pGroupBy->nExpr; j++){
|
for(j=0; j<pGroupBy->nExpr; j++){
|
||||||
if( groupBySort ){
|
if( groupBySort ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j);
|
sqlite3VdbeAddOp3(v, OP_Column, sAggInfo.sortingIdx, j, iBMem+j);
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.859 2009/04/22 15:32:59 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.860 2009/04/23 13:22:44 drh Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1893,6 +1893,13 @@ struct SelectDest {
|
|||||||
int nMem; /* Number of registers allocated */
|
int nMem; /* Number of registers allocated */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Size of the column cache
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE_N_COLCACHE
|
||||||
|
# define SQLITE_N_COLCACHE 10
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An SQL parser context. A copy of this structure is passed through
|
** An SQL parser context. A copy of this structure is passed through
|
||||||
** the parser and down into all the parser action routine in order to
|
** the parser and down into all the parser action routine in order to
|
||||||
@@ -1929,15 +1936,19 @@ struct Parse {
|
|||||||
int nMem; /* Number of memory cells used so far */
|
int nMem; /* Number of memory cells used so far */
|
||||||
int nSet; /* Number of sets used so far */
|
int nSet; /* Number of sets used so far */
|
||||||
int ckBase; /* Base register of data during check constraints */
|
int ckBase; /* Base register of data during check constraints */
|
||||||
int disableColCache; /* True to disable adding to column cache */
|
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||||
int nColCache; /* Number of entries in the column cache */
|
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||||
int iColCache; /* Next entry of the cache to replace */
|
u8 nColCache; /* Number of entries in the column cache */
|
||||||
|
u8 iColCache; /* Next entry of the cache to replace */
|
||||||
struct yColCache {
|
struct yColCache {
|
||||||
int iTable; /* Table cursor number */
|
int iTable; /* Table cursor number */
|
||||||
int iColumn; /* Table column number */
|
int iColumn; /* Table column number */
|
||||||
char affChange; /* True if this register has had an affinity change */
|
u8 affChange; /* True if this register has had an affinity change */
|
||||||
int iReg; /* Register holding value of this column */
|
u8 tempReg; /* iReg is a temp register that needs to be freed */
|
||||||
} aColCache[10]; /* One for each valid column cache entry */
|
int iLevel; /* Nesting level */
|
||||||
|
int iReg; /* Reg with value of this column. 0 means none. */
|
||||||
|
int lru; /* Least recently used entry has the smallest value */
|
||||||
|
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
|
||||||
u32 writeMask; /* Start a write transaction on these databases */
|
u32 writeMask; /* Start a write transaction on these databases */
|
||||||
u32 cookieMask; /* Bitmask of schema verified databases */
|
u32 cookieMask; /* Bitmask of schema verified databases */
|
||||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||||
@@ -2446,9 +2457,12 @@ void sqlite3WhereEnd(WhereInfo*);
|
|||||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
|
||||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||||
void sqlite3ExprCodeCopy(Parse*, int, int, int);
|
void sqlite3ExprCodeCopy(Parse*, int, int, int);
|
||||||
void sqlite3ExprClearColumnCache(Parse*, int);
|
void sqlite3ExprCacheStore(Parse*, int, int, int);
|
||||||
|
void sqlite3ExprCachePush(Parse*);
|
||||||
|
void sqlite3ExprCachePop(Parse*, int);
|
||||||
|
void sqlite3ExprCacheRemove(Parse*, int);
|
||||||
|
void sqlite3ExprCacheClear(Parse*);
|
||||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||||
void sqlite3ExprWritableRegister(Parse*,int);
|
|
||||||
void sqlite3ExprHardCopy(Parse*,int,int);
|
void sqlite3ExprHardCopy(Parse*,int,int);
|
||||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||||
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
** $Id: trigger.c,v 1.135 2009/02/28 10:47:42 danielk1977 Exp $
|
** $Id: trigger.c,v 1.136 2009/04/23 13:22:44 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -689,7 +689,7 @@ static int codeTriggerProgram(
|
|||||||
sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
|
||||||
VdbeComment((v, "begin trigger %s", pStepList->pTrig->name));
|
VdbeComment((v, "begin trigger %s", pStepList->pTrig->name));
|
||||||
while( pTriggerStep ){
|
while( pTriggerStep ){
|
||||||
sqlite3ExprClearColumnCache(pParse, -1);
|
sqlite3ExprCacheClear(pParse);
|
||||||
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
||||||
pParse->trigStack->orconf = orconf;
|
pParse->trigStack->orconf = orconf;
|
||||||
switch( pTriggerStep->op ){
|
switch( pTriggerStep->op ){
|
||||||
|
22
src/where.c
22
src/where.c
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.387 2009/04/22 17:15:03 drh Exp $
|
** $Id: where.c,v 1.388 2009/04/23 13:22:44 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -2469,20 +2469,16 @@ static Bitmask codeOneLoopStart(
|
|||||||
pVtabIdx->aConstraint;
|
pVtabIdx->aConstraint;
|
||||||
|
|
||||||
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
||||||
pParse->disableColCache++;
|
|
||||||
for(j=1; j<=nConstraint; j++){
|
for(j=1; j<=nConstraint; j++){
|
||||||
for(k=0; k<nConstraint; k++){
|
for(k=0; k<nConstraint; k++){
|
||||||
if( aUsage[k].argvIndex==j ){
|
if( aUsage[k].argvIndex==j ){
|
||||||
int iTerm = aConstraint[k].iTermOffset;
|
int iTerm = aConstraint[k].iTermOffset;
|
||||||
assert( pParse->disableColCache );
|
|
||||||
sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1);
|
sqlite3ExprCode(pParse, pWC->a[iTerm].pExpr->pRight, iReg+j+1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( k==nConstraint ) break;
|
if( k==nConstraint ) break;
|
||||||
}
|
}
|
||||||
assert( pParse->disableColCache );
|
|
||||||
pParse->disableColCache--;
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
|
sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
|
sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
|
||||||
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
|
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrBrk, iReg, pVtabIdx->idxStr,
|
||||||
@@ -2517,6 +2513,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
addrNxt = pLevel->addrNxt;
|
addrNxt = pLevel->addrNxt;
|
||||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
||||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
|
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
|
||||||
|
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||||
VdbeComment((v, "pk"));
|
VdbeComment((v, "pk"));
|
||||||
pLevel->op = OP_Noop;
|
pLevel->op = OP_Noop;
|
||||||
}else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
|
}else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){
|
||||||
@@ -2586,6 +2583,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
if( testOp!=OP_Noop ){
|
if( testOp!=OP_Noop ){
|
||||||
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
|
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
|
||||||
|
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||||
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
|
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
|
||||||
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
|
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
|
||||||
}
|
}
|
||||||
@@ -2712,12 +2710,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
/* Seek the index cursor to the start of the range. */
|
/* Seek the index cursor to the start of the range. */
|
||||||
nConstraint = nEq;
|
nConstraint = nEq;
|
||||||
if( pRangeStart ){
|
if( pRangeStart ){
|
||||||
int dcc = pParse->disableColCache;
|
|
||||||
if( pRangeEnd ){
|
|
||||||
pParse->disableColCache++;
|
|
||||||
}
|
|
||||||
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
|
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
|
||||||
pParse->disableColCache = dcc;
|
|
||||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
||||||
nConstraint++;
|
nConstraint++;
|
||||||
}else if( isMinQuery ){
|
}else if( isMinQuery ){
|
||||||
@@ -2743,6 +2736,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
*/
|
*/
|
||||||
nConstraint = nEq;
|
nConstraint = nEq;
|
||||||
if( pRangeEnd ){
|
if( pRangeEnd ){
|
||||||
|
sqlite3ExprCacheRemove(pParse, regBase+nEq);
|
||||||
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
|
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
|
||||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
||||||
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
|
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
|
||||||
@@ -2782,6 +2776,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
if( !omitTable ){
|
if( !omitTable ){
|
||||||
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
||||||
|
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||||
sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
|
sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2939,9 +2934,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pParse->disableColCache += k;
|
|
||||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||||
pParse->disableColCache -= k;
|
|
||||||
k = 1;
|
k = 1;
|
||||||
pTerm->wtFlags |= TERM_CODED;
|
pTerm->wtFlags |= TERM_CODED;
|
||||||
}
|
}
|
||||||
@@ -2953,8 +2946,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
|
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
|
||||||
VdbeComment((v, "record LEFT JOIN hit"));
|
VdbeComment((v, "record LEFT JOIN hit"));
|
||||||
sqlite3ExprClearColumnCache(pParse, pLevel->iTabCur);
|
sqlite3ExprCacheClear(pParse);
|
||||||
sqlite3ExprClearColumnCache(pParse, pLevel->iIdxCur);
|
|
||||||
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
|
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
|
||||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||||
testcase( pTerm->wtFlags & TERM_CODED );
|
testcase( pTerm->wtFlags & TERM_CODED );
|
||||||
@@ -3507,7 +3499,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
|
|
||||||
/* Generate loop termination code.
|
/* Generate loop termination code.
|
||||||
*/
|
*/
|
||||||
sqlite3ExprClearColumnCache(pParse, -1);
|
sqlite3ExprCacheClear(pParse);
|
||||||
for(i=pTabList->nSrc-1; i>=0; i--){
|
for(i=pTabList->nSrc-1; i>=0; i--){
|
||||||
pLevel = &pWInfo->a[i];
|
pLevel = &pWInfo->a[i];
|
||||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||||
|
@@ -13,11 +13,15 @@
|
|||||||
# focus of this script is correct code generation of aliased result-set
|
# focus of this script is correct code generation of aliased result-set
|
||||||
# values. See ticket #3343.
|
# values. See ticket #3343.
|
||||||
#
|
#
|
||||||
# $Id: alias.test,v 1.2 2008/10/25 15:03:21 drh Exp $
|
# $Id: alias.test,v 1.3 2009/04/23 13:22:44 drh Exp $
|
||||||
#
|
#
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# Aliases are currently evaluated twice. We might try to change this
|
||||||
|
# in the future. But not now.
|
||||||
|
return
|
||||||
|
|
||||||
# A procedure to return a sequence of increasing integers.
|
# A procedure to return a sequence of increasing integers.
|
||||||
#
|
#
|
||||||
namespace eval ::seq {
|
namespace eval ::seq {
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# This file implements tests to verify that ticket #3461 has been
|
# This file implements tests to verify that ticket #3461 has been
|
||||||
# fixed.
|
# fixed.
|
||||||
#
|
#
|
||||||
# $Id: tkt3461.test,v 1.2 2008/10/25 15:03:21 drh Exp $
|
# $Id: tkt3461.test,v 1.3 2009/04/23 13:22:44 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -57,6 +57,7 @@ do_test tkt3461-3.1 {
|
|||||||
INSERT INTO t2 VALUES(3, 4);
|
INSERT INTO t2 VALUES(3, 4);
|
||||||
}
|
}
|
||||||
# execsql { PRAGMA vdbe_trace = 1; PRAGMA vdbe_listing=1 }
|
# execsql { PRAGMA vdbe_trace = 1; PRAGMA vdbe_listing=1 }
|
||||||
|
breakpoint
|
||||||
execsql {
|
execsql {
|
||||||
SELECT a, b+1 AS b_plus_one, c, d
|
SELECT a, b+1 AS b_plus_one, c, d
|
||||||
FROM t1 LEFT JOIN t2
|
FROM t1 LEFT JOIN t2
|
||||||
|
Reference in New Issue
Block a user