1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

:-) (CVS 104)

FossilOrigin-Name: e1bf96a467b739373191bf75e6a097fc0f24bffc
This commit is contained in:
drh
2000-06-21 13:59:10 +00:00
parent 7ed19903c9
commit 967e8b7351
25 changed files with 677 additions and 547 deletions

View File

@ -1,50 +1,50 @@
C :-)\s(CVS\s103) C :-)\s(CVS\s104)
D 2000-06-19T19:10:29 D 2000-06-21T13:59:11
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 4dc16840f68e3b599915e1ec8463d365474dd286 F Makefile.in 4dc16840f68e3b599915e1ec8463d365474dd286
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
F configure c366a0402bce79ef11fe1bf703ad6ce4ff6afbb0 x F configure c366a0402bce79ef11fe1bf703ad6ce4ff6afbb0 x
F configure.in 1085ff994a334b131325de906ed318e926673588 F configure.in 1085ff994a334b131325de906ed318e926673588
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F src/build.c 9ce11eafbab395b7d19bc5722d1a8955961889b0 F src/build.c 55edb404bbf4476c73c81604ddb9738281a689a4
F src/dbbe.c ae5e77f010ba1b68a65aa3cd55c8578eda523dd2 F src/dbbe.c 99aa6daca9a039eebb284dd459bef712ea3843f9
F src/dbbe.h 9a678ae524c2daad22e959111edd4494e6144dbc F src/dbbe.h 8718b718b36d37584e9bbdfccec10588fa91271f
F src/delete.c 2d5758055ff546453385524d856feb1b51ea7b8a F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065
F src/expr.c 88ff9ea12a23a3f0dfaf117670524bdc160af597 F src/expr.c 2fa63f086707176d09092e71832f9bbdc6a8ac85
F src/insert.c b1434c7c7c387c69e467d993e9d05460f1047bcc F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
F src/main.c e3297835b8e38ca726ac73f2c2bdb7cf08103197 F src/main.c 30b33b6e0cdd5ae1c0af9f626e78a1dc7b835e26
F src/parse.y 974ed07702bda4f04171ef22776eccbb5dae81ca F src/parse.y 86e268c29a0f00ffc062bbe934d95ea0d6308b0a
F src/select.c 2a91f683d64de0362834248cb291bc601cd2950b F src/select.c aaf23d4a6ef44e4378840ec94b6aa64641c01b5c
F src/shell.c 78a35607a88b3d557e1666ae9d0c2c03cbb3553e F src/shell.c 8387580e44878022c88c02b189bf23bff1862bda
F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268 F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268
F src/sqliteInt.h 19954bd2f75632849b265b9d7163a67391ec5148 F src/sqliteInt.h ddc6f8081ef469ede272cf6a382773dac5758dfc
F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7 F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7
F src/tokenize.c 77ff8164a8751994bc9926ce282847f653ac0c16 F src/tokenize.c 77ff8164a8751994bc9926ce282847f653ac0c16
F src/update.c 162fc0b86dcd61d164dedc77081a5e7daf6b8fb0 F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc
F src/util.c 38e4bb5edf6fa92e677698c45785bf73c69b9e9f F src/util.c fcd7ac9d2be8353f746e52f665e6c4f5d6b3b805
F src/vdbe.c 00b2ab7e0c0df2ac6eb4bf659656afc30e76c66b F src/vdbe.c 38cec3e88db70b7689018377c1594ac18f746b19
F src/vdbe.h 5f58611b19799de2dbcdefa4eef33a255cfa8d0d F src/vdbe.h 5f58611b19799de2dbcdefa4eef33a255cfa8d0d
F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c F src/where.c 420f666a38b405cd58bd7af832ed99f1dbc7d336
F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7
F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
F test/dbbe.test 0a8e4293cf816e590dcbb01be4cd4e8f7f95bdc8 F test/dbbe.test 0a8e4293cf816e590dcbb01be4cd4e8f7f95bdc8
F test/delete.test 30edd2c7484274fb2e7dbc4a1ac769bb330b322e F test/delete.test 402ee3ccb6e544582d24c573ef70b34d09583ae7
F test/expr.test 09b55ccf81cb8cc2f9cd83d592a2ba187ee48ba8 F test/expr.test 09b55ccf81cb8cc2f9cd83d592a2ba187ee48ba8
F test/in.test 962a605b6a3a619214f84d1950dfc44fcf0d8b8f F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603
F test/index.test 620ceab7165dd078d1266bdc2cac6147f04534ac F test/index.test 620ceab7165dd078d1266bdc2cac6147f04534ac
F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c
F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6 F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6
F test/main.test b7366cc6f3690915a11834bc1090deeff08acaf9 F test/main.test b7366cc6f3690915a11834bc1090deeff08acaf9
F test/select1.test 64703852af34c85bb31b0a74bd73b340e8267f42 F test/select1.test 4e57b0b5eae0c991d9cc51d1288be0476110e6f6
F test/select2.test 5e2783a48360b83956366ea24b2c5f0293015a84 F test/select2.test ed6e7fc3437079686d7ae4390a00347bbd5f7bf8
F test/select3.test a9234b8424b6c6d71de534f43b91ade9be68e9cc F test/select3.test a9234b8424b6c6d71de534f43b91ade9be68e9cc
F test/select4.test cb5374d7c87680e294ac749307459a5cc547609d F test/select4.test cb5374d7c87680e294ac749307459a5cc547609d
F test/select5.test 80ea257ce35e736c559bc6cd342361974e60a979 F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2
F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31 F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31
F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5
F test/table.test d3e01e4916a99ade7d8f1d534ee1b36d57c00490 F test/table.test d3e01e4916a99ade7d8f1d534ee1b36d57c00490
F test/tester.tcl 95b286791e6256bb6db0165f9342c70fff549a62 F test/tester.tcl 95b286791e6256bb6db0165f9342c70fff549a62
F test/update.test 0f763adc3d84e85224e1dadff72237bcabab1938 F test/update.test 62f6ce99ff31756aab0ca832ff6d34c5a87b6250
F test/vacuum.test 8becf5cfeb897108b35cdd996793e7f1df2f28fd F test/vacuum.test 8becf5cfeb897108b35cdd996793e7f1df2f28fd
F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397 F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397
F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b
@ -57,14 +57,14 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156 F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156
F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87 F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87
F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40 F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40
F www/c_interface.tcl 9ac800854272db5fe439e07b7435b243a5422293 F www/c_interface.tcl 8eb800f67e6896b1894d666b81c0b418cea09fc7
F www/changes.tcl 160f7522145efaf49961f6cf3671c66c02f2207b F www/changes.tcl 160f7522145efaf49961f6cf3671c66c02f2207b
F www/fileformat.tcl b11435fcd2cf2238a1c5e6d16fe5e83bcd14d434 F www/fileformat.tcl b11435fcd2cf2238a1c5e6d16fe5e83bcd14d434
F www/index.tcl 4116afce6a8c63d68882d2b00aa10b079e0129cd F www/index.tcl 4116afce6a8c63d68882d2b00aa10b079e0129cd
F www/lang.tcl 1645e9107d75709be4c6099b643db235bbe0a151 F www/lang.tcl 1645e9107d75709be4c6099b643db235bbe0a151
F www/opcode.tcl 3cdc4bb2515fcfcbe853e3f0c91cd9199e82dadd F www/opcode.tcl 3cdc4bb2515fcfcbe853e3f0c91cd9199e82dadd
F www/sqlite.tcl 5420eab24b539928f80ea9b3088e2549d34f438d F www/sqlite.tcl 9fdcfd48fe9e5669116d02f29b2608903f295740
P 8cce4d279de00da45c5970c8f0946f49e03e6846 P af14a5b3ba4a13665142b700e8864bf63d591d95
R 24ae8084d8386391fc8e3403683f09be R 4b875fc1d381ebbdab00fc05e8ad8c74
U drh U drh
Z 34d7058e222643fe967104d6dc2aa522 Z e8d8e8697e4d556ecd0e3a4c2a206a66

View File

@ -1 +1 @@
af14a5b3ba4a13665142b700e8864bf63d591d95 e1bf96a467b739373191bf75e6a097fc0f24bffc

View File

