1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Added support for the "sqlite_temp_master" table. Increased the version

number to 2.5.2. (CVS 640)

FossilOrigin-Name: 9c1432bf7485258e485bd652e3acdaeabbfe8850
This commit is contained in:
drh
2002-06-25 01:09:11 +00:00
parent 1cc093c2b5
commit e0bc4048a0
17 changed files with 484 additions and 687 deletions

View File

@@ -1 +1 @@
2.5.1 2.5.2

View File

@@ -1,9 +1,9 @@
C Partial\sfix\sfor\sa\sproblem\swith\sLEFT\sOUTER\sJOIN.\s\sIt\sused\sto\sbe\sthat\sthe\stest\nfor\sthe\sright-hand\stable\snot\smatching\sthe\sleft\stable\soccurred\safter\sall\nON,\sUSING,\sWHERE\sclause\sprocessing.\s\sThe\stest\sshould\soccur\safter\sON\sand\nUSING\sclauses\sare\schecked\sbut\sbefore\sthe\sWHERE\sclause\sis\scheck.\s\sThis\sfix\nworks\sas\slong\sas\sthe\stotal\snumber\sof\s"AND"\sseparated\sterms\sin\sthe\sON,\sUSING,\nand\sWHERE\sclause\sdoes\snot\sexceed\s32.\s\sTo\sdo:\smake\sthis\swork\sfor\sany\snumber\nof\sterms\sand\sadd\stest\scases.\nthat\s(CVS\s639) C Added\ssupport\sfor\sthe\s"sqlite_temp_master"\stable.\s\sIncreased\sthe\sversion\nnumber\sto\s2.5.2.\s(CVS\s640)
D 2002-06-24T22:01:58 D 2002-06-25T01:09:11
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F VERSION 9a1a4bc4ca9e44b3ccf4c764cb670aae41b078a0 F VERSION 2ca20d4461e9496d4ae27191e7273a12369ff17c
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
F config.sub f14b07d544ca26b5d698259045136b783e18fc7f F config.sub f14b07d544ca26b5d698259045136b783e18fc7f
@@ -20,7 +20,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 6aaa67d7eab70c2531dc13e5d9eb87e626c0b4d7 F src/btree.c 6aaa67d7eab70c2531dc13e5d9eb87e626c0b4d7
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 95eac6ce4ae2871388d49066c78dd0657ce40a1f F src/build.c 846eb3ee0e160e691766108a7136e196f8f8231b
F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725 F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
F src/expr.c cb50a72c491954d58be2f182366e45a1e252bf2e F src/expr.c cb50a72c491954d58be2f182366e45a1e252bf2e
@@ -28,20 +28,20 @@ F src/func.c 5eae8227a8b0d276a64d51a3880a6e86f238fedf
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c
F src/main.c 0e922ecfe4ce58c3e5c49f111d86003607d2114b F src/main.c 43d5f4e38108129a13cf42c59087e6e20b3596ad
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
F src/pager.c 1e41053c949cea1f09d8dafada5fe8f90785e650 F src/pager.c 1e41053c949cea1f09d8dafada5fe8f90785e650
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
F src/parse.y 2285d8967d7334d52a2188089e5a881d73ba56f6 F src/parse.y c75ea2580de675bcb80ff8b7c10c0a15e02a21ab
F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c f7d74f20f5ecc335fbccba367eda727b9d6fb299 F src/select.c f7d74f20f5ecc335fbccba367eda727b9d6fb299
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15 F src/shell.c 7b9d98ef3976ff5e44c18620dd17d32af83fbdd6
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144 F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144
F src/sqliteInt.h d3c1448890ba65e6be381b50b7e7ce7fca142322 F src/sqliteInt.h 3d1d86cb9ea4f06e49af855267478e3661abcd1b
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1 F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf
@@ -49,12 +49,12 @@ F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619 F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619
F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1 F src/trigger.c d88ab4d68d68955c217b38fb6717e090fbbf54a4
F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f
F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95 F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95
F src/vdbe.c 774f79483ce809b27c3bdb02afd7295cc3c7acd4 F src/vdbe.c 0b1ad7c3cbc638d1f73725bbc4e667c3ee8f7081
F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2 F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2
F src/where.c 259d7fb77191b13718c271926b7c14afbbe7346b F src/where.c 913fa33977c8dddfc259d9b2c38504b475738c43
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1 F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1 F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
@@ -98,12 +98,12 @@ F test/subselect.test f3bc1dcbddddcea08d818fcff75228ad3464fc83
F test/table.test 42511f98a3e9bbee62913e3ae1774777faa23d35 F test/table.test 42511f98a3e9bbee62913e3ae1774777faa23d35
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533 F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
F test/temptable.test ae58694c0fdd2d0b781508b64adc5aee3416aeed F test/temptable.test 9ed7ec0288f887e132de66d90c428ad109105f67
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6 F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
F test/trigger1.test bb63749fa8a395a60541100607d86381604b7194 F test/trigger1.test bb63749fa8a395a60541100607d86381604b7194
F test/trigger2.test c12759a0d7ba6488d9d24c96a1352ddee995c1ab F test/trigger2.test c12759a0d7ba6488d9d24c96a1352ddee995c1ab
F test/trigger3.test b4aca721ba92956c7fa16bb0158254f3c1b73efa F test/trigger3.test 7dfe798d7e72c13720394685fe353112e3f31adf
F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44 F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
F test/update.test a0aa0bf83e6fad8407d0e4ad25ebb09b513f5bf4 F test/update.test a0aa0bf83e6fad8407d0e4ad25ebb09b513f5bf4
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
@@ -122,22 +122,22 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
F www/c_interface.tcl 58cf4d128dcae08d91d0011c6d4d11de323f470f F www/c_interface.tcl 58cf4d128dcae08d91d0011c6d4d11de323f470f
F www/changes.tcl 31a8fec4f078a60b7de5f19859297f375e9ec8da F www/changes.tcl 08de0b1b50d3651ac3bd6b0d44c9ebe0072b55b3
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49 F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/faq.tcl 45bdb18b75ac3aa1befec42985fb892413aac0bb F www/faq.tcl 06e95342a101fde3ce59dbf128233a178502587e
F www/formatchng.tcl f604cde78f1ac9c29420136109b04407408e876e F www/formatchng.tcl f604cde78f1ac9c29420136109b04407408e876e
F www/index.tcl d0c52fbf031d0a3ee6d9d77aa669d5a4b24b6130 F www/index.tcl d0c52fbf031d0a3ee6d9d77aa669d5a4b24b6130
F www/lang.tcl cf22bf18dbd6bec3b7d0b00ad998dd1f88193ea2 F www/lang.tcl 8c3d0bda030f110c754b5edbad75eddf5dbe2ed1
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/sqlite.tcl ac64065d0c5e2de0f71238d55b2c14bb5c5c194c
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P d861489e1f7dffd1105c271fe8597f73e5b1703c P 8b6574cfa86daaae910f8f3ee3c4723a21fb9e53
R d718b83d86c9331bc69c93f673a44be9 R c96fc24249eaf46c6e1d5e0a79495140
U drh U drh
Z b9b5d0f63e47642b79ff89410dec8a4b Z 421a17002ac6e743396eaf770c048af4

View File

@@ -1 +1 @@
8b6574cfa86daaae910f8f3ee3c4723a21fb9e53 9c1432bf7485258e485bd652e3acdaeabbfe8850

View File

