diff --git a/manifest b/manifest index 2ec09d6d89..91411719ac 100644 --- a/manifest +++ b/manifest @@ -1,50 +1,50 @@ -C :-)\s(CVS\s103) -D 2000-06-19T19:10:29 +C :-)\s(CVS\s104) +D 2000-06-21T13:59:11 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4 F Makefile.in 4dc16840f68e3b599915e1ec8463d365474dd286 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958 F configure c366a0402bce79ef11fe1bf703ad6ce4ff6afbb0 x F configure.in 1085ff994a334b131325de906ed318e926673588 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47 -F src/build.c 9ce11eafbab395b7d19bc5722d1a8955961889b0 -F src/dbbe.c ae5e77f010ba1b68a65aa3cd55c8578eda523dd2 -F src/dbbe.h 9a678ae524c2daad22e959111edd4494e6144dbc -F src/delete.c 2d5758055ff546453385524d856feb1b51ea7b8a -F src/expr.c 88ff9ea12a23a3f0dfaf117670524bdc160af597 -F src/insert.c b1434c7c7c387c69e467d993e9d05460f1047bcc -F src/main.c e3297835b8e38ca726ac73f2c2bdb7cf08103197 -F src/parse.y 974ed07702bda4f04171ef22776eccbb5dae81ca -F src/select.c 2a91f683d64de0362834248cb291bc601cd2950b -F src/shell.c 78a35607a88b3d557e1666ae9d0c2c03cbb3553e +F src/build.c 55edb404bbf4476c73c81604ddb9738281a689a4 +F src/dbbe.c 99aa6daca9a039eebb284dd459bef712ea3843f9 +F src/dbbe.h 8718b718b36d37584e9bbdfccec10588fa91271f +F src/delete.c 4d491eaf61b515516749c7ed68fa3b2ee8a09065 +F src/expr.c 2fa63f086707176d09092e71832f9bbdc6a8ac85 +F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958 +F src/main.c 30b33b6e0cdd5ae1c0af9f626e78a1dc7b835e26 +F src/parse.y 86e268c29a0f00ffc062bbe934d95ea0d6308b0a +F src/select.c aaf23d4a6ef44e4378840ec94b6aa64641c01b5c +F src/shell.c 8387580e44878022c88c02b189bf23bff1862bda F src/sqlite.h 58da0a8590133777b741f9836beaef3d58f40268 -F src/sqliteInt.h 19954bd2f75632849b265b9d7163a67391ec5148 +F src/sqliteInt.h ddc6f8081ef469ede272cf6a382773dac5758dfc F src/tclsqlite.c 9f358618ae803bedf4fb96da5154fd45023bc1f7 F src/tokenize.c 77ff8164a8751994bc9926ce282847f653ac0c16 -F src/update.c 162fc0b86dcd61d164dedc77081a5e7daf6b8fb0 -F src/util.c 38e4bb5edf6fa92e677698c45785bf73c69b9e9f -F src/vdbe.c 00b2ab7e0c0df2ac6eb4bf659656afc30e76c66b +F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc +F src/util.c fcd7ac9d2be8353f746e52f665e6c4f5d6b3b805 +F src/vdbe.c 38cec3e88db70b7689018377c1594ac18f746b19 F src/vdbe.h 5f58611b19799de2dbcdefa4eef33a255cfa8d0d -F src/where.c c9b90e7672f4662a83ef9a27a193020d69fe034c +F src/where.c 420f666a38b405cd58bd7af832ed99f1dbc7d336 F test/all.test 0950c135cab7e60c07bd745ccfad1476211e5bd7 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb F test/dbbe.test 0a8e4293cf816e590dcbb01be4cd4e8f7f95bdc8 -F test/delete.test 30edd2c7484274fb2e7dbc4a1ac769bb330b322e +F test/delete.test 402ee3ccb6e544582d24c573ef70b34d09583ae7 F test/expr.test 09b55ccf81cb8cc2f9cd83d592a2ba187ee48ba8 -F test/in.test 962a605b6a3a619214f84d1950dfc44fcf0d8b8f +F test/in.test 2c560c0f55fb777029fd9bb5378f2997582aa603 F test/index.test 620ceab7165dd078d1266bdc2cac6147f04534ac F test/insert.test 66f4c3bd600fec8eb1e733b928cbe6fa885eff0c F test/insert2.test 732405e30331635af8d159fccabe835eea5cd0c6 F test/main.test b7366cc6f3690915a11834bc1090deeff08acaf9 -F test/select1.test 64703852af34c85bb31b0a74bd73b340e8267f42 -F test/select2.test 5e2783a48360b83956366ea24b2c5f0293015a84 +F test/select1.test 4e57b0b5eae0c991d9cc51d1288be0476110e6f6 +F test/select2.test ed6e7fc3437079686d7ae4390a00347bbd5f7bf8 F test/select3.test a9234b8424b6c6d71de534f43b91ade9be68e9cc F test/select4.test cb5374d7c87680e294ac749307459a5cc547609d -F test/select5.test 80ea257ce35e736c559bc6cd342361974e60a979 +F test/select5.test e2b9d51d88cbd6c307c2c05b0ef55fe7ba811ac2 F test/sort.test d582086c4bb7df3fbf50aa72e69d7e235e9f8e31 F test/subselect.test bf8b251a92fb091973c1c469ce499dc9648a41d5 F test/table.test d3e01e4916a99ade7d8f1d534ee1b36d57c00490 F test/tester.tcl 95b286791e6256bb6db0165f9342c70fff549a62 -F test/update.test 0f763adc3d84e85224e1dadff72237bcabab1938 +F test/update.test 62f6ce99ff31756aab0ca832ff6d34c5a87b6250 F test/vacuum.test 8becf5cfeb897108b35cdd996793e7f1df2f28fd F test/where.test bbab5a308055fb6087dc23d600b4ad2b72797397 F tool/gdbmdump.c 529e67c78d920606ba196326ea55b57b75fcc82b @@ -57,14 +57,14 @@ F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9 F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156 F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87 F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40 -F www/c_interface.tcl 9ac800854272db5fe439e07b7435b243a5422293 +F www/c_interface.tcl 8eb800f67e6896b1894d666b81c0b418cea09fc7 F www/changes.tcl 160f7522145efaf49961f6cf3671c66c02f2207b F www/fileformat.tcl b11435fcd2cf2238a1c5e6d16fe5e83bcd14d434 F www/index.tcl 4116afce6a8c63d68882d2b00aa10b079e0129cd F www/lang.tcl 1645e9107d75709be4c6099b643db235bbe0a151 F www/opcode.tcl 3cdc4bb2515fcfcbe853e3f0c91cd9199e82dadd -F www/sqlite.tcl 5420eab24b539928f80ea9b3088e2549d34f438d -P 8cce4d279de00da45c5970c8f0946f49e03e6846 -R 24ae8084d8386391fc8e3403683f09be +F www/sqlite.tcl 9fdcfd48fe9e5669116d02f29b2608903f295740 +P af14a5b3ba4a13665142b700e8864bf63d591d95 +R 4b875fc1d381ebbdab00fc05e8ad8c74 U drh -Z 34d7058e222643fe967104d6dc2aa522 +Z e8d8e8697e4d556ecd0e3a4c2a206a66 diff --git a/manifest.uuid b/manifest.uuid index 842ff3b586..75bd74aa24 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -af14a5b3ba4a13665142b700e8864bf63d591d95 \ No newline at end of file +e1bf96a467b739373191bf75e6a097fc0f24bffc \ No newline at end of file diff --git a/src/build.c b/src/build.c index 4d0e1c78de..a49072e080 100644 --- a/src/build.c +++ b/src/build.c @@ -33,7 +33,7 @@ ** COPY ** 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" @@ -151,8 +151,8 @@ Index *sqliteFindIndex(sqlite *db, char *zName){ ** its memory structures. ** ** The index is removed from the database hash table, but it is -** not unlinked from the table that is being indexed. Unlinking -** from the table must be done by the calling function. +** not unlinked from the Table that is being indexed. Unlinking +** from the Table must be done by the calling function. */ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ int h; @@ -173,7 +173,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ /* ** 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 ** the table data structure from the hash table. But does it destroy @@ -512,11 +512,11 @@ void sqliteCreateIndex( pParse->nErr++; goto exit_create_index; } - pIndex->aiField = (int*)&pIndex[1]; - pIndex->zName = (char*)&pIndex->aiField[pList->nId]; + pIndex->aiColumn = (int*)&pIndex[1]; + pIndex->zName = (char*)&pIndex->aiColumn[pList->nId]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; - pIndex->nField = pList->nId; + pIndex->nColumn = pList->nId; /* Scan the names of the columns of the table to be indexed and ** load the column indices into the Index structure. Report an error @@ -533,7 +533,7 @@ void sqliteCreateIndex( sqliteFree(pIndex); goto exit_create_index; } - pIndex->aiField[i] = j; + pIndex->aiColumn[i] = j; } /* Link the new Index structure to its table and to the other @@ -590,10 +590,10 @@ void sqliteCreateIndex( lbl2 = sqliteVdbeMakeLabel(v); sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1); sqliteVdbeAddOp(v, OP_Key, 0, 0, 0, 0); - for(i=0; inField; i++){ - sqliteVdbeAddOp(v, OP_Field, 0, pIndex->aiField[i], 0, 0); + for(i=0; inColumn; i++){ + 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_Goto, 0, lbl1, 0, 0); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2); @@ -834,10 +834,10 @@ void sqliteCopy( if( pIdx->pNext ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } - for(j=0; jnField; j++){ - sqliteVdbeAddOp(v, OP_FileField, pIdx->aiField[j], 0, 0, 0); + for(j=0; jnColumn; j++){ + 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_Goto, 0, addr, 0, 0); diff --git a/src/dbbe.c b/src/dbbe.c index c8b0beb280..d690329beb 100644 --- a/src/dbbe.c +++ b/src/dbbe.c @@ -30,7 +30,7 @@ ** relatively simple to convert to a different database such ** 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 @@ -43,7 +43,7 @@ ** Information about each open disk file is an instance of this ** structure. There will only be one such structure for each ** 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 ** nRef of 2. */ @@ -87,12 +87,12 @@ struct Dbbe { /* ** 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 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 -** 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. */ -struct DbbeTable { +struct DbbeCursor { Dbbe *pBe; /* The database of which this record is a part */ BeFile *pFile; /* The database file for this table */ 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 -** that table. Space to hold the filename is obtained from +** Translate the name of an SQL table (or index) into the name +** 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. */ 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 -** DbbeTable structure into *ppTable. Return an integer success +** DbbeCursor structure into *ppCursr. Return an integer success ** code: ** ** 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 ** do an UPDATE or DELETE.) ** -** If zTable is 0 or "", then a temporary table is created and opened. -** This table will be deleted from the disk when it is closed. +** If zTable is 0 or "", then a temporary database file is created and +** 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 */ - 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 */ - DbbeTable **ppTable /* Write the resulting table pointer here */ + DbbeCursor **ppCursr /* Write the resulting table pointer here */ ){ 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 */ int rc = SQLITE_OK; /* Return value */ int rw_mask; /* Permissions mask for opening a table */ int mode; /* Mode for opening a table */ - *ppTable = 0; - pTable = sqliteMalloc( sizeof(*pTable) ); - if( pTable==0 ) return SQLITE_NOMEM; + *ppCursr = 0; + pCursr = sqliteMalloc( sizeof(*pCursr) ); + if( pCursr==0 ) return SQLITE_NOMEM; if( zTable ){ zFile = sqliteFileOfTable(pBe, zTable); for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){ @@ -376,11 +378,11 @@ int sqliteDbbeOpenTable( rc = SQLITE_READONLY; } } - pTable->pBe = pBe; - pTable->pFile = pFile; - pTable->readPending = 0; - pTable->needRewind = 1; - *ppTable = pTable; + pCursr->pBe = pBe; + pCursr->pFile = pFile; + pCursr->readPending = 0; + pCursr->needRewind = 1; + *ppCursr = pCursr; return rc; } @@ -400,28 +402,33 @@ void sqliteDbbeDropTable(Dbbe *pBe, const char *zTable){ ** Reorganize a table to reduce search times and disk usage. */ 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; } - if( pTab && pTab->pFile && pTab->pFile->dbf ){ - gdbm_reorganize(pTab->pFile->dbf); + if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){ + gdbm_reorganize(pCrsr->pFile->dbf); } - if( pTab ){ - sqliteDbbeCloseTable(pTab); + if( pCrsr ){ + 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; Dbbe *pBe; - if( pTable==0 ) return; - pFile = pTable->pFile; - pBe = pTable->pBe; + if( pCursr==0 ) return; + pFile = pCursr->pFile; + pBe = pCursr->pBe; pFile->nRef--; if( pFile->dbf!=NULL ){ gdbm_sync(pFile->dbf); @@ -445,10 +452,10 @@ void sqliteDbbeCloseTable(DbbeTable *pTable){ memset(pFile, 0, sizeof(*pFile)); sqliteFree(pFile); } - if( pTable->key.dptr ) free(pTable->key.dptr); - if( pTable->data.dptr ) free(pTable->data.dptr); - memset(pTable, 0, sizeof(*pTable)); - sqliteFree(pTable); + if( pCursr->key.dptr ) free(pCursr->key.dptr); + if( pCursr->data.dptr ) free(pCursr->data.dptr); + memset(pCursr, 0, sizeof(*pCursr)); + 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. */ -int sqliteDbbeFetch(DbbeTable *pTable, int nKey, char *pKey){ +int sqliteDbbeFetch(DbbeCursor *pCursr, int nKey, char *pKey){ datum key; key.dsize = nKey; key.dptr = pKey; - datumClear(&pTable->key); - datumClear(&pTable->data); - if( pTable->pFile && pTable->pFile->dbf ){ - pTable->data = gdbm_fetch(pTable->pFile->dbf, key); + datumClear(&pCursr->key); + datumClear(&pCursr->data); + if( pCursr->pFile && pCursr->pFile->dbf ){ + 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 ** if it is not. */ -int sqliteDbbeTest(DbbeTable *pTable, int nKey, char *pKey){ +int sqliteDbbeTest(DbbeCursor *pCursr, int nKey, char *pKey){ datum key; int result = 0; key.dsize = nKey; key.dptr = pKey; - if( pTable->pFile && pTable->pFile->dbf ){ - result = gdbm_exists(pTable->pFile->dbf, key); + if( pCursr->pFile && pCursr->pFile->dbf ){ + result = gdbm_exists(pCursr->pFile->dbf, key); } 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 ** 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; - if( offset>=pTable->key.dsize ) return 0; - if( offset+size>pTable->key.dsize ){ - n = pTable->key.dsize - offset; + if( offset>=pCursr->key.dsize ) return 0; + if( offset+size>pCursr->key.dsize ){ + n = pCursr->key.dsize - offset; }else{ n = size; } - memcpy(zBuf, &pTable->key.dptr[offset], n); + memcpy(zBuf, &pCursr->key.dptr[offset], 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; - if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ - pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); - pTable->readPending = 0; + if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ + pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); + pCursr->readPending = 0; } - if( offset>=pTable->data.dsize ) return 0; - if( offset+size>pTable->data.dsize ){ - n = pTable->data.dsize - offset; + if( offset>=pCursr->data.dsize ) return 0; + if( offset+size>pCursr->data.dsize ){ + n = pCursr->data.dsize - offset; }else{ n = size; } - memcpy(zBuf, &pTable->data.dptr[offset], n); + memcpy(zBuf, &pCursr->data.dptr[offset], 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 ** is ephemeral. */ -char *sqliteDbbeReadKey(DbbeTable *pTable, int offset){ - if( offset<0 || offset>=pTable->key.dsize ) return ""; - return &pTable->key.dptr[offset]; +char *sqliteDbbeReadKey(DbbeCursor *pCursr, int offset){ + if( offset<0 || offset>=pCursr->key.dsize ) return ""; + return &pCursr->key.dptr[offset]; } -char *sqliteDbbeReadData(DbbeTable *pTable, int offset){ - if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ - pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); - pTable->readPending = 0; +char *sqliteDbbeReadData(DbbeCursor *pCursr, int offset){ + if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ + pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); + pCursr->readPending = 0; } - if( offset<0 || offset>=pTable->data.dsize ) return ""; - return &pTable->data.dptr[offset]; + if( offset<0 || offset>=pCursr->data.dsize ) return ""; + return &pCursr->data.dptr[offset]; } /* ** Return the total number of bytes in either data or key. */ -int sqliteDbbeKeyLength(DbbeTable *pTable){ - return pTable->key.dsize; +int sqliteDbbeKeyLength(DbbeCursor *pCursr){ + return pCursr->key.dsize; } -int sqliteDbbeDataLength(DbbeTable *pTable){ - if( pTable->readPending && pTable->pFile && pTable->pFile->dbf ){ - pTable->data = gdbm_fetch(pTable->pFile->dbf, pTable->key); - pTable->readPending = 0; +int sqliteDbbeDataLength(DbbeCursor *pCursr){ + if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){ + pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key); + pCursr->readPending = 0; } - return pTable->data.dsize; + return pCursr->data.dsize; } /* ** Make is so that the next call to sqliteNextKey() finds the first ** key of the table. */ -int sqliteDbbeRewind(DbbeTable *pTable){ - pTable->needRewind = 1; +int sqliteDbbeRewind(DbbeCursor *pCursr){ + pCursr->needRewind = 1; return SQLITE_OK; } @@ -566,28 +573,28 @@ int sqliteDbbeRewind(DbbeTable *pTable){ ** Read the next key from the table. Return 1 on success. Return ** 0 if there are no more keys. */ -int sqliteDbbeNextKey(DbbeTable *pTable){ +int sqliteDbbeNextKey(DbbeCursor *pCursr){ datum nextkey; int rc; - if( pTable==0 || pTable->pFile==0 || pTable->pFile->dbf==0 ){ - pTable->readPending = 0; + if( pCursr==0 || pCursr->pFile==0 || pCursr->pFile->dbf==0 ){ + pCursr->readPending = 0; return 0; } - if( pTable->needRewind ){ - nextkey = gdbm_firstkey(pTable->pFile->dbf); - pTable->needRewind = 0; + if( pCursr->needRewind ){ + nextkey = gdbm_firstkey(pCursr->pFile->dbf); + pCursr->needRewind = 0; }else{ - nextkey = gdbm_nextkey(pTable->pFile->dbf, pTable->key); + nextkey = gdbm_nextkey(pCursr->pFile->dbf, pCursr->key); } - datumClear(&pTable->key); - datumClear(&pTable->data); - pTable->key = nextkey; - if( pTable->key.dptr ){ - pTable->readPending = 1; + datumClear(&pCursr->key); + datumClear(&pCursr->data); + pCursr->key = nextkey; + if( pCursr->key.dptr ){ + pCursr->readPending = 1; rc = 1; }else{ - pTable->needRewind = 1; - pTable->readPending = 0; + pCursr->needRewind = 1; + pCursr->readPending = 0; rc = 0; } return rc; @@ -596,15 +603,15 @@ int sqliteDbbeNextKey(DbbeTable *pTable){ /* ** Get a new integer key. */ -int sqliteDbbeNew(DbbeTable *pTable){ +int sqliteDbbeNew(DbbeCursor *pCursr){ int iKey; datum key; int go = 1; int i; struct rc4 *pRc4; - if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1; - pRc4 = &pTable->pBe->rc4; + if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1; + pRc4 = &pCursr->pBe->rc4; while( go ){ iKey = 0; for(i=0; i<4; i++){ @@ -612,7 +619,7 @@ int sqliteDbbeNew(DbbeTable *pTable){ } key.dptr = (char*)&iKey; key.dsize = 4; - go = gdbm_exists(pTable->pFile->dbf, key); + go = gdbm_exists(pCursr->pFile->dbf, key); } return iKey; } @@ -621,33 +628,33 @@ int sqliteDbbeNew(DbbeTable *pTable){ ** Write an entry into the table. Overwrite any prior entry with the ** 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; 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.dptr = pData; key.dsize = nKey; 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; - datumClear(&pTable->key); - datumClear(&pTable->data); + datumClear(&pCursr->key); + datumClear(&pCursr->data); return rc; } /* ** 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; int rc; - datumClear(&pTable->key); - datumClear(&pTable->data); - if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return SQLITE_ERROR; + datumClear(&pCursr->key); + datumClear(&pCursr->data); + if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR; key.dsize = nKey; key.dptr = pKey; - rc = gdbm_delete(pTable->pFile->dbf, key); + rc = gdbm_delete(pCursr->pFile->dbf, key); if( rc ) rc = SQLITE_ERROR; return rc; } diff --git a/src/dbbe.h b/src/dbbe.h index 0edab794a4..8ccb53f18f 100644 --- a/src/dbbe.h +++ b/src/dbbe.h @@ -28,7 +28,7 @@ ** This library was originally designed to support the following ** 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_ #define _SQLITE_DBBE_H_ @@ -37,7 +37,7 @@ /* ** The database backend supports two opaque structures. A Dbbe is ** 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 ** 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 ** 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 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 DbbeTable DbbeTable; +typedef struct DbbeCursor DbbeCursor; /* ** The 18 interface routines. @@ -64,13 +64,16 @@ Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr); /* Close the whole database. */ void sqliteDbbeClose(Dbbe*); -/* Open a particular table of a previously opened database. -** Create the table if it doesn't already exist and writeable!=0. +/* Open a cursor into particular file of a previously opened database. +** 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. */ -int sqliteDbbeOpenTable(Dbbe*, const char *zName, int writeable, DbbeTable **); +int sqliteDbbeOpenCursor(Dbbe*, const char *zName, int writeable, DbbeCursor**); /* Delete a table from the database */ 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 */ void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName); -/* Close a table */ -void sqliteDbbeCloseTable(DbbeTable*); +/* Close a cursor */ +void sqliteDbbeCloseCursor(DbbeCursor*); /* Fetch an entry from a table with the given key. Return 1 if ** 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 ** 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 ** bytes are read beginning with the offset-th byte. The return ** value is the actual number of bytes read. */ -int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf); -int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf); +int sqliteDbbeCopyKey(DbbeCursor*, 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, ** 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 ** that, you must make a copy. */ -char *sqliteDbbeReadKey(DbbeTable*, int offset); -char *sqliteDbbeReadData(DbbeTable*, int offset); +char *sqliteDbbeReadKey(DbbeCursor*, int offset); +char *sqliteDbbeReadData(DbbeCursor*, int offset); /* Return the length of the most recently fetched key or data. */ -int sqliteDbbeKeyLength(DbbeTable*); -int sqliteDbbeDataLength(DbbeTable*); +int sqliteDbbeKeyLength(DbbeCursor*); +int sqliteDbbeDataLength(DbbeCursor*); /* Retrieve the next entry in the table. The first key is retrieved ** the first time this routine is called, or after a call to ** sqliteDbbeRewind(). The return value is 1 if there is another ** 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 ** the first entry of the table. */ -int sqliteDbbeRewind(DbbeTable*); +int sqliteDbbeRewind(DbbeCursor*); /* 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 ** 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 */ -int sqliteDbbeDelete(DbbeTable*, int nKey, char *pKey); +int sqliteDbbeDelete(DbbeCursor*, int nKey, char *pKey); /* Open a file suitable for temporary storage */ int sqliteDbbeOpenTempFile(Dbbe*, FILE**); diff --git a/src/delete.c b/src/delete.c index e81272f735..f6822f9ab5 100644 --- a/src/delete.c +++ b/src/delete.c @@ -24,7 +24,7 @@ ** This file contains C code routines that are called by the parser ** 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" @@ -68,7 +68,7 @@ void sqliteDeleteFrom( } pTab = pTabList->a[0].pTab; - /* Resolve the field names in all the expressions. + /* Resolve the column names in all the expressions. */ if( pWhere ){ sqliteExprResolveInSelect(pParse, pWhere); @@ -117,10 +117,10 @@ void sqliteDeleteFrom( for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ int j; sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); - for(j=0; jnField; j++){ - sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0); + for(j=0; jnColumn; j++){ + 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); } } diff --git a/src/expr.c b/src/expr.c index 74873bc1e2..c94fd247a4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -24,7 +24,7 @@ ** This file contains routines used for analyzing expressions and ** 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" @@ -35,7 +35,7 @@ static int isConstant(Expr *p){ switch( p->op ){ case TK_ID: - case TK_FIELD: + case TK_COLUMN: case TK_DOT: return 0; default: { @@ -58,10 +58,10 @@ static int isConstant(Expr *p){ ** ** 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 ** 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 ** 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 -** table fields. 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 -** for such nodes is changed to TK_FIELD. The iTable value is changed +** table columns. Nodes of the form ID.ID or ID resolve into an +** index to the table in the table list and a column offset. The opcode +** 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 -** 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. ** ** 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 ** 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. */ 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 ){ cnt++; pExpr->iTable = i + pParse->nTab; - pExpr->iField = j; + pExpr->iColumn = j; } } } sqliteFree(z); if( cnt==0 ){ - sqliteSetNString(&pParse->zErrMsg, "no such field: ", -1, + sqliteSetNString(&pParse->zErrMsg, "no such column: ", -1, pExpr->token.z, pExpr->token.n, 0); pParse->nErr++; return 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); pParse->nErr++; return 1; } - pExpr->op = TK_FIELD; + pExpr->op = TK_COLUMN; break; } - /* A table name and field name: ID.ID */ + /* A table name and column name: ID.ID */ case TK_DOT: { int cnt = 0; /* Number of matches */ int i; /* Loop counter */ @@ -176,20 +176,20 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ cnt++; pExpr->iTable = i + pParse->nTab; - pExpr->iField = j; + pExpr->iColumn = j; } } } sqliteFree(zLeft); sqliteFree(zRight); if( cnt==0 ){ - sqliteSetNString(&pParse->zErrMsg, "no such field: ", -1, + sqliteSetNString(&pParse->zErrMsg, "no such column: ", -1, pLeft->token.z, pLeft->token.n, ".", 1, pRight->token.z, pRight->token.n, 0); pParse->nErr++; return 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, pRight->token.z, pRight->token.n, 0); pParse->nErr++; @@ -199,7 +199,7 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ pExpr->pLeft = 0; sqliteExprDelete(pRight); pExpr->pRight = 0; - pExpr->op = TK_FIELD; + pExpr->op = TK_COLUMN; break; } @@ -263,10 +263,10 @@ int sqliteExprResolveIds(Parse *pParse, IdList *pTabList, Expr *pExpr){ case TK_SELECT: { /* This has to be a scalar SELECT. Generate code to put the ** 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++; - if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iField) ){ + pExpr->iColumn = pParse->nMem++; + if( sqliteSelect(pParse, pExpr->pSelect, SRT_Mem, pExpr->iColumn) ){ return 1; } break; @@ -355,7 +355,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){ int too_few_args = 0; int is_agg = 0; int i; - pExpr->iField = id; + pExpr->iColumn = id; switch( id ){ case FN_Unknown: { no_such_func = 1; @@ -467,11 +467,11 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ default: break; } switch( pExpr->op ){ - case TK_FIELD: { + case TK_COLUMN: { if( pParse->useAgg ){ sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); }else{ - sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iField, 0, 0); + sqliteVdbeAddOp(v, OP_Field, pExpr->iTable, pExpr->iColumn, 0, 0); } break; } @@ -562,7 +562,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ } case TK_AGG_FUNCTION: { sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg, 0, 0); - if( pExpr->iField==FN_Avg ){ + if( pExpr->iColumn==FN_Avg ){ assert( pParse->iAggCount>=0 && pParse->iAggCountnAgg ); sqliteVdbeAddOp(v, OP_AggGet, 0, pParse->iAggCount, 0, 0); sqliteVdbeAddOp(v, OP_Divide, 0, 0, 0, 0); @@ -570,7 +570,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ break; } case TK_FUNCTION: { - int id = pExpr->iField; + int id = pExpr->iColumn; int op; int i; ExprList *pList = pExpr->pList; @@ -588,7 +588,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){ break; } case TK_SELECT: { - sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iField, 0, 0, 0); + sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0, 0, 0); break; } case TK_IN: { @@ -864,12 +864,12 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ if( pExpr==0 ) return 0; switch( pExpr->op ){ - case TK_FIELD: { + case TK_COLUMN: { aAgg = pParse->aAgg; for(i=0; inAgg; i++){ if( aAgg[i].isAgg ) continue; if( aAgg[i].pExpr->iTable==pExpr->iTable - && aAgg[i].pExpr->iField==pExpr->iField ){ + && aAgg[i].pExpr->iColumn==pExpr->iColumn ){ break; } } @@ -883,7 +883,7 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ break; } 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 ){ i = pParse->iAggCount; }else{ @@ -893,7 +893,7 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){ pParse->aAgg[i].pExpr = 0; pParse->iAggCount = i; } - if( pExpr->iField==FN_Count ){ + if( pExpr->iColumn==FN_Count ){ pExpr->iAgg = i; break; } diff --git a/src/insert.c b/src/insert.c index a40ea91c1c..a044bc1448 100644 --- a/src/insert.c +++ b/src/insert.c @@ -24,7 +24,7 @@ ** This file contains C code routines that are called by the parser ** 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" @@ -36,7 +36,7 @@ ** ** The IDLIST following the table name is always optional. If omitted, ** 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 ** 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 */ ExprList *pList, /* List of values to be inserted */ 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 */ 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 */ Index *pIdx; /* For looping over indices of the table */ 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 iCont, iBreak; /* Beginning and end of the loop over srcTab */ @@ -96,20 +96,20 @@ void sqliteInsert( rc = sqliteSelect(pParse, pSelect, SRT_Table, srcTab); if( rc ) goto insert_cleanup; assert( pSelect->pEList ); - nField = pSelect->pEList->nExpr; + nColumn = pSelect->pEList->nExpr; }else{ srcTab = -1; assert( pList ); - nField = pList->nExpr; + nColumn = pList->nExpr; } /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ - if( pField==0 && nField!=pTab->nCol ){ + if( pColumn==0 && nColumn!=pTab->nCol ){ char zNum1[30]; char zNum2[30]; - sprintf(zNum1,"%d", nField); + sprintf(zNum1,"%d", nColumn); sprintf(zNum2,"%d", pTab->nCol); sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, " has ", zNum2, " columns but ", @@ -117,11 +117,11 @@ void sqliteInsert( pParse->nErr++; goto insert_cleanup; } - if( pField!=0 && nField!=pField->nId ){ + if( pColumn!=0 && nColumn!=pColumn->nId ){ char zNum1[30]; char zNum2[30]; - sprintf(zNum1,"%d", nField); - sprintf(zNum2,"%d", pField->nId); + sprintf(zNum1,"%d", nColumn); + sprintf(zNum2,"%d", pColumn->nId); sqliteSetString(&pParse->zErrMsg, zNum1, " values for ", zNum2, " columns", 0); pParse->nErr++; @@ -132,20 +132,20 @@ void sqliteInsert( ** all elements of the IDLIST really are columns of the table and ** remember the column indices. */ - if( pField ){ - for(i=0; inId; i++){ - pField->a[i].idx = -1; + if( pColumn ){ + for(i=0; inId; i++){ + pColumn->a[i].idx = -1; } - for(i=0; inId; i++){ + for(i=0; inId; i++){ for(j=0; jnCol; j++){ - if( sqliteStrICmp(pField->a[i].zName, pTab->aCol[j].zName)==0 ){ - pField->a[i].idx = j; + if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ + pColumn->a[i].idx = j; break; } } if( j>=pTab->nCol ){ 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++; goto insert_cleanup; } @@ -179,14 +179,14 @@ void sqliteInsert( sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } for(i=0; inCol; i++){ - if( pField==0 ){ + if( pColumn==0 ){ j = i; }else{ - for(j=0; jnId; j++){ - if( pField->a[j].idx==i ) break; + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==i ) break; } } - if( pField && j>=pField->nId ){ + if( pColumn && j>=pColumn->nId ){ char *zDflt = pTab->aCol[i].zDflt; if( zDflt==0 ){ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); @@ -209,16 +209,16 @@ void sqliteInsert( if( pIdx->pNext ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); } - for(i=0; inField; i++){ - int idx = pIdx->aiField[i]; - if( pField==0 ){ + for(i=0; inColumn; i++){ + int idx = pIdx->aiColumn[i]; + if( pColumn==0 ){ j = idx; }else{ - for(j=0; jnId; j++){ - if( pField->a[j].idx==idx ) break; + for(j=0; jnId; j++){ + if( pColumn->a[j].idx==idx ) break; } } - if( pField && j>=pField->nId ){ + if( pColumn && j>=pColumn->nId ){ char *zDflt = pTab->aCol[idx].zDflt; if( zDflt==0 ){ sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0); @@ -231,7 +231,7 @@ void sqliteInsert( 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); } @@ -245,5 +245,5 @@ void sqliteInsert( insert_cleanup: if( pList ) sqliteExprListDelete(pList); if( pSelect ) sqliteSelectDelete(pSelect); - sqliteIdListDelete(pField); + sqliteIdListDelete(pColumn); } diff --git a/src/main.c b/src/main.c index 3c81beca33..06423b5453 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ ** other files are for internal use by SQLite and should not be ** 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" @@ -90,12 +90,12 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){ ** ); ** ** The sqlite_master table contains a single entry for each table - ** and each index. The "type" field tells whether the entry is - ** a table or index. The "name" field is the name of the object. + ** and each index. The "type" column tells whether the entry is + ** 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 field is always the same as name. For indices, the - ** tbl_name field contains the name of the table that the index - ** indexes. Finally, the sql field contains the complete text of + ** the tbl_name column is always the same as name. For indices, the + ** tbl_name column contains the name of the table that the index + ** indexes. Finally, the "sql" column contains the complete text of ** the CREATE TABLE or CREATE INDEX statement that originally created ** the table or index. ** diff --git a/src/parse.y b/src/parse.y index 862e1d6309..f59b662b64 100644 --- a/src/parse.y +++ b/src/parse.y @@ -26,7 +26,7 @@ ** the parser. Lemon will also generate a header file containing ** 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_type {Token} @@ -50,7 +50,7 @@ input ::= cmdlist. // add them to the parse.h output file. // 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 // @@ -250,9 +250,9 @@ setlist(A) ::= id(X) EQ expr(Y) COMMA setlist(Z). {A = sqliteExprListAppend(Z,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);} -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);} @@ -278,15 +278,15 @@ item(A) ::= MINUS FLOAT(X). { item(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);} item(A) ::= NULL. {A = sqliteExpr(TK_NULL, 0, 0, 0);} -%type fieldlist_opt {IdList*} -%destructor fieldlist_opt {sqliteIdListDelete($$);} -%type fieldlist {IdList*} -%destructor fieldlist {sqliteIdListDelete($$);} +%type inscollist_opt {IdList*} +%destructor inscollist_opt {sqliteIdListDelete($$);} +%type inscollist {IdList*} +%destructor inscollist {sqliteIdListDelete($$);} -fieldlist_opt(A) ::= . {A = 0;} -fieldlist_opt(A) ::= LP fieldlist(X) RP. {A = X;} -fieldlist(A) ::= fieldlist(X) COMMA id(Y). {A = sqliteIdListAppend(X,&Y);} -fieldlist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);} +inscollist_opt(A) ::= . {A = 0;} +inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;} +inscollist(A) ::= inscollist(X) COMMA id(Y). {A = sqliteIdListAppend(X,&Y);} +inscollist(A) ::= id(Y). {A = sqliteIdListAppend(0,&Y);} %left OR. %left AND. diff --git a/src/select.c b/src/select.c index e39e415a4c..d9d21c76a3 100644 --- a/src/select.c +++ b/src/select.c @@ -24,7 +24,7 @@ ** This file contains C code routines that are called by the parser ** 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" @@ -86,14 +86,14 @@ void sqliteParseInfoReset(Parse *pParse){ ** of a SELECT. ** ** 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. */ static int selectInnerLoop( Parse *pParse, /* The parser context */ ExprList *pEList, /* List of values being extracted */ 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 */ int distinct, /* If >=0, make sure results are distinct */ int eDest, /* How to dispose of the results */ @@ -104,15 +104,15 @@ static int selectInnerLoop( Vdbe *v = pParse->pVdbe; int i; - /* Pull the requested fields. + /* Pull the requested columns. */ if( pEList ){ for(i=0; inExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } - nField = pEList->nExpr; + nColumn = pEList->nExpr; }else{ - for(i=0; inExpr + 1 ); if( zSortOrder==0 ) return 1; for(i=0; inExpr; i++){ @@ -152,7 +152,7 @@ static int selectInnerLoop( ** table iParm. */ 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_Put, iParm, 0, 0, 0); }else @@ -160,7 +160,7 @@ static int selectInnerLoop( /* Store the result as data using a unique key. */ 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_Pull, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); @@ -171,7 +171,7 @@ static int selectInnerLoop( ** the temporary table iParm. */ 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); }else @@ -180,7 +180,7 @@ static int selectInnerLoop( ** item into the set table with bogus data. */ if( eDest==SRT_Set ){ - assert( nField==1 ); + assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0); sqliteVdbeAddOp(v, OP_Put, iParm, 0, 0, 0); }else @@ -191,7 +191,7 @@ static int selectInnerLoop( ** of the scan loop. */ if( eDest==SRT_Mem ){ - assert( nField==1 ); + assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iBreak, 0, 0); }else @@ -199,7 +199,7 @@ static int selectInnerLoop( /* 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; } @@ -210,12 +210,12 @@ static int selectInnerLoop( ** we need to run the sorter and output the results. The following ** 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 addr; sqliteVdbeAddOp(v, OP_Sort, 0, 0, 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_SortClose, 0, 0, 0, end); } @@ -240,7 +240,7 @@ void generateColumnNames(Parse *pParse, IdList *pTabList, ExprList *pEList){ continue; } p = pEList->a[i].pExpr; - if( p->op!=TK_FIELD || pTabList==0 ){ + if( p->op!=TK_COLUMN || pTabList==0 ){ char zName[30]; sprintf(zName, "column%d", i+1); 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; 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); sqliteFree(zName); }else{ 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); } } @@ -281,8 +281,8 @@ static const char *selectOpName(int id){ /* ** For the given SELECT statement, do two things. ** -** (1) Fill in the pTab fields of the IdList that defines the set -** of tables we are scanning. +** (1) Fill in the pTabList->a[].pTab fields in the IdList that +** defines the set of tables that should be scanned. ** ** (2) If the columns to be extracted variable (pEList) is NULL ** (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 ** 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 ** value of the top-level node is filled with iTable parameter. ** @@ -390,8 +390,8 @@ static int matchOrderbyToColumn( match = 1; } if( match ){ - pE->op = TK_FIELD; - pE->iField = j; + pE->op = TK_COLUMN; + pE->iColumn = j; pE->iTable = iTable; pOrderBy->a[i].done = 1; break; @@ -630,7 +630,7 @@ int sqliteSelect( WhereInfo *pWInfo; Vdbe *v; 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 */ Expr *pWhere; /* The WHERE 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 ** 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) ){ return 1; @@ -724,7 +724,7 @@ int sqliteSelect( ** need to handle subquerys and temporary tables. From here on we ** 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; inExpr; i++){ if( sqliteExprResolveIds(pParse, pTabList, pEList->a[i].pExpr) ){ @@ -906,7 +906,7 @@ int sqliteSelect( assert( pE->pList!=0 && pE->pList->nExpr==1 ); sqliteExprCode(pParse, pE->pList->a[0].pExpr); sqliteVdbeAddOp(v, OP_AggGet, 0, i, 0, 0); - switch( pE->iField ){ + switch( pE->iColumn ){ case FN_Min: op = OP_Min; break; case FN_Max: op = OP_Max; break; case FN_Avg: op = OP_Add; break; diff --git a/src/shell.c b/src/shell.c index e3bf5e9645..b34557dd3b 100644 --- a/src/shell.c +++ b/src/shell.c @@ -24,7 +24,7 @@ ** This file contains code to implement the "sqlite" command line ** 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 #include @@ -136,7 +136,7 @@ struct callback_data { /* ** 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_List 2 /* One record per line with a separator */ #define MODE_Html 3 /* Generate an XHTML table */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d4069eac86..9eef275306 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -23,7 +23,7 @@ ************************************************************************* ** 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 "dbbe.h" @@ -35,7 +35,20 @@ #include #include -/* #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 # define sqliteMalloc(X) sqliteMalloc_(X,__FILE__,__LINE__) # define sqliteFree(X) sqliteFree_(X,__FILE__,__LINE__) @@ -58,8 +71,8 @@ int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */ #endif /* -** The number of entries in the in-memory hash table holding the -** schema. +** The number of entries in the in-memory hash array holding the +** database schema. */ #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])) /* -** Integer identifiers for functions. +** Integer identifiers for built-in SQL functions. */ #define FN_Unknown 0 #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_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. */ struct Column { - char *zName; /* Name of this column */ - char *zDflt; /* Default value of this column */ - int notNull; /* True if there is a NOT NULL constraing */ + char *zName; /* Name of this column */ + char *zDflt; /* Default value of this column */ + int notNull; /* True if there is a NOT NULL constraint */ }; /* -** Each table is represented in memory by -** an instance of the following structure +** Each SQL table is represented in memory by +** an instance of the following structure. */ struct Table { - char *zName; /* Name of the table */ - Table *pHash; /* Next table with same hash on zName */ - int nCol; /* Number of columns in this table */ - Column *aCol; /* Information about each column */ - int readOnly; /* True if this table should not be written by the user */ - Index *pIndex; /* List of indices on this table. */ + char *zName; /* Name of the table */ + Table *pHash; /* Next table with same hash on zName */ + int nCol; /* Number of columns in this table */ + Column *aCol; /* Information about each column */ + int readOnly; /* True if this table should not be written by the user */ + 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. +** +** 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 { - char *zName; /* Name of this index */ - Index *pHash; /* Next index with the same hash on zName */ - int nField; /* Number of fields in the table indexed by this index */ - int *aiField; /* Indices of fields used by this index. 1st is 0 */ - Table *pTable; /* The table being indexed */ - int isUnique; /* True if keys must all be unique */ - Index *pNext; /* The next index associated with the same table */ + char *zName; /* Name of this index */ + Index *pHash; /* Next index with the same hash on zName */ + int nColumn; /* Number of columns in the table used by this index */ + int *aiColumn; /* Which columns are used by this index. 1st is 0 */ + Table *pTable; /* The SQL table being indexed */ + int isUnique; /* True if keys must all be unique */ + Index *pNext; /* The next index associated with the same table */ }; /* @@ -174,11 +202,11 @@ struct Expr { Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as a function argument */ Token token; /* An operand token */ - int iTable, iField; /* When op==TK_FIELD, then this node means the - ** iField-th field of the iTable-th table. When - ** op==TK_FUNCTION, iField holds the function id */ - int iAgg; /* When op==TK_FIELD and pParse->useAgg==TRUE, pull - ** value from these element of the aggregator */ + int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the + ** iColumn-th field of the iTable-th table. When + ** op==TK_FUNCTION, iColumn holds the function id */ + int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull + ** result from the iAgg-th element of the aggregator */ Select *pSelect; /* When the expression is a sub-select */ }; @@ -209,8 +237,8 @@ struct IdList { struct { char *zName; /* Text of the identifier. */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ - Table *pTab; /* Table corresponding to zName */ - int idx; /* Index of a field named zName in a table */ + Table *pTab; /* An SQL table corresponding to zName */ + int idx; /* Index in some Table.aCol[] of a column named zName */ } *a; /* One entry for each identifier on the list */ }; @@ -243,7 +271,7 @@ struct Select { Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ 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 */ }; /* diff --git a/src/update.c b/src/update.c index 982d125893..6902a94e3c 100644 --- a/src/update.c +++ b/src/update.c @@ -24,7 +24,7 @@ ** This file contains C code routines that are called by the parser ** 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" @@ -48,8 +48,8 @@ void sqliteUpdate( int base; /* Index of first available table cursor */ Index **apIdx = 0; /* An array of indices that need updating too */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the - ** an expression for the i-th field of the table. - ** aXRef[i]==-1 if the i-th field is not changed. */ + ** an expression for the i-th column of the table. + ** aXRef[i]==-1 if the i-th column is not changed. */ /* Locate the table which we want to update. This table has to be ** put in an IdList structure because some of the subroutines we @@ -77,9 +77,9 @@ void sqliteUpdate( if( aXRef==0 ) goto update_cleanup; for(i=0; inCol; i++) aXRef[i] = -1; - /* Resolve the field names in all the expressions in both the - ** WHERE clause and in the new values. Also find the field index - ** for each field to be updated in the pChanges array. + /* Resolve the column names in all the expressions in both the + ** WHERE clause and in the new values. Also find the column index + ** for each column to be updated in the pChanges array. */ if( pWhere ){ sqliteExprResolveInSelect(pParse, pWhere); @@ -109,7 +109,7 @@ void sqliteUpdate( } } if( j>=pTab->nCol ){ - sqliteSetString(&pParse->zErrMsg, "no such field: ", + sqliteSetString(&pParse->zErrMsg, "no such column: ", pChanges->a[i].zName, 0); pParse->nErr++; goto update_cleanup; @@ -118,21 +118,21 @@ void sqliteUpdate( /* Allocate memory for the array apIdx[] and fill it pointers to every ** 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(i=0; inField; i++){ - if( aXRef[pIdx->aiField[i]]>=0 ) break; + for(i=0; inColumn; i++){ + if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } - if( inField ) nIdx++; + if( inColumn ) nIdx++; } apIdx = sqliteMalloc( sizeof(Index*) * nIdx ); if( apIdx==0 ) goto update_cleanup; for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - for(i=0; inField; i++){ - if( aXRef[pIdx->aiField[i]]>=0 ) break; + for(i=0; inColumn; i++){ + if( aXRef[pIdx->aiColumn[i]]>=0 ) break; } - if( inField ) apIdx[nIdx++] = pIdx; + if( inColumn ) apIdx[nIdx++] = pIdx; } /* Begin generating code. @@ -165,7 +165,7 @@ void sqliteUpdate( } /* 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. ** Also, the old data is needed to delete the old index entires. */ @@ -179,10 +179,10 @@ void sqliteUpdate( for(i=0; inField; j++){ - sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiField[j], 0, 0); + for(j=0; jnColumn; j++){ + 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); } @@ -202,10 +202,10 @@ void sqliteUpdate( for(i=0; inCol, 0, 0, 0); /* The KEY */ pIdx = apIdx[i]; - for(j=0; jnField; j++){ - sqliteVdbeAddOp(v, OP_Dup, j+pTab->nCol-pIdx->aiField[j], 0, 0, 0); + for(j=0; jnColumn; j++){ + 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); } diff --git a/src/util.c b/src/util.c index 5d53beb98d..0d96bcdd5d 100644 --- a/src/util.c +++ b/src/util.c @@ -26,7 +26,7 @@ ** This file contains functions for allocating memory, comparing ** 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 @@ -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. */ int sqliteStrICmp(const char *zLeft, const char *zRight){ diff --git a/src/vdbe.c b/src/vdbe.c index 6dc03010cc..eb2b821e6b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -41,7 +41,7 @@ ** But other routines are also provided to help in building up ** 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 @@ -54,15 +54,21 @@ 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. */ -struct VdbeTable { - DbbeTable *pTable; /* The table structure of the backend */ +struct Cursor { + DbbeCursor *pCursor; /* The cursor structure of the backend */ int index; /* The next index to extract */ 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 @@ -117,7 +123,7 @@ typedef struct Mem Mem; #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 ** a key and one or more values. The values are used in processing ** aggregate functions in a SELECT. The key is used to implement @@ -130,7 +136,7 @@ struct Agg { AggElem *pCurrent; /* The AggElem currently in focus */ int nElem; /* The number of AggElems */ 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 */ }; struct AggElem { @@ -150,7 +156,7 @@ typedef struct Set Set; typedef struct SetElem SetElem; struct 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 { SetElem *pHash; /* Next element with the same hash on zKey */ @@ -175,8 +181,8 @@ struct Vdbe { Stack *aStack; /* The operand stack, except string values */ char **zStack; /* Text or binary values of the stack */ char **azColName; /* Becomes the 4th parameter to callbacks */ - int nTable; /* Number of slots in aTab[] */ - VdbeTable *aTab; /* On element of this array for each open table */ + int nCursor; /* Number of slots in aCsr[] */ + Cursor *aCsr; /* On element of this array for each open cursor */ int nList; /* Number of slots in apList[] */ FILE **apList; /* An open file for each list */ 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){ 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){ int size; @@ -634,7 +640,7 @@ static int hardNeedStack(Vdbe *p, int N){ /* ** 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. */ static void Cleanup(Vdbe *p){ @@ -642,15 +648,15 @@ static void Cleanup(Vdbe *p){ PopStack(p, p->tos+1); sqliteFree(p->azColName); p->azColName = 0; - for(i=0; inTable; i++){ - if( p->aTab[i].pTable ){ - sqliteDbbeCloseTable(p->aTab[i].pTable); - p->aTab[i].pTable = 0; + for(i=0; inCursor; i++){ + if( p->aCsr[i].pCursor ){ + sqliteDbbeCloseCursor(p->aCsr[i].pCursor); + p->aCsr[i].pCursor = 0; } } - sqliteFree(p->aTab); - p->aTab = 0; - p->nTable = 0; + sqliteFree(p->aCsr); + p->aCsr = 0; + p->nCursor = 0; for(i=0; inMem; i++){ if( p->aMem[i].s.flags & STK_Dyn ){ sqliteFree(p->aMem[i].z); @@ -786,7 +792,7 @@ int sqliteVdbeList( char **pzErrMsg /* Error msg written here */ ){ int i, rc; - char *azField[6]; + char *azValue[6]; char zAddr[20]; char zP1[20]; char zP2[20]; @@ -795,19 +801,19 @@ int sqliteVdbeList( }; if( xCallback==0 ) return 0; - azField[0] = zAddr; - azField[2] = zP1; - azField[3] = zP2; - azField[5] = 0; + azValue[0] = zAddr; + azValue[2] = zP1; + azValue[3] = zP2; + azValue[5] = 0; rc = SQLITE_OK; /* if( pzErrMsg ){ *pzErrMsg = 0; } */ for(i=0; rc==SQLITE_OK && inOp; i++){ sprintf(zAddr,"%d",i); sprintf(zP1,"%d", p->aOp[i].p1); sprintf(zP2,"%d", p->aOp[i].p2); - azField[4] = p->aOp[i].p3; - azField[1] = zOpName[p->aOp[i].opcode]; - if( xCallback(pArg, 5, azField, azColumnNames) ){ + azValue[4] = p->aOp[i].p3; + azValue[1] = zOpName[p->aOp[i].opcode]; + if( xCallback(pArg, 5, azValue, azColumnNames) ){ rc = SQLITE_ABORT; } } @@ -1492,7 +1498,7 @@ int sqliteVdbeExec( /* 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. */ case OP_Not: { @@ -1676,33 +1682,34 @@ int sqliteVdbeExec( /* Opcode: Open P1 P2 P3 ** - ** Open a new cursor for the database table named P3. Give the - ** cursor an identifier P1. - ** 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 + ** Open a new cursor for the database file named P3. Give the + ** cursor an identifier P1. The P1 values need not be ** contiguous but all P1 values should be small integers. It is ** an error for P1 to be negative. ** - ** If P3 is null or an empty string, a temporary table created. - ** This table is automatically deleted when the cursor is closed. + ** Open readonly if P2==0 and for reading and writing if P2!=0. + ** 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: { int i = pOp->p1; if( i<0 ) goto bad_instruction; - if( i>=p->nTable ){ + if( i>=p->nCursor ){ int j; - p->aTab = sqliteRealloc( p->aTab, (i+1)*sizeof(VdbeTable) ); - if( p->aTab==0 ){ p->nTable = 0; goto no_mem; } - for(j=p->nTable; j<=i; j++) p->aTab[j].pTable = 0; - p->nTable = i+1; - }else if( p->aTab[i].pTable ){ - sqliteDbbeCloseTable(p->aTab[i].pTable); + p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) ); + if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; } + for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0; + p->nCursor = i+1; + }else if( p->aCsr[i].pCursor ){ + 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 ){ case SQLITE_BUSY: { sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0); @@ -1722,21 +1729,21 @@ int sqliteVdbeExec( goto no_mem; } } - p->aTab[i].index = 0; - p->aTab[i].keyAsData = 0; + p->aCsr[i].index = 0; + p->aCsr[i].keyAsData = 0; break; } /* 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. */ case OP_Close: { int i = pOp->p1; - if( i>=0 && inTable && p->aTab[i].pTable ){ - sqliteDbbeCloseTable(p->aTab[i].pTable); - p->aTab[i].pTable = 0; + if( i>=0 && inCursor && p->aCsr[i].pCursor ){ + sqliteDbbeCloseCursor(p->aCsr[i].pCursor); + p->aCsr[i].pCursor = 0; } break; } @@ -1744,21 +1751,20 @@ int sqliteVdbeExec( /* Opcode: Fetch P1 * * ** ** 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 - ** in the P1 cursor until needed. The data is not pushed onto the - ** stack. + ** a record from cursor P1. The key/data pair is held + ** in the P1 cursor until needed. */ case OP_Fetch: { int i = pOp->p1; int tos = p->tos; if( tos<0 ) goto not_enough_stack; - if( i>=0 && inTable && p->aTab[i].pTable ){ + if( i>=0 && inCursor && p->aCsr[i].pCursor ){ 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); }else{ 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->nFetch++; @@ -1787,7 +1793,7 @@ int sqliteVdbeExec( /* Opcode: Distinct P1 P2 * ** ** 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. ** The key is not popped from the stack. ** @@ -1797,14 +1803,14 @@ int sqliteVdbeExec( /* Opcode: Found P1 P2 * ** ** 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. ** The key is popped from the stack. */ /* Opcode: NotFound P1 P2 * ** ** 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. ** The key is popped from the stack. ** @@ -1818,13 +1824,13 @@ int sqliteVdbeExec( int tos = p->tos; int alreadyExists = 0; if( tos<0 ) goto not_enough_stack; - if( i>=0 && inTable && p->aTab[i].pTable ){ + if( i>=0 && inCursor && p->aCsr[i].pCursor ){ 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); }else{ 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]); } } @@ -1841,16 +1847,16 @@ int sqliteVdbeExec( /* Opcode: New P1 * * ** - ** Get a new integer key not previous used by table P1 and - ** push it onto the stack. + ** Get a new integer key not previous used by the database file + ** associated with cursor P1 and push it onto the stack. */ case OP_New: { int i = pOp->p1; 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; }else{ - v = sqliteDbbeNew(p->aTab[i].pTable); + v = sqliteDbbeNew(p->aCsr[i].pCursor); } NeedStack(p, p->tos+1); p->tos++; @@ -1861,7 +1867,7 @@ int sqliteVdbeExec( /* 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 ** 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 @@ -1872,7 +1878,7 @@ int sqliteVdbeExec( int nos = p->tos-1; int i = pOp->p1; if( nos<0 ) goto not_enough_stack; - if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ + if( i>=0 && inCursor && p->aCsr[i].pCursor!=0 ){ char *zKey; int nKey; if( (p->aStack[nos].flags & STK_Int)==0 ){ @@ -1883,7 +1889,7 @@ int sqliteVdbeExec( nKey = sizeof(int); 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]); } PopStack(p, 2); @@ -1893,13 +1899,13 @@ int sqliteVdbeExec( /* Opcode: Delete P1 * * ** ** 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: { int tos = p->tos; int i = pOp->p1; if( tos<0 ) goto not_enough_stack; - if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ + if( i>=0 && inCursor && p->aCsr[i].pCursor!=0 ){ char *zKey; int nKey; if( p->aStack[tos].flags & STK_Int ){ @@ -1910,7 +1916,7 @@ int sqliteVdbeExec( nKey = p->aStack[tos].n; zKey = p->zStack[tos]; } - sqliteDbbeDelete(p->aTab[i].pTable, nKey, zKey); + sqliteDbbeDelete(p->aCsr[i].pCursor, nKey, zKey); } PopStack(p, 1); break; @@ -1925,16 +1931,18 @@ int sqliteVdbeExec( */ case OP_KeyAsData: { int i = pOp->p1; - if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ - p->aTab[i].keyAsData = pOp->p2; + if( i>=0 && inCursor && p->aCsr[i].pCursor!=0 ){ + p->aCsr[i].keyAsData = pOp->p2; } break; } /* Opcode: Field P1 P2 * ** - ** Push onto the stack the value of the P2-th field from the - ** most recent Fetch from table P1. + ** Interpret the data in the most recent fetch from cursor 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 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, ** then the field might be extracted from the key rather than the ** 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: { int *pAddr; @@ -1951,35 +1964,35 @@ int sqliteVdbeExec( int i = pOp->p1; int p2 = pOp->p2; int tos = ++p->tos; - DbbeTable *pTab; + DbbeCursor *pCrsr; char *z; if( NeedStack(p, tos) ) goto no_mem; - if( i>=0 && inTable && (pTab = p->aTab[i].pTable)!=0 ){ - if( p->aTab[i].keyAsData ){ - amt = sqliteDbbeKeyLength(pTab); + if( i>=0 && inCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){ + if( p->aCsr[i].keyAsData ){ + amt = sqliteDbbeKeyLength(pCrsr); if( amt<=sizeof(int)*(p2+1) ){ p->aStack[tos].flags = STK_Null; break; } - pAddr = (int*)sqliteDbbeReadKey(pTab, sizeof(int)*p2); + pAddr = (int*)sqliteDbbeReadKey(pCrsr, sizeof(int)*p2); if( *pAddr==0 ){ p->aStack[tos].flags = STK_Null; break; } - z = sqliteDbbeReadKey(pTab, *pAddr); + z = sqliteDbbeReadKey(pCrsr, *pAddr); }else{ - amt = sqliteDbbeDataLength(pTab); + amt = sqliteDbbeDataLength(pCrsr); if( amt<=sizeof(int)*(p2+1) ){ p->aStack[tos].flags = STK_Null; break; } - pAddr = (int*)sqliteDbbeReadData(pTab, sizeof(int)*p2); + pAddr = (int*)sqliteDbbeReadData(pCrsr, sizeof(int)*p2); if( *pAddr==0 ){ p->aStack[tos].flags = STK_Null; break; } - z = sqliteDbbeReadData(pTab, *pAddr); + z = sqliteDbbeReadData(pCrsr, *pAddr); } p->zStack[tos] = z; p->aStack[tos].n = strlen(z) + 1; @@ -1991,21 +2004,22 @@ int sqliteVdbeExec( /* Opcode: Key P1 * * ** ** 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. - ** A sequential scan is started using the Next opcode. + ** the key to the current entry in a sequential scan of the database + ** file P1. The sequential scan should have been started using the + ** Next opcode. */ case OP_Key: { int i = pOp->p1; int tos = ++p->tos; - DbbeTable *pTab; + DbbeCursor *pCrsr; if( NeedStack(p, p->tos) ) goto no_mem; - if( i>=0 && inTable && (pTab = p->aTab[i].pTable)!=0 ){ - char *z = sqliteDbbeReadKey(pTab, 0); - if( p->aTab[i].keyAsData ){ + if( i>=0 && inCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){ + char *z = sqliteDbbeReadKey(pCrsr, 0); + if( p->aCsr[i].keyAsData ){ p->zStack[tos] = z; p->aStack[tos].flags = STK_Str; - p->aStack[tos].n = sqliteDbbeKeyLength(pTab); + p->aStack[tos].n = sqliteDbbeKeyLength(pCrsr); }else{ memcpy(&p->aStack[tos].i, z, sizeof(int)); p->aStack[tos].flags = STK_Int; @@ -2017,25 +2031,25 @@ int sqliteVdbeExec( /* Opcode: Rewind 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: { int i = pOp->p1; - if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ - sqliteDbbeRewind(p->aTab[i].pTable); + if( i>=0 && inCursor && p->aCsr[i].pCursor!=0 ){ + sqliteDbbeRewind(p->aCsr[i].pCursor); } break; } /* Opcode: Next P1 P2 * ** - ** Advance P1 to the next entry in the table. Or, if there are no - ** more entries, rewind P1 and jump to location P2. + ** Advance P1 to the next key/data pair in the file. Or, if there are no + ** more key/data pairs, rewind P1 and jump to location P2. */ case OP_Next: { int i = pOp->p1; - if( i>=0 && inTable && p->aTab[i].pTable!=0 ){ - if( sqliteDbbeNextKey(p->aTab[i].pTable)==0 ){ + if( i>=0 && inCursor && p->aCsr[i].pCursor!=0 ){ + if( sqliteDbbeNextKey(p->aCsr[i].pCursor)==0 ){ pc = pOp->p2 - 1; }else{ p->nFetch++; @@ -2046,37 +2060,48 @@ int sqliteVdbeExec( /* Opcode: ResetIdx P1 * * ** - ** Begin treating the current row of table P1 as an index. The next - ** NextIdx instruction will refer to the first index in the table. + ** Begin treating the current data in cursor P1 as a bunch of integer + ** 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: { int i = pOp->p1; - if( i>=0 && inTable ){ - p->aTab[i].index = 0; + if( i>=0 && inCursor ){ + p->aCsr[i].index = 0; } break; } /* Opcode: NextIdx P1 P2 * ** - ** Push the next index from the current entry of table P1 onto the - ** stack and advance the pointer. If there are no more indices, then - ** reset the table entry and jump to P2 + ** The P1 cursor points to an SQL index. The data from the most + ** recent fetch on that cursor consists of a bunch of integers where + ** 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: { int i = pOp->p1; int tos = ++p->tos; - DbbeTable *pTab; + DbbeCursor *pCrsr; if( NeedStack(p, p->tos) ) goto no_mem; p->zStack[tos] = 0; - if( i>=0 && inTable && (pTab = p->aTab[i].pTable)!=0 ){ + if( i>=0 && inCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){ int *aIdx; int nIdx; int j; - nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); - aIdx = (int*)sqliteDbbeReadData(pTab, 0); - for(j=p->aTab[i].index; jaCsr[i].index; jaStack[tos].i = aIdx[j]; p->aStack[tos].flags = STK_Int; @@ -2088,47 +2113,47 @@ int sqliteVdbeExec( pc = pOp->p2 - 1; PopStack(p, 1); } - p->aTab[i].index = j+1; + p->aCsr[i].index = j+1; } break; } /* Opcode: PutIdx P1 * * ** - ** The top of the stack hold an index key (probably made using the - ** MakeKey instruction) and next on stack holds an index value for - ** a table. Locate the record in the index P1 that has the key - ** and insert the index value into its - ** data. Write the results back to the index. - ** If the key doesn't exist it is created. + ** The top of the stack hold an SQL index key (probably made using the + ** MakeKey instruction) and next on stack holds an integer which + ** the key to an SQL table entry. Locate the record in cursor P1 + ** that has the same key as on the TOS. Create a new record if + ** necessary. Then append the integer table key to the data for that + ** record and write it back to the P1 file. */ case OP_PutIdx: { int i = pOp->p1; int tos = p->tos; int nos = tos - 1; - DbbeTable *pTab; + DbbeCursor *pCrsr; if( nos<0 ) goto not_enough_stack; - if( i>=0 && inTable && (pTab = p->aTab[i].pTable)!=0 ){ + if( i>=0 && inCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){ int r; int newVal; Integerify(p, nos); newVal = p->aStack[nos].i; 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 ){ /* 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); }else{ /* Extend the existing record */ int nIdx; int *aIdx; - nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); + nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int); aIdx = sqliteMalloc( sizeof(int)*(nIdx+1) ); 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; - sqliteDbbePut(pTab, p->aStack[tos].n, p->zStack[tos], + sqliteDbbePut(pCrsr, p->aStack[tos].n, p->zStack[tos], sizeof(int)*(nIdx+1), (char*)aIdx); sqliteFree(aIdx); } @@ -2139,20 +2164,24 @@ int sqliteVdbeExec( /* Opcode: DeleteIdx P1 * * ** - ** The top of the stack is a key and next on stack is an index value. - ** Locate the record - ** in index P1 that has the key and remove the index value from its - ** data. Write the results back to the table. If after removing - ** the index value no more indices remain in the record, then the - ** record is removed from the table. + ** The top of the stack is a key and next on stack is integer + ** which is the key to a record in an SQL table. + ** Locate the record in the cursor P1 (P1 represents an SQL index) + ** that has the same key as the top of stack. Then look through + ** the integer table-keys contained in the data of the P1 record. + ** 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: { int i = pOp->p1; int tos = p->tos; int nos = tos - 1; - DbbeTable *pTab; + DbbeCursor *pCrsr; if( nos<0 ) goto not_enough_stack; - if( i>=0 && inTable && (pTab = p->aTab[i].pTable)!=0 ){ + if( i>=0 && inCursor && (pCrsr = p->aCsr[i].pCursor)!=0 ){ int *aIdx; int nIdx; int j; @@ -2161,17 +2190,17 @@ int sqliteVdbeExec( Integerify(p, nos); oldVal = p->aStack[nos].i; 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; - nIdx = sqliteDbbeDataLength(pTab)/sizeof(int); - aIdx = (int*)sqliteDbbeReadData(pTab, 0); + nIdx = sqliteDbbeDataLength(pCrsr)/sizeof(int); + aIdx = (int*)sqliteDbbeReadData(pCrsr, 0); for(j=0; j=nIdx ) break; aIdx[j] = aIdx[nIdx-1]; if( nIdx==1 ){ - sqliteDbbeDelete(pTab, p->aStack[tos].n, p->zStack[tos]); + sqliteDbbeDelete(pCrsr, p->aStack[tos].n, p->zStack[tos]); }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); } } @@ -2181,8 +2210,9 @@ int sqliteVdbeExec( /* Opcode: Destroy * * P3 ** - ** Drop the table whose name is P3. The file that holds this table - ** is removed from the disk drive. + ** Drop the disk file whose name is P3. All key/data pairs in + ** the file are deleted and the file itself is removed + ** from the disk. */ case OP_Destroy: { sqliteDbbeDropTable(p->pBe, pOp->p3); @@ -2200,7 +2230,7 @@ int sqliteVdbeExec( /* 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 ** interactions. If another temporary file with the P1 handle is ** already opened, the prior file is closed and a new one opened @@ -2260,7 +2290,7 @@ int sqliteVdbeExec( /* Opcode: ListRead P1 P2 * ** ** 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. */ case OP_ListRead: { @@ -2693,7 +2723,7 @@ int sqliteVdbeExec( /* Opcode: FileField P1 * * ** ** Push onto the stack the P1-th field of the most recently read line - ** from the file. + ** from the input file. */ case OP_FileField: { int i = pOp->p1; @@ -2828,8 +2858,8 @@ int sqliteVdbeExec( /* Opcode: AggIncr P1 P2 * ** - ** Increment the P2-th field of the aggregate element current - ** in focus by an amount P1. + ** Increase the integer value in the P2-th field of the aggregate + ** element current in focus by an amount P1. */ case OP_AggIncr: { AggElem *pFocus = AggInFocus(p->agg); diff --git a/src/where.c b/src/where.c index bfdd2a7829..5cf7d7a3af 100644 --- a/src/where.c +++ b/src/where.c @@ -25,7 +25,7 @@ ** the WHERE clause of SQL statements. Also found here are subroutines ** 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" @@ -38,10 +38,10 @@ typedef struct ExprInfo ExprInfo; struct ExprInfo { Expr *p; /* Pointer to the subexpression */ int indexable; /* True if this subexprssion is usable by an index */ - int idxLeft; /* p->pLeft is a field in this table number. -1 if - ** p->pLeft is not the field of any table */ - int idxRight; /* p->pRight is a field in this table number. -1 if - ** p->pRight is not the field of any table */ + int idxLeft; /* p->pLeft is a column in this table number. -1 if + ** p->pLeft is not the column of any table */ + int idxRight; /* p->pRight is a column in this table number. -1 if + ** p->pRight is not the column of any table */ unsigned prereqLeft; /* Tables referenced by p->pLeft */ 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){ unsigned int mask = 0; if( p==0 ) return 0; - if( p->op==TK_FIELD ){ + if( p->op==TK_COLUMN ){ return 1<< (p->iTable - base); } if( p->pRight ){ @@ -124,11 +124,11 @@ static void exprAnalyze(int base, ExprInfo *pInfo){ pInfo->idxLeft = -1; pInfo->idxRight = -1; 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->indexable = 1; } - if( pExpr->pLeft->op==TK_FIELD ){ + if( pExpr->pLeft->op==TK_COLUMN ){ pInfo->idxLeft = pExpr->pLeft->iTable - base; pInfo->indexable = 1; } @@ -225,41 +225,41 @@ WhereInfo *sqliteWhereBegin( ** the most specific usable index. ** ** "Most specific" means that pBestIdx is the usable index that - ** has the largest value for nField. A usable index is one for - ** which there are subexpressions to compute every field of the + ** has the largest value for nColumn. A usable index is one for + ** which there are subexpressions to compute every column of the ** index. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; - int fieldMask = 0; + int columnMask = 0; - if( pIdx->nField>32 ) continue; + if( pIdx->nColumn>32 ) continue; for(j=0; jpLeft->iField; + int iColumn = aExpr[j].p->pLeft->iColumn; int k; - for(k=0; knField; k++){ - if( pIdx->aiField[k]==iField ){ - fieldMask |= 1<nColumn; k++){ + if( pIdx->aiColumn[k]==iColumn ){ + columnMask |= 1<pRight->iField; + int iColumn = aExpr[j].p->pRight->iColumn; int k; - for(k=0; knField; k++){ - if( pIdx->aiField[k]==iField ){ - fieldMask |= 1<nColumn; k++){ + if( pIdx->aiColumn[k]==iColumn ){ + columnMask |= 1<nField) ){ - if( pBestIdx==0 || pBestIdx->nFieldnField ){ + if( columnMask + 1 == (1<nColumn) ){ + if( pBestIdx==0 || pBestIdx->nColumnnColumn ){ pBestIdx = pIdx; } } @@ -297,12 +297,12 @@ WhereInfo *sqliteWhereBegin( }else{ /* Case 2: We do have a usable index in pIdx. */ - for(j=0; jnField; j++){ + for(j=0; jnColumn; j++){ for(k=0; kpLeft->iField==pIdx->aiField[j] + && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j] ){ sqliteExprCode(pParse, aExpr[k].p->pRight); aExpr[k].p = 0; @@ -310,7 +310,7 @@ WhereInfo *sqliteWhereBegin( } if( aExpr[k].idxRight==idx && (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); 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_NextIdx, base+pTabList->nId+i, brk, 0, cont); if( i==pTabList->nId-1 && pushKey ){ diff --git a/test/delete.test b/test/delete.test index 9bebd86fdf..b00e3c0d3e 100644 --- a/test/delete.test +++ b/test/delete.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # 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] source $testdir/tester.tcl @@ -72,7 +72,7 @@ do_test delete-4.1 { execsql {CREATE TABLE table2(f1 int, f2 int)} set v [catch {execsql {DELETE FROM table2 WHERE f3=5}} msg] lappend v $msg -} {1 {no such field: f3}} +} {1 {no such column: f3}} do_test delete-4.2 { set v [catch {execsql {DELETE FROM table2 WHERE xyzzy(f1+4)}} msg] diff --git a/test/in.test b/test/in.test index 01276b79a7..bd77c1fef2 100644 --- a/test/in.test +++ b/test/in.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # 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] source $testdir/tester.tcl @@ -106,7 +106,7 @@ do_test in-2.10 { do_test in-2.11 { set v [catch {execsql {SELECT a FROM t1 WHERE c IN (10,20)}} 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 # diff --git a/test/select1.test b/test/select1.test index b415a596b1..b9b6e5eae3 100644 --- a/test/select1.test +++ b/test/select1.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # 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] source $testdir/tester.tcl @@ -49,7 +49,7 @@ do_test select1-1.3 { 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 { execsql {SELECT f1 FROM test1} @@ -244,7 +244,7 @@ do_test select1-5.1 { execsql {CREATE TABLE test2(t1 test, t2 text)} execsql {INSERT INTO test2 VALUES('abc','xyz')} -# Check for field naming +# Check for column naming # do_test select1-6.1 { 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 ORDER BY f2}} msg] lappend v $msg -} {1 {ambiguous field name: f1}} +} {1 {ambiguous column name: f1}} do_test select1-6.8b { set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B ORDER BY f2}} msg] lappend v $msg -} {1 {ambiguous field name: f2}} +} {1 {ambiguous column name: f2}} do_test select1-6.8c { set v [catch {execsql2 {SELECT A.f1, f1 FROM test1 as A, test1 as A ORDER BY f2}} msg] lappend v $msg -} {1 {ambiguous field name: A.f1}} +} {1 {ambiguous column name: A.f1}} do_test select1-6.9 { set v [catch {execsql2 {SELECT A.f1, B.f1 FROM test1 as A, test1 as B ORDER BY A.f1, B.f1}} msg] diff --git a/test/select2.test b/test/select2.test index 664e12995b..59d759d559 100644 --- a/test/select2.test +++ b/test/select2.test @@ -23,7 +23,7 @@ # This file implements regression tests for SQLite library. The # 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] source $testdir/tester.tcl @@ -106,7 +106,7 @@ do_test select2-3.2c { do_test select2-3.2d { 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] - expr {$t1*0.9<$t2 && $t2*0.9<$t1} + expr {$t1*0.8<$t2 && $t2*0.8<$t1} } {1} # Make sure queries run faster with an index than without diff --git a/test/select5.test b/test/select5.test index f6bd150979..816e88da88 100644 --- a/test/select5.test +++ b/test/select5.test @@ -24,7 +24,7 @@ # focus of this file is testing aggregate functions and the # 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] source $testdir/tester.tcl @@ -66,7 +66,7 @@ do_test select5-2.1 { SELECT y, count(*) FROM t1 GROUP BY z ORDER BY y }} msg] lappend v $msg -} {1 {no such field: z}} +} {1 {no such column: z}} do_test select5-2.2 { set v [catch {execsql { 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(*) @@ -88,7 +88,7 @@ for any reason.

Closing the database

-

To close an SQLite database, just call the sqlite_close() +

To close an SQLite database, call the sqlite_close() function passing it the sqlite structure pointer that was obtained from a prior call to sqlite_open. @@ -147,6 +147,62 @@ argv[i] == 0 function returns non-zero, the query is immediately aborted and sqlite_exec() will return SQLITE_ABORT.

+

The sqlite_exec() function returns an integer to indicate +success or failure of the operation. The following are possible +return values:

+ +
+
+
SQLITE_OK
+

This value is returned if everything worked and there were no errors. +

+
SQLITE_INTERNAL
+

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 sqlite_exec() call, please report the problem on the SQLite +mailing list. +

+
SQLITE_ERROR
+

This return value indicates that there was an error in the SQL +that was passed into the sqlite_exec(). +

+
SQLITE_PERM
+

This return value says that the access permissions on one of the +GDBM files is such that the file cannot be opened. +

+
SQLITE_ABORT
+

This value is returned if the callback function returns non-zero. +

+
SQLITE_BUSY
+

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 +sqlite_exec() 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.

+

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. +

+
SQLITE_NOMEM
+

This value is returned if a call to malloc() fails. +

+
SQLITE_READONLY
+

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. +

+
+
+

Testing for a complete SQL statement

The last interface routine to SQLite is a convenience function used diff --git a/www/sqlite.tcl b/www/sqlite.tcl index b17c653bb5..b3ee470805 100644 --- a/www/sqlite.tcl +++ b/www/sqlite.tcl @@ -1,7 +1,7 @@ # # 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 { @@ -150,6 +150,7 @@ sqlite> (((.help))) .help Show this message .indices TABLE Show names of all indices on TABLE .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 stdout Send output to the screen .schema ?TABLE? Show the CREATE statements @@ -163,13 +164,13 @@ puts {

Changing Output Formats

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 formats.

The default output mode is "list". In 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 ("|"). 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.

} @@ -196,9 +197,9 @@ sqlite> } puts { -

In "line" mode, each field in a record of the database -is shown on a line by itself. Each line consists of the field -name, an equal sign and the field data. Successive records are +

In "line" mode, each column in a row of the database +is shown on a line by itself. Each line consists of the column +name, an equal sign and the column data. Successive records are separated by a blank line. Here is an example of line mode output:

} @@ -263,6 +264,11 @@ sqlite> } puts { +

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.

+

The last output mode is "html". In this mode, sqlite writes the results of the query as an XHTML table. The beginning <TABLE> and the ending </TABLE> are not written, but