@ -33,7 +33,7 @@
** COPY ** COPY
** VACUUM ** VACUUM
** **
** $Id: build.c,v 1.18 2000/06/17 13:12:39 drh Exp $ ** $Id: build.c,v 1.19 2000/06/21 13:59:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -151,8 +151,8 @@ Index *sqliteFindIndex(sqlite *db, char *zName){
** its memory structures. ** its memory structures.
** **
** The index is removed from the database hash table, but it is ** The index is removed from the database hash table, but it is
** not unlinked from the table that is being indexed. Unlinking ** not unlinked from the Table that is being indexed. Unlinking
** from the table must be done by the calling function. ** from the Table must be done by the calling function.
*/ */
static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
int h; int h;
@ -173,7 +173,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
/* /*
** Remove the memory data structures associated with the given ** Remove the memory data structures associated with the given
** table. No changes are made to disk by this routine. ** Table. No changes are made to disk by this routine.
** **
** This routine just deletes the data structure. It does not unlink ** This routine just deletes the data structure. It does not unlink
** the table data structure from the hash table. But does it destroy ** the table data structure from the hash table. But does it destroy
@ -512,11 +512,11 @@ void sqliteCreateIndex(
pParse->nErr++; pParse->nErr++;
goto exit_create_index; goto exit_create_index;
} }
pIndex->aiField = (int*)&pIndex[1]; pIndex->aiColumn = (int*)&pIndex[1];
pIndex->zName = (char*)&pIndex->aiField[pList->nId]; pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
strcpy(pIndex->zName, zName); strcpy(pIndex->zName, zName);
pIndex->pTable = pTab; pIndex->pTable = pTab;
pIndex->nField = pList->nId; pIndex->nColumn = pList->nId;
/* Scan the names of the columns of the table to be indexed and /* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error ** load the column indices into the Index structure. Report an error
@ -533,7 +533,7 @@ void sqliteCreateIndex(
sqliteFree(pIndex); sqliteFree(pIndex);
goto exit_create_index; goto exit_create_index;
} }
pIndex->aiField[i] = j; pIndex->aiColumn[i] = j;
} }
/* Link the new Index structure to its table and to the other /* Link the new Index structure to its table and to the other
@ -590,10 +590,10 @@ void sqliteCreateIndex(
lbl2 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1); sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0);
for(i=0; i<pIndex->nField; i++){ for(i=0; i<pIndex->nColumn; i++){
sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiField[i], 0, 0); sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiColumn[i], 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIndex->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIndex->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, 1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
@ -834,10 +834,10 @@ void sqliteCopy(
if( pIdx->pNext ){ if( pIdx->pNext ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
} }
for(j=0; j<pIdx->nField; j++){ for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_FileField, pIdx->aiField[j], 0, 0, 0); sqliteVdbeAddOp(v, OP_FileField, pIdx->aiColumn[j], 0, 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, i, 0, 0, 0);
} }
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);

View File

@ -30,7 +30,7 @@
** relatively simple to convert to a different database such ** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB. ** as NDBM, SDBM, or BerkeleyDB.
** **
** $Id: dbbe.c,v 1.14 2000/06/17 13:12:39 drh Exp $ ** $Id: dbbe.c,v 1.15 2000/06/21 13:59:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <gdbm.h> #include <gdbm.h>
@ -43,7 +43,7 @@
** Information about each open disk file is an instance of this ** Information about each open disk file is an instance of this
** structure. There will only be one such structure for each ** structure. There will only be one such structure for each
** disk file. If the VDBE opens the same file twice (as will happen ** disk file. If the VDBE opens the same file twice (as will happen
** for a self-join, for example) then two DbbeTable structures are ** for a self-join, for example) then two DbbeCursor structures are
** created but there is only a single BeFile structure with an ** created but there is only a single BeFile structure with an
** nRef of 2. ** nRef of 2.
*/ */
@ -87,12 +87,12 @@ struct Dbbe {
/* /*
** An cursor into a database file is an instance of the following structure. ** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but ** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeTable structures. Each DbbeTable represents ** there can be multiple DbbeCursor structures. Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile. The ** a cursor pointing to a particular part of the open BeFile. The
** BeFile.nRef field hold a count of the number of DbbeTable structures ** BeFile.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file. ** associated with the same disk file.
*/ */
struct DbbeTable { struct DbbeCursor {
Dbbe *pBe; /* The database of which this record is a part */ Dbbe *pBe; /* The database of which this record is a part */
BeFile *pFile; /* The database file for this table */ BeFile *pFile; /* The database file for this table */
datum key; /* Most recently used key */ datum key; /* Most recently used key */
@ -226,8 +226,9 @@ void sqliteDbbeClose(Dbbe *pBe){
} }
/* /*
** Translate the name of a table into the name of a file that holds ** Translate the name of an SQL table (or index) into the name
** that table. Space to hold the filename is obtained from ** of a file that holds the key/data pairs for that table or
** index. Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function. ** sqliteMalloc() and must be freed by the calling function.
*/ */
static char *sqliteFileOfTable(Dbbe *pBe, const char *zTable){ static char *sqliteFileOfTable(Dbbe *pBe, const char *zTable){
@ -269,7 +270,7 @@ static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
/* /*
** Open a new table cursor. Write a pointer to the corresponding ** Open a new table cursor. Write a pointer to the corresponding
** DbbeTable structure into *ppTable. Return an integer success ** DbbeCursor structure into *ppCursr. Return an integer success
** code: ** code:
** **
** SQLITE_OK It worked! ** SQLITE_OK It worked!
@ -287,25 +288,26 @@ static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
** (This can happen if a SELECT callback tries to ** (This can happen if a SELECT callback tries to
** do an UPDATE or DELETE.) ** do an UPDATE or DELETE.)
** **
** If zTable is 0 or "", then a temporary table is created and opened. ** If zTable is 0 or "", then a temporary database file is created and
** This table will be deleted from the disk when it is closed. ** a cursor to that temporary file is opened. The temporary file
** will be deleted from the disk when it is closed.
*/ */
int sqliteDbbeOpenTable( int sqliteDbbeOpenCursor(
Dbbe *pBe, /* The database the table belongs to */ Dbbe *pBe, /* The database the table belongs to */
const char *zTable, /* The name of the table */ const char *zTable, /* The SQL name of the file to be opened */
int writeable, /* True to open for writing */ int writeable, /* True to open for writing */
DbbeTable **ppTable /* Write the resulting table pointer here */ DbbeCursor **ppCursr /* Write the resulting table pointer here */
){ ){
char *zFile; /* Name of the table file */ char *zFile; /* Name of the table file */
DbbeTable *pTable; /* The new table cursor */ DbbeCursor *pCursr; /* The new table cursor */
BeFile *pFile; /* The underlying data file for this table */ BeFile *pFile; /* The underlying data file for this table */
int rc = SQLITE_OK; /* Return value */ int rc = SQLITE_OK; /* Return value */
int rw_mask; /* Permissions mask for opening a table */ int rw_mask; /* Permissions mask for opening a table */
int mode; /* Mode for opening a table */ int mode; /* Mode for opening a table */
*ppTable = 0; *ppCursr = 0;
pTable = sqliteMalloc( sizeof(*pTable) ); pCursr = sqliteMalloc( sizeof(*pCursr) );
if( pTable==0 ) return SQLITE_NOMEM; if( pCursr==0 ) return SQLITE_NOMEM;
if( zTable ){ if( zTable ){
zFile = sqliteFileOfTable(pBe, zTable); zFile = sqliteFileOfTable(pBe, zTable);
for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
@ -376,11 +378,11 @@ int sqliteDbbeOpenTable(
rc = SQLITE_READONLY; rc = SQLITE_READONLY;
} }
} }
pTable->pBe = pBe; pCursr->pBe = pBe;
pTable->pFile = pFile; pCursr->pFile = pFile;
pTable->readPending = 0; pCursr->readPending = 0;
pTable->needRewind = 1; pCursr->needRewind = 1;
*ppTable = pTable; *ppCursr = pCursr;
return rc; return rc;
} }
@ -400,28 +402,33 @@ void sqliteDbbeDropTable(Dbbe *pBe, const char *zTable){
** Reorganize a table to reduce search times and disk usage. ** Reorganize a table to reduce search times and disk usage.
*/ */
void sqliteDbbeReorganizeTable(Dbbe *pBe, const char *zTable){ void sqliteDbbeReorganizeTable(Dbbe *pBe, const char *zTable){
DbbeTable *pTab; DbbeCursor *pCrsr;
if( sqliteDbbeOpenTable(pBe, zTable, 1, &pTab)!=SQLITE_OK ){ if( sqliteDbbeOpenCursor(pBe, zTable, 1, &pCrsr)!=SQLITE_OK ){
return; return;
} }
if( pTab && pTab->pFile && pTab->pFile->dbf ){ if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){
gdbm_reorganize(pTab->pFile->dbf); gdbm_reorganize(pCrsr->pFile->dbf);
} }
if( pTab ){ if( pCrsr ){
sqliteDbbeCloseTable(pTab); sqliteDbbeCloseCursor(pCrsr);
} }
} }
/* /*
** Close a table previously opened by sqliteDbbeOpenTable(). ** Close a cursor previously opened by sqliteDbbeOpenCursor().
**
** There can be multiple cursors pointing to the same open file.
** The underlying file is not closed until all cursors have been
** closed. This routine decrements the BeFile.nref field of the
** underlying file and closes the file when nref reaches 0.
*/ */
void sqliteDbbeCloseTable(DbbeTable *pTable){ void sqliteDbbeCloseCursor(DbbeCursor *pCursr){
BeFile *pFile; BeFile *pFile;
Dbbe *pBe; Dbbe *pBe;
if( pTable==0 ) return; if( pCursr==0 ) return;
pFile = pTable->pFile; pFile = pCursr->pFile;
pBe = pTable->pBe; pBe = pCursr->pBe;
pFile->nRef--; pFile->nRef--;
if( pFile->dbf!=NULL ){ if( pFile->dbf!=NULL ){
gdbm_sync(pFile->dbf); gdbm_sync(pFile->dbf);
@ -445,10 +452,10 @@ void sqliteDbbeCloseTable(DbbeTable *pTable){
memset(pFile, 0, sizeof(*pFile)); memset(pFile, 0, sizeof(*pFile));
sqliteFree(pFile); sqliteFree(pFile);
} }
if( pTable->key.dptr ) free(pTable->key.dptr); if( pCursr->key.dptr ) free(pCursr->key.dptr);
if( pTable->data.dptr ) free(pTable->data.dptr); if( pCursr->data.dptr ) free(pCursr->data.dptr);
memset(pTable, 0, sizeof(*pTable)); memset(pCursr, 0, sizeof(*pCursr));
sqliteFree(pTable); sqliteFree(pCursr);
} }
/* /*
@ -461,32 +468,32 @@ static void datumClear(datum *p){
} }
/* /*
** Fetch a single record from an open table. Return 1 on success ** Fetch a single record from an open cursor. Return 1 on success
** and 0 on failure. ** and 0 on failure.
*/ */
int sqliteDbbeFetch(DbbeTable *pTable, int nKey, char *pKey){ int sqliteDbbeFetch(DbbeCursor *pCursr, int nKey, char *pKey){
datum key; datum key;
key.dsize = nKey; key.dsize = nKey;
key.dptr = pKey; key.dptr = pKey;
datumClear(&pTable->key); datumClear(&pCursr->key);
datumClear(&pTable->data); datumClear(&pCursr->data);
if( pTable->pFile && pTable->pFile->dbf ){ if( pCursr->pFile && pCursr->pFile->dbf ){
pTable->data = gdbm_fetch(pTable->pFile->dbf, key); pCursr->data = gdbm_fetch(pCursr->pFile->dbf, key);
} }
return pTable->data.dptr!=0; return pCursr->data.dptr!=0;
} }
/* /*
** Return 1 if the given key is already in the table. Return 0 ** Return 1 if the given key is already in the table. Return 0
** if it is not. ** if it is not.
*/ */
int sqliteDbbeTest(DbbeTable *pTable, int nKey, char *pKey){ int sqliteDbbeTest(DbbeCursor *pCursr, int nKey, char *pKey){
datum key; datum key;
int result = 0; int result = 0;
key.dsize = nKey; key.dsize = nKey;
key.dptr = pKey; key.dptr = pKey;
if( pTable->pFile && pTable->pFile->dbf ){ if( pCursr->pFile && pCursr->pFile->dbf ){
result = gdbm_exists(pTable->pFile->dbf, key); result = gdbm_exists(pCursr->pFile->dbf, key);
} }
return result; return result;
} }
@ -495,30 +502,30 @@ int sqliteDbbeTest(DbbeTable *pTable, int nKey, char *pKey){
** Copy bytes from the current key or data into a buffer supplied by ** Copy bytes from the current key or data into a buffer supplied by
** the calling function. Return the number of bytes copied. ** the calling function. Return the number of bytes copied.
*/ */
int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){ int sqliteDbbeCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){
int n; int n;
if( offset>=pTable->key.dsize ) return 0; if( offset>=pCursr->key.dsize ) return 0;
if( offset+size>pTable->key.dsize ){ if( offset+size>pCursr->key.dsize ){
n = pTable->key.dsize - offset; n = pCursr->key.dsize - offset;
}else{ }else{
n = size; n = size;
} }
memcpy(zBuf, &pTable->key.dptr[offset], n); memcpy(zBuf, &pCursr->key.dptr[offset], n);
return n; return n;
} }
int sqliteDbbeCopyData(DbbeTable *pTable, int offset, int size, char *zBuf){ int sqliteDbbeCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){
int n; int n;
if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
pTable->readPending = 0; pCursr->readPending = 0;
} }
if( offset>=pTable->data.dsize ) return 0; if( offset>=pCursr->data.dsize ) return 0;
if( offset+size>pTable->data.dsize ){ if( offset+size>pCursr->data.dsize ){
n = pTable->data.dsize - offset; n = pCursr->data.dsize - offset;
}else{ }else{
n = size; n = size;
} }
memcpy(zBuf, &pTable->data.dptr[offset], n); memcpy(zBuf, &pCursr->data.dptr[offset], n);
return n; return n;
} }
@ -526,39 +533,39 @@ int sqliteDbbeCopyData(DbbeTable *pTable, int offset, int size, char *zBuf){
** Return a pointer to bytes from the key or data. The data returned ** Return a pointer to bytes from the key or data. The data returned
** is ephemeral. ** is ephemeral.
*/ */
char *sqliteDbbeReadKey(DbbeTable *pTable, int offset){ char *sqliteDbbeReadKey(DbbeCursor *pCursr, int offset){
if( offset<0 || offset>=pTable->key.dsize ) return ""; if( offset<0 || offset>=pCursr->key.dsize ) return "";
return &pTable->key.dptr[offset]; return &pCursr->key.dptr[offset];
} }
char *sqliteDbbeReadData(DbbeTable *pTable, int offset){ char *sqliteDbbeReadData(DbbeCursor *pCursr, int offset){
if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
pTable->readPending = 0; pCursr->readPending = 0;
} }
if( offset<0 || offset>=pTable->data.dsize ) return ""; if( offset<0 || offset>=pCursr->data.dsize ) return "";
return &pTable->data.dptr[offset]; return &pCursr->data.dptr[offset];
} }
/* /*
** Return the total number of bytes in either data or key. ** Return the total number of bytes in either data or key.
*/ */
int sqliteDbbeKeyLength(DbbeTable *pTable){ int sqliteDbbeKeyLength(DbbeCursor *pCursr){
return pTable->key.dsize; return pCursr->key.dsize;
} }
int sqliteDbbeDataLength(DbbeTable *pTable){ int sqliteDbbeDataLength(DbbeCursor *pCursr){
if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
pTable->readPending = 0; pCursr->readPending = 0;
} }
return pTable->data.dsize; return pCursr->data.dsize;
} }
/* /*
** Make is so that the next call to sqliteNextKey() finds the first ** Make is so that the next call to sqliteNextKey() finds the first
** key of the table. ** key of the table.
*/ */
int sqliteDbbeRewind(DbbeTable *pTable){ int sqliteDbbeRewind(DbbeCursor *pCursr){
pTable->needRewind = 1; pCursr->needRewind = 1;
return SQLITE_OK; return SQLITE_OK;
} }
@ -566,28 +573,28 @@ int sqliteDbbeRewind(DbbeTable *pTable){
** Read the next key from the table. Return 1 on success. Return ** Read the next key from the table. Return 1 on success. Return
** 0 if there are no more keys. ** 0 if there are no more keys.
*/ */
int sqliteDbbeNextKey(DbbeTable *pTable){ int sqliteDbbeNextKey(DbbeCursor *pCursr){
datum nextkey; datum nextkey;
int rc; int rc;
if( pTable==0 || pTable->pFile==0 || pTable->pFile->dbf==0 ){ if( pCursr==0 || pCursr->pFile==0 || pCursr->pFile->dbf==0 ){
pTable->readPending = 0; pCursr->readPending = 0;
return 0; return 0;
} }
if( pTable->needRewind ){ if( pCursr->needRewind ){
nextkey = gdbm_firstkey(pTable->pFile->dbf); nextkey = gdbm_firstkey(pCursr->pFile->dbf);
pTable->needRewind = 0; pCursr->needRewind = 0;
}else{ }else{
nextkey = gdbm_nextkey(pTable->pFile->dbf, pTable->key); nextkey = gdbm_nextkey(pCursr->pFile->dbf, pCursr->key);
} }
datumClear(&pTable->key); datumClear(&pCursr->key);
datumClear(&pTable->data); datumClear(&pCursr->data);
pTable->key = nextkey; pCursr->key = nextkey;
if( pTable->key.dptr ){ if( pCursr->key.dptr ){
pTable->readPending = 1; pCursr->readPending = 1;
rc = 1; rc = 1;
}else{ }else{
pTable->needRewind = 1; pCursr->needRewind = 1;
pTable->readPending = 0; pCursr->readPending = 0;
rc = 0; rc = 0;
} }
return rc; return rc;
@ -596,15 +603,15 @@ int sqliteDbbeNextKey(DbbeTable *pTable){
/* /*
** Get a new integer key. ** Get a new integer key.
*/ */
int sqliteDbbeNew(DbbeTable *pTable){ int sqliteDbbeNew(DbbeCursor *pCursr){
int iKey; int iKey;
datum key; datum key;
int go = 1; int go = 1;
int i; int i;
struct rc4 *pRc4; struct rc4 *pRc4;
if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1; if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
pRc4 = &pTable->pBe->rc4; pRc4 = &pCursr->pBe->rc4;
while( go ){ while( go ){
iKey = 0; iKey = 0;
for(i=0; i<4; i++){ for(i=0; i<4; i++){
@ -612,7 +619,7 @@ int sqliteDbbeNew(DbbeTable *pTable){
} }
key.dptr = (char*)&iKey; key.dptr = (char*)&iKey;
key.dsize = 4; key.dsize = 4;
go = gdbm_exists(pTable->pFile->dbf, key); go = gdbm_exists(pCursr->pFile->dbf, key);
} }
return iKey; return iKey;
} }
@ -621,33 +628,33 @@ int sqliteDbbeNew(DbbeTable *pTable){
** Write an entry into the table. Overwrite any prior entry with the ** Write an entry into the table. Overwrite any prior entry with the
** same key. ** same key.
*/ */
int sqliteDbbePut(DbbeTable *pTable, int nKey,char *pKey,int nData,char *pData){ int sqliteDbbePut(DbbeCursor *pCursr, int nKey,char *pKey,int nData,char *pData){
datum data, key; datum data, key;
int rc; int rc;
if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return SQLITE_ERROR; if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
data.dsize = nData; data.dsize = nData;
data.dptr = pData; data.dptr = pData;
key.dsize = nKey; key.dsize = nKey;
key.dptr = pKey; key.dptr = pKey;
rc = gdbm_store(pTable->pFile->dbf, key, data, GDBM_REPLACE); rc = gdbm_store(pCursr->pFile->dbf, key, data, GDBM_REPLACE);
if( rc ) rc = SQLITE_ERROR; if( rc ) rc = SQLITE_ERROR;
datumClear(&pTable->key); datumClear(&pCursr->key);
datumClear(&pTable->data); datumClear(&pCursr->data);
return rc; return rc;
} }
/* /*
** Remove an entry from a table, if the entry exists. ** Remove an entry from a table, if the entry exists.
*/ */
int sqliteDbbeDelete(DbbeTable *pTable, int nKey, char *pKey){ int sqliteDbbeDelete(DbbeCursor *pCursr, int nKey, char *pKey){
datum key; datum key;
int rc; int rc;
datumClear(&pTable->key); datumClear(&pCursr->key);
datumClear(&pTable->data); datumClear(&pCursr->data);
if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return SQLITE_ERROR; if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
key.dsize = nKey; key.dsize = nKey;
key.dptr = pKey; key.dptr = pKey;
rc = gdbm_delete(pTable->pFile->dbf, key); rc = gdbm_delete(pCursr->pFile->dbf, key);
if( rc ) rc = SQLITE_ERROR; if( rc ) rc = SQLITE_ERROR;
return rc; return rc;
} }

View File

@ -28,7 +28,7 @@
** This library was originally designed to support the following ** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB. ** backends: GDBM, NDBM, SDBM, Berkeley DB.
** **
** $Id: dbbe.h,v 1.5 2000/06/17 13:12:39 drh Exp $ ** $Id: dbbe.h,v 1.6 2000/06/21 13:59:11 drh Exp $
*/ */
#ifndef _SQLITE_DBBE_H_ #ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_ #define _SQLITE_DBBE_H_
@ -37,7 +37,7 @@
/* /*
** The database backend supports two opaque structures. A Dbbe is ** The database backend supports two opaque structures. A Dbbe is
** a context for the entire set of tables forming a complete ** a context for the entire set of tables forming a complete
** database. A DbbeTable is a single table. ** database. A DbbeCursor is a pointer into a single single table.
** **
** Note that at this level, the term "table" can mean either an ** Note that at this level, the term "table" can mean either an
** SQL table or an SQL index. In this module, a table stores a ** SQL table or an SQL index. In this module, a table stores a
@ -46,13 +46,13 @@
** segregation of data into various fields or columns is handled ** segregation of data into various fields or columns is handled
** by software at higher layers. ** by software at higher layers.
** **
** The DbbeTable structure holds some state information, such as ** The DbbeCursor structure holds some state information, such as
** the key and data from the last retrieval. For this reason, ** the key and data from the last retrieval. For this reason,
** the backend must allow the creation of multiple independent ** the backend must allow the creation of multiple independent
** DbbeTable structures for each table in the database. ** DbbeCursor structures for each table in the database.
*/ */
typedef struct Dbbe Dbbe; typedef struct Dbbe Dbbe;
typedef struct DbbeTable DbbeTable; typedef struct DbbeCursor DbbeCursor;
/* /*
** The 18 interface routines. ** The 18 interface routines.
@ -64,13 +64,16 @@ Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);
/* Close the whole database. */ /* Close the whole database. */
void sqliteDbbeClose(Dbbe*); void sqliteDbbeClose(Dbbe*);
/* Open a particular table of a previously opened database. /* Open a cursor into particular file of a previously opened database.
** Create the table if it doesn't already exist and writeable!=0. ** Create the file if it doesn't already exist and writeable!=0. zName
** is the base name of the file to be opened. This routine will add
** an appropriate path and extension to the filename to locate the
** actual file.
** **
** If zTableName is 0 or "", then a temporary table is created that ** If zName is 0 or "", then a temporary file is created that
** will be deleted when closed. ** will be deleted when closed.
*/ */
int sqliteDbbeOpenTable(Dbbe*, const char *zName, int writeable, DbbeTable **); int sqliteDbbeOpenCursor(Dbbe*, const char *zName, int writeable, DbbeCursor**);
/* Delete a table from the database */ /* Delete a table from the database */
void sqliteDbbeDropTable(Dbbe*, const char *zTableName); void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
@ -78,58 +81,58 @@ void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
/* Reorganize a table to speed access or reduce its disk usage */ /* Reorganize a table to speed access or reduce its disk usage */
void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName); void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName);
/* Close a table */ /* Close a cursor */
void sqliteDbbeCloseTable(DbbeTable*); void sqliteDbbeCloseCursor(DbbeCursor*);
/* Fetch an entry from a table with the given key. Return 1 if /* Fetch an entry from a table with the given key. Return 1 if
** successful and 0 if no such entry exists. ** successful and 0 if no such entry exists.
*/ */
int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey); int sqliteDbbeFetch(DbbeCursor*, int nKey, char *pKey);
/* Return 1 if the given key is already in the table. Return 0 /* Return 1 if the given key is already in the table. Return 0
** if it is not. ** if it is not.
*/ */
int sqliteDbbeTest(DbbeTable*, int nKey, char *pKey); int sqliteDbbeTest(DbbeCursor*, int nKey, char *pKey);
/* Retrieve the key or data used for the last fetch. Only size /* Retrieve the key or data used for the last fetch. Only size
** bytes are read beginning with the offset-th byte. The return ** bytes are read beginning with the offset-th byte. The return
** value is the actual number of bytes read. ** value is the actual number of bytes read.
*/ */
int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf); int sqliteDbbeCopyKey(DbbeCursor*, int offset, int size, char *zBuf);
int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf); int sqliteDbbeCopyData(DbbeCursor*, int offset, int size, char *zBuf);
/* Retrieve the key or data. The result is ephemeral. In other words, /* Retrieve the key or data. The result is ephemeral. In other words,
** the result is stored in a buffer that might be overwritten on the next ** the result is stored in a buffer that might be overwritten on the next
** call to any DBBE routine. If the results are needed for longer than ** call to any DBBE routine. If the results are needed for longer than
** that, you must make a copy. ** that, you must make a copy.
*/ */
char *sqliteDbbeReadKey(DbbeTable*, int offset); char *sqliteDbbeReadKey(DbbeCursor*, int offset);
char *sqliteDbbeReadData(DbbeTable*, int offset); char *sqliteDbbeReadData(DbbeCursor*, int offset);
/* Return the length of the most recently fetched key or data. */ /* Return the length of the most recently fetched key or data. */
int sqliteDbbeKeyLength(DbbeTable*); int sqliteDbbeKeyLength(DbbeCursor*);
int sqliteDbbeDataLength(DbbeTable*); int sqliteDbbeDataLength(DbbeCursor*);
/* Retrieve the next entry in the table. The first key is retrieved /* Retrieve the next entry in the table. The first key is retrieved
** the first time this routine is called, or after a call to ** the first time this routine is called, or after a call to
** sqliteDbbeRewind(). The return value is 1 if there is another ** sqliteDbbeRewind(). The return value is 1 if there is another
** entry, or 0 if there are no more entries. */ ** entry, or 0 if there are no more entries. */
int sqliteDbbeNextKey(DbbeTable*); int sqliteDbbeNextKey(DbbeCursor*);
/* Make it so that the next call to sqliteDbbeNextKey() returns /* Make it so that the next call to sqliteDbbeNextKey() returns
** the first entry of the table. */ ** the first entry of the table. */
int sqliteDbbeRewind(DbbeTable*); int sqliteDbbeRewind(DbbeCursor*);
/* Get a new integer key for this table. */ /* Get a new integer key for this table. */
int sqliteDbbeNew(DbbeTable*); int sqliteDbbeNew(DbbeCursor*);
/* Write an entry into a table. If another entry already exists with /* Write an entry into a table. If another entry already exists with
** the same key, the old entry is discarded first. ** the same key, the old entry is discarded first.
*/ */
int sqliteDbbePut(DbbeTable*, int nKey, char *pKey, int nData, char *pData); int sqliteDbbePut(DbbeCursor*, int nKey, char *pKey, int nData, char *pData);
/* Remove an entry from the table */ /* Remove an entry from the table */
int sqliteDbbeDelete(DbbeTable*, int nKey, char *pKey); int sqliteDbbeDelete(DbbeCursor*, int nKey, char *pKey);
/* Open a file suitable for temporary storage */ /* Open a file suitable for temporary storage */
int sqliteDbbeOpenTempFile(Dbbe*, FILE**); int sqliteDbbeOpenTempFile(Dbbe*, FILE**);

View File

@ -24,7 +24,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 DELETE FROM statements. ** to handle DELETE FROM statements.
** **
** $Id: delete.c,v 1.5 2000/06/17 13:12:39 drh Exp $ ** $Id: delete.c,v 1.6 2000/06/21 13:59:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -68,7 +68,7 @@ void sqliteDeleteFrom(
} }
pTab = pTabList->a[0].pTab; pTab = pTabList->a[0].pTab;
/* Resolve the field names in all the expressions. /* Resolve the column names in all the expressions.
*/ */
if( pWhere ){ if( pWhere ){
sqliteExprResolveInSelect(pParse, pWhere); sqliteExprResolveInSelect(pParse, pWhere);
@ -117,10 +117,10 @@ void sqliteDeleteFrom(
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
int j; int j;
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
for(j=0; j<pIdx->nField; j++){ for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0); sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0); sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
} }
} }