@@ -25,11 +25,29 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.97 2002/06/20 11:36:49 drh Exp $ ** $Id: build.c,v 1.98 2002/06/25 01:09:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
/*
** This routine is called when a new SQL statement is beginning to
** be parsed. Check to see if the schema for the database needs
** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
** If it does, then read it.
*/
void sqliteBeginParse(Parse *pParse, int explainFlag){
sqlite *db = pParse->db;
pParse->explain = explainFlag;
if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
int rc = sqliteInit(db, &pParse->zErrMsg);
if( rc!=SQLITE_OK ){
pParse->rc = rc;
pParse->nErr++;
}
}
}
/* /*
** This routine is called after a single SQL statement has been ** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement ** parsed and we want to execute the VDBE code to implement
@@ -48,6 +66,7 @@ void sqliteExec(Parse *pParse){
if( pParse->explain ){ if( pParse->explain ){
rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg, rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg,
&pParse->zErrMsg); &pParse->zErrMsg);
db->next_cookie = db->schema_cookie;
}else{ }else{
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqliteVdbeTrace(pParse->pVdbe, trace); sqliteVdbeTrace(pParse->pVdbe, trace);
@@ -70,7 +89,8 @@ void sqliteExec(Parse *pParse){
** of that table. Return NULL if not found. ** of that table. Return NULL if not found.
*/ */
Table *sqliteFindTable(sqlite *db, const char *zName){ Table *sqliteFindTable(sqlite *db, const char *zName){
Table *p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1); Table *p;
p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1);
return p; return p;
} }
@@ -80,7 +100,8 @@ Table *sqliteFindTable(sqlite *db, const char *zName){
** Return NULL if not found. ** Return NULL if not found.
*/ */
Index *sqliteFindIndex(sqlite *db, const char *zName){ Index *sqliteFindIndex(sqlite *db, const char *zName){
Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1); Index *p;
p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
return p; return p;
} }
@@ -99,7 +120,6 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){
if( pOld!=0 && pOld!=p ){ if( pOld!=0 && pOld!=p ){
sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld); sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld);
} }
sqliteHashInsert(&db->idxDrop, p, 0, 0);
sqliteFree(p); sqliteFree(p);
} }
@@ -122,26 +142,51 @@ void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
} }
/* /*
** Move the given index to the pending DROP INDEX queue if it has ** Erase all schema information from the in-memory hash tables of
** been committed. If this index was never committed, then just ** database connection. This routine is called to reclaim memory
** delete it. ** before the connection closes. It is also called during a rollback
** ** if there were schema changes during the transaction.
** Indices on the pending drop queue are deleted when a COMMIT is
** executed. If a ROLLBACK occurs, the indices are moved back into
** the main index hash table.
*/ */
static void sqlitePendingDropIndex(sqlite *db, Index *p){ void sqliteResetInternalSchema(sqlite *db){
if( !p->isCommit ){ HashElem *pElem;
sqliteUnlinkAndDeleteIndex(db, p); Hash temp1;
}else{ Hash temp2;
Index *pOld;
pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0); temp1 = db->tblHash;
if( pOld!=0 && pOld!=p ){ temp2 = db->trigHash;
sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld); sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashClear(&db->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
Trigger *pTrigger = sqliteHashData(pElem);
sqliteDeleteTrigger(pTrigger);
} }
sqliteHashInsert(&db->idxDrop, p, 0, p); sqliteHashClear(&temp2);
p->isDropped = 1; sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqliteDeleteTable(db, pTab);
} }
sqliteHashClear(&temp1);
db->flags &= ~(SQLITE_Initialized|SQLITE_InternChanges);
}
/*
** This routine is called whenever a rollback occurs. If there were
** schema changes during the transaction, then we have to reset the
** internal hash tables and reload them from disk.
*/
void sqliteRollbackInternalChanges(sqlite *db){
if( db->flags & SQLITE_InternChanges ){
sqliteResetInternalSchema(db);
}
}
/*
** This routine is called when a commit occurs.
*/
void sqliteCommitInternalChanges(sqlite *db){
db->schema_cookie = db->next_cookie;
db->flags &= ~SQLITE_InternChanges;
} }
/* /*
@@ -185,185 +230,9 @@ static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
assert( db!=0 ); assert( db!=0 );
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0); pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
assert( pOld==0 || pOld==p ); assert( pOld==0 || pOld==p );
sqliteHashInsert(&db->tblDrop, p, 0, 0);
sqliteDeleteTable(db, p); sqliteDeleteTable(db, p);
} }
/*
** Move the given table to the pending DROP TABLE queue if it has
** been committed. If this table was never committed, then just
** delete it. Do the same for all its indices.
**
** Table on the drop queue are not actually deleted until a COMMIT
** statement is executed. If a ROLLBACK occurs instead of a COMMIT,
** then the tables on the drop queue are moved back into the main
** hash table.
*/
static void sqlitePendingDropTable(sqlite *db, Table *pTbl){
if( !pTbl->isCommit ){
sqliteUnlinkAndDeleteTable(db, pTbl);
}else{
Table *pOld;
Index *pIndex, *pNext;
pOld = sqliteHashInsert(&db->tblHash, pTbl->zName, strlen(pTbl->zName)+1,0);
assert( pOld==pTbl );
sqliteHashInsert(&db->tblDrop, pTbl, 0, pTbl);
for(pIndex = pTbl->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
sqlitePendingDropIndex(db, pIndex);
}
}
}
/*
** Check all Tables and Indexes in the internal hash table and commit
** any additions or deletions to those hash tables.
**
** When executing CREATE TABLE and CREATE INDEX statements, the Table
** and Index structures are created and added to the hash tables, but
** the "isCommit" field is not set. This routine sets those fields.
** When executing DROP TABLE and DROP INDEX, the table or index structures
** are moved out of tblHash and idxHash into tblDrop and idxDrop. This
** routine deletes the structure in tblDrop and idxDrop.
**
** See also: sqliteRollbackInternalChanges()
*/
void sqliteCommitInternalChanges(sqlite *db){
HashElem *pElem;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
db->schema_cookie = db->next_cookie;
for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
Table *pTable = sqliteHashData(pElem);
pTable->isCommit = 1;
}
for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
Table *pTable = sqliteHashData(pElem);
sqliteDeleteTable(db, pTable);
}
sqliteHashClear(&db->tblDrop);
for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
Index *pIndex = sqliteHashData(pElem);
pIndex->isCommit = 1;
}
while( (pElem=sqliteHashFirst(&db->idxDrop))!=0 ){
Index *pIndex = sqliteHashData(pElem);
sqliteUnlinkAndDeleteIndex(db, pIndex);
}
sqliteHashClear(&db->idxDrop);
/* Set the commit flag on all triggers added this transaction */
for(pElem=sqliteHashFirst(&db->trigHash); pElem; pElem=sqliteHashNext(pElem)){
Trigger *pTrigger = sqliteHashData(pElem);
pTrigger->isCommit = 1;
}
/* Delete the structures for triggers removed this transaction */
pElem = sqliteHashFirst(&db->trigDrop);
while( pElem ){
Trigger *pTrigger = sqliteHashData(pElem);
sqliteDeleteTrigger(pTrigger);
pElem = sqliteHashNext(pElem);
}
sqliteHashClear(&db->trigDrop);
db->flags &= ~SQLITE_InternChanges;
}
/*
** This routine runs when one or more CREATE TABLE, CREATE INDEX,
** DROP TABLE, or DROP INDEX statements gets rolled back. The
** additions or deletions of Table and Index structures in the
** internal hash tables are undone.
**
** See also: sqliteCommitInternalChanges()
*/
void sqliteRollbackInternalChanges(sqlite *db){
Hash toDelete;
HashElem *pElem;
if( (db->flags & SQLITE_InternChanges)==0 ) return;
sqliteHashInit(&toDelete, SQLITE_HASH_POINTER, 0);
db->next_cookie = db->schema_cookie;
for(pElem=sqliteHashFirst(&db->tblHash); pElem; pElem=sqliteHashNext(pElem)){
Table *pTable = sqliteHashData(pElem);
if( !pTable->isCommit ){
sqliteHashInsert(&toDelete, pTable, 0, pTable);
}
}
for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
Table *pTable = sqliteHashData(pElem);
sqliteUnlinkAndDeleteTable(db, pTable);
}
sqliteHashClear(&toDelete);
for(pElem=sqliteHashFirst(&db->tblDrop); pElem; pElem=sqliteHashNext(pElem)){
Table *pOld, *p = sqliteHashData(pElem);
assert( p->isCommit );
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
assert( pOld==0 || pOld==p );
}
sqliteHashClear(&db->tblDrop);
for(pElem=sqliteHashFirst(&db->idxHash); pElem; pElem=sqliteHashNext(pElem)){
Index *pIndex = sqliteHashData(pElem);
if( !pIndex->isCommit ){
sqliteHashInsert(&toDelete, pIndex, 0, pIndex);
}
}
for(pElem=sqliteHashFirst(&toDelete); pElem; pElem=sqliteHashNext(pElem)){
Index *pIndex = sqliteHashData(pElem);
sqliteUnlinkAndDeleteIndex(db, pIndex);
}
sqliteHashClear(&toDelete);
for(pElem=sqliteHashFirst(&db->idxDrop); pElem; pElem=sqliteHashNext(pElem)){
Index *pOld, *p = sqliteHashData(pElem);
assert( p->isCommit );
p->isDropped = 0;
pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, p);
assert( pOld==0 || pOld==p );
}
sqliteHashClear(&db->idxDrop);
/* Remove any triggers that haven't been commited yet */
for(pElem = sqliteHashFirst(&db->trigHash); pElem;
pElem = (pElem?sqliteHashNext(pElem):0)){
Trigger *pTrigger = sqliteHashData(pElem);
if( !pTrigger->isCommit ){
Table *pTbl = sqliteFindTable(db, pTrigger->table);
if( pTbl ){
if( pTbl->pTrigger == pTrigger ){
pTbl->pTrigger = pTrigger->pNext;
}else{
Trigger *cc = pTbl->pTrigger;
while( cc ){
if( cc->pNext == pTrigger ){
cc->pNext = cc->pNext->pNext;
break;
}
cc = cc->pNext;
}
assert(cc);
}
}
sqliteHashInsert(&db->trigHash, pTrigger->name,
1 + strlen(pTrigger->name), 0);
sqliteDeleteTrigger(pTrigger);
pElem = sqliteHashFirst(&db->trigHash);
}
}
/* Any triggers that were dropped - put 'em back in place */
for(pElem = sqliteHashFirst(&db->trigDrop); pElem;
pElem = sqliteHashNext(pElem)){
Trigger *pTrigger = sqliteHashData(pElem);
Table *pTbl = sqliteFindTable(db, pTrigger->table);
sqliteHashInsert(&db->trigHash, pTrigger->name,
strlen(pTrigger->name) + 1, pTrigger);
pTrigger->pNext = pTbl->pTrigger;
pTbl->pTrigger = pTrigger;
}
sqliteHashClear(&db->trigDrop);
db->flags &= ~SQLITE_InternChanges;
}
/* /*
** Construct the name of a user table or index from a token. ** Construct the name of a user table or index from a token.
** **
@@ -376,13 +245,31 @@ char *sqliteTableNameFromToken(Token *pName){
return zName; return zName;
} }
/*
** Generate code to open the appropriate master table. The table
** opened will be SQLITE_MASTER for persistent tables and
** SQLITE_TEMP_MASTER for temporary tables. The table is opened
** on cursor 0.
*/
void sqliteOpenMasterTable(Vdbe *v, int isTemp){
if( isTemp ){
sqliteVdbeAddOp(v, OP_OpenWrAux, 0, 2);
sqliteVdbeChangeP3(v, -1, TEMP_MASTER_NAME, P3_STATIC);
}else{
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
}
}
/* /*
** Begin constructing a new table representation in memory. This is ** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response ** the first of several action routines that get called in response
** to a CREATE TABLE statement. In particular, this routine is called ** to a CREATE TABLE statement. In particular, this routine is called
** after seeing tokens "CREATE" and "TABLE" and the table name. The ** after seeing tokens "CREATE" and "TABLE" and the table name. The
** pStart token is the CREATE and pName is the table name. The isTemp ** pStart token is the CREATE and pName is the table name. The isTemp
** flag is true if the "TEMP" or "TEMPORARY" keyword occurs in between ** flag is true if the table should be stored in the auxiliary database
** file instead of in the main database file. This is normally the case
** when the "TEMP" or "TEMPORARY" keyword occurs in between
** CREATE and TABLE. ** CREATE and TABLE.
** **
** The new table record is initialized and put in pParse->pNewTable. ** The new table record is initialized and put in pParse->pNewTable.
@@ -408,7 +295,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
if( isTemp && db->pBeTemp==0 ){ if( isTemp && db->pBeTemp==0 ){
int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->pBeTemp); int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->pBeTemp);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqliteSetNString(&pParse->zErrMsg, "unable to open a temporary database " sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
"file for storing temporary tables", 0); "file for storing temporary tables", 0);
pParse->nErr++; pParse->nErr++;
return; return;
@@ -482,14 +369,13 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
if( !isTemp ){ if( !isTemp ){
sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0); sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 1); sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2); }
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC); sqliteOpenMasterTable(v, isTemp);
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
} }
}
} }
/* /*
@@ -725,10 +611,12 @@ void sqliteAddCollateType(Parse *pParse, int collType){
** and the probability of hitting the same cookie value is only ** and the probability of hitting the same cookie value is only
** 1 chance in 2^32. So we're safe enough. ** 1 chance in 2^32. So we're safe enough.
*/ */
void sqliteChangeCookie(sqlite *db){ void sqliteChangeCookie(sqlite *db, Vdbe *v){
if( db->next_cookie==db->schema_cookie ){ if( db->next_cookie==db->schema_cookie ){
db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1; db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
} }
} }
@@ -791,11 +679,10 @@ static char *createTableStmt(Table *p){
zSep2 = ",\n "; zSep2 = ",\n ";
zEnd = "\n)"; zEnd = "\n)";
} }
n += 25 + 6*p->nCol; n += 35 + 6*p->nCol;
zStmt = sqliteMalloc( n ); zStmt = sqliteMalloc( n );
if( zStmt==0 ) return 0; if( zStmt==0 ) return 0;
assert( !p->isTemp ); strcpy(zStmt, p->isTemp ? "CREATE TEMP TABLE " : "CREATE TABLE ");
strcpy(zStmt, "CREATE TABLE ");
k = strlen(zStmt); k = strlen(zStmt);
identPut(zStmt, &k, p->zName); identPut(zStmt, &k, p->zName);
zStmt[k++] = '('; zStmt[k++] = '(';
@@ -867,10 +754,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
} }
/* If the initFlag is 1 it means we are reading the SQL off the /* If the initFlag is 1 it means we are reading the SQL off the
** "sqlite_master" table on the disk. So do not write to the disk ** "sqlite_master" or "sqlite_temp_master" table on the disk.
** again. Extract the root page number for the table from the ** So do not write to the disk again. Extract the root page number
** pParse->newTnum field. (The page number should have been put ** for the table from the pParse->newTnum field. (The page number
** there by the sqliteOpenCb routine.) ** should have been put there by the sqliteOpenCb routine.)
*/ */
if( pParse->initFlag ){ if( pParse->initFlag ){
p->tnum = pParse->newTnum; p->tnum = pParse->newTnum;
@@ -880,8 +767,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
** in the SQLITE_MASTER table of the database. The record number ** in the SQLITE_MASTER table of the database. The record number
** for the new table entry should already be on the stack. ** for the new table entry should already be on the stack.
** **
** If this is a TEMPORARY table, then just create the table. Do not ** If this is a TEMPORARY table, write the entry into the auxiliary
** make an entry in SQLITE_MASTER. ** file instead of into the main database file.
*/ */
if( !pParse->initFlag ){ if( !pParse->initFlag ){
int n; int n;
@@ -898,7 +785,6 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqliteVdbeAddOp(v, OP_Integer, 0, 0); sqliteVdbeAddOp(v, OP_Integer, 0, 0);
} }
p->tnum = 0; p->tnum = 0;
if( !p->isTemp ){
sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
if( p->pSelect==0 ){ if( p->pSelect==0 ){
@@ -924,11 +810,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
} }
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
sqliteChangeCookie(db); if( !p->isTemp ){
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0); sqliteChangeCookie(db, v);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 0, 0);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0);
if( pSelect ){ if( pSelect ){
int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite; int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
sqliteVdbeAddOp(v, op, 1, 0); sqliteVdbeAddOp(v, op, 1, 0);
@@ -1151,34 +1036,38 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
static VdbeOp dropTable[] = { static VdbeOp dropTable[] = {
{ OP_OpenWrite, 0, 2, MASTER_NAME}, { OP_Rewind, 0, ADDR(8), 0},
{ OP_Rewind, 0, ADDR(9), 0}, { OP_String, 0, 0, 0}, /* 1 */
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_MemStore, 1, 1, 0}, { OP_MemStore, 1, 1, 0},
{ OP_MemLoad, 1, 0, 0}, /* 4 */ { OP_MemLoad, 1, 0, 0}, /* 3 */
{ OP_Column, 0, 2, 0}, { OP_Column, 0, 2, 0},
{ OP_Ne, 0, ADDR(8), 0}, { OP_Ne, 0, ADDR(7), 0},
{ OP_Delete, 0, 0, 0}, { OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(4), 0}, /* 8 */ { OP_Next, 0, ADDR(3), 0}, /* 7 */
{ OP_Integer, 0, 0, 0}, /* 9 */
{ OP_SetCookie, 0, 0, 0},
{ OP_Close, 0, 0, 0},
}; };
Index *pIdx; Index *pIdx;
Trigger *pTrigger;
sqliteBeginWriteOperation(pParse, 0); sqliteBeginWriteOperation(pParse, 0);
sqliteOpenMasterTable(v, pTable->isTemp);
/* Drop all triggers associated with the table being dropped */ /* Drop all triggers associated with the table being dropped */
while( pTable->pTrigger ){ pTrigger = pTable->pTrigger;
while( pTrigger ){
Token tt; Token tt;
tt.z = pTable->pTrigger->name; tt.z = pTable->pTrigger->name;
tt.n = strlen(pTable->pTrigger->name); tt.n = strlen(pTable->pTrigger->name);
sqliteDropTrigger(pParse, &tt, 1); sqliteDropTrigger(pParse, &tt, 1);
if( pParse->explain ){
pTrigger = pTrigger->pNext;
}else{
pTrigger = pTable->pTrigger;
}
} }
if( !pTable->isTemp ){
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
sqliteChangeCookie(db); if( !pTable->isTemp ){
sqliteVdbeChangeP1(v, base+9, db->next_cookie); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp); sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
@@ -1188,16 +1077,13 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
/* Move the table (and all its indices) to the pending DROP queue. /* Delete the in-memory description of the table.
** Or, if the table was never committed, just delete it. If the table
** has been committed and is placed on the pending DROP queue, then the
** delete will occur when sqliteCommitInternalChanges() executes.
** **
** Exception: if the SQL statement began with the EXPLAIN keyword, ** Exception: if the SQL statement began with the EXPLAIN keyword,
** then no changes should be made. ** then no changes should be made.
*/ */
if( !pParse->explain ){ if( !pParse->explain ){
sqlitePendingDropTable(db, pTable); sqliteUnlinkAndDeleteTable(db, pTable);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
sqliteViewResetAll(db); sqliteViewResetAll(db);
@@ -1264,7 +1150,7 @@ void sqliteCreateIndex(
** Since its table has been suppressed, we need to also suppress the ** Since its table has been suppressed, we need to also suppress the
** index. ** index.
*/ */
if( pParse->initFlag && pTab->isTemp ){ if( pParse->initFlag && !pParse->isTemp && pTab->isTemp ){
goto exit_create_index; goto exit_create_index;
} }
@@ -1429,12 +1315,8 @@ void sqliteCreateIndex(
if( v==0 ) goto exit_create_index; if( v==0 ) goto exit_create_index;
if( pTable!=0 ){ if( pTable!=0 ){
sqliteBeginWriteOperation(pParse, 0); sqliteBeginWriteOperation(pParse, 0);
if( !isTemp ){ sqliteOpenMasterTable(v, isTemp);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
} }
}
if( !isTemp ){
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, "index", P3_STATIC); sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
@@ -1442,19 +1324,17 @@ void sqliteCreateIndex(
sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
}
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp); addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp);
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER); sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER);
pIndex->tnum = 0; pIndex->tnum = 0;
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
if( isTemp ){ if( isTemp ){
sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0); sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0);
}else{ }else{
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0); sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
} }
} }
if( !isTemp ){
addr = sqliteVdbeAddOp(v, OP_String, 0, 0); addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
if( pStart && pEnd ){ if( pStart && pEnd ){
n = Addr(pEnd->z) - Addr(pStart->z) + 1; n = Addr(pEnd->z) - Addr(pStart->z) + 1;
@@ -1462,7 +1342,6 @@ void sqliteCreateIndex(
} }
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
}
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum); sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@@ -1481,11 +1360,9 @@ void sqliteCreateIndex(
} }
if( pTable!=0 ){ if( pTable!=0 ){
if( !isTemp ){ if( !isTemp ){
sqliteChangeCookie(db); sqliteChangeCookie(db, v);
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 0, 0);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
} }
@@ -1523,42 +1400,35 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
static VdbeOp dropIndex[] = { static VdbeOp dropIndex[] = {
{ OP_OpenWrite, 0, 2, MASTER_NAME}, { OP_Rewind, 0, ADDR(9), 0},
{ OP_Rewind, 0, ADDR(10),0}, { OP_String, 0, 0, 0}, /* 1 */
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_MemStore, 1, 1, 0}, { OP_MemStore, 1, 1, 0},
{ OP_MemLoad, 1, 0, 0}, /* 4 */ { OP_MemLoad, 1, 0, 0}, /* 3 */
{ OP_Column, 0, 1, 0}, { OP_Column, 0, 1, 0},
{ OP_Eq, 0, ADDR(9), 0}, { OP_Eq, 0, ADDR(8), 0},
{ OP_Next, 0, ADDR(4), 0}, { OP_Next, 0, ADDR(3), 0},
{ OP_Goto, 0, ADDR(10),0}, { OP_Goto, 0, ADDR(9), 0},
{ OP_Delete, 0, 0, 0}, /* 9 */ { OP_Delete, 0, 0, 0}, /* 8 */
{ OP_Integer, 0, 0, 0}, /* 10 */
{ OP_SetCookie, 0, 0, 0},
{ OP_Close, 0, 0, 0},
}; };
int base; int base;
Table *pTab = pIndex->pTable; Table *pTab = pIndex->pTable;
sqliteBeginWriteOperation(pParse, 0); sqliteBeginWriteOperation(pParse, 0);
if( !pTab->isTemp ){ sqliteOpenMasterTable(v, pTab->isTemp);
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC); sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
sqliteChangeCookie(db); if( !pTab->isTemp ){
sqliteVdbeChangeP1(v, base+10, db->next_cookie); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp); sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
/* Move the index onto the pending DROP queue. Or, if the index was /* Delete the in-memory description of this index.
** never committed, just delete it. Indices on the pending DROP queue
** get deleted by sqliteCommitInternalChanges() when the user executes
** a COMMIT. Or if a rollback occurs, the elements of the DROP queue
** are moved back into the main hash table.
*/ */
if( !pParse->explain ){ if( !pParse->explain ){
sqlitePendingDropIndex(db, pIndex); sqliteUnlinkAndDeleteIndex(db, pIndex);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
} }

