New Next opcode and indexing style implemented. (CVS 304)
FossilOrigin-Name: decbeb9151885fee473b3fa58c8cf78a2338d2d8
This commit is contained in:
parent
8721ce4ae7
commit
6b56344d4a
28
manifest
28
manifest
@ -1,5 +1,5 @@
|
||||
C Incremental\supdate.\s\sWe\sare\sin\sthe\smiddle\sof\smodifying\sthe\sindex\ssystem\nto\ssupport\srange\squeries\swithout\sdoing\sa\scomplete\stable\sscan.\s(CVS\s303)
|
||||
D 2001-11-07T14:22:00
|
||||
C New\sNext\sopcode\sand\sindexing\sstyle\simplemented.\s(CVS\s304)
|
||||
D 2001-11-07T16:48:27
|
||||
F Makefile.in 6801df952cb1df64aa32e4de85fed24511d28efd
|
||||
F Makefile.template 1fdb891f14083ee0b63cf7282f91529634438e7a
|
||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||
@ -21,13 +21,13 @@ F publish.sh 33cbe6798969f637698044023c139080e5d772a6
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c add522fad1b18c0face24e6f9f7468a6c696c5cc
|
||||
F src/btree.h 0250a0a577a98cc64ddf1582d50c08b8d2451650
|
||||
F src/build.c b459cbe33ee617f46b1975f96ae605d3519583d9
|
||||
F src/delete.c 9cb0b1470e50881d3404f78af353df3ebb6399e5
|
||||
F src/build.c 40b7d14435e2cfc5298e8b7bab5e92ed26f42310
|
||||
F src/delete.c 5d93a21c1388cfb1359bda01c072f25583a2f4f2
|
||||
F src/expr.c 2dd0252ced345c1e64db015b94dc6b5d7a57eef3
|
||||
F src/hash.c d0110e6da70a5962e21575fccf8206f7d9d75e00
|
||||
F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac
|
||||
F src/insert.c 962f277340adc265fbde4dd952055df7ede4e67b
|
||||
F src/main.c e2ae5e14a3f936d5fa7e3d9d9477610b5f16e7eb
|
||||
F src/insert.c 3526be771a01035198bef28d8f370cbcab94f46d
|
||||
F src/main.c 0b0e7244c7af91613111d5b72387e33f8789ed72
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/os.c 66b677479eae37e30bdfbe32deb0fe6a2efca983
|
||||
F src/os.h bed702c9e3b768bc3cb1b12c90b83d099c1546be
|
||||
@ -36,11 +36,11 @@ F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
|
||||
F src/parse.y 5295f393f41ea89958287e5738e6c12c7cd67482
|
||||
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
|
||||
F src/random.c 2a9cc2c9716d14815fd4c2accf89d87a1143e46b
|
||||
F src/select.c a97d3d27c544dc9a4849bfbad1cfa3e7c673bda9
|
||||
F src/select.c fa1c7144a9ad7ce3f16373b443bc25e764af4be7
|
||||
F src/shell.c 71597951753b56a97fea1c7a30908f31e635c00c
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 934de9112747ad8d8e7d5fec44876246b24ca5a3
|
||||
F src/sqliteInt.h fc2f7da1fee1e871b20b375c50c582065d891c7f
|
||||
F src/sqliteInt.h 555cff59458966ac16f044cc985f2267c75a606e
|
||||
F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
|
||||
F src/tclsqlite.c 4896e078495bf868742f5394dcf01c5efe5bea02
|
||||
F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
|
||||
@ -49,9 +49,9 @@ F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
|
||||
F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf
|
||||
F src/update.c b1e315e20b98a013d30fd9ff3b7d9dc4f29b39b3
|
||||
F src/util.c ac83973ecc647d3d3c58708f148442365abf9b94
|
||||
F src/vdbe.c 24306643bed5e19406735152ad68e98d598dcab0
|
||||
F src/vdbe.h a1170446638ce5b7f078279e640dcf91ec50de01
|
||||
F src/where.c 601f096f2a37ca688a775ca36d33534b13b876cb
|
||||
F src/vdbe.c 66e82eb4d042e34752ed23c3c13f921a895376af
|
||||
F src/vdbe.h da7c01076268f4fa1a17b7d6f27e21c3fd9a5d3f
|
||||
F src/where.c a6cac72314905902542c5239683d07fed27f6ee1
|
||||
F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe
|
||||
F test/bigrow.test 9458134d67f81559845f934fdd6802fe19a68ad1
|
||||
F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
|
||||
@ -115,7 +115,7 @@ F www/speed.tcl 212a91d555384e01873160d6a189f1490c791bc2
|
||||
F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
|
||||
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
|
||||
F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
|
||||
P 177012249ae93dbea4a11fb50faaae7912848bd0
|
||||
R 28881ea0807c6135a3c8ce43fbf768db
|
||||
P e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
|
||||
R 2ff273a13d7d9aa297cec267ea881bcc
|
||||
U drh
|
||||
Z bdd4c0f13b513e97b71388c7bea5ec3a
|
||||
Z 17c5246b4b0cf0179995e37754c3ee96
|
||||
|
@ -1 +1 @@
|
||||
e6ca23fa4569bc33065bf57ce7ce6132cd6a9de0
|
||||
decbeb9151885fee473b3fa58c8cf78a2338d2d8
|
39
src/build.c
39
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.54 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: build.c,v 1.55 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -692,14 +692,14 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
if( v ){
|
||||
static VdbeOp dropTable[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(9), 0}, /* 3 */
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_MemStore, 1, 1, 0},
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 4 */
|
||||
{ OP_Column, 0, 2, 0},
|
||||
{ OP_Ne, 0, ADDR(3), 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Goto, 0, ADDR(3), 0},
|
||||
{ OP_Next, 0, ADDR(4), 0}, /* 8 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 9 */
|
||||
{ OP_Close, 0, 0, 0},
|
||||
};
|
||||
@ -981,20 +981,16 @@ void sqliteCreateIndex(
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
lbl1 = sqliteVdbeMakeLabel(v);
|
||||
lbl2 = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 2, 0);
|
||||
sqliteVdbeResolveLabel(v, lbl1);
|
||||
sqliteVdbeAddOp(v, OP_Next, 2, lbl2);
|
||||
sqliteVdbeAddOp(v, OP_Recno, 2, 0);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
|
||||
lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);
|
||||
for(i=0; i<pIndex->nColumn; i++){
|
||||
sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i]);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->isUnique);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1);
|
||||
sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
|
||||
sqliteVdbeResolveLabel(v, lbl2);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 2, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 1, 0);
|
||||
}
|
||||
@ -1043,15 +1039,16 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
if( v ){
|
||||
static VdbeOp dropIndex[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_Rewind, 0, ADDR(10),0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Next, 0, ADDR(8), 0}, /* 3 */
|
||||
{ OP_Dup, 0, 0, 0},
|
||||
{ OP_MemStore, 1, 1, 0},
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 4 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Ne, 0, ADDR(3), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Destroy, 0, 0, 0}, /* 8 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 9 */
|
||||
{ OP_Eq, 0, ADDR(9), 0},
|
||||
{ OP_Next, 0, ADDR(4), 0},
|
||||
{ OP_Goto, 0, ADDR(10),0},
|
||||
{ OP_Delete, 0, 0, 0}, /* 9 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 10 */
|
||||
{ OP_Close, 0, 0, 0},
|
||||
};
|
||||
int base;
|
||||
@ -1066,7 +1063,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
|
||||
changeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+9, db->next_cookie);
|
||||
sqliteVdbeChangeP1(v, base+10, db->next_cookie);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.20 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: delete.c,v 1.21 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -106,10 +106,9 @@ void sqliteDeleteFrom(
|
||||
int addr;
|
||||
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
|
||||
sqliteVdbeAddOp(v, openOp, 0, pTab->tnum);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_Next, 0, endOfLoop);
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, 0, sqliteVdbeCurrentAddr(v)+2);
|
||||
addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_Next, 0, addr);
|
||||
sqliteVdbeResolveLabel(v, endOfLoop);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
}
|
||||
|
14
src/insert.c
14
src/insert.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.25 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: insert.c,v 1.26 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -173,9 +173,9 @@ void sqliteInsert(
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Rewind, srcTab, 0);
|
||||
iBreak = sqliteVdbeMakeLabel(v);
|
||||
iCont = sqliteVdbeAddOp(v, OP_Next, srcTab, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
|
||||
iCont = sqliteVdbeCurrentAddr(v);
|
||||
}
|
||||
|
||||
/* Create a new entry in the table and fill it with data.
|
||||
@ -245,9 +245,13 @@ void sqliteInsert(
|
||||
/* The bottom of the loop, if the data source is a SELECT statement
|
||||
*/
|
||||
if( srcTab>=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
|
||||
sqliteVdbeAddOp(v, OP_Next, srcTab, iCont);
|
||||
sqliteVdbeResolveLabel(v, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, srcTab, 0);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, base, 0);
|
||||
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
||||
sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
|
||||
}
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0);
|
||||
|
31
src/main.c
31
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.48 2001/11/03 23:57:09 drh Exp $
|
||||
** $Id: main.c,v 1.49 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -157,40 +157,37 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
*/
|
||||
static VdbeOp initProg[] = {
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0},
|
||||
{ OP_Next, 0, 12, 0}, /* 2 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Rewind, 0, 31, 0},
|
||||
{ OP_Column, 0, 0, 0}, /* 2 */
|
||||
{ OP_String, 0, 0, "meta"},
|
||||
{ OP_Ne, 0, 2, 0},
|
||||
{ OP_Ne, 0, 10, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 2, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 12 */
|
||||
{ OP_Next, 0, 23, 0}, /* 13 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Next, 0, 2, 0}, /* 10 */
|
||||
{ OP_Rewind, 0, 31, 0}, /* 11 */
|
||||
{ OP_Column, 0, 0, 0}, /* 12 */
|
||||
{ OP_String, 0, 0, "table"},
|
||||
{ OP_Ne, 0, 13, 0},
|
||||
{ OP_Ne, 0, 20, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 13, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 23 */
|
||||
{ OP_Next, 0, 34, 0}, /* 24 */
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Next, 0, 12, 0}, /* 20 */
|
||||
{ OP_Rewind, 0, 31, 0}, /* 21 */
|
||||
{ OP_Column, 0, 0, 0}, /* 22 */
|
||||
{ OP_String, 0, 0, "index"},
|
||||
{ OP_Ne, 0, 24, 0},
|
||||
{ OP_Ne, 0, 30, 0},
|
||||
{ OP_Column, 0, 0, 0},
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Column, 0, 3, 0},
|
||||
{ OP_Column, 0, 4, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
{ OP_Goto, 0, 24, 0},
|
||||
{ OP_String, 0, 0, "meta"}, /* 34 */
|
||||
{ OP_Next, 0, 22, 0}, /* 30 */
|
||||
{ OP_String, 0, 0, "meta"}, /* 31 */
|
||||
{ OP_String, 0, 0, "schema-cookie"},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_ReadCookie,0,0, 0},
|
||||
|
23
src/select.c
23
src/select.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.48 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: select.c,v 1.49 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -557,17 +557,19 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
** it is that we currently need.
|
||||
*/
|
||||
if( eDest!=priorOp ){
|
||||
int iCont, iBreak;
|
||||
int iCont, iBreak, iStart;
|
||||
assert( p->pEList );
|
||||
generateColumnNames(pParse, 0, p->pEList);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, unionTab, 0);
|
||||
iBreak = sqliteVdbeMakeLabel(v);
|
||||
iCont = sqliteVdbeAddOp(v, OP_Next, unionTab, iBreak);
|
||||
iCont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, unionTab, iBreak);
|
||||
iStart = sqliteVdbeCurrentAddr(v);
|
||||
rc = selectInnerLoop(pParse, 0, unionTab, p->pEList->nExpr,
|
||||
p->pOrderBy, -1, eDest, iParm,
|
||||
iCont, iBreak);
|
||||
if( rc ) return 1;
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
|
||||
sqliteVdbeResolveLabel(v, iCont);
|
||||
sqliteVdbeAddOp(v, OP_Next, unionTab, iStart);
|
||||
sqliteVdbeResolveLabel(v, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_Close, unionTab, 0);
|
||||
if( p->pOrderBy ){
|
||||
@ -578,7 +580,7 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
}
|
||||
case TK_INTERSECT: {
|
||||
int tab1, tab2;
|
||||
int iCont, iBreak;
|
||||
int iCont, iBreak, iStart;
|
||||
|
||||
/* INTERSECT is different from the others since it requires
|
||||
** two temporary tables. Hence it has its own case. Begin
|
||||
@ -611,16 +613,17 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
|
||||
*/
|
||||
assert( p->pEList );
|
||||
generateColumnNames(pParse, 0, p->pEList);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, tab1, 0);
|
||||
iBreak = sqliteVdbeMakeLabel(v);
|
||||
iCont = sqliteVdbeAddOp(v, OP_Next, tab1, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
|
||||
iCont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, tab1, iBreak);
|
||||
iStart = sqliteVdbeAddOp(v, OP_FullKey, tab1, 0);
|
||||
sqliteVdbeAddOp(v, OP_NotFound, tab2, iCont);
|
||||
rc = selectInnerLoop(pParse, 0, tab1, p->pEList->nExpr,
|
||||
p->pOrderBy, -1, eDest, iParm,
|
||||
iCont, iBreak);
|
||||
if( rc ) return 1;
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, iCont);
|
||||
sqliteVdbeResolveLabel(v, iCont);
|
||||
sqliteVdbeAddOp(v, OP_Next, tab1, iStart);
|
||||
sqliteVdbeResolveLabel(v, iBreak);
|
||||
sqliteVdbeAddOp(v, OP_Close, tab2, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, tab1, 0);
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.67 2001/11/06 04:00:19 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.68 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@ -139,6 +139,7 @@ typedef struct Parse Parse;
|
||||
typedef struct Token Token;
|
||||
typedef struct IdList IdList;
|
||||
typedef struct WhereInfo WhereInfo;
|
||||
typedef struct WhereLevel WhereLevel;
|
||||
typedef struct Select Select;
|
||||
typedef struct AggExpr AggExpr;
|
||||
|
||||
@ -298,6 +299,21 @@ struct IdList {
|
||||
} *a; /* One entry for each identifier on the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** For each nested loop in a WHERE clause implementation, the WhereInfo
|
||||
** structure contains a single instance of this structure. This structure
|
||||
** is intended to be private the the where.c module and should not be
|
||||
** access or modified by other modules.
|
||||
*/
|
||||
struct WhereLevel {
|
||||
int iMem; /* Memory cell used by this level */
|
||||
Index *pIdx; /* Index used */
|
||||
int iCur; /* Cursor number used for this index */
|
||||
int brk; /* Jump here to break out of the loop */
|
||||
int cont; /* Jump here to continue with the next loop cycle */
|
||||
int op, p1, p2; /* Opcode used to terminate the loop */
|
||||
};
|
||||
|
||||
/*
|
||||
** The WHERE clause processing routine has two halves. The
|
||||
** first part does the start of the WHERE loop and the second
|
||||
@ -311,7 +327,8 @@ struct WhereInfo {
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
int iBreak; /* Jump here to break out of the loop */
|
||||
int base; /* Index of first Open opcode */
|
||||
Index *aIdx[32]; /* Indices used for each table */
|
||||
int nLevel; /* Number of nested loop */
|
||||
WhereLevel a[1]; /* Information about each nest loop in the WHERE */
|
||||
};
|
||||
|
||||
/*
|
||||
|
238
src/vdbe.c
238
src/vdbe.c
@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.94 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: vdbe.c,v 1.95 2001/11/07 16:48:27 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -64,8 +64,6 @@ struct Cursor {
|
||||
Bool keyAsData; /* The OP_Column command works on key instead of data */
|
||||
Bool atFirst; /* True if pointing to first entry */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
char *zKey; /* Key used in BeginIdx and NextIdx operators */
|
||||
int nKey; /* Number of bytes in zKey[] */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
@ -277,6 +275,39 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new symbolic label for an instruction that has yet to be
|
||||
** coded. The symbolic label is really just a negative number. The
|
||||
** label can be used as the P2 value of an operation. Later, when
|
||||
** the label is resolved to a specific address, the VDBE will scan
|
||||
** through its operation list and change all values of P2 which match
|
||||
** the label into the resolved address.
|
||||
**
|
||||
** The VDBE knows that a P2 value is a label because labels are
|
||||
** always negative and P2 values are suppose to be non-negative.
|
||||
** Hence, a negative P2 value is a label that has yet to be resolved.
|
||||
*/
|
||||
int sqliteVdbeMakeLabel(Vdbe *p){
|
||||
int i;
|
||||
i = p->nLabel++;
|
||||
if( i>=p->nLabelAlloc ){
|
||||
int *aNew;
|
||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||
aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
if( aNew==0 ){
|
||||
sqliteFree(p->aLabel);
|
||||
}
|
||||
p->aLabel = aNew;
|
||||
}
|
||||
if( p->aLabel==0 ){
|
||||
p->nLabel = 0;
|
||||
p->nLabelAlloc = 0;
|
||||
return 0;
|
||||
}
|
||||
p->aLabel[i] = -1;
|
||||
return -1-i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Resolve label "x" to be the address of the next instruction to
|
||||
** be inserted.
|
||||
@ -284,6 +315,8 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||
void sqliteVdbeResolveLabel(Vdbe *p, int x){
|
||||
int j;
|
||||
if( x<0 && (-x)<=p->nLabel && p->aOp ){
|
||||
if( p->aLabel[-1-x]==p->nOp ) return;
|
||||
assert( p->aLabel[-1-x]<0 );
|
||||
p->aLabel[-1-x] = p->nOp;
|
||||
for(j=0; j<p->nOp; j++){
|
||||
if( p->aOp[j].p2==x ) p->aOp[j].p2 = p->nOp;
|
||||
@ -440,39 +473,6 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new symbolic label for an instruction that has yet to be
|
||||
** coded. The symbolic label is really just a negative number. The
|
||||
** label can be used as the P2 value of an operation. Later, when
|
||||
** the label is resolved to a specific address, the VDBE will scan
|
||||
** through its operation list and change all values of P2 which match
|
||||
** the label into the resolved address.
|
||||
**
|
||||
** The VDBE knows that a P2 value is a label because labels are
|
||||
** always negative and P2 values are suppose to be non-negative.
|
||||
** Hence, a negative P2 value is a label that has yet to be resolved.
|
||||
*/
|
||||
int sqliteVdbeMakeLabel(Vdbe *p){
|
||||
int i;
|
||||
i = p->nLabel++;
|
||||
if( i>=p->nLabelAlloc ){
|
||||
int *aNew;
|
||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||
aNew = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||
if( aNew==0 ){
|
||||
sqliteFree(p->aLabel);
|
||||
}
|
||||
p->aLabel = aNew;
|
||||
}
|
||||
if( p->aLabel==0 ){
|
||||
p->nLabel = 0;
|
||||
p->nLabelAlloc = 0;
|
||||
return 0;
|
||||
}
|
||||
p->aLabel[i] = -1;
|
||||
return -1-i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset an Agg structure. Delete all its contents.
|
||||
*/
|
||||
@ -721,9 +721,6 @@ static void cleanupCursor(Cursor *pCx){
|
||||
if( pCx->pCursor ){
|
||||
sqliteBtreeCloseCursor(pCx->pCursor);
|
||||
}
|
||||
if( pCx->zKey ){
|
||||
sqliteFree(pCx->zKey);
|
||||
}
|
||||
if( pCx->pBt ){
|
||||
sqliteBtreeClose(pCx->pBt);
|
||||
}
|
||||
@ -843,29 +840,28 @@ static char *zOpName[] = { 0,
|
||||
"MoveTo", "Fcnt", "NewRecno", "Put",
|
||||
"Distinct", "Found", "NotFound", "Delete",
|
||||
"Column", "KeyAsData", "Recno", "FullKey",
|
||||
"Rewind", "Next", "NextN", "Destroy",
|
||||
"Clear", "CreateIndex", "CreateTable", "Reorganize",
|
||||
"BeginIdx", "NextIdx", "IdxPut", "IdxDelete",
|
||||
"IdxRecno", "IdxGT", "IdxGE", "MemLoad",
|
||||
"MemStore", "ListWrite", "ListRewind", "ListRead",
|
||||
"ListReset", "SortPut", "SortMakeRec", "SortMakeKey",
|
||||
"Sort", "SortNext", "SortCallback", "SortReset",
|
||||
"FileOpen", "FileRead", "FileColumn", "AggReset",
|
||||
"AggFocus", "AggIncr", "AggNext", "AggSet",
|
||||
"AggGet", "SetInsert", "SetFound", "SetNotFound",
|
||||
"MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
|
||||
"Goto", "If", "Halt", "ColumnCount",
|
||||
"ColumnName", "Callback", "NullCallback", "Integer",
|
||||
"String", "Pop", "Dup", "Pull",
|
||||
"Add", "AddImm", "Subtract", "Multiply",
|
||||
"Divide", "Remainder", "BitAnd", "BitOr",
|
||||
"BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
|
||||
"Precision", "Min", "Max", "Like",
|
||||
"Glob", "Eq", "Ne", "Lt",
|
||||
"Le", "Gt", "Ge", "IsNull",
|
||||
"NotNull", "Negative", "And", "Or",
|
||||
"Not", "Concat", "Noop", "Strlen",
|
||||
"Substr", "Limit",
|
||||
"Rewind", "Next", "Destroy", "Clear",
|
||||
"CreateIndex", "CreateTable", "Reorganize", "IdxPut",
|
||||
"IdxDelete", "IdxRecno", "IdxGT", "IdxGE",
|
||||
"MemLoad", "MemStore", "ListWrite", "ListRewind",
|
||||
"ListRead", "ListReset", "SortPut", "SortMakeRec",
|
||||
"SortMakeKey", "Sort", "SortNext", "SortCallback",
|
||||
"SortReset", "FileOpen", "FileRead", "FileColumn",
|
||||
"AggReset", "AggFocus", "AggIncr", "AggNext",
|
||||
"AggSet", "AggGet", "SetInsert", "SetFound",
|
||||
"SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey",
|
||||
"IncrKey", "Goto", "If", "Halt",
|
||||
"ColumnCount", "ColumnName", "Callback", "NullCallback",
|
||||
"Integer", "String", "Pop", "Dup",
|
||||
"Pull", "Add", "AddImm", "Subtract",
|
||||
"Multiply", "Divide", "Remainder", "BitAnd",
|
||||
"BitOr", "BitNot", "ShiftLeft", "ShiftRight",
|
||||
"AbsValue", "Precision", "Min", "Max",
|
||||
"Like", "Glob", "Eq", "Ne",
|
||||
"Lt", "Le", "Gt", "Ge",
|
||||
"IsNull", "NotNull", "Negative", "And",
|
||||
"Or", "Not", "Concat", "Noop",
|
||||
"Strlen", "Substr", "Limit",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1043,6 +1039,8 @@ int sqliteVdbeExec(
|
||||
zStack = p->zStack;
|
||||
aStack = p->aStack;
|
||||
p->tos = -1;
|
||||
p->iLimit = 0;
|
||||
p->iOffset = 0;
|
||||
|
||||
/* Initialize the aggregrate hash table.
|
||||
*/
|
||||
@ -2929,36 +2927,11 @@ case OP_Rewind: {
|
||||
/* Opcode: Next P1 P2 *
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table. Or, if there are no more key/data pairs, jump to location P2.
|
||||
*/
|
||||
case OP_Next: {
|
||||
int i = pOp->p1;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
if( !p->aCsr[i].atFirst ){
|
||||
int res;
|
||||
rc = sqliteBtreeNext(pCrsr, &res);
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
p->nFetch++;
|
||||
}
|
||||
}
|
||||
p->aCsr[i].atFirst = 0;
|
||||
p->aCsr[i].recnoIsValid = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: NextN P1 P2 *
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
** to the following instruction. But if the cursor advance was successful,
|
||||
** jump immediately to P2.
|
||||
*/
|
||||
case OP_NextN: {
|
||||
case OP_Next: {
|
||||
int i = pOp->p1;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
@ -2974,92 +2947,6 @@ case OP_NextN: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: BeginIdx P1 * *
|
||||
**
|
||||
** Begin searching an index for records with the key found on the
|
||||
** top of the stack. The key on the top of the stack should be built
|
||||
** using the MakeKey opcode. Subsequent calls to NextIdx will push
|
||||
** record numbers onto the stack until all records with the same key
|
||||
** have been returned.
|
||||
**
|
||||
** Note that the key for this opcode should be built using MakeKey
|
||||
** but the key used for PutIdx and DeleteIdx should be built using
|
||||
** MakeIdxKey. The difference is that MakeIdxKey adds a 4-bytes
|
||||
** record number to the end of the key in order to specify a particular
|
||||
** entry in the index. MakeKey omits the 4-byte record number.
|
||||
** The search that this BeginIdx instruction initiates will span all
|
||||
** entries in the index where the MakeKey generated key matches all
|
||||
** but the last four bytes of the MakeIdxKey generated key.
|
||||
*/
|
||||
case OP_BeginIdx: {
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
int res, rx;
|
||||
Cursor *pCrsr;
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; )
|
||||
if( i>=0 && i<p->nCursor && (pCrsr = &p->aCsr[i])->pCursor!=0 ){
|
||||
if( Stringify(p, tos) ) goto no_mem;
|
||||
if( pCrsr->zKey ) sqliteFree(pCrsr->zKey);
|
||||
pCrsr->nKey = aStack[tos].n;
|
||||
pCrsr->zKey = sqliteMalloc( pCrsr->nKey+1 );
|
||||
if( pCrsr->zKey==0 ) goto no_mem;
|
||||
memcpy(pCrsr->zKey, zStack[tos], aStack[tos].n);
|
||||
pCrsr->zKey[aStack[tos].n] = 0;
|
||||
rx = sqliteBtreeMoveto(pCrsr->pCursor, zStack[tos], aStack[tos].n, &res);
|
||||
pCrsr->atFirst = rx==SQLITE_OK && res>0;
|
||||
pCrsr->recnoIsValid = 0;
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: NextIdx P1 P2 *
|
||||
**
|
||||
** The P1 cursor points to an SQL index for which a BeginIdx operation
|
||||
** has been issued. This operation retrieves the next record from that
|
||||
** cursor and verifies that the key on the record minus the last 4 bytes
|
||||
** matches the key that was pulled from the stack by the BeginIdx instruction.
|
||||
** If they match, then the last 4 bytes of the key on the record hold a record
|
||||
** number and that record number is extracted and pushed on the stack.
|
||||
** If the keys do not match, there is an immediate jump to instruction P2.
|
||||
*/
|
||||
case OP_NextIdx: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
Cursor *pCrsr;
|
||||
BtCursor *pCur;
|
||||
int rx, res, size;
|
||||
|
||||
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
|
||||
zStack[tos] = 0;
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = &p->aCsr[i])->pCursor!=0 ){
|
||||
pCur = pCrsr->pCursor;
|
||||
if( pCrsr->atFirst ){
|
||||
pCrsr->atFirst = 0;
|
||||
res = 0;
|
||||
}else{
|
||||
rx = sqliteBtreeNext(pCur, &res);
|
||||
if( rx!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
sqliteBtreeKeySize(pCur, &size);
|
||||
if( res>0 || size!=pCrsr->nKey+sizeof(u32) ||
|
||||
sqliteBtreeKeyCompare(pCur, pCrsr->zKey, pCrsr->nKey, 4, &res)!=SQLITE_OK
|
||||
|| res!=0
|
||||
){
|
||||
pc = pOp->p2 - 1;
|
||||
POPSTACK;
|
||||
}else{
|
||||
int recno;
|
||||
sqliteBtreeKey(pCur, pCrsr->nKey, sizeof(u32), (char*)&recno);
|
||||
recno = bigEndian(recno);
|
||||
p->aCsr[i].lastRecno = aStack[tos].i = recno;
|
||||
p->aCsr[i].recnoIsValid = 1;
|
||||
aStack[tos].flags = STK_Int;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxPut P1 P2 P3
|
||||
**
|
||||
** The top of the stack hold an SQL index key made using the
|
||||
@ -3197,6 +3084,7 @@ case OP_IdxGE: {
|
||||
pc = pOp->p2 - 1 ;
|
||||
}
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3780,7 +3668,7 @@ case OP_MemStore: {
|
||||
if( pMem->s.flags & (STK_Static|STK_Dyn) ){
|
||||
if( pOp->p2==0 && (pMem->s.flags & STK_Dyn)!=0 ){
|
||||
pMem->z = sqliteMalloc( pMem->s.n );
|
||||
if( pMem->z ) goto no_mem;
|
||||
if( pMem->z==0 ) goto no_mem;
|
||||
memcpy(pMem->z, zStack[tos], pMem->s.n);
|
||||
}else{
|
||||
pMem->z = zStack[tos];
|
||||
|
177
src/vdbe.h
177
src/vdbe.h
@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.34 2001/11/07 14:22:00 drh Exp $
|
||||
** $Id: vdbe.h,v 1.35 2001/11/07 16:48:28 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -96,111 +96,108 @@ typedef struct VdbeOp VdbeOp;
|
||||
#define OP_FullKey 24
|
||||
#define OP_Rewind 25
|
||||
#define OP_Next 26
|
||||
#define OP_NextN 27
|
||||
|
||||
#define OP_Destroy 28
|
||||
#define OP_Clear 29
|
||||
#define OP_CreateIndex 30
|
||||
#define OP_CreateTable 31
|
||||
#define OP_Reorganize 32
|
||||
#define OP_Destroy 27
|
||||
#define OP_Clear 28
|
||||
#define OP_CreateIndex 29
|
||||
#define OP_CreateTable 30
|
||||
#define OP_Reorganize 31
|
||||
|
||||
#define OP_BeginIdx 33
|
||||
#define OP_NextIdx 34
|
||||
#define OP_IdxPut 35
|
||||
#define OP_IdxDelete 36
|
||||
#define OP_IdxRecno 37
|
||||
#define OP_IdxGT 38
|
||||
#define OP_IdxGE 39
|
||||
#define OP_IdxPut 32
|
||||
#define OP_IdxDelete 33
|
||||
#define OP_IdxRecno 34
|
||||
#define OP_IdxGT 35
|
||||
#define OP_IdxGE 36
|
||||
|
||||
#define OP_MemLoad 40
|
||||
#define OP_MemStore 41
|
||||
#define OP_MemLoad 37
|
||||
#define OP_MemStore 38
|
||||
|
||||
#define OP_ListWrite 42
|
||||
#define OP_ListRewind 43
|
||||
#define OP_ListRead 44
|
||||
#define OP_ListReset 45
|
||||
#define OP_ListWrite 39
|
||||
#define OP_ListRewind 40
|
||||
#define OP_ListRead 41
|
||||
#define OP_ListReset 42
|
||||
|
||||
#define OP_SortPut 46
|
||||
#define OP_SortMakeRec 47
|
||||
#define OP_SortMakeKey 48
|
||||
#define OP_Sort 49
|
||||
#define OP_SortNext 50
|
||||
#define OP_SortCallback 51
|
||||
#define OP_SortReset 52
|
||||
#define OP_SortPut 43
|
||||
#define OP_SortMakeRec 44
|
||||
#define OP_SortMakeKey 45
|
||||
#define OP_Sort 46
|
||||
#define OP_SortNext 47
|
||||
#define OP_SortCallback 48
|
||||
#define OP_SortReset 49
|
||||
|
||||
#define OP_FileOpen 53
|
||||
#define OP_FileRead 54
|
||||
#define OP_FileColumn 55
|
||||
#define OP_FileOpen 50
|
||||
#define OP_FileRead 51
|
||||
#define OP_FileColumn 52
|
||||
|
||||
#define OP_AggReset 56
|
||||
#define OP_AggFocus 57
|
||||
#define OP_AggIncr 58
|
||||
#define OP_AggNext 59
|
||||
#define OP_AggSet 60
|
||||
#define OP_AggGet 61
|
||||
#define OP_AggReset 53
|
||||
#define OP_AggFocus 54
|
||||
#define OP_AggIncr 55
|
||||
#define OP_AggNext 56
|
||||
#define OP_AggSet 57
|
||||
#define OP_AggGet 58
|
||||
|
||||
#define OP_SetInsert 62
|
||||
#define OP_SetFound 63
|
||||
#define OP_SetNotFound 64
|
||||
#define OP_SetInsert 59
|
||||
#define OP_SetFound 60
|
||||
#define OP_SetNotFound 61
|
||||
|
||||
#define OP_MakeRecord 65
|
||||
#define OP_MakeKey 66
|
||||
#define OP_MakeIdxKey 67
|
||||
#define OP_IncrKey 68
|
||||
#define OP_MakeRecord 62
|
||||
#define OP_MakeKey 63
|
||||
#define OP_MakeIdxKey 64
|
||||
#define OP_IncrKey 65
|
||||
|
||||
#define OP_Goto 69
|
||||
#define OP_If 70
|
||||
#define OP_Halt 71
|
||||
#define OP_Goto 66
|
||||
#define OP_If 67
|
||||
#define OP_Halt 68
|
||||
|
||||
#define OP_ColumnCount 72
|
||||
#define OP_ColumnName 73
|
||||
#define OP_Callback 74
|
||||
#define OP_NullCallback 75
|
||||
#define OP_ColumnCount 69
|
||||
#define OP_ColumnName 70
|
||||
#define OP_Callback 71
|
||||
#define OP_NullCallback 72
|
||||
|
||||
#define OP_Integer 76
|
||||
#define OP_String 77
|
||||
#define OP_Pop 78
|
||||
#define OP_Dup 79
|
||||
#define OP_Pull 80
|
||||
#define OP_Integer 73
|
||||
#define OP_String 74
|
||||
#define OP_Pop 75
|
||||
#define OP_Dup 76
|
||||
#define OP_Pull 77
|
||||
|
||||
#define OP_Add 81
|
||||
#define OP_AddImm 82
|
||||
#define OP_Subtract 83
|
||||
#define OP_Multiply 84
|
||||
#define OP_Divide 85
|
||||
#define OP_Remainder 86
|
||||
#define OP_BitAnd 87
|
||||
#define OP_BitOr 88
|
||||
#define OP_BitNot 89
|
||||
#define OP_ShiftLeft 90
|
||||
#define OP_ShiftRight 91
|
||||
#define OP_AbsValue 92
|
||||
#define OP_Precision 93
|
||||
#define OP_Min 94
|
||||
#define OP_Max 95
|
||||
#define OP_Like 96
|
||||
#define OP_Glob 97
|
||||
#define OP_Eq 98
|
||||
#define OP_Ne 99
|
||||
#define OP_Lt 100
|
||||
#define OP_Le 101
|
||||
#define OP_Gt 102
|
||||
#define OP_Ge 103
|
||||
#define OP_IsNull 104
|
||||
#define OP_NotNull 105
|
||||
#define OP_Negative 106
|
||||
#define OP_And 107
|
||||
#define OP_Or 108
|
||||
#define OP_Not 109
|
||||
#define OP_Concat 110
|
||||
#define OP_Noop 111
|
||||
#define OP_Add 78
|
||||
#define OP_AddImm 79
|
||||
#define OP_Subtract 80
|
||||
#define OP_Multiply 81
|
||||
#define OP_Divide 82
|
||||
#define OP_Remainder 83
|
||||
#define OP_BitAnd 84
|
||||
#define OP_BitOr 85
|
||||
#define OP_BitNot 86
|
||||
#define OP_ShiftLeft 87
|
||||
#define OP_ShiftRight 88
|
||||
#define OP_AbsValue 89
|
||||
#define OP_Precision 90
|
||||
#define OP_Min 91
|
||||
#define OP_Max 92
|
||||
#define OP_Like 93
|
||||
#define OP_Glob 94
|
||||
#define OP_Eq 95
|
||||
#define OP_Ne 96
|
||||
#define OP_Lt 97
|
||||
#define OP_Le 98
|
||||
#define OP_Gt 99
|
||||
#define OP_Ge 100
|
||||
#define OP_IsNull 101
|
||||
#define OP_NotNull 102
|
||||
#define OP_Negative 103
|
||||
#define OP_And 104
|
||||
#define OP_Or 105
|
||||
#define OP_Not 106
|
||||
#define OP_Concat 107
|
||||
#define OP_Noop 108
|
||||
|
||||
#define OP_Strlen 112
|
||||
#define OP_Substr 113
|
||||
#define OP_Strlen 109
|
||||
#define OP_Substr 110
|
||||
|
||||
#define OP_Limit 114
|
||||
#define OP_Limit 111
|
||||
|
||||
#define OP_MAX 114
|
||||
#define OP_MAX 111
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
95
src/where.c
95
src/where.c
@ -13,7 +13,7 @@
|
||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||
** to generate VDBE code to evaluate expressions.
|
||||
**
|
||||
** $Id: where.c,v 1.24 2001/11/04 18:32:48 drh Exp $
|
||||
** $Id: where.c,v 1.25 2001/11/07 16:48:28 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -147,17 +147,17 @@ WhereInfo *sqliteWhereBegin(
|
||||
int loopMask; /* One bit set for each outer loop */
|
||||
int haveKey; /* True if KEY is on the stack */
|
||||
int base; /* First available index for OP_Open opcodes */
|
||||
Index *aIdx[32]; /* Index to use on each nested loop. */
|
||||
int nCur; /* Next unused cursor number */
|
||||
int aDirect[32]; /* If TRUE, then index this table using ROWID */
|
||||
ExprInfo aExpr[50]; /* The WHERE clause is divided into these expressions */
|
||||
|
||||
/* Allocate space for aOrder[]. */
|
||||
/* Allocate space for aOrder[] and aiMem[]. */
|
||||
aOrder = sqliteMalloc( sizeof(int) * pTabList->nId );
|
||||
|
||||
/* Allocate and initialize the WhereInfo structure that will become the
|
||||
** return value.
|
||||
*/
|
||||
pWInfo = sqliteMalloc( sizeof(WhereInfo) );
|
||||
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nId*sizeof(WhereLevel) );
|
||||
if( sqlite_malloc_failed ){
|
||||
sqliteFree(aOrder);
|
||||
sqliteFree(pWInfo);
|
||||
@ -166,6 +166,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
pWInfo->pParse = pParse;
|
||||
pWInfo->pTabList = pTabList;
|
||||
base = pWInfo->base = pParse->nTab;
|
||||
nCur = base + pTabList->nId;
|
||||
|
||||
/* Split the WHERE clause into as many as 32 separate subexpressions
|
||||
** where each subexpression is separated by an AND operator. Any additional
|
||||
@ -197,8 +198,8 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
|
||||
/* Figure out what index to use (if any) for each nested loop.
|
||||
** Make aIdx[i] point to the index to use for the i-th nested loop
|
||||
** where i==0 is the outer loop and i==pTabList->nId-1 is the inner
|
||||
** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
|
||||
** loop where i==0 is the outer loop and i==pTabList->nId-1 is the inner
|
||||
** loop. If the expression uses only the ROWID field, then set
|
||||
** aDirect[i] to 1.
|
||||
**
|
||||
@ -206,7 +207,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
** first 32 tables are candidates for indices.
|
||||
*/
|
||||
loopMask = 0;
|
||||
for(i=0; i<pTabList->nId && i<ARRAYSIZE(aIdx); i++){
|
||||
for(i=0; i<pTabList->nId && i<ARRAYSIZE(aDirect); i++){
|
||||
int j;
|
||||
int idx = aOrder[i];
|
||||
Table *pTab = pTabList->a[idx].pTab;
|
||||
@ -232,7 +233,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
if( aDirect[i] ){
|
||||
loopMask |= 1<<idx;
|
||||
aIdx[i] = 0;
|
||||
pWInfo->a[i].pIdx = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -278,11 +279,14 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
}
|
||||
}
|
||||
aIdx[i] = pBestIdx;
|
||||
pWInfo->a[i].pIdx = pBestIdx;
|
||||
loopMask |= 1<<idx;
|
||||
if( pBestIdx ){
|
||||
pWInfo->a[i].iCur = nCur++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open all tables in the pTabList and all indices in aIdx[].
|
||||
/* Open all tables in the pTabList and all indices used by those tables.
|
||||
*/
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
int openOp;
|
||||
@ -297,25 +301,25 @@ WhereInfo *sqliteWhereBegin(
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
|
||||
sqliteVdbeAddOp(v, openOp, base+pTabList->nId+i, aIdx[i]->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, aIdx[i]->zName, P3_STATIC);
|
||||
if( pWInfo->a[i].pIdx!=0 ){
|
||||
sqliteVdbeAddOp(v, openOp, pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
|
||||
}
|
||||
}
|
||||
memcpy(pWInfo->aIdx, aIdx, sizeof(aIdx));
|
||||
|
||||
/* Generate the code to do the search
|
||||
*/
|
||||
pWInfo->iBreak = brk = sqliteVdbeMakeLabel(v);
|
||||
loopMask = 0;
|
||||
pWInfo->iBreak = sqliteVdbeMakeLabel(v);
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
int j, k;
|
||||
int idx = aOrder[i];
|
||||
int goDirect;
|
||||
Index *pIdx;
|
||||
WhereLevel *pLevel = &pWInfo->a[i];
|
||||
|
||||
if( i<ARRAYSIZE(aIdx) ){
|
||||
pIdx = aIdx[i];
|
||||
if( i<ARRAYSIZE(aDirect) ){
|
||||
pIdx = pLevel->pIdx;
|
||||
goDirect = aDirect[i];
|
||||
}else{
|
||||
pIdx = 0;
|
||||
@ -346,25 +350,33 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_AddImm, 0, 0);
|
||||
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
||||
cont = pLevel->cont = brk;
|
||||
if( i==pTabList->nId-1 && pushKey ){
|
||||
haveKey = 1;
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk);
|
||||
haveKey = 0;
|
||||
}
|
||||
pLevel->op = OP_Noop;
|
||||
}else if( pIdx==0 ){
|
||||
/* Case 2: There was no usable index. We must do a complete
|
||||
** scan of the table.
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_Rewind, base+idx, 0);
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeResolveLabel(v, cont);
|
||||
sqliteVdbeAddOp(v, OP_Next, base+idx, brk);
|
||||
int start;
|
||||
|
||||
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
||||
cont = pLevel->cont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_Rewind, base+idx, brk);
|
||||
start = sqliteVdbeCurrentAddr(v);
|
||||
pLevel->op = OP_Next;
|
||||
pLevel->p1 = base+idx;
|
||||
pLevel->p2 = start;
|
||||
haveKey = 0;
|
||||
}else{
|
||||
/* Case 3: We do have a usable index in pIdx.
|
||||
*/
|
||||
cont = sqliteVdbeMakeLabel(v);
|
||||
int start;
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
for(k=0; k<nExpr; k++){
|
||||
if( aExpr[k].p==0 ) continue;
|
||||
@ -386,16 +398,24 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
}
|
||||
}
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
||||
cont = pLevel->cont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0);
|
||||
sqliteVdbeAddOp(v, OP_BeginIdx, base+pTabList->nId+i, 0);
|
||||
sqliteVdbeResolveLabel(v, cont);
|
||||
sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk);
|
||||
sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
|
||||
start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||
sqliteVdbeAddOp(v, OP_IdxGT, pLevel->iCur, brk);
|
||||
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
|
||||
if( i==pTabList->nId-1 && pushKey ){
|
||||
haveKey = 1;
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
|
||||
haveKey = 0;
|
||||
}
|
||||
pLevel->op = OP_Next;
|
||||
pLevel->p1 = pLevel->iCur;
|
||||
pLevel->p2 = start;
|
||||
}
|
||||
loopMask |= 1<<idx;
|
||||
|
||||
@ -429,21 +449,24 @@ WhereInfo *sqliteWhereBegin(
|
||||
void sqliteWhereEnd(WhereInfo *pWInfo){
|
||||
Vdbe *v = pWInfo->pParse->pVdbe;
|
||||
int i;
|
||||
int brk = pWInfo->iBreak;
|
||||
int base = pWInfo->base;
|
||||
WhereLevel *pLevel;
|
||||
|
||||
sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue);
|
||||
for(i=0; i<pWInfo->pTabList->nId; i++){
|
||||
sqliteVdbeResolveLabel(v, brk);
|
||||
sqliteVdbeAddOp(v, OP_Close, base+i, 0);
|
||||
brk = 0;
|
||||
if( i<ARRAYSIZE(pWInfo->aIdx) && pWInfo->aIdx[i]!=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Close, base+pWInfo->pTabList->nId+i, 0);
|
||||
for(i=pWInfo->pTabList->nId-1; i>=0; i--){
|
||||
pLevel = &pWInfo->a[i];
|
||||
sqliteVdbeResolveLabel(v, pLevel->cont);
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
sqliteVdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
|
||||
}
|
||||
sqliteVdbeResolveLabel(v, pLevel->brk);
|
||||
}
|
||||
if( brk!=0 ){
|
||||
sqliteVdbeResolveLabel(v, brk);
|
||||
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
|
||||
sqliteVdbeResolveLabel(v, pWInfo->iBreak);
|
||||
for(i=0; i<pWInfo->pTabList->nId; i++){
|
||||
pLevel = &pWInfo->a[i];
|
||||
sqliteVdbeAddOp(v, OP_Close, base+i, 0);
|
||||
if( pLevel->pIdx!=0 ){
|
||||
sqliteVdbeAddOp(v, OP_Close, pLevel->iCur, 0);
|
||||
}
|
||||
}
|
||||
sqliteFree(pWInfo);
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user