View File

@ -24,7 +24,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. ** for generating VDBE code that evaluates expressions.
** **
** $Id: expr.c,v 1.17 2000/06/17 13:12:40 drh Exp $ ** $Id: expr.c,v 1.18 2000/06/21 13:59:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -35,7 +35,7 @@
static int isConstant(Expr *p){ static int isConstant(Expr *p){
switch( p->op ){ switch( p->op ){
case TK_ID: case TK_ID:
case TK_FIELD: case TK_COLUMN:
case TK_DOT: case TK_DOT:
return 0; return 0;
default: { default: {
@ -58,10 +58,10 @@ static int isConstant(Expr *p){
** **
** expr IN (SELECT ...) ** expr IN (SELECT ...)
** **
** These operators have to be processed before field names are ** These operators have to be processed before column names are
** resolved because each such operator increments pParse->nTab ** resolved because each such operator increments pParse->nTab
** to reserve cursor numbers for its own use. But pParse->nTab ** to reserve cursor numbers for its own use. But pParse->nTab
** needs to be constant once we begin resolving field names. ** needs to be constant once we begin resolving column names.
** **
** Actually, the processing of IN-SELECT is only started by this ** Actually, the processing of IN-SELECT is only started by this
** routine. This routine allocates a cursor number to the IN-SELECT ** routine. This routine allocates a cursor number to the IN-SELECT
@ -87,11 +87,11 @@ void sqliteExprResolveInSelect(Parse *pParse, Expr *pExpr){
/* /*
** This routine walks an expression tree and resolves references to ** This routine walks an expression tree and resolves references to
** table fields. Nodes of the form ID.ID or ID resolve into an ** table columns. Nodes of the form ID.ID or ID resolve into an
** index to the table in the table list and a field offset. The opcode ** index to the table in the table list and a column offset. The opcode
** for such nodes is changed to TK_FIELD. The iTable value is changed ** for such nodes is changed to TK_COLUMN. The iTable value is changed
** to the index of the referenced table in pTabList plus the pParse->nTab ** to the index of the referenced table in pTabList plus the pParse->nTab
** value. The iField value is changed to the index of the field of the ** value. The iColumn value is changed to the index of the column of the
** referenced table. ** referenced table.
** **
** We also check for instances of the IN operator. IN comes in two ** We also check for instances of the IN operator. IN comes in two
@ -109,7 +109,7 @@ void sqliteExprResolveInSelect(Parse *pParse, Expr *pExpr){
** If it finds any, it generates code to write the value of that select ** If it finds any, it generates code to write the value of that select
** into a memory cell. ** into a memory cell.
** **
** Unknown fields or tables provoke an error. The function returns ** Unknown columns or tables provoke an error. The function returns
** the number of errors seen and leaves an error message on pParse->zErrMsg. ** the number of errors seen and leaves an error message on pParse->zErrMsg.
*/ */
int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
@ -128,27 +128,27 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){ if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
cnt++; cnt++;
pExpr->iTable = i + pParse->nTab; pExpr->iTable = i + pParse->nTab;
pExpr->iField = j; pExpr->iColumn = j;
} }
} }
} }
sqliteFree(z); sqliteFree(z);
if( cnt==0 ){ if( cnt==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such field: ", -1, sqliteSetNString(&pParse->zErrMsg, "no such column: ", -1,
pExpr->token.z, pExpr->token.n, 0); pExpr->token.z, pExpr->token.n, 0);
pParse->nErr++; pParse->nErr++;
return 1; return 1;
}else if( cnt>1 ){ }else if( cnt>1 ){
sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: ", -1, sqliteSetNString(&pParse->zErrMsg, "ambiguous column name: ", -1,
pExpr->token.z, pExpr->token.n, 0); pExpr->token.z, pExpr->token.n, 0);
pParse->nErr++; pParse->nErr++;
return 1; return 1;
} }
pExpr->op = TK_FIELD; pExpr->op = TK_COLUMN;
break; break;
} }
/* A table name and field name: ID.ID */ /* A table name and column name: ID.ID */
case TK_DOT: { case TK_DOT: {
int cnt = 0; /* Number of matches */ int cnt = 0; /* Number of matches */
int i; /* Loop counter */ int i; /* Loop counter */
@ -176,20 +176,20 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++; cnt++;
pExpr->iTable = i + pParse->nTab; pExpr->iTable = i + pParse->nTab;
pExpr->iField = j; pExpr->iColumn = j;
} }
} }
} }
sqliteFree(zLeft); sqliteFree(zLeft);
sqliteFree(zRight); sqliteFree(zRight);
if( cnt==0 ){ if( cnt==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such field: ", -1, sqliteSetNString(&pParse->zErrMsg, "no such column: ", -1,
pLeft->token.z, pLeft->token.n, ".", 1, pLeft->token.z, pLeft->token.n, ".", 1,
pRight->token.z, pRight->token.n, 0); pRight->token.z, pRight->token.n, 0);
pParse->nErr++; pParse->nErr++;
return 1; return 1;
}else if( cnt>1 ){ }else if( cnt>1 ){
sqliteSetNString(&pParse->zErrMsg, "ambiguous field name: ", -1, sqliteSetNString(&pParse->zErrMsg, "ambiguous column name: ", -1,
pLeft->token.z, pLeft->token.n, ".", 1, pLeft->token.z, pLeft->token.n, ".", 1,
pRight->token.z, pRight->token.n, 0); pRight->token.z, pRight->token.n, 0);
pParse->nErr++; pParse->nErr++;
@ -199,7 +199,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
pExpr->pLeft = 0; pExpr->pLeft = 0;
sqliteExprDelete(pRight); sqliteExprDelete(pRight);
pExpr->pRight = 0; pExpr->pRight = 0;
pExpr->op = TK_FIELD; pExpr->op = TK_COLUMN;
break; break;
} }
@ -263,10 +263,10 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){
case TK_SELECT: { case TK_SELECT: {
/* This has to be a scalar SELECT. Generate code to put the /* This has to be a scalar SELECT. Generate code to put the
** value of this select in a memory cell and record the number ** value of this select in a memory cell and record the number
** of the memory cell in iField. ** of the memory cell in iColumn.
*/ */
pExpr->iField = pParse->nMem++; pExpr->iColumn = pParse->nMem++;
if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iField) ){ if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iColumn) ){
return 1; return 1;
} }
break; break;
@ -355,7 +355,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
int too_few_args = 0; int too_few_args = 0;
int is_agg = 0; int is_agg = 0;
int i; int i;
pExpr->iField = id; pExpr->iColumn = id;
switch( id ){ switch( id ){
case FN_Unknown: { case FN_Unknown: {
no_such_func = 1; no_such_func = 1;
@ -467,11 +467,11 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
default: break; default: break;
} }
switch( pExpr->op ){ switch( pExpr->op ){
case TK_FIELD: { case TK_COLUMN: {
if( pParse->useAgg ){ if( pParse->useAgg ){
sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0);
}else{ }else{
sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iField, 0, 0); sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iColumn, 0, 0);
} }
break; break;
} }
@ -562,7 +562,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
} }
case TK_AGG_FUNCTION: { case TK_AGG_FUNCTION: {
sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0);
if( pExpr->iField==FN_Avg ){ if( pExpr->iColumn==FN_Avg ){
assert( pParse->iAggCount>=0 && pParse->iAggCount<pParse->nAgg ); assert( pParse->iAggCount>=0 && pParse->iAggCount<pParse->nAgg );
sqliteVdbeAddOp(v, OP_AggGet, 0, pParse->iAggCount, 0, 0); sqliteVdbeAddOp(v, OP_AggGet, 0, pParse->iAggCount, 0, 0);
sqliteVdbeAddOp(v, OP_Divide, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Divide, 0, 0, 0, 0);
@ -570,7 +570,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
break; break;
} }
case TK_FUNCTION: { case TK_FUNCTION: {
int id = pExpr->iField; int id = pExpr->iColumn;
int op; int op;
int i; int i;
ExprList *pList = pExpr->pList; ExprList *pList = pExpr->pList;
@ -588,7 +588,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
break; break;
} }
case TK_SELECT: { case TK_SELECT: {
sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0, 0, 0);
break; break;
} }
case TK_IN: { case TK_IN: {
@ -864,12 +864,12 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
if( pExpr==0 ) return 0; if( pExpr==0 ) return 0;
switch( pExpr->op ){ switch( pExpr->op ){
case TK_FIELD: { case TK_COLUMN: {
aAgg = pParse->aAgg; aAgg = pParse->aAgg;
for(i=0; i<pParse->nAgg; i++){ for(i=0; i<pParse->nAgg; i++){
if( aAgg[i].isAgg ) continue; if( aAgg[i].isAgg ) continue;
if( aAgg[i].pExpr->iTable==pExpr->iTable if( aAgg[i].pExpr->iTable==pExpr->iTable
&& aAgg[i].pExpr->iField==pExpr->iField ){ && aAgg[i].pExpr->iColumn==pExpr->iColumn ){
break; break;
} }
} }
@ -883,7 +883,7 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
break; break;
} }
case TK_AGG_FUNCTION: { case TK_AGG_FUNCTION: {
if( pExpr->iField==FN_Count || pExpr->iField==FN_Avg ){ if( pExpr->iColumn==FN_Count || pExpr->iColumn==FN_Avg ){
if( pParse->iAggCount>=0 ){ if( pParse->iAggCount>=0 ){
i = pParse->iAggCount; i = pParse->iAggCount;
}else{ }else{
@ -893,7 +893,7 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
pParse->aAgg[i].pExpr = 0; pParse->aAgg[i].pExpr = 0;
pParse->iAggCount = i; pParse->iAggCount = i;
} }
if( pExpr->iField==FN_Count ){ if( pExpr->iColumn==FN_Count ){
pExpr->iAgg = i; pExpr->iAgg = i;
break; break;
} }

View File

@ -24,7 +24,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 INSERT statements. ** to handle INSERT statements.
** **
** $Id: insert.c,v 1.10 2000/06/17 13:12:40 drh Exp $ ** $Id: insert.c,v 1.11 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -36,7 +36,7 @@
** **
** The IDLIST following the table name is always optional. If omitted, ** The IDLIST following the table name is always optional. If omitted,
** then a list of all columns for the table is substituted. The IDLIST ** then a list of all columns for the table is substituted. The IDLIST
** appears in the pField parameter. pField is NULL if IDLIST is omitted. ** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
** **
** The pList parameter holds EXPRLIST in the first form of the INSERT ** The pList parameter holds EXPRLIST in the first form of the INSERT
** statement above, and pSelect is NULL. For the second form, pList is ** statement above, and pSelect is NULL. For the second form, pList is
@ -48,7 +48,7 @@ void sqliteInsert(
Token *pTableName, /* Name of table into which we are inserting */ Token *pTableName, /* Name of table into which we are inserting */
ExprList *pList, /* List of values to be inserted */ ExprList *pList, /* List of values to be inserted */
Select *pSelect, /* A SELECT statement to use as the data source */ Select *pSelect, /* A SELECT statement to use as the data source */
IdList *pField /* Field names corresponding to IDLIST. */ IdList *pColumn /* Column names corresponding to IDLIST. */
){ ){
Table *pTab; /* The table to insert into */ Table *pTab; /* The table to insert into */
char *zTab; /* Name of the table into which we are inserting */ char *zTab; /* Name of the table into which we are inserting */
@ -56,7 +56,7 @@ void sqliteInsert(
Vdbe *v; /* Generate code into this virtual machine */ Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
int srcTab; /* Date comes from this temporary cursor if >=0 */ int srcTab; /* Date comes from this temporary cursor if >=0 */
int nField; /* Number of columns in the data */ int nColumn; /* Number of columns in the data */
int base; /* First available cursor */ int base; /* First available cursor */
int iCont, iBreak; /* Beginning and end of the loop over srcTab */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */
@ -96,20 +96,20 @@ void sqliteInsert(
rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab);
if( rc ) goto insert_cleanup; if( rc ) goto insert_cleanup;
assert( pSelect->pEList ); assert( pSelect->pEList );
nField = pSelect->pEList->nExpr; nColumn = pSelect->pEList->nExpr;
}else{ }else{
srcTab = -1; srcTab = -1;
assert( pList ); assert( pList );
nField = pList->nExpr; nColumn = pList->nExpr;
} }
/* Make sure the number of columns in the source data matches the number /* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table. ** of columns to be inserted into the table.
*/ */
if( pField==0 && nField!=pTab->nCol ){ if( pColumn==0 && nColumn!=pTab->nCol ){
char zNum1[30]; char zNum1[30];
char zNum2[30]; char zNum2[30];
sprintf(zNum1,"%d", nField); sprintf(zNum1,"%d", nColumn);
sprintf(zNum2,"%d", pTab->nCol); sprintf(zNum2,"%d", pTab->nCol);
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" has ", zNum2, " columns but ", " has ", zNum2, " columns but ",
@ -117,11 +117,11 @@ void sqliteInsert(
pParse->nErr++; pParse->nErr++;
goto insert_cleanup; goto insert_cleanup;
} }
if( pField!=0 && nField!=pField->nId ){ if( pColumn!=0 && nColumn!=pColumn->nId ){
char zNum1[30]; char zNum1[30];
char zNum2[30]; char zNum2[30];
sprintf(zNum1,"%d", nField); sprintf(zNum1,"%d", nColumn);
sprintf(zNum2,"%d", pField->nId); sprintf(zNum2,"%d", pColumn->nId);
sqliteSetString(&pParse->zErrMsg, zNum1, " values for ", sqliteSetString(&pParse->zErrMsg, zNum1, " values for ",
zNum2, " columns", 0); zNum2, " columns", 0);
pParse->nErr++; pParse->nErr++;
@ -132,20 +132,20 @@ void sqliteInsert(
** all elements of the IDLIST really are columns of the table and ** all elements of the IDLIST really are columns of the table and
** remember the column indices. ** remember the column indices.
*/ */
if( pField ){ if( pColumn ){
for(i=0; i<pField->nId; i++){ for(i=0; i<pColumn->nId; i++){
pField->a[i].idx = -1; pColumn->a[i].idx = -1;
} }
for(i=0; i<pField->nId; i++){ for(i=0; i<pColumn->nId; i++){
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pField->a[i].zName, pTab->aCol[j].zName)==0 ){ if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
pField->a[i].idx = j; pColumn->a[i].idx = j;
break; break;
} }
} }
if( j>=pTab->nCol ){ if( j>=pTab->nCol ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" has no column named ", pField->a[i].zName, 0); " has no column named ", pColumn->a[i].zName, 0);
pParse->nErr++; pParse->nErr++;
goto insert_cleanup; goto insert_cleanup;
} }
@ -179,14 +179,14 @@ void sqliteInsert(
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
} }
for(i=0; i<pTab->nCol; i++){ for(i=0; i<pTab->nCol; i++){
if( pField==0 ){ if( pColumn==0 ){
j = i; j = i;
}else{ }else{
for(j=0; j<pField->nId; j++){ for(j=0; j<pColumn->nId; j++){
if( pField->a[j].idx==i ) break; if( pColumn->a[j].idx==i ) break;
} }
} }
if( pField && j>=pField->nId ){ if( pColumn && j>=pColumn->nId ){
char *zDflt = pTab->aCol[i].zDflt; char *zDflt = pTab->aCol[i].zDflt;
if( zDflt==0 ){ if( zDflt==0 ){
sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
@ -209,16 +209,16 @@ void sqliteInsert(
if( pIdx->pNext ){ if( pIdx->pNext ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
} }
for(i=0; i<pIdx->nField; i++){ for(i=0; i<pIdx->nColumn; i++){
int idx = pIdx->aiField[i]; int idx = pIdx->aiColumn[i];
if( pField==0 ){ if( pColumn==0 ){
j = idx; j = idx;
}else{ }else{
for(j=0; j<pField->nId; j++){ for(j=0; j<pColumn->nId; j++){
if( pField->a[j].idx==idx ) break; if( pColumn->a[j].idx==idx ) break;
} }
} }
if( pField && j>=pField->nId ){ if( pColumn && j>=pColumn->nId ){
char *zDflt = pTab->aCol[idx].zDflt; char *zDflt = pTab->aCol[idx].zDflt;
if( zDflt==0 ){ if( zDflt==0 ){
sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
@ -231,7 +231,7 @@ void sqliteInsert(
sqliteExprCode(pParse, pList->a[j].pExpr); sqliteExprCode(pParse, pList->a[j].pExpr);
} }
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, idx+base, 0, 0, 0);
} }
@ -245,5 +245,5 @@ void sqliteInsert(
insert_cleanup: insert_cleanup:
if( pList ) sqliteExprListDelete(pList); if( pList ) sqliteExprListDelete(pList);
if( pSelect ) sqliteSelectDelete(pSelect); if( pSelect ) sqliteSelectDelete(pSelect);
sqliteIdListDelete(pField); sqliteIdListDelete(pColumn);
} }

View File

@ -26,7 +26,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.12 2000/06/07 23:51:50 drh Exp $ ** $Id: main.c,v 1.13 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -90,12 +90,12 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
** ); ** );
** **
** The sqlite_master table contains a single entry for each table ** The sqlite_master table contains a single entry for each table
** and each index. The "type" field tells whether the entry is ** and each index. The "type" column tells whether the entry is
** a table or index. The "name" field is the name of the object. ** a table or index. The "name" column is the name of the object.
** The "tbl_name" is the name of the associated table. For tables, ** The "tbl_name" is the name of the associated table. For tables,
** the tbl_name field is always the same as name. For indices, the ** the tbl_name column is always the same as name. For indices, the
** tbl_name field contains the name of the table that the index ** tbl_name column contains the name of the table that the index
** indexes. Finally, the sql field contains the complete text of ** indexes. Finally, the "sql" column contains the complete text of
** the CREATE TABLE or CREATE INDEX statement that originally created ** the CREATE TABLE or CREATE INDEX statement that originally created
** the table or index. ** the table or index.
** **

View File

@ -26,7 +26,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** numeric codes for all of the tokens.
** **
** @(#) $Id: parse.y,v 1.22 2000/06/19 19:09:09 drh Exp $ ** @(#) $Id: parse.y,v 1.23 2000/06/21 13:59:12 drh Exp $
*/ */
%token_prefix TK_ %token_prefix TK_
%token_type {Token} %token_type {Token}
@ -50,7 +50,7 @@ input ::= cmdlist.
// add them to the parse.h output file. // add them to the parse.h output file.
// //
input ::= END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION input ::= END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
UMINUS FIELD AGG_FUNCTION. UMINUS COLUMN AGG_FUNCTION.
// A list of commands is zero or more commands // A list of commands is zero or more commands
// //
@ -250,9 +250,9 @@ setlist(A) ::= id(X) EQ expr(Y) COMMA setlist(Z).
{A = sqliteExprListAppend(Z,Y,&X);} {A = sqliteExprListAppend(Z,Y,&X);}
setlist(A) ::= id(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);} setlist(A) ::= id(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);}
cmd ::= INSERT INTO id(X) fieldlist_opt(F) VALUES LP itemlist(Y) RP. cmd ::= INSERT INTO id(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
{sqliteInsert(pParse, &X, Y, 0, F);} {sqliteInsert(pParse, &X, Y, 0, F);}
cmd ::= INSERT INTO id(X) fieldlist_opt(F) select(S). cmd ::= INSERT INTO id(X) inscollist_opt(F) select(S).
{sqliteInsert(pParse, &X, 0, S, F);} {sqliteInsert(pParse, &X, 0, S, F);}
@ -278,15 +278,15 @@ item(A) ::= MINUS FLOAT(X). {
item(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);} item(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);}
item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);} item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);}
%type fieldlist_opt {IdList*} %type inscollist_opt {IdList*}
%destructor fieldlist_opt {sqliteIdListDelete($$);} %destructor inscollist_opt {sqliteIdListDelete($$);}
%type fieldlist {IdList*} %type inscollist {IdList*}
%destructor fieldlist {sqliteIdListDelete($$);} %destructor inscollist {sqliteIdListDelete($$);}
fieldlist_opt(A) ::= . {A = 0;} inscollist_opt(A) ::= . {A = 0;}
fieldlist_opt(A) ::= LP fieldlist(X) RP. {A = X;} inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
fieldlist(A) ::= fieldlist(X) COMMA id(Y). {A = sqliteIdListAppend(X,&Y);} inscollist(A) ::= inscollist(X) COMMA id(Y). {A = sqliteIdListAppend(X,&Y);}
fieldlist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);} inscollist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);}
%left OR. %left OR.
%left AND. %left AND.

View File

@ -24,7 +24,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. ** to handle SELECT statements.
** **
** $Id: select.c,v 1.24 2000/06/19 19:09:09 drh Exp $ ** $Id: select.c,v 1.25 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -86,14 +86,14 @@ void sqliteParseInfoReset(Parse *pParse){
** of a SELECT. ** of a SELECT.
** **
** The pEList is used to determine the values for each column in the ** The pEList is used to determine the values for each column in the
** result row. Except if pEList==NULL, then we just read nField ** result row. Except if pEList==NULL, then we just read nColumn
** elements from the srcTab table. ** elements from the srcTab table.
*/ */
static int selectInnerLoop( static int selectInnerLoop(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
ExprList *pEList, /* List of values being extracted */ ExprList *pEList, /* List of values being extracted */
int srcTab, /* Pull data from this table */ int srcTab, /* Pull data from this table */
int nField, /* Number of fields in the source table */ int nColumn, /* Number of columns in the source table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */ ExprList *pOrderBy, /* If not NULL, sort results using this key */
int distinct, /* If >=0, make sure results are distinct */ int distinct, /* If >=0, make sure results are distinct */
int eDest, /* How to dispose of the results */ int eDest, /* How to dispose of the results */
@ -104,15 +104,15 @@ static int selectInnerLoop(
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int i; int i;
/* Pull the requested fields. /* Pull the requested columns.
*/ */
if( pEList ){ if( pEList ){
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
sqliteExprCode(pParse, pEList->a[i].pExpr); sqliteExprCode(pParse, pEList->a[i].pExpr);
} }
nField = pEList->nExpr; nColumn = pEList->nExpr;
}else{ }else{
for(i=0; i<nField; i++){ for(i=0; i<nColumn; i++){
sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0); sqliteVdbeAddOp(v, OP_Field, srcTab, i, 0, 0);
} }
} }
@ -135,7 +135,7 @@ static int selectInnerLoop(
*/ */
if( pOrderBy ){ if( pOrderBy ){
char *zSortOrder; char *zSortOrder;
sqliteVdbeAddOp(v, OP_SortMakeRec, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_SortMakeRec, nColumn, 0, 0, 0);
zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 ); zSortOrder = sqliteMalloc( pOrderBy->nExpr + 1 );
if( zSortOrder==0 ) return 1; if( zSortOrder==0 ) return 1;
for(i=0; i<pOrderBy->nExpr; i++){ for(i=0; i<pOrderBy->nExpr; i++){
@ -152,7 +152,7 @@ static int selectInnerLoop(
** table iParm. ** table iParm.
*/ */
if( eDest==SRT_Union ){ if( eDest==SRT_Union ){
sqliteVdbeAddOp(v, OP_MakeRecord, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_String, iParm, 0, "", 0); sqliteVdbeAddOp(v, OP_String, iParm, 0, "", 0);
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else }else
@ -160,7 +160,7 @@ static int selectInnerLoop(
/* Store the result as data using a unique key. /* Store the result as data using a unique key.
*/ */
if( eDest==SRT_Table ){ if( eDest==SRT_Table ){
sqliteVdbeAddOp(v, OP_MakeRecord, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_New, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_New, iParm, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
@ -171,7 +171,7 @@ static int selectInnerLoop(
** the temporary table iParm. ** the temporary table iParm.
*/ */
if( eDest==SRT_Except ){ if( eDest==SRT_Except ){
sqliteVdbeAddOp(v, OP_MakeRecord, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Delete, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Delete, iParm, 0, 0, 0);
}else }else
@ -180,7 +180,7 @@ static int selectInnerLoop(
** item into the set table with bogus data. ** item into the set table with bogus data.
*/ */
if( eDest==SRT_Set ){ if( eDest==SRT_Set ){
assert( nField==1 ); assert( nColumn==1 );
sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0); sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0);
}else }else
@ -191,7 +191,7 @@ static int selectInnerLoop(
** of the scan loop. ** of the scan loop.
*/ */
if( eDest==SRT_Mem ){ if( eDest==SRT_Mem ){
assert( nField==1 ); assert( nColumn==1 );
sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, iBreak, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iBreak, 0, 0);
}else }else
@ -199,7 +199,7 @@ static int selectInnerLoop(
/* If none of the above, send the data to the callback function. /* If none of the above, send the data to the callback function.
*/ */
{ {
sqliteVdbeAddOp(v, OP_Callback, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_Callback, nColumn, 0, 0, 0);
} }
return 0; return 0;
} }
@ -210,12 +210,12 @@ static int selectInnerLoop(
** we need to run the sorter and output the results. The following ** we need to run the sorter and output the results. The following
** routine generates the code needed to do that. ** routine generates the code needed to do that.
*/ */
static void generateSortTail(Vdbe *v, int nField){ static void generateSortTail(Vdbe *v, int nColumn){
int end = sqliteVdbeMakeLabel(v); int end = sqliteVdbeMakeLabel(v);
int addr; int addr;
sqliteVdbeAddOp(v, OP_Sort, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Sort, 0, 0, 0, 0);
addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end, 0, 0); addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end, 0, 0);
sqliteVdbeAddOp(v, OP_SortCallback, nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
sqliteVdbeAddOp(v, OP_SortClose, 0, 0, 0, end); sqliteVdbeAddOp(v, OP_SortClose, 0, 0, 0, end);
} }
@ -240,7 +240,7 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
continue; continue;
} }
p = pEList->a[i].pExpr; p = pEList->a[i].pExpr;
if( p->op!=TK_FIELD || pTabList==0 ){ if( p->op!=TK_COLUMN || pTabList==0 ){
char zName[30]; char zName[30];
sprintf(zName, "column%d", i+1); sprintf(zName, "column%d", i+1);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
@ -252,12 +252,12 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){
zTab = pTabList->a[p->iTable].zAlias; zTab = pTabList->a[p->iTable].zAlias;
if( zTab==0 ) zTab = pTab->zName; if( zTab==0 ) zTab = pTab->zName;
sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iField].zName, 0); sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iColumn].zName, 0);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
sqliteFree(zName); sqliteFree(zName);
}else{ }else{
Table *pTab = pTabList->a[0].pTab; Table *pTab = pTabList->a[0].pTab;
char *zName = pTab->aCol[p->iField].zName; char *zName = pTab->aCol[p->iColumn].zName;
sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
} }
} }
@ -281,8 +281,8 @@ static const char *selectOpName(int id){
/* /*
** For the given SELECT statement, do two things. ** For the given SELECT statement, do two things.
** **
** (1) Fill in the pTab fields of the IdList that defines the set ** (1) Fill in the pTabList->a[].pTab fields in the IdList that
** of tables we are scanning. ** defines the set of tables that should be scanned.
** **
** (2) If the columns to be extracted variable (pEList) is NULL ** (2) If the columns to be extracted variable (pEList) is NULL
** (meaning that a "*" was used in the SQL statement) then ** (meaning that a "*" was used in the SQL statement) then
@ -338,7 +338,7 @@ static int fillInColumnList(Parse *pParse, Select *p){
/* /*
** This routine associates entries in an ORDER BY expression list with ** This routine associates entries in an ORDER BY expression list with
** columns in a result. For each ORDER BY expression, the opcode of ** columns in a result. For each ORDER BY expression, the opcode of
** the top-level node is changed to TK_FIELD and the iField value of ** the top-level node is changed to TK_COLUMN and the iColumn value of
** the top-level node is filled in with column number and the iTable ** the top-level node is filled in with column number and the iTable
** value of the top-level node is filled with iTable parameter. ** value of the top-level node is filled with iTable parameter.
** **
@ -390,8 +390,8 @@ static int matchOrderbyToColumn(
match = 1; match = 1;
} }
if( match ){ if( match ){
pE->op = TK_FIELD; pE->op = TK_COLUMN;
pE->iField = j; pE->iColumn = j;
pE->iTable = iTable; pE->iTable = iTable;
pOrderBy->a[i].done = 1; pOrderBy->a[i].done = 1;
break; break;
@ -630,7 +630,7 @@ int sqliteSelect(
WhereInfo *pWInfo; WhereInfo *pWInfo;
Vdbe *v; Vdbe *v;
int isAgg = 0; /* True for select lists like "count(*)" */ int isAgg = 0; /* True for select lists like "count(*)" */
ExprList *pEList; /* List of fields to extract. NULL means "*" */ ExprList *pEList; /* List of columns to extract. NULL means "*" */
IdList *pTabList; /* List of tables to select from */ IdList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */ Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */ ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
@ -669,7 +669,7 @@ int sqliteSelect(
/* Look up every table in the table list and create an appropriate /* Look up every table in the table list and create an appropriate
** columnlist in pEList if there isn't one already. (The parser leaves ** columnlist in pEList if there isn't one already. (The parser leaves
** a NULL in the pEList field if the SQL said "SELECT * FROM ...") ** a NULL in the p->pEList if the SQL said "SELECT * FROM ...")
*/ */
if( fillInColumnList(pParse, p) ){ if( fillInColumnList(pParse, p) ){
return 1; return 1;
@ -724,7 +724,7 @@ int sqliteSelect(
** need to handle subquerys and temporary tables. From here on we ** need to handle subquerys and temporary tables. From here on we
** are committed to keeping the same value for pParse->nTab. ** are committed to keeping the same value for pParse->nTab.
** **
** Resolve the field names and do a semantics check on all the expressions. ** Resolve the column names and do a semantics check on all the expressions.
*/ */
for(i=0; i<pEList->nExpr; i++){ for(i=0; i<pEList->nExpr; i++){
if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){ if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){
@ -906,7 +906,7 @@ int sqliteSelect(
assert( pE->pList!=0 && pE->pList->nExpr==1 ); assert( pE->pList!=0 && pE->pList->nExpr==1 );
sqliteExprCode(pParse, pE->pList->a[0].pExpr); sqliteExprCode(pParse, pE->pList->a[0].pExpr);
sqliteVdbeAddOp(v, OP_AggGet, 0, i, 0, 0); sqliteVdbeAddOp(v, OP_AggGet, 0, i, 0, 0);
switch( pE->iField ){ switch( pE->iColumn ){
case FN_Min: op = OP_Min; break; case FN_Min: op = OP_Min; break;
case FN_Max: op = OP_Max; break; case FN_Max: op = OP_Max; break;
case FN_Avg: op = OP_Add; break; case FN_Avg: op = OP_Add; break;

View File

@ -24,7 +24,7 @@
** This file contains code to implement the "sqlite" command line ** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases. ** utility for accessing SQLite databases.
** **
** $Id: shell.c,v 1.14 2000/06/15 16:49:49 drh Exp $ ** $Id: shell.c,v 1.15 2000/06/21 13:59:12 drh Exp $
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -136,7 +136,7 @@ struct callback_data {
/* /*
** These are the allowed modes. ** These are the allowed modes.
*/ */
#define MODE_Line 0 /* One field per line. Blank line between records */ #define MODE_Line 0 /* One column per line. Blank line between records */
#define MODE_Column 1 /* One record per line in neat columns */ #define MODE_Column 1 /* One record per line in neat columns */
#define MODE_List 2 /* One record per line with a separator */ #define MODE_List 2 /* One record per line with a separator */
#define MODE_Html 3 /* Generate an XHTML table */ #define MODE_Html 3 /* Generate an XHTML table */

View File

@ -23,7 +23,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.24 2000/06/11 23:50:13 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.25 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqlite.h" #include "sqlite.h"
#include "dbbe.h" #include "dbbe.h"
@ -35,7 +35,20 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
/* #define MEMORY_DEBUG 1 */ /*
** If memory allocation problems are found, recompile with
**
** -DMEMORY_DEBUG=1
**
** to enable some sanity checking on malloc() and free(). To
** check for memory leaks, recompile with
**
** -DMEMORY_DEBUG=2
**
** and a line of text will be written to standard error for
** each malloc() and free(). This output can be analyzed
** by an AWK script to determine if there are any leaks.
*/
#ifdef MEMORY_DEBUG #ifdef MEMORY_DEBUG
# define sqliteMalloc(X) sqliteMalloc_(X,__FILE__,__LINE__) # define sqliteMalloc(X) sqliteMalloc_(X,__FILE__,__LINE__)
# define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__) # define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__)
@ -58,8 +71,8 @@ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */
#endif #endif
/* /*
** The number of entries in the in-memory hash table holding the ** The number of entries in the in-memory hash array holding the
** schema. ** database schema.
*/ */
#define N_HASH 51 #define N_HASH 51
@ -77,7 +90,7 @@ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */
#define ArraySize(X) (sizeof(X)/sizeof(X[0])) #define ArraySize(X) (sizeof(X)/sizeof(X[0]))
/* /*
** Integer identifiers for functions. ** Integer identifiers for built-in SQL functions.
*/ */
#define FN_Unknown 0 #define FN_Unknown 0
#define FN_Count 1 #define FN_Count 1
@ -114,46 +127,61 @@ struct sqlite {
}; };
/* /*
** Possible values for the flags field of sqlite ** Possible values for the sqlite.flags.
*/ */
#define SQLITE_VdbeTrace 0x00000001 #define SQLITE_VdbeTrace 0x00000001
#define SQLITE_Initialized 0x00000002 #define SQLITE_Initialized 0x00000002
/* /*
** information about each column of a table is held in an instance ** information about each column of an SQL table is held in an instance
** of this structure. ** of this structure.
*/ */
struct Column { struct Column {
char *zName; /* Name of this column */ char *zName; /* Name of this column */
char *zDflt; /* Default value of this column */ char *zDflt; /* Default value of this column */
int notNull; /* True if there is a NOT NULL constraing */ int notNull; /* True if there is a NOT NULL constraint */
}; };
/* /*
** Each table is represented in memory by ** Each SQL table is represented in memory by
** an instance of the following structure ** an instance of the following structure.
*/ */
struct Table { struct Table {
char *zName; /* Name of the table */ char *zName; /* Name of the table */
Table *pHash; /* Next table with same hash on zName */ Table *pHash; /* Next table with same hash on zName */
int nCol; /* Number of columns in this table */ int nCol; /* Number of columns in this table */
Column *aCol; /* Information about each column */ Column *aCol; /* Information about each column */
int readOnly; /* True if this table should not be written by the user */ int readOnly; /* True if this table should not be written by the user */
Index *pIndex; /* List of indices on this table. */ Index *pIndex; /* List of SQL indexes on this table. */
}; };
/* /*
** Each index is represented in memory by and ** Each SQL index is represented in memory by and
** instance of the following structure. ** instance of the following structure.
**
** The columns of the table that are to be indexed are described
** by the aiColumn[] field of this structure. For example, suppose
** we have the following table and index:
**
** CREATE TABLE Ex1(c1 int, c2 int, c3 text);
** CREATE INDEX Ex2 ON Ex1(c3,c1);
**
** In the Table structure describing Ex1, nCol==3 because there are
** three columns in the table. In the Index structure describing
** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
** The second column to be indexed (c1) has an index of 0 in
** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
*/ */
struct Index { struct Index {
char *zName; /* Name of this index */ char *zName; /* Name of this index */
Index *pHash; /* Next index with the same hash on zName */ Index *pHash; /* Next index with the same hash on zName */
int nField; /* Number of fields in the table indexed by this index */ int nColumn; /* Number of columns in the table used by this index */
int *aiField; /* Indices of fields used by this index. 1st is 0 */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */
Table *pTable; /* The table being indexed */ Table *pTable; /* The SQL table being indexed */
int isUnique; /* True if keys must all be unique */ int isUnique; /* True if keys must all be unique */
Index *pNext; /* The next index associated with the same table */ Index *pNext; /* The next index associated with the same table */
}; };
/* /*
@ -174,11 +202,11 @@ struct Expr {
Expr *pLeft, *pRight; /* Left and right subnodes */ Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as a function argument */ ExprList *pList; /* A list of expressions used as a function argument */
Token token; /* An operand token */ Token token; /* An operand token */
int iTable, iField; /* When op==TK_FIELD, then this node means the int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iField-th field of the iTable-th table. When ** iColumn-th field of the iTable-th table. When
** op==TK_FUNCTION, iField holds the function id */ ** op==TK_FUNCTION, iColumn holds the function id */
int iAgg; /* When op==TK_FIELD and pParse->useAgg==TRUE, pull int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
** value from these element of the aggregator */ ** result from the iAgg-th element of the aggregator */
Select *pSelect; /* When the expression is a sub-select */ Select *pSelect; /* When the expression is a sub-select */
}; };
@ -209,8 +237,8 @@ struct IdList {
struct { struct {
char *zName; /* Text of the identifier. */ char *zName; /* Text of the identifier. */
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
Table *pTab; /* Table corresponding to zName */ Table *pTab; /* An SQL table corresponding to zName */
int idx; /* Index of a field named zName in a table */ int idx; /* Index in some Table.aCol[] of a column named zName */
} *a; /* One entry for each identifier on the list */ } *a; /* One entry for each identifier on the list */
}; };
@ -243,7 +271,7 @@ struct Select {
Expr *pHaving; /* The HAVING clause */ Expr *pHaving; /* The HAVING clause */
ExprList *pOrderBy; /* The ORDER BY clause */ ExprList *pOrderBy; /* The ORDER BY clause */
int op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ int op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
Select *pPrior; /* Prior select to which this one joins */ Select *pPrior; /* Prior select in a compound select statement */
}; };
/* /*

View File

@ -24,7 +24,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 UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.7 2000/06/19 19:09:09 drh Exp $ ** $Id: update.c,v 1.8 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -48,8 +48,8 @@ void sqliteUpdate(
int base; /* Index of first available table cursor */ int base; /* Index of first available table cursor */
Index **apIdx = 0; /* An array of indices that need updating too */ Index **apIdx = 0; /* An array of indices that need updating too */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th field of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th field is not changed. */ ** aXRef[i]==-1 if the i-th column is not changed. */
/* Locate the table which we want to update. This table has to be /* Locate the table which we want to update. This table has to be
** put in an IdList structure because some of the subroutines we ** put in an IdList structure because some of the subroutines we
@ -77,9 +77,9 @@ void sqliteUpdate(
if( aXRef==0 ) goto update_cleanup; if( aXRef==0 ) goto update_cleanup;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
/* Resolve the field names in all the expressions in both the /* Resolve the column names in all the expressions in both the
** WHERE clause and in the new values. Also find the field index ** WHERE clause and in the new values. Also find the column index
** for each field to be updated in the pChanges array. ** for each column to be updated in the pChanges array.
*/ */
if( pWhere ){ if( pWhere ){
sqliteExprResolveInSelect(pParse, pWhere); sqliteExprResolveInSelect(pParse, pWhere);
@ -109,7 +109,7 @@ void sqliteUpdate(
} }
} }
if( j>=pTab->nCol ){ if( j>=pTab->nCol ){
sqliteSetString(&pParse->zErrMsg, "no such field: ", sqliteSetString(&pParse->zErrMsg, "no such column: ",
pChanges->a[i].zName, 0); pChanges->a[i].zName, 0);
pParse->nErr++; pParse->nErr++;
goto update_cleanup; goto update_cleanup;
@ -118,21 +118,21 @@ void sqliteUpdate(
/* Allocate memory for the array apIdx[] and fill it pointers to every /* Allocate memory for the array apIdx[] and fill it pointers to every
** index that needs to be updated. Indices only need updating if their ** index that needs to be updated. Indices only need updating if their
** key includes one of the fields named in pChanges. ** key includes one of the columns named in pChanges.
*/ */
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
for(i=0; i<pIdx->nField; i++){ for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiField[i]]>=0 ) break; if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
} }
if( i<pIdx->nField ) nIdx++; if( i<pIdx->nColumn ) nIdx++;
} }
apIdx = sqliteMalloc( sizeof(Index*) * nIdx ); apIdx = sqliteMalloc( sizeof(Index*) * nIdx );
if( apIdx==0 ) goto update_cleanup; if( apIdx==0 ) goto update_cleanup;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
for(i=0; i<pIdx->nField; i++){ for(i=0; i<pIdx->nColumn; i++){
if( aXRef[pIdx->aiField[i]]>=0 ) break; if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
} }
if( i<pIdx->nField ) apIdx[nIdx++] = pIdx; if( i<pIdx->nColumn ) apIdx[nIdx++] = pIdx;
} }
/* Begin generating code. /* Begin generating code.
@ -165,7 +165,7 @@ void sqliteUpdate(
} }
/* Loop over every record that needs updating. We have to load /* Loop over every record that needs updating. We have to load
** the old data for each record to be updated because some fields ** the old data for each record to be updated because some columns
** might not change and we will need to copy the old value. ** might not change and we will need to copy the old value.
** Also, the old data is needed to delete the old index entires. ** Also, the old data is needed to delete the old index entires.
*/ */
@ -179,10 +179,10 @@ void sqliteUpdate(
for(i=0; i<nIdx; i++){ for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
pIdx = apIdx[i]; pIdx = apIdx[i];
for(j=0; j<pIdx->nField; j++){ for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0); sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0); sqliteVdbeAddOp(v, OP_DeleteIdx, base+i+1, 0, 0, 0);
} }
@ -202,10 +202,10 @@ void sqliteUpdate(
for(i=0; i<nIdx; i++){ for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */ sqliteVdbeAddOp(v, OP_Dup, pTab->nCol, 0, 0, 0); /* The KEY */
pIdx = apIdx[i]; pIdx = apIdx[i];
for(j=0; j<pIdx->nField; j++){ for(j=0; j<pIdx->nColumn; j++){
sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0); sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiColumn[j], 0, 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0); sqliteVdbeAddOp(v, OP_PutIdx, base+i+1, 0, 0, 0);
} }

View File

@ -26,7 +26,7 @@
** This file contains functions for allocating memory, comparing ** This file contains functions for allocating memory, comparing
** strings, and stuff like that. ** strings, and stuff like that.
** **
** $Id: util.c,v 1.12 2000/06/08 13:36:41 drh Exp $ ** $Id: util.c,v 1.13 2000/06/21 13:59:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <stdarg.h> #include <stdarg.h>
@ -360,7 +360,7 @@ int sqliteHashNoCase(const char *z, int n){
} }
/* /*
** Some system shave stricmp(). Others have strcasecmp(). Because ** Some systems have stricmp(). Others have strcasecmp(). Because
** there is no consistency, we will define our own. ** there is no consistency, we will define our own.
*/ */
int sqliteStrICmp(const char *zLeft, const char *zRight){ int sqliteStrICmp(const char *zLeft, const char *zRight){

View File

@ -41,7 +41,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** a program instruction by instruction.
** **
** $Id: vdbe.c,v 1.33 2000/06/11 23:50:13 drh Exp $ ** $Id: vdbe.c,v 1.34 2000/06/21 13:59:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <unistd.h> #include <unistd.h>
@ -54,15 +54,21 @@
typedef struct VdbeOp Op; typedef struct VdbeOp Op;
/* /*
** Every table that the virtual machine has open is represented by an ** A cursor is a pointer into a database file. The database file
** can represent either an SQL table or an SQL index. Each file is
** a bag of key/data pairs. The cursor can loop over all key/data
** pairs (in an arbitrary order) or it can retrieve a particular
** key/data pair given a copy of the key.
**
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure. ** instance of the following structure.
*/ */
struct VdbeTable { struct Cursor {
DbbeTable *pTable; /* The table structure of the backend */ DbbeCursor *pCursor; /* The cursor structure of the backend */
int index; /* The next index to extract */ int index; /* The next index to extract */
int keyAsData; /* The OP_Field command works on key instead of data */ int keyAsData; /* The OP_Field command works on key instead of data */
}; };
typedef struct VdbeTable VdbeTable; typedef struct Cursor Cursor;
/* /*
** A sorter builds a list of elements to be sorted. Each element of ** A sorter builds a list of elements to be sorted. Each element of
@ -117,7 +123,7 @@ typedef struct Mem Mem;
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[*] */ #define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[*] */
/* /*
** An Agg structure describes and Aggregator. Each Agg consists of ** An Agg structure describes an Aggregator. Each Agg consists of
** zero or more Aggregator elements (AggElem). Each AggElem contains ** zero or more Aggregator elements (AggElem). Each AggElem contains
** a key and one or more values. The values are used in processing ** a key and one or more values. The values are used in processing
** aggregate functions in a SELECT. The key is used to implement ** aggregate functions in a SELECT. The key is used to implement
@ -130,7 +136,7 @@ struct Agg {
AggElem *pCurrent; /* The AggElem currently in focus */ AggElem *pCurrent; /* The AggElem currently in focus */
int nElem; /* The number of AggElems */ int nElem; /* The number of AggElems */
int nHash; /* Number of slots in apHash[] */ int nHash; /* Number of slots in apHash[] */
AggElem **apHash; /* A hash table for looking up AggElems by zKey */ AggElem **apHash; /* A hash array for looking up AggElems by zKey */
AggElem *pFirst; /* A list of all AggElems */ AggElem *pFirst; /* A list of all AggElems */
}; };
struct AggElem { struct AggElem {
@ -150,7 +156,7 @@ typedef struct Set Set;
typedef struct SetElem SetElem; typedef struct SetElem SetElem;
struct Set { struct Set {
SetElem *pAll; /* All elements of this set */ SetElem *pAll; /* All elements of this set */
SetElem *apHash[41]; /* A hash table for all elements in this set */ SetElem *apHash[41]; /* A hash array for all elements in this set */
}; };
struct SetElem { struct SetElem {
SetElem *pHash; /* Next element with the same hash on zKey */ SetElem *pHash; /* Next element with the same hash on zKey */
@ -175,8 +181,8 @@ struct Vdbe {
Stack *aStack; /* The operand stack, except string values */ Stack *aStack; /* The operand stack, except string values */
char **zStack; /* Text or binary values of the stack */ char **zStack; /* Text or binary values of the stack */
char **azColName; /* Becomes the 4th parameter to callbacks */ char **azColName; /* Becomes the 4th parameter to callbacks */
int nTable; /* Number of slots in aTab[] */ int nCursor; /* Number of slots in aCsr[] */
VdbeTable *aTab; /* On element of this array for each open table */ Cursor *aCsr; /* On element of this array for each open cursor */
int nList; /* Number of slots in apList[] */ int nList; /* Number of slots in apList[] */
FILE **apList; /* An open file for each list */ FILE **apList; /* An open file for each list */
int nSort; /* Number of slots in apSort[] */ int nSort; /* Number of slots in apSort[] */
@ -394,7 +400,7 @@ static void AggReset(Agg *p){
} }
/* /*
** Add the given AggElem to the hash table ** Add the given AggElem to the hash array
*/ */
static void AggEnhash(Agg *p, AggElem *pElem){ static void AggEnhash(Agg *p, AggElem *pElem){
int h = sqliteHashNoCase(pElem->zKey, 0) % p->nHash; int h = sqliteHashNoCase(pElem->zKey, 0) % p->nHash;
@ -403,7 +409,7 @@ static void AggEnhash(Agg *p, AggElem *pElem){
} }
/* /*
** Change the size of the hash table to the amount given. ** Change the size of the hash array to the amount given.
*/ */
static void AggRehash(Agg *p, int nHash){ static void AggRehash(Agg *p, int nHash){
int size; int size;
@ -634,7 +640,7 @@ static int hardNeedStack(Vdbe *p, int N){
/* /*
** Clean up the VM after execution. ** Clean up the VM after execution.
** **
** This routine will automatically close any tables, list, and/or ** This routine will automatically close any cursors, list, and/or
** sorters that were left open. ** sorters that were left open.
*/ */
static void Cleanup(Vdbe *p){ static void Cleanup(Vdbe *p){
@ -642,15 +648,15 @@ static void Cleanup(Vdbe *p){
PopStack(p, p->tos+1); PopStack(p, p->tos+1);
sqliteFree(p->azColName); sqliteFree(p->azColName);
p->azColName = 0; p->azColName = 0;
for(i=0; i<p->nTable; i++){ for(i=0; i<p->nCursor; i++){
if( p->aTab[i].pTable ){ if( p->aCsr[i].pCursor ){
sqliteDbbeCloseTable(p->aTab[i].pTable); sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
p->aTab[i].pTable = 0; p->aCsr[i].pCursor = 0;
} }
} }
sqliteFree(p->aTab); sqliteFree(p->aCsr);
p->aTab = 0; p->aCsr = 0;
p->nTable = 0; p->nCursor = 0;
for(i=0; i<p->nMem; i++){ for(i=0; i<p->nMem; i++){
if( p->aMem[i].s.flags & STK_Dyn ){ if( p->aMem[i].s.flags & STK_Dyn ){
sqliteFree(p->aMem[i].z); sqliteFree(p->aMem[i].z);
@ -786,7 +792,7 @@ int sqliteVdbeList(
char **pzErrMsg /* Error msg written here */ char **pzErrMsg /* Error msg written here */
){ ){
int i, rc; int i, rc;
char *azField[6]; char *azValue[6];
char zAddr[20]; char zAddr[20];
char zP1[20]; char zP1[20];
char zP2[20]; char zP2[20];
@ -795,19 +801,19 @@ int sqliteVdbeList(
}; };
if( xCallback==0 ) return 0; if( xCallback==0 ) return 0;
azField[0] = zAddr; azValue[0] = zAddr;
azField[2] = zP1; azValue[2] = zP1;
azField[3] = zP2; azValue[3] = zP2;
azField[5] = 0; azValue[5] = 0;
rc = SQLITE_OK; rc = SQLITE_OK;
/* if( pzErrMsg ){ *pzErrMsg = 0; } */ /* if( pzErrMsg ){ *pzErrMsg = 0; } */
for(i=0; rc==SQLITE_OK && i<p->nOp; i++){ for(i=0; rc==SQLITE_OK && i<p->nOp; i++){
sprintf(zAddr,"%d",i); sprintf(zAddr,"%d",i);
sprintf(zP1,"%d", p->aOp[i].p1); sprintf(zP1,"%d", p->aOp[i].p1);
sprintf(zP2,"%d", p->aOp[i].p2); sprintf(zP2,"%d", p->aOp[i].p2);
azField[4] = p->aOp[i].p3; azValue[4] = p->aOp[i].p3;
azField[1] = zOpName[p->aOp[i].opcode]; azValue[1] = zOpName[p->aOp[i].opcode];
if( xCallback(pArg, 5, azField, azColumnNames) ){ if( xCallback(pArg, 5, azValue, azColumnNames) ){
rc = SQLITE_ABORT; rc = SQLITE_ABORT;
} }
} }
@ -1492,7 +1498,7 @@ int sqliteVdbeExec(
/* Opcode: Not * * * /* Opcode: Not * * *
** **
** Treat the top of the stack as a boolean value. Replace it ** Interpret the top of the stack as a boolean value. Replace it
** with its complement. ** with its complement.
*/ */
case OP_Not: { case OP_Not: {
@ -1676,33 +1682,34 @@ int sqliteVdbeExec(
/* Opcode: Open P1 P2 P3 /* Opcode: Open P1 P2 P3
** **
** Open a new cursor for the database table named P3. Give the ** Open a new cursor for the database file named P3. Give the
** cursor an identifier P1. ** cursor an identifier P1. The P1 values need not be
** Open readonly if P2==0 and for reading and writing if P2!=0.
** The table is created if it does not already exist and P2!=0.
** If there is already another cursor opened with identifier P1,
** then the old cursor is closed first.
** All cursors are automatically closed when
** the VDBE finishes execution. The P1 values need not be
** contiguous but all P1 values should be small integers. It is ** contiguous but all P1 values should be small integers. It is
** an error for P1 to be negative. ** an error for P1 to be negative.
** **
** If P3 is null or an empty string, a temporary table created. ** Open readonly if P2==0 and for reading and writing if P2!=0.
** This table is automatically deleted when the cursor is closed. ** The file is created if it does not already exist and P2!=0.
** If there is already another cursor opened with identifier P1,
** then the old cursor is closed first. All cursors are
** automatically closed when the VDBE finishes execution.
**
** If P3 is null or an empty string, a temporary database file
** is created. This temporary database file is automatically
** deleted when the cursor is closed.
*/ */
case OP_Open: { case OP_Open: {
int i = pOp->p1; int i = pOp->p1;
if( i<0 ) goto bad_instruction; if( i<0 ) goto bad_instruction;
if( i>=p->nTable ){ if( i>=p->nCursor ){
int j; int j;
p->aTab = sqliteRealloc( p->aTab, (i+1)*sizeof(VdbeTable) ); p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
if( p->aTab==0 ){ p->nTable = 0; goto no_mem; } if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
for(j=p->nTable; j<=i; j++) p->aTab[j].pTable = 0; for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
p->nTable = i+1; p->nCursor = i+1;
}else if( p->aTab[i].pTable ){ }else if( p->aCsr[i].pCursor ){
sqliteDbbeCloseTable(p->aTab[i].pTable); sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
} }
rc = sqliteDbbeOpenTable(p->pBe, pOp->p3, pOp->p2, &p->aTab[i].pTable); rc = sqliteDbbeOpenCursor(p->pBe, pOp->p3, pOp->p2,&p->aCsr[i].pCursor);
switch( rc ){ switch( rc ){
case SQLITE_BUSY: { case SQLITE_BUSY: {
sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0); sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
@ -1722,21 +1729,21 @@ int sqliteVdbeExec(
goto no_mem; goto no_mem;
} }
} }
p->aTab[i].index = 0; p->aCsr[i].index = 0;
p->aTab[i].keyAsData = 0; p->aCsr[i].keyAsData = 0;
break; break;
} }
/* Opcode: Close P1 * * /* Opcode: Close P1 * *
** **
** Close a database table previously opened as P1. If P1 is not ** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op. ** currently open, this instruction is a no-op.
*/ */
case OP_Close: { case OP_Close: {
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
sqliteDbbeCloseTable(p->aTab[i].pTable); sqliteDbbeCloseCursor(p->aCsr[i].pCursor);
p->aTab[i].pTable = 0; p->aCsr[i].pCursor = 0;
} }
break; break;
} }
@ -1744,21 +1751,20 @@ int sqliteVdbeExec(
/* Opcode: Fetch P1 * * /* Opcode: Fetch P1 * *
** **
** Pop the top of the stack and use its value as a key to fetch ** Pop the top of the stack and use its value as a key to fetch
** a record from database table or index P1. The data is held ** a record from cursor P1. The key/data pair is held
** in the P1 cursor until needed. The data is not pushed onto the ** in the P1 cursor until needed.
** stack.
*/ */
case OP_Fetch: { case OP_Fetch: {
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
if( p->aStack[tos].flags & STK_Int ){ if( p->aStack[tos].flags & STK_Int ){
sqliteDbbeFetch(p->aTab[i].pTable, sizeof(int), sqliteDbbeFetch(p->aCsr[i].pCursor, sizeof(int),
(char*)&p->aStack[tos].i); (char*)&p->aStack[tos].i);
}else{ }else{
if( Stringify(p, tos) ) goto no_mem; if( Stringify(p, tos) ) goto no_mem;
sqliteDbbeFetch(p->aTab[i].pTable, p->aStack[tos].n, sqliteDbbeFetch(p->aCsr[i].pCursor, p->aStack[tos].n,
p->zStack[tos]); p->zStack[tos]);
} }
p->nFetch++; p->nFetch++;
@ -1787,7 +1793,7 @@ int sqliteVdbeExec(
/* Opcode: Distinct P1 P2 * /* Opcode: Distinct P1 P2 *
** **
** Use the top of the stack as a key. If a record with that key ** Use the top of the stack as a key. If a record with that key
** does not exist in table P1, then jump to P2. If the record ** does not exist in file P1, then jump to P2. If the record
** does already exist, then fall thru. The record is not retrieved. ** does already exist, then fall thru. The record is not retrieved.
** The key is not popped from the stack. ** The key is not popped from the stack.
** **
@ -1797,14 +1803,14 @@ int sqliteVdbeExec(
/* Opcode: Found P1 P2 * /* Opcode: Found P1 P2 *
** **
** Use the top of the stack as a key. If a record with that key ** Use the top of the stack as a key. If a record with that key
** does exist in table P1, then jump to P2. If the record ** does exist in file P1, then jump to P2. If the record
** does not exist, then fall thru. The record is not retrieved. ** does not exist, then fall thru. The record is not retrieved.
** The key is popped from the stack. ** The key is popped from the stack.
*/ */
/* Opcode: NotFound P1 P2 * /* Opcode: NotFound P1 P2 *
** **
** Use the top of the stack as a key. If a record with that key ** Use the top of the stack as a key. If a record with that key
** does not exist in table P1, then jump to P2. If the record ** does not exist in file P1, then jump to P2. If the record
** does exist, then fall thru. The record is not retrieved. ** does exist, then fall thru. The record is not retrieved.
** The key is popped from the stack. ** The key is popped from the stack.
** **
@ -1818,13 +1824,13 @@ int sqliteVdbeExec(
int tos = p->tos; int tos = p->tos;
int alreadyExists = 0; int alreadyExists = 0;
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && p->aTab[i].pTable ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
if( p->aStack[tos].flags & STK_Int ){ if( p->aStack[tos].flags & STK_Int ){
alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, sizeof(int), alreadyExists = sqliteDbbeTest(p->aCsr[i].pCursor, sizeof(int),
(char*)&p->aStack[tos].i); (char*)&p->aStack[tos].i);
}else{ }else{
if( Stringify(p, tos) ) goto no_mem; if( Stringify(p, tos) ) goto no_mem;
alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->aStack[tos].n, alreadyExists = sqliteDbbeTest(p->aCsr[i].pCursor,p->aStack[tos].n,
p->zStack[tos]); p->zStack[tos]);
} }
} }
@ -1841,16 +1847,16 @@ int sqliteVdbeExec(
/* Opcode: New P1 * * /* Opcode: New P1 * *
** **
** Get a new integer key not previous used by table P1 and ** Get a new integer key not previous used by the database file
** push it onto the stack. ** associated with cursor P1 and push it onto the stack.
*/ */
case OP_New: { case OP_New: {
int i = pOp->p1; int i = pOp->p1;
int v; int v;
if( i<0 || i>=p->nTable || p->aTab[i].pTable==0 ){ if( i<0 || i>=p->nCursor || p->aCsr[i].pCursor==0 ){
v = 0; v = 0;
}else{ }else{
v = sqliteDbbeNew(p->aTab[i].pTable); v = sqliteDbbeNew(p->aCsr[i].pCursor);
} }
NeedStack(p, p->tos+1); NeedStack(p, p->tos+1);
p->tos++; p->tos++;
@ -1861,7 +1867,7 @@ int sqliteVdbeExec(
/* Opcode: Put P1 * * /* Opcode: Put P1 * *
** **
** Write an entry into the database table P1. A new entry is ** Write an entry into the database file P1. A new entry is
** created if it doesn't already exist, or the data for an existing ** created if it doesn't already exist, or the data for an existing
** entry is overwritten. The data is the value on the top of the ** entry is overwritten. The data is the value on the top of the
** stack. The key is the next value down on the stack. The stack ** stack. The key is the next value down on the stack. The stack
@ -1872,7 +1878,7 @@ int sqliteVdbeExec(
int nos = p->tos-1; int nos = p->tos-1;
int i = pOp->p1; int i = pOp->p1;
if( nos<0 ) goto not_enough_stack; if( nos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
char *zKey; char *zKey;
int nKey; int nKey;
if( (p->aStack[nos].flags & STK_Int)==0 ){ if( (p->aStack[nos].flags & STK_Int)==0 ){
@ -1883,7 +1889,7 @@ int sqliteVdbeExec(
nKey = sizeof(int); nKey = sizeof(int);
zKey = (char*)&p->aStack[nos].i; zKey = (char*)&p->aStack[nos].i;
} }
sqliteDbbePut(p->aTab[i].pTable, nKey, zKey, sqliteDbbePut(p->aCsr[i].pCursor, nKey, zKey,
p->aStack[tos].n, p->zStack[tos]); p->aStack[tos].n, p->zStack[tos]);
} }
PopStack(p, 2); PopStack(p, 2);
@ -1893,13 +1899,13 @@ int sqliteVdbeExec(
/* Opcode: Delete P1 * * /* Opcode: Delete P1 * *
** **
** The top of the stack is a key. Remove this key and its data ** The top of the stack is a key. Remove this key and its data
** from database table P1. Then pop the stack to discard the key. ** from database file P1. Then pop the stack to discard the key.
*/ */
case OP_Delete: { case OP_Delete: {
int tos = p->tos; int tos = p->tos;
int i = pOp->p1; int i = pOp->p1;
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
char *zKey; char *zKey;
int nKey; int nKey;
if( p->aStack[tos].flags & STK_Int ){ if( p->aStack[tos].flags & STK_Int ){
@ -1910,7 +1916,7 @@ int sqliteVdbeExec(
nKey = p->aStack[tos].n; nKey = p->aStack[tos].n;
zKey = p->zStack[tos]; zKey = p->zStack[tos];
} }
sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey); sqliteDbbeDelete(p->aCsr[i].pCursor, nKey, zKey);
} }
PopStack(p, 1); PopStack(p, 1);
break; break;
@ -1925,16 +1931,18 @@ int sqliteVdbeExec(
*/ */
case OP_KeyAsData: { case OP_KeyAsData: {
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
p->aTab[i].keyAsData = pOp->p2; p->aCsr[i].keyAsData = pOp->p2;
} }
break; break;
} }
/* Opcode: Field P1 P2 * /* Opcode: Field P1 P2 *
** **
** Push onto the stack the value of the P2-th field from the ** Interpret the data in the most recent fetch from cursor P1
** most recent Fetch from table P1. ** is a structure built using the MakeRecord instruction.
** Push onto the stack the value of the P2-th field of that
** structure.
** **
** The value pushed is just a pointer to the data in the cursor. ** The value pushed is just a pointer to the data in the cursor.
** The value will go away the next time a record is fetched from P1, ** The value will go away the next time a record is fetched from P1,
@ -1944,6 +1952,11 @@ int sqliteVdbeExec(
** If the KeyAsData opcode has previously executed on this cursor, ** If the KeyAsData opcode has previously executed on this cursor,
** then the field might be extracted from the key rather than the ** then the field might be extracted from the key rather than the
** data. ** data.
**
** Viewed from a higher level, this instruction retrieves the
** data from a single column in a particular row of an SQL table
** file. Perhaps the name of this instruction should be
** "Column" instead of "Field"...
*/ */
case OP_Field: { case OP_Field: {
int *pAddr; int *pAddr;
@ -1951,35 +1964,35 @@ int sqliteVdbeExec(
int i = pOp->p1; int i = pOp->p1;
int p2 = pOp->p2; int p2 = pOp->p2;
int tos = ++p->tos; int tos = ++p->tos;
DbbeTable *pTab; DbbeCursor *pCrsr;
char *z; char *z;
if( NeedStack(p, tos) ) goto no_mem; if( NeedStack(p, tos) ) goto no_mem;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
if( p->aTab[i].keyAsData ){ if( p->aCsr[i].keyAsData ){
amt = sqliteDbbeKeyLength(pTab); amt = sqliteDbbeKeyLength(pCrsr);
if( amt<=sizeof(int)*(p2+1) ){ if( amt<=sizeof(int)*(p2+1) ){
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
break; break;
} }
pAddr = (int*)sqliteDbbeReadKey(pTab, sizeof(int)*p2); pAddr = (int*)sqliteDbbeReadKey(pCrsr, sizeof(int)*p2);
if( *pAddr==0 ){ if( *pAddr==0 ){
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
break; break;
} }
z = sqliteDbbeReadKey(pTab, *pAddr); z = sqliteDbbeReadKey(pCrsr, *pAddr);
}else{ }else{
amt = sqliteDbbeDataLength(pTab); amt = sqliteDbbeDataLength(pCrsr);
if( amt<=sizeof(int)*(p2+1) ){ if( amt<=sizeof(int)*(p2+1) ){
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
break; break;
} }
pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2); pAddr = (int*)sqliteDbbeReadData(pCrsr, sizeof(int)*p2);
if( *pAddr==0 ){ if( *pAddr==0 ){
p->aStack[tos].flags = STK_Null; p->aStack[tos].flags = STK_Null;
break; break;
} }
z = sqliteDbbeReadData(pTab, *pAddr); z = sqliteDbbeReadData(pCrsr, *pAddr);
} }
p->zStack[tos] = z; p->zStack[tos] = z;
p->aStack[tos].n = strlen(z) + 1; p->aStack[tos].n = strlen(z) + 1;
@ -1991,21 +2004,22 @@ int sqliteVdbeExec(
/* Opcode: Key P1 * * /* Opcode: Key P1 * *
** **
** Push onto the stack an integer which is the first 4 bytes of the ** Push onto the stack an integer which is the first 4 bytes of the
** the key to the current entry in a sequential scan of the table P1. ** the key to the current entry in a sequential scan of the database
** A sequential scan is started using the Next opcode. ** file P1. The sequential scan should have been started using the
** Next opcode.
*/ */
case OP_Key: { case OP_Key: {
int i = pOp->p1; int i = pOp->p1;
int tos = ++p->tos; int tos = ++p->tos;
DbbeTable *pTab; DbbeCursor *pCrsr;
if( NeedStack(p, p->tos) ) goto no_mem; if( NeedStack(p, p->tos) ) goto no_mem;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
char *z = sqliteDbbeReadKey(pTab, 0); char *z = sqliteDbbeReadKey(pCrsr, 0);
if( p->aTab[i].keyAsData ){ if( p->aCsr[i].keyAsData ){
p->zStack[tos] = z; p->zStack[tos] = z;
p->aStack[tos].flags = STK_Str; p->aStack[tos].flags = STK_Str;
p->aStack[tos].n = sqliteDbbeKeyLength(pTab); p->aStack[tos].n = sqliteDbbeKeyLength(pCrsr);
}else{ }else{
memcpy(&p->aStack[tos].i, z, sizeof(int)); memcpy(&p->aStack[tos].i, z, sizeof(int));
p->aStack[tos].flags = STK_Int; p->aStack[tos].flags = STK_Int;
@ -2017,25 +2031,25 @@ int sqliteVdbeExec(
/* Opcode: Rewind P1 * * /* Opcode: Rewind P1 * *
** **
** The next use of the Key or Field or Next instruction for P1 ** The next use of the Key or Field or Next instruction for P1
** will refer to the first entry in the table. ** will refer to the first entry in the database file.
*/ */
case OP_Rewind: { case OP_Rewind: {
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
sqliteDbbeRewind(p->aTab[i].pTable); sqliteDbbeRewind(p->aCsr[i].pCursor);
} }
break; break;
} }
/* Opcode: Next P1 P2 * /* Opcode: Next P1 P2 *
** **
** Advance P1 to the next entry in the table. Or, if there are no ** Advance P1 to the next key/data pair in the file. Or, if there are no
** more entries, rewind P1 and jump to location P2. ** more key/data pairs, rewind P1 and jump to location P2.
*/ */
case OP_Next: { case OP_Next: {
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nTable && p->aTab[i].pTable!=0 ){ if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor!=0 ){
if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){ if( sqliteDbbeNextKey(p->aCsr[i].pCursor)==0 ){
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
}else{ }else{
p->nFetch++; p->nFetch++;
@ -2046,37 +2060,48 @@ int sqliteVdbeExec(
/* Opcode: ResetIdx P1 * * /* Opcode: ResetIdx P1 * *
** **
** Begin treating the current row of table P1 as an index. The next ** Begin treating the current data in cursor P1 as a bunch of integer
** NextIdx instruction will refer to the first index in the table. ** keys to records of a (separate) SQL table file. This instruction
** causes the new NextIdx instruction push the first integer table
** key in the data.
*/ */
case OP_ResetIdx: { case OP_ResetIdx: {
int i = pOp->p1; int i = pOp->p1;
if( i>=0 && i<p->nTable ){ if( i>=0 && i<p->nCursor ){
p->aTab[i].index = 0; p->aCsr[i].index = 0;
} }
break; break;
} }
/* Opcode: NextIdx P1 P2 * /* Opcode: NextIdx P1 P2 *
** **
** Push the next index from the current entry of table P1 onto the ** The P1 cursor points to an SQL index. The data from the most
** stack and advance the pointer. If there are no more indices, then ** recent fetch on that cursor consists of a bunch of integers where
** reset the table entry and jump to P2 ** each integer is the key to a record in an SQL table file.
** This instruction grabs the next integer table key from the data
** of P1 and pushes that integer onto the stack. The first time
** this instruction is executed after a fetch, the first integer
** table key is pushed. Subsequent integer table keys are pushed
** in each subsequent execution of this instruction.
**
** If there are no more integer table keys in the data of P1
** when this instruction is executed, then nothing gets pushed and
** there is an immediate jump to instruction P2.
*/ */
case OP_NextIdx: { case OP_NextIdx: {
int i = pOp->p1; int i = pOp->p1;
int tos = ++p->tos; int tos = ++p->tos;
DbbeTable *pTab; DbbeCursor *pCrsr;
if( NeedStack(p, p->tos) ) goto no_mem; if( NeedStack(p, p->tos) ) goto no_mem;
p->zStack[tos] = 0; p->zStack[tos] = 0;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
int *aIdx; int *aIdx;
int nIdx; int nIdx;
int j; int j;
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
aIdx = (int*)sqliteDbbeReadData(pTab, 0); aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
for(j=p->aTab[i].index; j<nIdx; j++){ for(j=p->aCsr[i].index; j<nIdx; j++){
if( aIdx[j]!=0 ){ if( aIdx[j]!=0 ){
p->aStack[tos].i = aIdx[j]; p->aStack[tos].i = aIdx[j];
p->aStack[tos].flags = STK_Int; p->aStack[tos].flags = STK_Int;
@ -2088,47 +2113,47 @@ int sqliteVdbeExec(
pc = pOp->p2 - 1; pc = pOp->p2 - 1;
PopStack(p, 1); PopStack(p, 1);
} }
p->aTab[i].index = j+1; p->aCsr[i].index = j+1;
} }
break; break;
} }
/* Opcode: PutIdx P1 * * /* Opcode: PutIdx P1 * *
** **
** The top of the stack hold an index key (probably made using the ** The top of the stack hold an SQL index key (probably made using the
** MakeKey instruction) and next on stack holds an index value for ** MakeKey instruction) and next on stack holds an integer which
** a table. Locate the record in the index P1 that has the key ** the key to an SQL table entry. Locate the record in cursor P1
** and insert the index value into its ** that has the same key as on the TOS. Create a new record if
** data. Write the results back to the index. ** necessary. Then append the integer table key to the data for that
** If the key doesn't exist it is created. ** record and write it back to the P1 file.
*/ */
case OP_PutIdx: { case OP_PutIdx: {
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
int nos = tos - 1; int nos = tos - 1;
DbbeTable *pTab; DbbeCursor *pCrsr;
if( nos<0 ) goto not_enough_stack; if( nos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
int r; int r;
int newVal; int newVal;
Integerify(p, nos); Integerify(p, nos);
newVal = p->aStack[nos].i; newVal = p->aStack[nos].i;
if( Stringify(p, tos) ) goto no_mem; if( Stringify(p, tos) ) goto no_mem;
r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]); r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
if( r==0 ){ if( r==0 ){
/* Create a new record for this index */ /* Create a new record for this index */
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos], sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
sizeof(int), (char*)&newVal); sizeof(int), (char*)&newVal);
}else{ }else{
/* Extend the existing record */ /* Extend the existing record */
int nIdx; int nIdx;
int *aIdx; int *aIdx;
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) ); aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) );
if( aIdx==0 ) goto no_mem; if( aIdx==0 ) goto no_mem;
sqliteDbbeCopyData(pTab, 0, nIdx*sizeof(int), (char*)aIdx); sqliteDbbeCopyData(pCrsr, 0, nIdx*sizeof(int), (char*)aIdx);
aIdx[nIdx] = newVal; aIdx[nIdx] = newVal;
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos], sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
sizeof(int)*(nIdx+1), (char*)aIdx); sizeof(int)*(nIdx+1), (char*)aIdx);
sqliteFree(aIdx); sqliteFree(aIdx);
} }
@ -2139,20 +2164,24 @@ int sqliteVdbeExec(
/* Opcode: DeleteIdx P1 * * /* Opcode: DeleteIdx P1 * *
** **
** The top of the stack is a key and next on stack is an index value. ** The top of the stack is a key and next on stack is integer
** Locate the record ** which is the key to a record in an SQL table.
** in index P1 that has the key and remove the index value from its ** Locate the record in the cursor P1 (P1 represents an SQL index)
** data. Write the results back to the table. If after removing ** that has the same key as the top of stack. Then look through
** the index value no more indices remain in the record, then the ** the integer table-keys contained in the data of the P1 record.
** record is removed from the table. ** Remove the integer table-key that matches the NOS and write the
** revised data back to P1 with the same key.
**
** If this routine removes the very last integer table-key from
** the P1 data, then the corresponding P1 record is deleted.
*/ */
case OP_DeleteIdx: { case OP_DeleteIdx: {
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
int nos = tos - 1; int nos = tos - 1;
DbbeTable *pTab; DbbeCursor *pCrsr;
if( nos<0 ) goto not_enough_stack; if( nos<0 ) goto not_enough_stack;
if( i>=0 && i<p->nTable && (pTab = p->aTab[i].pTable)!=0 ){ if( i>=0 && i<p->nCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){
int *aIdx; int *aIdx;
int nIdx; int nIdx;
int j; int j;
@ -2161,17 +2190,17 @@ int sqliteVdbeExec(
Integerify(p, nos); Integerify(p, nos);
oldVal = p->aStack[nos].i; oldVal = p->aStack[nos].i;
if( Stringify(p, tos) ) goto no_mem; if( Stringify(p, tos) ) goto no_mem;
r = sqliteDbbeFetch(pTab, p->aStack[tos].n, p->zStack[tos]); r = sqliteDbbeFetch(pCrsr, p->aStack[tos].n, p->zStack[tos]);
if( r==0 ) break; if( r==0 ) break;
nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int);
aIdx = (int*)sqliteDbbeReadData(pTab, 0); aIdx = (int*)sqliteDbbeReadData(pCrsr, 0);
for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){} for(j=0; j<nIdx && aIdx[j]!=oldVal; j++){}
if( j>=nIdx ) break; if( j>=nIdx ) break;
aIdx[j] = aIdx[nIdx-1]; aIdx[j] = aIdx[nIdx-1];
if( nIdx==1 ){ if( nIdx==1 ){
sqliteDbbeDelete(pTab, p->aStack[tos].n, p->zStack[tos]); sqliteDbbeDelete(pCrsr, p->aStack[tos].n, p->zStack[tos]);
}else{ }else{
sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos], sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos],
sizeof(int)*(nIdx-1), (char*)aIdx); sizeof(int)*(nIdx-1), (char*)aIdx);
} }
} }
@ -2181,8 +2210,9 @@ int sqliteVdbeExec(
/* Opcode: Destroy * * P3 /* Opcode: Destroy * * P3
** **
** Drop the table whose name is P3. The file that holds this table ** Drop the disk file whose name is P3. All key/data pairs in
** is removed from the disk drive. ** the file are deleted and the file itself is removed
** from the disk.
*/ */
case OP_Destroy: { case OP_Destroy: {
sqliteDbbeDropTable(p->pBe, pOp->p3); sqliteDbbeDropTable(p->pBe, pOp->p3);
@ -2200,7 +2230,7 @@ int sqliteVdbeExec(
/* Opcode: ListOpen P1 * * /* Opcode: ListOpen P1 * *
** **
** Open a file used for temporary storage of index numbers. P1 ** Open a file used for temporary storage of integer table keys. P1
** will server as a handle to this temporary file for future ** will server as a handle to this temporary file for future
** interactions. If another temporary file with the P1 handle is ** interactions. If another temporary file with the P1 handle is
** already opened, the prior file is closed and a new one opened ** already opened, the prior file is closed and a new one opened
@ -2260,7 +2290,7 @@ int sqliteVdbeExec(
/* Opcode: ListRead P1 P2 * /* Opcode: ListRead P1 P2 *
** **
** Attempt to read an integer from temporary storage buffer P1 ** Attempt to read an integer from temporary storage buffer P1
** and push it onto the stack. If the storage buffer is empty ** and push it onto the stack. If the storage buffer is empty,
** push nothing but instead jump to P2. ** push nothing but instead jump to P2.
*/ */
case OP_ListRead: { case OP_ListRead: {
@ -2693,7 +2723,7 @@ int sqliteVdbeExec(
/* Opcode: FileField P1 * * /* Opcode: FileField P1 * *
** **
** Push onto the stack the P1-th field of the most recently read line ** Push onto the stack the P1-th field of the most recently read line
** from the file. ** from the input file.
*/ */
case OP_FileField: { case OP_FileField: {
int i = pOp->p1; int i = pOp->p1;
@ -2828,8 +2858,8 @@ int sqliteVdbeExec(
/* Opcode: AggIncr P1 P2 * /* Opcode: AggIncr P1 P2 *
** **
** Increment the P2-th field of the aggregate element current ** Increase the integer value in the P2-th field of the aggregate
** in focus by an amount P1. ** element current in focus by an amount P1.
*/ */
case OP_AggIncr: { case OP_AggIncr: {
AggElem *pFocus = AggInFocus(p->agg); AggElem *pFocus = AggInFocus(p->agg);

View File

@ -25,7 +25,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines ** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions. ** to generate VDBE code to evaluate expressions.
** **
** $Id: where.c,v 1.7 2000/06/06 13:54:16 drh Exp $ ** $Id: where.c,v 1.8 2000/06/21 13:59:13 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -38,10 +38,10 @@ typedef struct ExprInfo ExprInfo;
struct ExprInfo { struct ExprInfo {
Expr *p; /* Pointer to the subexpression */ Expr *p; /* Pointer to the subexpression */
int indexable; /* True if this subexprssion is usable by an index */ int indexable; /* True if this subexprssion is usable by an index */
int idxLeft; /* p->pLeft is a field in this table number. -1 if int idxLeft; /* p->pLeft is a column in this table number. -1 if
** p->pLeft is not the field of any table */ ** p->pLeft is not the column of any table */
int idxRight; /* p->pRight is a field in this table number. -1 if int idxRight; /* p->pRight is a column in this table number. -1 if
** p->pRight is not the field of any table */ ** p->pRight is not the column of any table */
unsigned prereqLeft; /* Tables referenced by p->pLeft */ unsigned prereqLeft; /* Tables referenced by p->pLeft */
unsigned prereqRight; /* Tables referenced by p->pRight */ unsigned prereqRight; /* Tables referenced by p->pRight */
}; };
@ -94,7 +94,7 @@ static int exprSplit(int nSlot, ExprInfo *aSlot, Expr *pExpr){
static int exprTableUsage(int base, Expr *p){ static int exprTableUsage(int base, Expr *p){
unsigned int mask = 0; unsigned int mask = 0;
if( p==0 ) return 0; if( p==0 ) return 0;
if( p->op==TK_FIELD ){ if( p->op==TK_COLUMN ){
return 1<< (p->iTable - base); return 1<< (p->iTable - base);
} }
if( p->pRight ){ if( p->pRight ){
@ -124,11 +124,11 @@ static void exprAnalyze(int base, ExprInfo *pInfo){
pInfo->idxLeft = -1; pInfo->idxLeft = -1;
pInfo->idxRight = -1; pInfo->idxRight = -1;
if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){ if( pExpr->op==TK_EQ && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
if( pExpr->pRight->op==TK_FIELD ){ if( pExpr->pRight->op==TK_COLUMN ){
pInfo->idxRight = pExpr->pRight->iTable - base; pInfo->idxRight = pExpr->pRight->iTable - base;
pInfo->indexable = 1; pInfo->indexable = 1;
} }
if( pExpr->pLeft->op==TK_FIELD ){ if( pExpr->pLeft->op==TK_COLUMN ){
pInfo->idxLeft = pExpr->pLeft->iTable - base; pInfo->idxLeft = pExpr->pLeft->iTable - base;
pInfo->indexable = 1; pInfo->indexable = 1;
} }
@ -225,41 +225,41 @@ WhereInfo *sqliteWhereBegin(
** the most specific usable index. ** the most specific usable index.
** **
** "Most specific" means that pBestIdx is the usable index that ** "Most specific" means that pBestIdx is the usable index that
** has the largest value for nField. A usable index is one for ** has the largest value for nColumn. A usable index is one for
** which there are subexpressions to compute every field of the ** which there are subexpressions to compute every column of the
** index. ** index.
*/ */
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int j; int j;
int fieldMask = 0; int columnMask = 0;
if( pIdx->nField>32 ) continue; if( pIdx->nColumn>32 ) continue;
for(j=0; j<nExpr; j++){ for(j=0; j<nExpr; j++){
if( aExpr[j].idxLeft==idx if( aExpr[j].idxLeft==idx
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){ && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
int iField = aExpr[j].p->pLeft->iField; int iColumn = aExpr[j].p->pLeft->iColumn;
int k; int k;
for(k=0; k<pIdx->nField; k++){ for(k=0; k<pIdx->nColumn; k++){
if( pIdx->aiField[k]==iField ){ if( pIdx->aiColumn[k]==iColumn ){
fieldMask |= 1<<k; columnMask |= 1<<k;
break; break;
} }
} }
} }
if( aExpr[j].idxRight==idx if( aExpr[j].idxRight==idx
&& (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){ && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ){
int iField = aExpr[j].p->pRight->iField; int iColumn = aExpr[j].p->pRight->iColumn;
int k; int k;
for(k=0; k<pIdx->nField; k++){ for(k=0; k<pIdx->nColumn; k++){
if( pIdx->aiField[k]==iField ){ if( pIdx->aiColumn[k]==iColumn ){
fieldMask |= 1<<k; columnMask |= 1<<k;
break; break;
} }
} }
} }
} }
if( fieldMask + 1 == (1<<pIdx->nField) ){ if( columnMask + 1 == (1<<pIdx->nColumn) ){
if( pBestIdx==0 || pBestIdx->nField<pIdx->nField ){ if( pBestIdx==0 || pBestIdx->nColumn<pIdx->nColumn ){
pBestIdx = pIdx; pBestIdx = pIdx;
} }
} }
@ -297,12 +297,12 @@ WhereInfo *sqliteWhereBegin(
}else{ }else{
/* Case 2: We do have a usable index in pIdx. /* Case 2: We do have a usable index in pIdx.
*/ */
for(j=0; j<pIdx->nField; j++){ for(j=0; j<pIdx->nColumn; j++){
for(k=0; k<nExpr; k++){ for(k=0; k<nExpr; k++){
if( aExpr[k].p==0 ) continue; if( aExpr[k].p==0 ) continue;
if( aExpr[k].idxLeft==idx if( aExpr[k].idxLeft==idx
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
&& aExpr[k].p->pLeft->iField==pIdx->aiField[j] && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
){ ){
sqliteExprCode(pParse, aExpr[k].p->pRight); sqliteExprCode(pParse, aExpr[k].p->pRight);
aExpr[k].p = 0; aExpr[k].p = 0;
@ -310,7 +310,7 @@ WhereInfo *sqliteWhereBegin(
} }
if( aExpr[k].idxRight==idx if( aExpr[k].idxRight==idx
&& (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
&& aExpr[k].p->pRight->iField==pIdx->aiField[j] && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
){ ){
sqliteExprCode(pParse, aExpr[k].p->pLeft); sqliteExprCode(pParse, aExpr[k].p->pLeft);
aExpr[k].p = 0; aExpr[k].p = 0;
@ -318,7 +318,7 @@ WhereInfo *sqliteWhereBegin(
} }
} }
} }
sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nField, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Fetch, base+pTabList->nId+i, 0, 0, 0); sqliteVdbeAddOp(v, OP_Fetch, base+pTabList->nId+i, 0, 0, 0);
sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont); sqliteVdbeAddOp(v, OP_NextIdx, base+pTabList->nId+i, brk, 0, cont);
if( i==pTabList->nId-1 && pushKey ){ if( i==pTabList->nId-1 && pushKey ){

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the DELETE FROM statement. # focus of this file is testing the DELETE FROM statement.
# #
# $Id: delete.test,v 1.5 2000/06/08 15:10:48 drh Exp $ # $Id: delete.test,v 1.6 2000/06/21 13:59:13 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -72,7 +72,7 @@ do_test delete-4.1 {
execsql {CREATE TABLE table2(f1 int, f2 int)} execsql {CREATE TABLE table2(f1 int, f2 int)}
set v [catch {execsql {DELETE FROM table2 WHERE f3=5}} msg] set v [catch {execsql {DELETE FROM table2 WHERE f3=5}} msg]
lappend v $msg lappend v $msg
} {1 {no such field: f3}} } {1 {no such column: f3}}
do_test delete-4.2 { do_test delete-4.2 {
set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg] set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg]

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the IN and BETWEEN operator. # focus of this file is testing the IN and BETWEEN operator.
# #
# $Id: in.test,v 1.2 2000/06/07 23:51:51 drh Exp $ # $Id: in.test,v 1.3 2000/06/21 13:59:13 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -106,7 +106,7 @@ do_test in-2.10 {
do_test in-2.11 { do_test in-2.11 {
set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg] set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} msg]
lappend v $msg lappend v $msg
} {1 {no such field: c}} } {1 {no such column: c}}
# Testing the IN operator where the right-hand side is a SELECT # Testing the IN operator where the right-hand side is a SELECT
# #

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement. # focus of this file is testing the SELECT statement.
# #
# $Id: select1.test,v 1.5 2000/06/07 15:11:27 drh Exp $ # $Id: select1.test,v 1.6 2000/06/21 13:59:13 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -49,7 +49,7 @@ do_test select1-1.3 {
execsql {INSERT INTO test1(f1,f2) VALUES(11,22)} execsql {INSERT INTO test1(f1,f2) VALUES(11,22)}
# Make sure the fields are extracted correctly. # Make sure the columns are extracted correctly.
# #
do_test select1-1.4 { do_test select1-1.4 {
execsql {SELECT f1 FROM test1} execsql {SELECT f1 FROM test1}
@ -244,7 +244,7 @@ do_test select1-5.1 {
execsql {CREATE TABLE test2(t1 test, t2 text)} execsql {CREATE TABLE test2(t1 test, t2 text)}
execsql {INSERT INTO test2 VALUES('abc','xyz')} execsql {INSERT INTO test2 VALUES('abc','xyz')}
# Check for field naming # Check for column naming
# #
do_test select1-6.1 { do_test select1-6.1 {
set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg] set v [catch {execsql2 {SELECT f1 FROM test1 ORDER BY f2}} msg]
@ -280,17 +280,17 @@ do_test select1-6.8 {
set v [catch {execsql2 {SELECT A.f1, f1 FROM test1 as A, test1 as B set v [catch {execsql2 {SELECT A.f1, f1 FROM test1 as A, test1 as B
ORDER BY f2}} msg] ORDER BY f2}} msg]
lappend v $msg lappend v $msg
} {1 {ambiguous field name: f1}} } {1 {ambiguous column name: f1}}
do_test select1-6.8b { do_test select1-6.8b {
set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B
ORDER BY f2}} msg] ORDER BY f2}} msg]
lappend v $msg lappend v $msg
} {1 {ambiguous field name: f2}} } {1 {ambiguous column name: f2}}
do_test select1-6.8c { do_test select1-6.8c {
set v [catch {execsql2 {SELECT A.f1, f1 FROM test1 as A, test1 as A set v [catch {execsql2 {SELECT A.f1, f1 FROM test1 as A, test1 as A
ORDER BY f2}} msg] ORDER BY f2}} msg]
lappend v $msg lappend v $msg
} {1 {ambiguous field name: A.f1}} } {1 {ambiguous column name: A.f1}}
do_test select1-6.9 { do_test select1-6.9 {
set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B
ORDER BY A.f1, B.f1}} msg] ORDER BY A.f1, B.f1}} msg]

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement. # focus of this file is testing the SELECT statement.
# #
# $Id: select2.test,v 1.6 2000/06/08 16:54:40 drh Exp $ # $Id: select2.test,v 1.7 2000/06/21 13:59:13 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -106,7 +106,7 @@ do_test select2-3.2c {
do_test select2-3.2d { do_test select2-3.2d {
set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0] set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0]
set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0] set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0]
expr {$t1*0.9<$t2 && $t2*0.9<$t1} expr {$t1*0.8<$t2 && $t2*0.8<$t1}
} {1} } {1}
# Make sure queries run faster with an index than without # Make sure queries run faster with an index than without

View File

@ -24,7 +24,7 @@
# focus of this file is testing aggregate functions and the # focus of this file is testing aggregate functions and the
# GROUP BY and HAVING clauses of SELECT statements. # GROUP BY and HAVING clauses of SELECT statements.
# #
# $Id: select5.test,v 1.3 2000/06/08 16:26:25 drh Exp $ # $Id: select5.test,v 1.4 2000/06/21 13:59:13 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -66,7 +66,7 @@ do_test select5-2.1 {
SELECT y, count(*) FROM t1 GROUP BY z ORDER BY y SELECT y, count(*) FROM t1 GROUP BY z ORDER BY y
}} msg] }} msg]
lappend v $msg lappend v $msg
} {1 {no such field: z}} } {1 {no such column: z}}
do_test select5-2.2 { do_test select5-2.2 {
set v [catch {execsql { set v [catch {execsql {
SELECT y, count(*) FROM t1 GROUP BY z(y) ORDER BY y SELECT y, count(*) FROM t1 GROUP BY z(y) ORDER BY y
@ -90,7 +90,7 @@ do_test select5-2.5 {
SELECT y, count(*) FROM t1 GROUP BY y HAVING count(*)<z ORDER BY y SELECT y, count(*) FROM t1 GROUP BY y HAVING count(*)<z ORDER BY y
}} msg] }} msg]
lappend v $msg lappend v $msg
} {1 {no such field: z}} } {1 {no such column: z}}
# Get the Agg function to rehash in vdbe.c # Get the Agg function to rehash in vdbe.c
# #

View File

@ -23,7 +23,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is testing the UPDATE statement. # focus of this file is testing the UPDATE statement.
# #
# $Id: update.test,v 1.3 2000/06/19 19:09:09 drh Exp $ # $Id: update.test,v 1.4 2000/06/21 13:59:14 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@ -54,20 +54,20 @@ do_test update-3.1 {
execsql {SELECT * FROM test1 ORDER BY f1} execsql {SELECT * FROM test1 ORDER BY f1}
} {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024} } {1 2 2 4 3 8 4 16 5 32 6 64 7 128 8 256 9 512 10 1024}
# Unknown field name in an expression # Unknown column name in an expression
# #
do_test update-3.2 { do_test update-3.2 {
set v [catch {execsql {UPDATE test1 SET f1=f3*2 WHERE f2==32}} msg] set v [catch {execsql {UPDATE test1 SET f1=f3*2 WHERE f2==32}} msg]
lappend v $msg lappend v $msg
} {1 {no such field: f3}} } {1 {no such column: f3}}
do_test update-3.3 { do_test update-3.3 {
set v [catch {execsql {UPDATE test1 SET f1=test2.f1*2 WHERE f2==32}} msg] set v [catch {execsql {UPDATE test1 SET f1=test2.f1*2 WHERE f2==32}} msg]
lappend v $msg lappend v $msg
} {1 {no such field: test2.f1}} } {1 {no such column: test2.f1}}
do_test update-3.4 { do_test update-3.4 {
set v [catch {execsql {UPDATE test1 SET f3=f1*2 WHERE f2==32}} msg] set v [catch {execsql {UPDATE test1 SET f3=f1*2 WHERE f2==32}} msg]
lappend v $msg lappend v $msg
} {1 {no such field: f3}} } {1 {no such column: f3}}
# Actually do some updates # Actually do some updates
# #
@ -117,7 +117,7 @@ do_test update-4.1 {
UPDATE test1 SET x=11 WHERE f1=1025 UPDATE test1 SET x=11 WHERE f1=1025
}} msg] }} msg]
lappend v $msg lappend v $msg
} {1 {no such field: x}} } {1 {no such column: x}}
do_test update-4.2 { do_test update-4.2 {
set v [catch {execsql { set v [catch {execsql {
UPDATE test1 SET f1=x(11) WHERE f1=1025 UPDATE test1 SET f1=x(11) WHERE f1=1025
@ -129,7 +129,7 @@ do_test update-4.3 {
UPDATE test1 SET f1=11 WHERE x=1025 UPDATE test1 SET f1=11 WHERE x=1025
}} msg] }} msg]
lappend v $msg lappend v $msg
} {1 {no such field: x}} } {1 {no such column: x}}
do_test update-4.4 { do_test update-4.4 {
set v [catch {execsql { set v [catch {execsql {
UPDATE test1 SET f1=11 WHERE x(f1)=1025 UPDATE test1 SET f1=11 WHERE x(f1)=1025

View File

@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: c_interface.tcl,v 1.4 2000/06/06 18:24:42 drh Exp $} set rcsid {$Id: c_interface.tcl,v 1.5 2000/06/21 13:59:14 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@ -88,7 +88,7 @@ for any reason.</p>
<h2>Closing the database</h2> <h2>Closing the database</h2>
<p>To close an SQLite database, just call the <b>sqlite_close()</b> <p>To close an SQLite database, call the <b>sqlite_close()</b>
function passing it the sqlite structure pointer that was obtained function passing it the sqlite structure pointer that was obtained
from a prior call to <b>sqlite_open</b>. from a prior call to <b>sqlite_open</b>.
@ -147,6 +147,62 @@ argv[i] == 0
function returns non-zero, the query is immediately aborted and function returns non-zero, the query is immediately aborted and
<b>sqlite_exec()</b> will return SQLITE_ABORT.</p> <b>sqlite_exec()</b> will return SQLITE_ABORT.</p>
<p>The <b>sqlite_exec()</b> function returns an integer to indicate
success or failure of the operation. The following are possible
return values:</p>
<blockquote>
<dl>
<dt>SQLITE_OK</dt>
<dd><p>This value is returned if everything worked and there were no errors.
</p></dd>
<dt>SQLITE_INTERNAL</dt>
<dd><p>This value indicates that an internal consistency check within
the SQLite library failed. This can only happen if there is a bug in
the SQLite library. If you ever get an SQLITE_INTERNAL reply from
an <b>sqlite_exec()</b> call, please report the problem on the SQLite
mailing list.
</p></dd>
<dt>SQLITE_ERROR</dt>
<dd><p>This return value indicates that there was an error in the SQL
that was passed into the <b>sqlite_exec()</b>.
</p></dd>
<dt>SQLITE_PERM</dt>
<dd><p>This return value says that the access permissions on one of the
GDBM files is such that the file cannot be opened.
</p></dd>
<dt>SQLITE_ABORT</dt>
<dd><p>This value is returned if the callback function returns non-zero.
</p></dd>
<dt>SQLITE_BUSY</dt>
<dd><p>This return code indicates that one of the underlying GDBM files
is locked because it is currently being accessed by another thread or
process. GDBM allows mutiple readers of the same file, but only one
writer. So multiple processes can query an SQLite database at once.
But only a single process can write to an SQLite database at one time.
If an attempt is made to write to an SQLite database that another
process is currently reading, the write is not performed and
<b>sqlite_exec()</b> returns SQLITE_BUSY. Similarly, an attempt to read
an SQLite database that is currently being written by another process
will return SQLITE_BUSY. In both cases, the write or query attempt
can be retried after the other process finishes.</p>
<p>Note that locking is done at the file level. One process can
write to table ABC (for example) while another process simultaneously
reads from a different table XYZ. But you cannot have two processes reading
and writing table ABC at the same time.
</p></dd>
<dt>SQLITE_NOMEM</dt>
<dd><p>This value is returned if a call to <b>malloc()</b> fails.
</p></dd>
<dt>SQLITE_READONLY</dt>
<dd><p>This return code indicates that an attempt was made to write to
a database file that was originally opened for reading only. This can
happen if the callback from a query attempts to update the table
being queried.
</p></dd>
</dl>
</blockquote>
<h2>Testing for a complete SQL statement</h2> <h2>Testing for a complete SQL statement</h2>
<p>The last interface routine to SQLite is a convenience function used <p>The last interface routine to SQLite is a convenience function used

View File

@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: sqlite.tcl,v 1.8 2000/06/08 19:43:40 drh Exp $} set rcsid {$Id: sqlite.tcl,v 1.9 2000/06/21 13:59:14 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@ -150,6 +150,7 @@ sqlite> (((.help)))
.help Show this message .help Show this message
.indices TABLE Show names of all indices on TABLE .indices TABLE Show names of all indices on TABLE
.mode MODE Set mode to one of "line", "column", "list", or "html" .mode MODE Set mode to one of "line", "column", "list", or "html"
.mode insert TABLE Generate SQL insert statements for TABLE
.output FILENAME Send output to FILENAME .output FILENAME Send output to FILENAME
.output stdout Send output to the screen .output stdout Send output to the screen
.schema ?TABLE? Show the CREATE statements .schema ?TABLE? Show the CREATE statements
@ -163,13 +164,13 @@ puts {
<h2>Changing Output Formats</h2> <h2>Changing Output Formats</h2>
<p>The sqlite program is able to show the results of a query <p>The sqlite program is able to show the results of a query
in four different formats: "line", "column", "list", and "html". in five different formats: "line", "column", "list", "html", and "insert".
You can use the ".mode" dot command to switch between these three output You can use the ".mode" dot command to switch between these three output
formats.</p> formats.</p>
<p>The default output mode is "list". In <p>The default output mode is "list". In
list mode, each record of a query result is written on one line of list mode, each record of a query result is written on one line of
output and each field within that record is separated by a specific output and each column within that record is separated by a specific
separator string. The default separator is a pipe symbol ("|"). separator string. The default separator is a pipe symbol ("|").
List mode is especially useful when you are going to send the output List mode is especially useful when you are going to send the output
of a query to another program (such as AWK) for additional processing.</p>} of a query to another program (such as AWK) for additional processing.</p>}
@ -196,9 +197,9 @@ sqlite>
} }
puts { puts {
<p>In "line" mode, each field in a record of the database <p>In "line" mode, each column in a row of the database
is shown on a line by itself. Each line consists of the field is shown on a line by itself. Each line consists of the column
name, an equal sign and the field data. Successive records are name, an equal sign and the column data. Successive records are
separated by a blank line. Here is an example of line mode separated by a blank line. Here is an example of line mode
output:</p>} output:</p>}
@ -263,6 +264,11 @@ sqlite>
} }
puts { puts {
<p>Another useful output mode is "insert". In insert mode, the output
is formatted to look like SQL INSERT statements. You can use insert
mode to generate text that can later be used to input data into a
different database.</p>
<p>The last output mode is "html". In this mode, sqlite writes <p>The last output mode is "html". In this mode, sqlite writes
the results of the query as an XHTML table. The beginning the results of the query as an XHTML table. The beginning
&lt;TABLE&gt; and the ending &lt;/TABLE&gt; are not written, but &lt;TABLE&gt; and the ending &lt;/TABLE&gt; are not written, but