View File

@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.83 2002/06/22 02:33:38 drh Exp $ ** $Id: main.c,v 1.84 2002/06/25 01:09:11 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -30,6 +30,7 @@
** argv[1] = table or index name or meta statement type. ** argv[1] = table or index name or meta statement type.
** argv[2] = root page number for table or index. NULL for meta. ** argv[2] = root page number for table or index. NULL for meta.
** argv[3] = SQL create statement for the table or index ** argv[3] = SQL create statement for the table or index
** argv[4] = "1" for temporary files, "0" for main database
** **
*/ */
int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
@@ -41,29 +42,8 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
** make sure fields do not contain NULLs. Otherwise we might core ** make sure fields do not contain NULLs. Otherwise we might core
** when attempting to initialize from a corrupt database file. */ ** when attempting to initialize from a corrupt database file. */
assert( argc==4 ); assert( argc==5 );
switch( argv[0][0] ){ switch( argv[0][0] ){
case 'c': { /* Recommended pager cache size */
int size = atoi(argv[3]);
if( size==0 ){ size = MAX_PAGES; }
db->cache_size = size;
sqliteBtreeSetCacheSize(db->pBe, size);
break;
}
case 'f': { /* File format */
/*
** file_format==1 Version 2.1.0.
** file_format==2 Version 2.2.0. Integer primary key.
** file_format==3 Version 2.6.0. Separate text and numeric datatypes.
*/
db->file_format = atoi(argv[3]);
break;
}
case 's': { /* Schema cookie */
db->schema_cookie = atoi(argv[3]);
db->next_cookie = db->schema_cookie;
break;
}
case 'v': case 'v':
case 'i': case 'i':
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
@@ -76,6 +56,7 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = db; sParse.db = db;
sParse.initFlag = 1; sParse.initFlag = 1;
sParse.isTemp = argv[4][0] - '0';
sParse.newTnum = atoi(argv[2]); sParse.newTnum = atoi(argv[2]);
sqliteRunParser(&sParse, argv[3], 0); sqliteRunParser(&sParse, argv[3], 0);
}else{ }else{
@@ -120,15 +101,29 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
** has the sqlite_master table locked) than another attempt ** has the sqlite_master table locked) than another attempt
** is made the first time the database is accessed. ** is made the first time the database is accessed.
*/ */
static int sqliteInit(sqlite *db, char **pzErrMsg){ int sqliteInit(sqlite *db, char **pzErrMsg){
Vdbe *vdbe;
int rc; int rc;
BtCursor *curMain;
int size;
Table *pTab;
char *azArg[6];
int meta[SQLITE_N_BTREE_META];
Parse sParse;
/* /*
** The master database table has a structure like this ** The master database table has a structure like this
*/ */
static char master_schema[] = static char master_schema[] =
"CREATE TABLE " MASTER_NAME " (\n" "CREATE TABLE sqlite_master(\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
")"
;
static char temp_master_schema[] =
"CREATE TEMP TABLE sqlite_temp_master(\n"
" type text,\n" " type text,\n"
" name text,\n" " name text,\n"
" tbl_name text,\n" " tbl_name text,\n"
@@ -137,165 +132,117 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
")" ")"
; ;
/* The following VDBE program is used to initialize the internal /* The following SQL will read the schema from the master tables.
** structure holding the tables and indexes of the database. ** The first version works with SQLite file formats 2 or greater.
** The database contains a special table named "sqlite_master" ** The second version is for format 1 files.
** defined as follows:
** **
** CREATE TABLE sqlite_master ( ** Beginning with file format 2, the rowid for new table entries
** type text, -- Either "table" or "index" or "meta" ** (including entries in sqlite_master) is an increasing integer.
** name text, -- Name of table or index ** So for file format 2 and later, we can play back sqlite_master
** tbl_name text, -- Associated table ** and all the CREATE statements will appear in the right order.
** rootpage integer, -- The integer page number of root page ** But with file format 1, table entries were random and so we
** sql text -- The CREATE statement for this object ** have to make sure the CREATE TABLEs occur before their corresponding
** ); ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or
** ** CREATE TRIGGER in file format 1 because those constructs did
** The sqlite_master table contains a single entry for each table ** not exist then.)
** 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 column is always the same as name. For indices, the
** tbl_name column contains the name of the table that the index
** indexes. The "rootpage" column holds the number of the root page
** for the b-tree for the table or index. Finally, the "sql" column
** contains the complete text of the CREATE TABLE or CREATE INDEX
** statement that originally created the table or index. If an index
** was created to fulfill a PRIMARY KEY or UNIQUE constraint on a table,
** then the "sql" column is NULL.
**
** In format 1, entries in the sqlite_master table are in a random
** order. Two passes must be made through the table to initialize
** internal data structures. The first pass reads table definitions
** and the second pass read index definitions. Having two passes
** insures that indices appear after their tables.
**
** In format 2, entries appear in chronological order. Only a single
** pass needs to be made through the table since everything will be
** in the write order. VIEWs may only occur in format 2.
**
** The following program invokes its callback on the SQL for each
** table then goes back and invokes the callback on the
** SQL for each index. The callback will invoke the
** parser to build the internal representation of the
** database scheme.
*/ */
static VdbeOp initProg[] = { static char init_script[] =
/* Send the file format to the callback routine "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
*/ "UNION ALL "
{ OP_Open, 0, 2, 0}, "SELECT type, name, rootpage, sql, 0 FROM sqlite_master";
{ OP_String, 0, 0, "file-format"}, static char older_init_script[] =
{ OP_String, 0, 0, 0}, "SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
{ OP_String, 0, 0, 0}, "UNION ALL "
{ OP_ReadCookie, 0, 1, 0}, "SELECT type, name, rootpage, sql, 0 FROM sqlite_master "
{ OP_Callback, 4, 0, 0}, "WHERE type='table' "
"UNION ALL "
"SELECT type, name, rootpage, sql, 0 FROM sqlite_master "
"WHERE type='index'";
/* Send the recommended pager cache size to the callback routine
*/
{ OP_String, 0, 0, "cache-size"},
{ OP_String, 0, 0, 0},
{ OP_String, 0, 0, 0},
{ OP_ReadCookie, 0, 2, 0},
{ OP_Callback, 4, 0, 0},
/* Send the initial schema cookie to the callback /* Construct the schema tables: sqlite_master and sqlite_temp_master
*/ */
{ OP_String, 0, 0, "schema_cookie"},
{ OP_String, 0, 0, 0},
{ OP_String, 0, 0, 0},
{ OP_ReadCookie, 0, 0, 0},
{ OP_Callback, 4, 0, 0},
/* Check the file format. If the format number is 2 or more,
** then do a single pass through the SQLITE_MASTER table. For
** a format number of less than 2, jump forward to a different
** algorithm that makes two passes through the SQLITE_MASTER table,
** once for tables and a second time for indices.
*/
{ OP_ReadCookie, 0, 1, 0},
{ OP_Integer, 2, 0, 0},
{ OP_Lt, 0, 28, 0},
/* This is the code for doing a single scan through the SQLITE_MASTER
** table. This code runs for format 2 and greater.
*/
{ OP_Rewind, 0, 26, 0},
{ OP_Column, 0, 0, 0}, /* 20 */
{ OP_Column, 0, 1, 0},
{ OP_Column, 0, 3, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 4, 0, 0},
{ OP_Next, 0, 20, 0},
{ OP_Close, 0, 0, 0}, /* 26 */
{ OP_Halt, 0, 0, 0},
/* This is the code for doing two passes through SQLITE_MASTER. This
** code runs for file format 1.
*/
{ OP_Rewind, 0, 48, 0}, /* 28 */
{ OP_Column, 0, 0, 0}, /* 29 */
{ OP_String, 0, 0, "table"},
{ OP_Ne, 0, 37, 0},
{ OP_Column, 0, 0, 0},
{ OP_Column, 0, 1, 0},
{ OP_Column, 0, 3, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 4, 0, 0},
{ OP_Next, 0, 29, 0}, /* 37 */
{ OP_Rewind, 0, 48, 0}, /* 38 */
{ OP_Column, 0, 0, 0}, /* 39 */
{ OP_String, 0, 0, "index"},
{ OP_Ne, 0, 47, 0},
{ OP_Column, 0, 0, 0},
{ OP_Column, 0, 1, 0},
{ OP_Column, 0, 3, 0},
{ OP_Column, 0, 4, 0},
{ OP_Callback, 4, 0, 0},
{ OP_Next, 0, 39, 0}, /* 47 */
{ OP_Close, 0, 0, 0}, /* 48 */
{ OP_Halt, 0, 0, 0},
};
/* Create a virtual machine to run the initialization program. Run
** the program. Then delete the virtual machine.
*/
vdbe = sqliteVdbeCreate(db);
if( vdbe==0 ){
sqliteSetString(pzErrMsg, "out of memory", 0);
return SQLITE_NOMEM;
}
sqliteVdbeAddOpList(vdbe, sizeof(initProg)/sizeof(initProg[0]), initProg);
rc = sqliteVdbeExec(vdbe, sqliteInitCallback, db, pzErrMsg,
db->pBusyArg, db->xBusyCallback);
sqliteVdbeDelete(vdbe);
if( rc==SQLITE_OK && db->nTable==0 ){
db->file_format = 2;
}
if( rc==SQLITE_OK && db->file_format>2 ){
sqliteSetString(pzErrMsg, "unsupported file format", 0);
rc = SQLITE_ERROR;
}
/* The schema for the SQLITE_MASTER table is not stored in the
** database itself. We have to invoke the callback one extra
** time to get it to process the SQLITE_MASTER table defintion.
*/
if( rc==SQLITE_OK ){
Table *pTab;
char *azArg[6];
azArg[0] = "table"; azArg[0] = "table";
azArg[1] = MASTER_NAME; azArg[1] = MASTER_NAME;
azArg[2] = "2"; azArg[2] = "2";
azArg[3] = master_schema; azArg[3] = master_schema;
azArg[4] = 0; azArg[4] = "0";
sqliteInitCallback(db, 4, azArg, 0); azArg[5] = 0;
sqliteInitCallback(db, 5, azArg, 0);
pTab = sqliteFindTable(db, MASTER_NAME); pTab = sqliteFindTable(db, MASTER_NAME);
if( pTab ){ if( pTab ){
pTab->readOnly = 1; pTab->readOnly = 1;
} }
azArg[1] = TEMP_MASTER_NAME;
azArg[3] = temp_master_schema;
azArg[4] = "1";
sqliteInitCallback(db, 5, azArg, 0);
pTab = sqliteFindTable(db, TEMP_MASTER_NAME);
if( pTab ){
pTab->readOnly = 1;
}
/* Create a cursor to hold the database open
*/
if( db->pBe==0 ) return SQLITE_OK;
rc = sqliteBtreeCursor(db->pBe, 2, 0, &curMain);
if( rc ) return rc;
/* Get the database meta information
*/
rc = sqliteBtreeGetMeta(db->pBe, meta);
if( rc ){
sqliteBtreeCloseCursor(curMain);
return rc;
}
db->schema_cookie = meta[1];
db->next_cookie = db->schema_cookie;
db->file_format = meta[2];
size = meta[3];
if( size==0 ){ size = MAX_PAGES; }
db->cache_size = size;
sqliteBtreeSetCacheSize(db->pBe, size);
/*
** file_format==1 Version 2.1.0.
** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY.
** file_format==3 Version 2.6.0. Add support for separate numeric and
** text datatypes.
*/
if( db->file_format==0 ){
db->file_format = 2;
}else if( db->file_format>2 ){
sqliteBtreeCloseCursor(curMain);
sqliteSetString(pzErrMsg, "unsupported file format", 0);
rc = SQLITE_ERROR;
}
/* Read the schema information out of the schema tables
*/
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.pBe = db->pBe;
sParse.xCallback = sqliteInitCallback;
sParse.pArg = (void*)db;
sParse.initFlag = 1;
sqliteRunParser(&sParse,
db->file_format>=2 ? init_script : older_init_script,
pzErrMsg);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
sqliteBtreeRollback(db->pBe);
sqliteResetInternalSchema(db);
}
if( sParse.rc==SQLITE_OK ){
db->flags |= SQLITE_Initialized; db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db); sqliteCommitInternalChanges(db);
}else{
db->flags &= ~SQLITE_Initialized;
sqliteResetInternalSchema(db);
} }
return rc; sqliteBtreeCloseCursor(curMain);
return sParse.rc;
} }
/* /*
@@ -333,9 +280,6 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->trigDrop, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->tblDrop, SQLITE_HASH_POINTER, 0);
sqliteHashInit(&db->idxDrop, SQLITE_HASH_POINTER, 0);
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1); sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
sqliteRegisterBuiltinFunctions(db); sqliteRegisterBuiltinFunctions(db);
db->onError = OE_Default; db->onError = OE_Default;
@@ -377,74 +321,6 @@ no_mem_on_open:
return 0; return 0;
} }
/*
** Erase all schema information from the schema hash table. Except
** tables that are created using CREATE TEMPORARY TABLE are preserved
** if the preserveTemps flag is true.
**
** The database schema is normally read in once when the database
** is first opened and stored in a hash table in the sqlite structure.
** This routine erases the stored schema. This erasure occurs because
** either the database is being closed or because some other process
** changed the schema and this process needs to reread it.
*/
static void clearHashTable(sqlite *db, int preserveTemps){
HashElem *pElem;
Hash temp1;
Hash temp2;
/* Make sure there are no uncommited DROPs */
assert( sqliteHashFirst(&db->tblDrop)==0 || sqlite_malloc_failed );
assert( sqliteHashFirst(&db->idxDrop)==0 || sqlite_malloc_failed );
assert( sqliteHashFirst(&db->trigDrop)==0 || sqlite_malloc_failed );
temp1 = db->tblHash;
temp2 = db->trigHash;
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashClear(&db->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
Trigger * pTrigger = sqliteHashData(pElem);
Table *pTab = sqliteFindTable(db, pTrigger->table);
assert(pTab);
if( pTab->isTemp && preserveTemps ){
sqliteHashInsert(&db->trigHash, pTrigger->name, strlen(pTrigger->name),
pTrigger);
}else{
sqliteDeleteTrigger(pTrigger);
}
}
sqliteHashClear(&temp2);
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
if( preserveTemps && pTab->isTemp ){
Index *pIdx;
int nName = strlen(pTab->zName);
Table *pOld = sqliteHashInsert(&db->tblHash, pTab->zName, nName+1, pTab);
if( pOld!=0 ){
assert( pOld==pTab ); /* Malloc failed on the HashInsert */
sqliteDeleteTable(db, pOld);
continue;
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int n = strlen(pIdx->zName)+1;
Index *pOldIdx;
pOldIdx = sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx);
if( pOld ){
assert( pOldIdx==pIdx );
sqliteUnlinkAndDeleteIndex(db, pOldIdx);
}
}
}else{
sqliteDeleteTable(db, pTab);
}
}
sqliteHashClear(&temp1);
db->flags &= ~SQLITE_Initialized;
}
/* /*
** Return the ROWID of the most recent insert ** Return the ROWID of the most recent insert
*/ */
@@ -467,8 +343,7 @@ void sqlite_close(sqlite *db){
if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; } if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
db->magic = SQLITE_MAGIC_CLOSED; db->magic = SQLITE_MAGIC_CLOSED;
sqliteBtreeClose(db->pBe); sqliteBtreeClose(db->pBe);
sqliteRollbackInternalChanges(db); sqliteResetInternalSchema(db);
clearHashTable(db, 0);
if( db->pBeTemp ){ if( db->pBeTemp ){
sqliteBtreeClose(db->pBeTemp); sqliteBtreeClose(db->pBeTemp);
} }
@@ -638,11 +513,11 @@ int sqlite_exec(
sqliteBtreeRollback(db->pBe); sqliteBtreeRollback(db->pBe);
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp); if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
db->flags &= ~SQLITE_InTrans; db->flags &= ~SQLITE_InTrans;
clearHashTable(db, 0); sqliteResetInternalSchema(db);
} }
sqliteStrRealloc(pzErrMsg); sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){ if( sParse.rc==SQLITE_SCHEMA ){
clearHashTable(db, 1); sqliteResetInternalSchema(db);
} }
db->recursionDepth--; db->recursionDepth--;
if( sqliteSafetyOff(db) ) goto exec_misuse; if( sqliteSafetyOff(db) ) goto exec_misuse;

View File

@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** numeric codes for all of the tokens.
** **
** @(#) $Id: parse.y,v 1.74 2002/06/17 17:07:20 drh Exp $ ** @(#) $Id: parse.y,v 1.75 2002/06/25 01:09:12 drh Exp $
*/ */
%token_prefix TK_ %token_prefix TK_
%token_type {Token} %token_type {Token}
@@ -65,9 +65,9 @@ input ::= cmdlist.
cmdlist ::= ecmd. cmdlist ::= ecmd.
cmdlist ::= cmdlist ecmd. cmdlist ::= cmdlist ecmd.
ecmd ::= explain cmd SEMI. {sqliteExec(pParse);} ecmd ::= explain cmd SEMI. {sqliteExec(pParse);}
ecmd ::= cmd SEMI. {sqliteExec(pParse);}
ecmd ::= SEMI. ecmd ::= SEMI.
explain ::= EXPLAIN. {pParse->explain = 1;} explain ::= EXPLAIN. { sqliteBeginParse(pParse, 1); }
explain ::= . { sqliteBeginParse(pParse, 0); }
///////////////////// Begin and end transactions. //////////////////////////// ///////////////////// Begin and end transactions. ////////////////////////////
// //
@@ -87,8 +87,8 @@ create_table ::= CREATE(X) temp(T) TABLE ids(Y). {
sqliteStartTable(pParse,&X,&Y,T); sqliteStartTable(pParse,&X,&Y,T);
} }
%type temp {int} %type temp {int}
temp(A) ::= TEMP. {A = 1;} temp(A) ::= TEMP. {A = pParse->isTemp || !pParse->initFlag;}
temp(A) ::= . {A = 0;} temp(A) ::= . {A = pParse->isTemp;}
create_table_args ::= LP columnlist conslist_opt RP(X). { create_table_args ::= LP columnlist conslist_opt RP(X). {
sqliteEndTable(pParse,&X,0); sqliteEndTable(pParse,&X,0);
} }

View File

@@ -12,7 +12,7 @@
** This file contains code to implement the "sqlite" command line ** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases. ** utility for accessing SQLite databases.
** **
** $Id: shell.c,v 1.57 2002/05/21 13:02:24 drh Exp $ ** $Id: shell.c,v 1.58 2002/06/25 01:09:12 drh Exp $
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -660,8 +660,11 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
sqlite_exec_printf(db, sqlite_exec_printf(db,
"SELECT name FROM sqlite_master " "SELECT name FROM sqlite_master "
"WHERE type='index' AND tbl_name LIKE '%q' " "WHERE type='index' AND tbl_name LIKE '%q' "
"ORDER BY name", "UNION ALL "
callback, &data, &zErrMsg, azArg[1] "SELECT name FROM sqlite_temp_master "
"WHERE type='index' AND tbl_name LIKE '%q' "
"ORDER BY 1",
callback, &data, &zErrMsg, azArg[1], azArg[1]
); );
if( zErrMsg ){ if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg); fprintf(stderr,"Error: %s\n", zErrMsg);
@@ -796,18 +799,35 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
new_colv[0] = "sql"; new_colv[0] = "sql";
new_colv[1] = 0; new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv); callback(&data, 1, new_argv, new_colv);
}else if( sqliteStrICmp(azArg[1],"sqlite_temp_master")==0 ){
char *new_argv[2], *new_colv[2];
new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
")";
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
}else{ }else{
sqlite_exec_printf(db, sqlite_exec_printf(db,
"SELECT sql FROM sqlite_master " "SELECT sql FROM "
" (SELECT * FROM sqlite_master UNION ALL"
" SELECT * FROM sqlite_temp_master) "
"WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL " "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL "
"ORDER BY type DESC, name", "ORDER BY substr(type,2,1), name",
callback, &data, &zErrMsg, azArg[1]); callback, &data, &zErrMsg, azArg[1]);
} }
}else{ }else{
sqlite_exec(db, sqlite_exec(db,
"SELECT sql FROM sqlite_master " "SELECT sql FROM "
" (SELECT * FROM sqlite_master UNION ALL"
" SELECT * FROM sqlite_temp_master) "
"WHERE type!='meta' AND sql NOTNULL " "WHERE type!='meta' AND sql NOTNULL "
"ORDER BY tbl_name, type DESC, name", "ORDER BY substr(type,2,1), name",
callback, &data, &zErrMsg callback, &data, &zErrMsg
); );
} }
@@ -846,15 +866,21 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
rc = sqlite_get_table(db, rc = sqlite_get_table(db,
"SELECT name FROM sqlite_master " "SELECT name FROM sqlite_master "
"WHERE type IN ('table','view') " "WHERE type IN ('table','view') "
"ORDER BY name", "UNION ALL "
"SELECT name FROM sqlite_temp_master "
"WHERE type IN ('table','view') "
"ORDER BY 1",
&azResult, &nRow, 0, &zErrMsg &azResult, &nRow, 0, &zErrMsg
); );
}else{ }else{
rc = sqlite_get_table_printf(db, rc = sqlite_get_table_printf(db,
"SELECT name FROM sqlite_master " "SELECT name FROM sqlite_master "
"WHERE type IN ('table','view') AND name LIKE '%%%q%%' " "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
"ORDER BY name", "UNION ALL "
&azResult, &nRow, 0, &zErrMsg, azArg[1] "SELECT name FROM sqlite_temp_master "
"WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
"ORDER BY 1",
&azResult, &nRow, 0, &zErrMsg, azArg[1], azArg[1]
); );
} }
if( zErrMsg ){ if( zErrMsg ){

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.130 2002/06/24 22:01:58 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.131 2002/06/25 01:09:12 drh Exp $
*/ */
#include "sqlite.h" #include "sqlite.h"
#include "hash.h" #include "hash.h"
@@ -146,6 +146,7 @@ extern int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */
** user tables and indices. ** user tables and indices.
*/ */
#define MASTER_NAME "sqlite_master" #define MASTER_NAME "sqlite_master"
#define TEMP_MASTER_NAME "sqlite_temp_master"
/* /*
** A convenience macro that returns the number of elements in ** A convenience macro that returns the number of elements in
@@ -202,8 +203,7 @@ struct sqlite {
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
Hash tblHash; /* All tables indexed by name */ Hash tblHash; /* All tables indexed by name */
Hash idxHash; /* All (named) indices indexed by name */ Hash idxHash; /* All (named) indices indexed by name */
Hash tblDrop; /* Uncommitted DROP TABLEs */ Hash trigHash; /* All triggers indexed by name */
Hash idxDrop; /* Uncommitted DROP INDEXs */
Hash aFunc; /* All functions that can be in SQL exprs */ Hash aFunc; /* All functions that can be in SQL exprs */
int lastRowid; /* ROWID of most recent insert */ int lastRowid; /* ROWID of most recent insert */
int priorNewRowid; /* Last randomly generated ROWID */ int priorNewRowid; /* Last randomly generated ROWID */
@@ -211,9 +211,6 @@ struct sqlite {
int magic; /* Magic number for detect library misuse */ int magic; /* Magic number for detect library misuse */
int nChange; /* Number of rows changed */ int nChange; /* Number of rows changed */
int recursionDepth; /* Number of nested calls to sqlite_exec() */ int recursionDepth; /* Number of nested calls to sqlite_exec() */
Hash trigHash; /* All triggers indexed by name */
Hash trigDrop; /* Uncommited dropped triggers */
}; };
/* /*
@@ -325,12 +322,10 @@ struct Table {
int tnum; /* Root BTree node for this table (see note above) */ int tnum; /* Root BTree node for this table (see note above) */
Select *pSelect; /* NULL for tables. Points to definition if a view. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */
u8 readOnly; /* True if this table should not be written by the user */ u8 readOnly; /* True if this table should not be written by the user */
u8 isCommit; /* True if creation of this table has been committed */
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */ u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 isTransient; /* True if automatically deleted when VDBE finishes */
u8 hasPrimKey; /* True if there exists a primary key */ u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
Trigger *pTrigger; /* List of SQL triggers on this table */ Trigger *pTrigger; /* List of SQL triggers on this table */
}; };
@@ -386,8 +381,6 @@ struct Index {
Table *pTable; /* The SQL table being indexed */ Table *pTable; /* The SQL table being indexed */
int tnum; /* Page containing root of this index in database file */ int tnum; /* Page containing root of this index in database file */
u8 isUnique; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 isUnique; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 isCommit; /* True if creation of this index has been committed */
u8 isDropped; /* True if a DROP INDEX has executed on this index */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
Index *pNext; /* The next index associated with the same table */ Index *pNext; /* The next index associated with the same table */
}; };
@@ -648,10 +641,15 @@ struct Parse {
Token sLastToken; /* The last token parsed */ Token sLastToken; /* The last token parsed */
Table *pNewTable; /* A table being constructed by CREATE TABLE */ Table *pNewTable; /* A table being constructed by CREATE TABLE */
Vdbe *pVdbe; /* An engine for executing database bytecode */ Vdbe *pVdbe; /* An engine for executing database bytecode */
int colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */ u8 colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */
int explain; /* True if the EXPLAIN flag is found on the query */ u8 explain; /* True if the EXPLAIN flag is found on the query */
int initFlag; /* True if reparsing CREATE TABLEs */ u8 initFlag; /* True if reparsing CREATE TABLEs */
int nameClash; /* A permanent table name clashes with temp table name */ u8 nameClash; /* A permanent table name clashes with temp table name */
u8 useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace
** other than after an OP_Transaction */
u8 isTemp; /* True if parsing temporary tables */
int newTnum; /* Table number to use when reparsing CREATE TABLEs */ int newTnum; /* Table number to use when reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */ int nTab; /* Number of previously allocated VDBE cursors */
@@ -659,10 +657,6 @@ struct Parse {
int nSet; /* Number of sets used so far */ int nSet; /* Number of sets used so far */
int nAgg; /* Number of aggregate expressions */ int nAgg; /* Number of aggregate expressions */
AggExpr *aAgg; /* An array of aggregate expressions */ AggExpr *aAgg; /* An array of aggregate expressions */
int useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
int schemaVerified; /* True if an OP_VerifySchema has been coded someplace
** other than after an OP_Transaction */
TriggerStack *trigStack; TriggerStack *trigStack;
}; };
@@ -711,7 +705,6 @@ struct Trigger {
TriggerStep *step_list; /* Link list of trigger program steps */ TriggerStep *step_list; /* Link list of trigger program steps */
char *strings; /* pointer to allocation of Token strings */ char *strings; /* pointer to allocation of Token strings */
Trigger *pNext; /* Next trigger associated with the table */ Trigger *pNext; /* Next trigger associated with the table */
int isCommit; /* Set to TRUE once the trigger has been committed */
}; };
/* /*
@@ -847,9 +840,13 @@ void sqliteExprDelete(Expr*);
ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*); ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
void sqliteExprListDelete(ExprList*); void sqliteExprListDelete(ExprList*);
void sqlitePragma(Parse*,Token*,Token*,int); void sqlitePragma(Parse*,Token*,Token*,int);
void sqliteCommitInternalChanges(sqlite*); void sqliteResetInternalSchema(sqlite*);
int sqliteInit(sqlite*, char**);
void sqliteBeginParse(Parse*,int);
void sqliteRollbackInternalChanges(sqlite*); void sqliteRollbackInternalChanges(sqlite*);
void sqliteCommitInternalChanges(sqlite*);
Table *sqliteResultSetOfSelect(Parse*,char*,Select*); Table *sqliteResultSetOfSelect(Parse*,char*,Select*);
void sqliteOpenMasterTable(Vdbe *v, int);
void sqliteStartTable(Parse*,Token*,Token*,int); void sqliteStartTable(Parse*,Token*,Token*,int);
void sqliteAddColumn(Parse*,Token*); void sqliteAddColumn(Parse*,Token*);
void sqliteAddNotNull(Parse*, int); void sqliteAddNotNull(Parse*, int);
@@ -929,7 +926,7 @@ void sqliteRegisterBuiltinFunctions(sqlite*);
int sqliteSafetyOn(sqlite*); int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*); int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*); int sqliteSafetyCheck(sqlite*);
void sqliteChangeCookie(sqlite *); void sqliteChangeCookie(sqlite*, Vdbe*);
void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*, void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*,
int, Expr*, TriggerStep*, char const*,int); int, Expr*, TriggerStep*, char const*,int);
void sqliteDropTrigger(Parse*, Token*, int); void sqliteDropTrigger(Parse*, Token*, int);

View File

@@ -70,6 +70,12 @@ void sqliteCreateTrigger(
pParse->nErr++; pParse->nErr++;
goto trigger_cleanup; goto trigger_cleanup;
} }
if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){
sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
"table: " TEMP_MASTER_NAME, 0);
pParse->nErr++;
goto trigger_cleanup;
}
if( tab->pSelect && tr_tm != TK_INSTEAD ){ if( tab->pSelect && tr_tm != TK_INSTEAD ){
sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1, sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
@@ -100,7 +106,6 @@ void sqliteCreateTrigger(
nt->pColumns = pColumns; nt->pColumns = pColumns;
nt->foreach = foreach; nt->foreach = foreach;
nt->step_list = pStepList; nt->step_list = pStepList;
nt->isCommit = 0;
offset = (int)(nt->strings - zData); offset = (int)(nt->strings - zData);
sqliteExprMoveStrings(nt->pWhen, offset); sqliteExprMoveStrings(nt->pWhen, offset);
@@ -119,20 +124,16 @@ void sqliteCreateTrigger(
/* if we are not initializing, and this trigger is not on a TEMP table, /* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry ** build the sqlite_master entry
*/ */
if( !pParse->initFlag && !tab->isTemp ){ if( !pParse->initFlag ){
static VdbeOp insertTrig[] = { static VdbeOp insertTrig[] = {
{ OP_OpenWrite, 0, 2, MASTER_NAME},
{ OP_NewRecno, 0, 0, 0 }, { OP_NewRecno, 0, 0, 0 },
{ OP_String, 0, 0, "trigger" }, { OP_String, 0, 0, "trigger" },
{ OP_String, 0, 0, 0 }, /* 3: trigger name */ { OP_String, 0, 0, 0 }, /* 2: trigger name */
{ OP_String, 0, 0, 0 }, /* 4: table name */ { OP_String, 0, 0, 0 }, /* 3: table name */
{ OP_Integer, 0, 0, 0 }, { OP_Integer, 0, 0, 0 },
{ OP_String, 0, 0, 0 }, /* 6: SQL */ { OP_String, 0, 0, 0 }, /* 5: SQL */
{ OP_MakeRecord, 5, 0, 0 }, { OP_MakeRecord, 5, 0, 0 },
{ OP_PutIntKey, 0, 0, 0 }, { OP_PutIntKey, 0, 0, 0 },
{ OP_Integer, 0, 0, 0 }, /* 9: Next cookie */
{ OP_SetCookie, 0, 0, 0 },
{ OP_Close, 0, 0, 0 },
}; };
int addr; int addr;
Vdbe *v; Vdbe *v;
@@ -141,12 +142,17 @@ void sqliteCreateTrigger(
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto trigger_cleanup; if( v==0 ) goto trigger_cleanup;
sqliteBeginWriteOperation(pParse, 0); sqliteBeginWriteOperation(pParse, 0);
sqliteOpenMasterTable(v, tab->isTemp);
addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqliteVdbeChangeP3(v, addr+3, nt->name, 0); sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
sqliteVdbeChangeP3(v, addr+4, nt->table, 0); P3_STATIC);
sqliteVdbeChangeP3(v, addr+6, nt->strings, 0); sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
sqliteChangeCookie(pParse->db); sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
sqliteVdbeChangeP1(v, addr+9, pParse->db->next_cookie); sqliteVdbeChangeP3(v, addr+5, nt->strings, 0);
if( !tab->isTemp ){
sqliteChangeCookie(pParse->db, v);
}
sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
@@ -312,11 +318,11 @@ void sqliteDeleteTrigger(Trigger *pTrigger){
* table. This is so that the trigger can be restored into the database schema * table. This is so that the trigger can be restored into the database schema
* if the transaction is rolled back. * if the transaction is rolled back.
*/ */
void sqliteDropTrigger(Parse *pParse, Token *pName, int nested) void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
{
char *zName; char *zName;
Trigger *pTrigger; Trigger *pTrigger;
Table *pTable; Table *pTable;
Vdbe *v;
zName = sqliteStrNDup(pName->z, pName->n); zName = sqliteStrNDup(pName->z, pName->n);
@@ -330,12 +336,9 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
} }
/* /*
* If this is not an "explain", do the following: * If this is not an "explain", then delete the trigger structure.
* 1. Remove the trigger from its associated table structure
* 2. Move the trigger from the trigHash hash to trigDrop
*/ */
if( !pParse->explain ){ if( !pParse->explain ){
/* 1 */
pTable = sqliteFindTable(pParse->db, pTrigger->table); pTable = sqliteFindTable(pParse->db, pTrigger->table);
assert(pTable); assert(pTable);
if( pTable->pTrigger == pTrigger ){ if( pTable->pTrigger == pTrigger ){
@@ -351,47 +354,35 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
} }
assert(cc); assert(cc);
} }
sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
/* 2 */ sqliteDeleteTrigger(pTrigger);
sqliteHashInsert(&(pParse->db->trigHash), zName,
pName->n + 1, NULL);
sqliteHashInsert(&(pParse->db->trigDrop), pTrigger->name,
pName->n + 1, pTrigger);
} }
/* Unless this is a trigger on a TEMP TABLE, generate code to destroy the /* Generate code to destroy the database record of the trigger.
* database record of the trigger */ */
if( !pTable->isTemp ){ if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
int base; int base;
static VdbeOp dropTrigger[] = { static VdbeOp dropTrigger[] = {
{ OP_OpenWrite, 0, 2, MASTER_NAME}, { OP_Rewind, 0, ADDR(8), 0},
{ OP_Rewind, 0, ADDR(9), 0}, { OP_String, 0, 0, 0}, /* 1 */
{ OP_String, 0, 0, 0}, /* 2 */
{ OP_MemStore, 1, 1, 0}, { OP_MemStore, 1, 1, 0},
{ OP_MemLoad, 1, 0, 0}, /* 4 */ { OP_MemLoad, 1, 0, 0}, /* 3 */
{ OP_Column, 0, 1, 0}, { OP_Column, 0, 1, 0},
{ OP_Ne, 0, ADDR(8), 0}, { OP_Ne, 0, ADDR(7), 0},
{ OP_Delete, 0, 0, 0}, { OP_Delete, 0, 0, 0},
{ OP_Next, 0, ADDR(4), 0}, /* 8 */ { OP_Next, 0, ADDR(3), 0}, /* 7 */
{ OP_Integer, 0, 0, 0}, /* 9 */
{ OP_SetCookie, 0, 0, 0},
{ OP_Close, 0, 0, 0},
}; };
if( !nested ){
sqliteBeginWriteOperation(pParse, 0); sqliteBeginWriteOperation(pParse, 0);
sqliteOpenMasterTable(v, pTable->isTemp);
base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqliteVdbeChangeP3(v, base+1, zName, 0);
if( !pTable->isTemp ){
sqliteChangeCookie(pParse->db, v);
} }
base = sqliteVdbeAddOpList(pParse->pVdbe, sqliteVdbeAddOp(v, OP_Close, 0, 0);
ArraySize(dropTrigger), dropTrigger);
sqliteVdbeChangeP3(pParse->pVdbe, base+2, zName, 0);
if( !nested ){
sqliteChangeCookie(pParse->db);
}
sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie);
if( !nested ){
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
}
sqliteFree(zName); sqliteFree(zName);
} }

View File

@@ -30,7 +30,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** a program instruction by instruction.
** **
** $Id: vdbe.c,v 1.158 2002/06/21 23:01:50 drh Exp $ ** $Id: vdbe.c,v 1.159 2002/06/25 01:09:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -3021,7 +3021,6 @@ case OP_Open: {
case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break; case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break;
case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break; case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break;
} }
assert( pX!=0 );
if( p2<=0 ){ if( p2<=0 ){
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
Integerify(p, tos); Integerify(p, tos);
@@ -3047,6 +3046,7 @@ case OP_Open: {
cleanupCursor(&p->aCsr[i]); cleanupCursor(&p->aCsr[i]);
memset(&p->aCsr[i], 0, sizeof(Cursor)); memset(&p->aCsr[i], 0, sizeof(Cursor));
p->aCsr[i].nullRow = 1; p->aCsr[i].nullRow = 1;
if( pX==0 ) break;
do{ do{
rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor); rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
switch( rc ){ switch( rc ){

View File

@@ -13,7 +13,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines ** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions. ** to generate VDBE code to evaluate expressions.
** **
** $Id: where.c,v 1.55 2002/06/24 22:01:59 drh Exp $ ** $Id: where.c,v 1.56 2002/06/25 01:09:12 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -479,7 +479,6 @@ WhereInfo *sqliteWhereBegin(
int inMask = 0; /* Index columns covered by an x IN .. term */ int inMask = 0; /* Index columns covered by an x IN .. term */
int nEq, m, score; int nEq, m, score;
if( pIdx->isDropped ) continue; /* Ignore dropped indices */
if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */ if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
for(j=0; j<nExpr; j++){ for(j=0; j<nExpr; j++){
if( aExpr[j].idxLeft==idx if( aExpr[j].idxLeft==idx

View File

@@ -12,7 +12,7 @@
# #
# This file implements tests for temporary tables and indices. # This file implements tests for temporary tables and indices.
# #
# $Id: temptable.test,v 1.6 2002/06/06 23:16:06 drh Exp $ # $Id: temptable.test,v 1.7 2002/06/25 01:09:12 drh Exp $
set testdir [file dirname $argv0] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -115,7 +115,6 @@ do_test temptable-2.5 {
lappend r $msg lappend r $msg
} {1 {no such table: t2}} } {1 {no such table: t2}}
# Make sure indices on temporary tables are also temporary. # Make sure indices on temporary tables are also temporary.
# #
do_test temptable-3.1 { do_test temptable-3.1 {

View File

@@ -160,4 +160,4 @@ catchsql { DROP TABLE tbl; }
catchsql { DROP TABLE tbl2; } catchsql { DROP TABLE tbl2; }
catchsql { DROP VIEW tbl_view; } catchsql { DROP VIEW tbl_view; }
finish_test

View File

@@ -25,6 +25,19 @@ proc chng {date desc} {
puts "<DD><P><UL>$desc</UL></P></DD>" puts "<DD><P><UL>$desc</UL></P></DD>"
} }
chng {2002 Jun 24 (2.5.2)} {
<li>Added the new <b>SQLITE_TEMP_MASTER</b> table which records the schema
for temporary tables in the same way that <b>SQLITE_MASTER</b> does for
persistent tables.</li>
<li>Added an optimization to UNION ALL</li>
<li>Fixed a bug in the processing of LEFT OUTER JOIN</li>
<li>The LIMIT clause now works on subselects</li>
<li>ORDER BY works on subselects</li>
<li>There is a new TypeOf() function used to determine if an expression
is numeric or text.</li>
<li>Autoincrement now works for INSERT from a SELECT.</li>
}
chng {2002 Jun 19 (2.5.1)} { chng {2002 Jun 19 (2.5.1)} {
<li>The query optimizer now attempts to implement the ORDER BY clause <li>The query optimizer now attempts to implement the ORDER BY clause
using an index. Sorting is still used if not suitable index is using an index. Sorting is still used if not suitable index is

View File

@@ -1,7 +1,7 @@
# #
# Run this script to generated a faq.html output file # Run this script to generated a faq.html output file
# #
set rcsid {$Id: faq.tcl,v 1.10 2002/04/25 00:21:50 drh Exp $} set rcsid {$Id: faq.tcl,v 1.11 2002/06/25 01:09:13 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@@ -276,8 +276,19 @@ ORDER BY name;
using UPDATE, INSERT, or DELETE. The table is automatically updated by using UPDATE, INSERT, or DELETE. The table is automatically updated by
CREATE TABLE, CREATE INDEX, DROP TABLE, and DROP INDEX commands.</p> CREATE TABLE, CREATE INDEX, DROP TABLE, and DROP INDEX commands.</p>
<p>Temporary tables do not appear in the SQLITE_MASTER table. At this time <p>Temporary tables do not appear in the SQLITE_MASTER table. Temporary
there is no way to get a listing of temporary tables and indices.</p> tables and their indices and triggers occur in another special table
named SQLITE_TEMP_MASTER. SQLITE_TEMP_MASTER works just like SQLITE_MASTER
except that it is only visible to the application that created the
temporary tables. To get a list of all tables, both permanent and
temporary, one can use a command similar to the following:
</blockquote><pre>
SELECT name FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE type='table'
ORDER BY name
</pre></blockquote>
} }
faq { faq {

View File

@@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: lang.tcl,v 1.40 2002/06/12 22:33:54 drh Exp $} set rcsid {$Id: lang.tcl,v 1.41 2002/06/25 01:09:13 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@@ -236,7 +236,9 @@ See the section titled
<p>The exact text <p>The exact text
of each CREATE INDEX statement is stored in the <b>sqlite_master</b> of each CREATE INDEX statement is stored in the <b>sqlite_master</b>
table. Everytime the database is opened, all CREATE INDEX statements or <b>sqlite_temp_master</b> table, depending on whether the table
being indexed is temporary. Everytime the database is opened,
all CREATE INDEX statements
are read from the <b>sqlite_master</b> table and used to regenerate are read from the <b>sqlite_master</b> table and used to regenerate
SQLite's internal representation of the index layout.</p> SQLite's internal representation of the index layout.</p>
} }
@@ -275,8 +277,8 @@ puts {
<p>A CREATE TABLE statement is basically the keywords "CREATE TABLE" <p>A CREATE TABLE statement is basically the keywords "CREATE TABLE"
followed by the name of a new table and a parenthesized list of column followed by the name of a new table and a parenthesized list of column
definitions and constraints. The table name can be either an identifier definitions and constraints. The table name can be either an identifier
or a string. The only reserved table name is "<b>sqlite_master</b>" which or a string. Tables names that begin with "<b>sqlite_</b>" are reserved
is the name of the table that records the database schema.</p> for use by the engine.</p>
<p>Each column definition is the name of the column followed by the <p>Each column definition is the name of the column followed by the
datatype for that column, then one or more optional column constraints. datatype for that column, then one or more optional column constraints.
@@ -343,6 +345,8 @@ SQLite's internal representation of the table layout.
If the original command was a CREATE TABLE AS then then an equivalent If the original command was a CREATE TABLE AS then then an equivalent
CREATE TABLE statement is synthesized and store in <b>sqlite_master</b> CREATE TABLE statement is synthesized and store in <b>sqlite_master</b>
in place of the original command. in place of the original command.
The text of CREATE TEMPORARY TABLE statements are stored in the
<b>sqlite_temp_master</b> table.
</p> </p>
} }
Section {CREATE TRIGGER} createtrigger Section {CREATE TRIGGER} createtrigger

View File

@@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: sqlite.tcl,v 1.16 2001/11/24 13:23:05 drh Exp $} set rcsid {$Id: sqlite.tcl,v 1.17 2002/06/25 01:09:13 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@@ -117,6 +117,14 @@ indices from the database. You can not make manual changes
to the sqlite_master table. to the sqlite_master table.
</p> </p>
<p>
The schema for TEMPORARY tables is not stored in the "sqlite_master" table
since TEMPORARY tables are not visible to applications other than the
application that created the table. The schema for TEMPORARY tables
is stored in another special table named "sqlite_temp_master". The
"sqlite_temp_master" table is temporary itself.
</p>
<h2>Special commands to sqlite</h2> <h2>Special commands to sqlite</h2>
<p> <p>
@@ -335,8 +343,8 @@ puts {
executing the following query:</p> executing the following query:</p>
<blockquote><pre> <blockquote><pre>
SELECT name FROM sqlite_master SELECT name FROM sqlite_master WHERE type='table'
WHERE type='table' UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table'
ORDER BY name; ORDER BY name;
</pre></blockquote> </pre></blockquote>
@@ -376,7 +384,9 @@ puts {
list mode, then entering the following query:</p> list mode, then entering the following query:</p>
<blockquote><pre> <blockquote><pre>
SELECT sql FROM sqlite_master SELECT sql FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE type!='meta' WHERE type!='meta'
ORDER BY tbl_name, type DESC, name ORDER BY tbl_name, type DESC, name
</pre></blockquote> </pre></blockquote>
@@ -385,7 +395,9 @@ ORDER BY tbl_name, type DESC, name
want the schema for a single table, the query looks like this:</p> want the schema for a single table, the query looks like this:</p>
<blockquote><pre> <blockquote><pre>
SELECT sql FROM sqlite_master SELECT sql FROM
(SELECT * FROM sqlite_master UNION ALL
SELECT * FROM sqlite_temp_master)
WHERE tbl_name LIKE '%s' AND type!='meta' WHERE tbl_name LIKE '%s' AND type!='meta'
ORDER BY type DESC, name ORDER BY type DESC, name
</pre></blockquote> </pre></blockquote>