mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +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:
40
manifest
40
manifest
@@ -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)
|
||||
D 2002-06-24T22:01:58
|
||||
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-25T01:09:11
|
||||
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
|
||||
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
|
||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||
F VERSION 9a1a4bc4ca9e44b3ccf4c764cb670aae41b078a0
|
||||
F VERSION 2ca20d4461e9496d4ae27191e7273a12369ff17c
|
||||
F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d
|
||||
F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588
|
||||
F config.sub f14b07d544ca26b5d698259045136b783e18fc7f
|
||||
@@ -20,7 +20,7 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c 6aaa67d7eab70c2531dc13e5d9eb87e626c0b4d7
|
||||
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
||||
F src/build.c 95eac6ce4ae2871388d49066c78dd0657ce40a1f
|
||||
F src/build.c 846eb3ee0e160e691766108a7136e196f8f8231b
|
||||
F src/delete.c 44c45460b1e03033756e35adc6d569ffbf30b725
|
||||
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
||||
F src/expr.c cb50a72c491954d58be2f182366e45a1e252bf2e
|
||||
@@ -28,20 +28,20 @@ F src/func.c 5eae8227a8b0d276a64d51a3880a6e86f238fedf
|
||||
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||
F src/insert.c 4bb40ed9dbaba4516fc2abbcff3f08d5687b073c
|
||||
F src/main.c 0e922ecfe4ce58c3e5c49f111d86003607d2114b
|
||||
F src/main.c 43d5f4e38108129a13cf42c59087e6e20b3596ad
|
||||
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
|
||||
F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc
|
||||
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
||||
F src/pager.c 1e41053c949cea1f09d8dafada5fe8f90785e650
|
||||
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
||||
F src/parse.y 2285d8967d7334d52a2188089e5a881d73ba56f6
|
||||
F src/parse.y c75ea2580de675bcb80ff8b7c10c0a15e02a21ab
|
||||
F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c f7d74f20f5ecc335fbccba367eda727b9d6fb299
|
||||
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
|
||||
F src/shell.c 7b9d98ef3976ff5e44c18620dd17d32af83fbdd6
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 7c8882e352cb70818cfaf9bdb5b1b3bee81ef144
|
||||
F src/sqliteInt.h d3c1448890ba65e6be381b50b7e7ce7fca142322
|
||||
F src/sqliteInt.h 3d1d86cb9ea4f06e49af855267478e3661abcd1b
|
||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
|
||||
F src/test1.c 5cc4f0bbf38237e04e1b2077e285b41bfb4c4cbf
|
||||
@@ -49,12 +49,12 @@ F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730
|
||||
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
||||
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
||||
F src/tokenize.c ac4c46f190346b87da54ec3e2605d160af80c619
|
||||
F src/trigger.c 21342af6ac031fece39c8fc6eabd1739ca5327c1
|
||||
F src/trigger.c d88ab4d68d68955c217b38fb6717e090fbbf54a4
|
||||
F src/update.c 6f6a4dcd71cd9ff730b7f12c83de5498cde4924f
|
||||
F src/util.c 876b259f9186e84b944b72e793dd3dad50e63e95
|
||||
F src/vdbe.c 774f79483ce809b27c3bdb02afd7295cc3c7acd4
|
||||
F src/vdbe.c 0b1ad7c3cbc638d1f73725bbc4e667c3ee8f7081
|
||||
F src/vdbe.h a9292f2b5fcecef924fa255fb74609e9cbc776c2
|
||||
F src/where.c 259d7fb77191b13718c271926b7c14afbbe7346b
|
||||
F src/where.c 913fa33977c8dddfc259d9b2c38504b475738c43
|
||||
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
|
||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
|
||||
@@ -98,12 +98,12 @@ F test/subselect.test f3bc1dcbddddcea08d818fcff75228ad3464fc83
|
||||
F test/table.test 42511f98a3e9bbee62913e3ae1774777faa23d35
|
||||
F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
|
||||
F test/tclsqlite.test 79deeffd7cd637ca0f06c5dbbf2f44d272079533
|
||||
F test/temptable.test ae58694c0fdd2d0b781508b64adc5aee3416aeed
|
||||
F test/temptable.test 9ed7ec0288f887e132de66d90c428ad109105f67
|
||||
F test/tester.tcl dc1b56bd628b487e4d75bfd1e7480b5ed8810ac6
|
||||
F test/trans.test ae0b9a82d5d34122c3a3108781eb8d078091ccee
|
||||
F test/trigger1.test bb63749fa8a395a60541100607d86381604b7194
|
||||
F test/trigger2.test c12759a0d7ba6488d9d24c96a1352ddee995c1ab
|
||||
F test/trigger3.test b4aca721ba92956c7fa16bb0158254f3c1b73efa
|
||||
F test/trigger3.test 7dfe798d7e72c13720394685fe353112e3f31adf
|
||||
F test/unique.test 572aa791327c1e8d797932263e9d67f176cfdb44
|
||||
F test/update.test a0aa0bf83e6fad8407d0e4ad25ebb09b513f5bf4
|
||||
F test/vacuum.test 059871b312eb910bbe49dafde1d01490cc2c6bbe
|
||||
@@ -122,22 +122,22 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||
F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
|
||||
F www/c_interface.tcl 58cf4d128dcae08d91d0011c6d4d11de323f470f
|
||||
F www/changes.tcl 31a8fec4f078a60b7de5f19859297f375e9ec8da
|
||||
F www/changes.tcl 08de0b1b50d3651ac3bd6b0d44c9ebe0072b55b3
|
||||
F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
|
||||
F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
|
||||
F www/download.tcl 29aa6679ca29621d10613f60ebbbda18f4b91c49
|
||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||
F www/faq.tcl 45bdb18b75ac3aa1befec42985fb892413aac0bb
|
||||
F www/faq.tcl 06e95342a101fde3ce59dbf128233a178502587e
|
||||
F www/formatchng.tcl f604cde78f1ac9c29420136109b04407408e876e
|
||||
F www/index.tcl d0c52fbf031d0a3ee6d9d77aa669d5a4b24b6130
|
||||
F www/lang.tcl cf22bf18dbd6bec3b7d0b00ad998dd1f88193ea2
|
||||
F www/lang.tcl 8c3d0bda030f110c754b5edbad75eddf5dbe2ed1
|
||||
F www/mingw.tcl f1c7c0a7f53387dd9bb4f8c7e8571b7561510ebc
|
||||
F www/opcode.tcl bdec8ef9f100dbd87bbef8976c54b88e43fd8ccc
|
||||
F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||
F www/sqlite.tcl ac64065d0c5e2de0f71238d55b2c14bb5c5c194c
|
||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P d861489e1f7dffd1105c271fe8597f73e5b1703c
|
||||
R d718b83d86c9331bc69c93f673a44be9
|
||||
P 8b6574cfa86daaae910f8f3ee3c4723a21fb9e53
|
||||
R c96fc24249eaf46c6e1d5e0a79495140
|
||||
U drh
|
||||
Z b9b5d0f63e47642b79ff89410dec8a4b
|
||||
Z 421a17002ac6e743396eaf770c048af4
|
||||
|
@@ -1 +1 @@
|
||||
8b6574cfa86daaae910f8f3ee3c4723a21fb9e53
|
||||
9c1432bf7485258e485bd652e3acdaeabbfe8850
|
496
src/build.c
496
src/build.c
@@ -25,11 +25,29 @@
|
||||
** ROLLBACK
|
||||
** 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 <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
|
||||
** parsed and we want to execute the VDBE code to implement
|
||||
@@ -48,6 +66,7 @@ void sqliteExec(Parse *pParse){
|
||||
if( pParse->explain ){
|
||||
rc = sqliteVdbeList(pParse->pVdbe, pParse->xCallback, pParse->pArg,
|
||||
&pParse->zErrMsg);
|
||||
db->next_cookie = db->schema_cookie;
|
||||
}else{
|
||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||
sqliteVdbeTrace(pParse->pVdbe, trace);
|
||||
@@ -70,7 +89,8 @@ void sqliteExec(Parse *pParse){
|
||||
** of that table. Return NULL if not found.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -80,7 +100,8 @@ Table *sqliteFindTable(sqlite *db, const char *zName){
|
||||
** Return NULL if not found.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -99,7 +120,6 @@ static void sqliteDeleteIndex(sqlite *db, Index *p){
|
||||
if( pOld!=0 && pOld!=p ){
|
||||
sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld);
|
||||
}
|
||||
sqliteHashInsert(&db->idxDrop, p, 0, 0);
|
||||
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
|
||||
** been committed. If this index was never committed, then just
|
||||
** delete it.
|
||||
**
|
||||
** 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.
|
||||
** Erase all schema information from the in-memory hash tables of
|
||||
** database connection. This routine is called to reclaim memory
|
||||
** before the connection closes. It is also called during a rollback
|
||||
** if there were schema changes during the transaction.
|
||||
*/
|
||||
static void sqlitePendingDropIndex(sqlite *db, Index *p){
|
||||
if( !p->isCommit ){
|
||||
sqliteUnlinkAndDeleteIndex(db, p);
|
||||
}else{
|
||||
Index *pOld;
|
||||
pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0);
|
||||
if( pOld!=0 && pOld!=p ){
|
||||
sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld);
|
||||
}
|
||||
sqliteHashInsert(&db->idxDrop, p, 0, p);
|
||||
p->isDropped = 1;
|
||||
void sqliteResetInternalSchema(sqlite *db){
|
||||
HashElem *pElem;
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
|
||||
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);
|
||||
sqliteDeleteTrigger(pTrigger);
|
||||
}
|
||||
sqliteHashClear(&temp2);
|
||||
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 );
|
||||
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0);
|
||||
assert( pOld==0 || pOld==p );
|
||||
sqliteHashInsert(&db->tblDrop, p, 0, 0);
|
||||
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.
|
||||
**
|
||||
@@ -376,13 +245,31 @@ char *sqliteTableNameFromToken(Token *pName){
|
||||
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
|
||||
** the first of several action routines that get called in response
|
||||
** to a CREATE TABLE statement. In particular, this routine is called
|
||||
** after seeing tokens "CREATE" and "TABLE" and the table name. The
|
||||
** 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.
|
||||
**
|
||||
** 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 ){
|
||||
int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->pBeTemp);
|
||||
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);
|
||||
pParse->nErr++;
|
||||
return;
|
||||
@@ -482,13 +369,12 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
|
||||
if( !isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
|
||||
sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
}
|
||||
sqliteOpenMasterTable(v, isTemp);
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 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
|
||||
** 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 ){
|
||||
db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
|
||||
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 ";
|
||||
zEnd = "\n)";
|
||||
}
|
||||
n += 25 + 6*p->nCol;
|
||||
n += 35 + 6*p->nCol;
|
||||
zStmt = sqliteMalloc( n );
|
||||
if( zStmt==0 ) return 0;
|
||||
assert( !p->isTemp );
|
||||
strcpy(zStmt, "CREATE TABLE ");
|
||||
strcpy(zStmt, p->isTemp ? "CREATE TEMP TABLE " : "CREATE TABLE ");
|
||||
k = strlen(zStmt);
|
||||
identPut(zStmt, &k, p->zName);
|
||||
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
|
||||
** "sqlite_master" table on the disk. So do not write to the disk
|
||||
** again. Extract the root page number for the table from the
|
||||
** pParse->newTnum field. (The page number should have been put
|
||||
** there by the sqliteOpenCb routine.)
|
||||
** "sqlite_master" or "sqlite_temp_master" table on the disk.
|
||||
** So do not write to the disk again. Extract the root page number
|
||||
** for the table from the pParse->newTnum field. (The page number
|
||||
** should have been put there by the sqliteOpenCb routine.)
|
||||
*/
|
||||
if( pParse->initFlag ){
|
||||
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
|
||||
** for the new table entry should already be on the stack.
|
||||
**
|
||||
** If this is a TEMPORARY table, then just create the table. Do not
|
||||
** make an entry in SQLITE_MASTER.
|
||||
** If this is a TEMPORARY table, write the entry into the auxiliary
|
||||
** file instead of into the main database file.
|
||||
*/
|
||||
if( !pParse->initFlag ){
|
||||
int n;
|
||||
@@ -898,37 +785,35 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
|
||||
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
||||
}
|
||||
p->tnum = 0;
|
||||
if( !p->isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( p->pSelect==0 ){
|
||||
sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
|
||||
}else{
|
||||
sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 4, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pSelect ){
|
||||
char *z = createTableStmt(p);
|
||||
n = z ? strlen(z) : 0;
|
||||
sqliteVdbeChangeP3(v, -1, z, n);
|
||||
sqliteFree(z);
|
||||
}else{
|
||||
assert( pEnd!=0 );
|
||||
n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
|
||||
sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
sqliteChangeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( p->pSelect==0 ){
|
||||
sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
|
||||
}else{
|
||||
sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_Dup, 4, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pSelect ){
|
||||
char *z = createTableStmt(p);
|
||||
n = z ? strlen(z) : 0;
|
||||
sqliteVdbeChangeP3(v, -1, z, n);
|
||||
sqliteFree(z);
|
||||
}else{
|
||||
assert( pEnd!=0 );
|
||||
n = Addr(pEnd->z) - Addr(pParse->sFirstToken.z) + 1;
|
||||
sqliteVdbeChangeP3(v, -1, pParse->sFirstToken.z, n);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
if( !p->isTemp ){
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
if( pSelect ){
|
||||
int op = p->isTemp ? OP_OpenWrAux : OP_OpenWrite;
|
||||
sqliteVdbeAddOp(v, op, 1, 0);
|
||||
@@ -1151,34 +1036,38 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropTable[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Rewind, 0, ADDR(8), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 1 */
|
||||
{ OP_MemStore, 1, 1, 0},
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 4 */
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 3 */
|
||||
{ OP_Column, 0, 2, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_Ne, 0, ADDR(7), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(4), 0}, /* 8 */
|
||||
{ OP_Integer, 0, 0, 0}, /* 9 */
|
||||
{ OP_SetCookie, 0, 0, 0},
|
||||
{ OP_Close, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(3), 0}, /* 7 */
|
||||
};
|
||||
Index *pIdx;
|
||||
Trigger *pTrigger;
|
||||
sqliteBeginWriteOperation(pParse, 0);
|
||||
sqliteOpenMasterTable(v, pTable->isTemp);
|
||||
/* Drop all triggers associated with the table being dropped */
|
||||
while( pTable->pTrigger ){
|
||||
pTrigger = pTable->pTrigger;
|
||||
while( pTrigger ){
|
||||
Token tt;
|
||||
tt.z = pTable->pTrigger->name;
|
||||
tt.n = strlen(pTable->pTrigger->name);
|
||||
sqliteDropTrigger(pParse, &tt, 1);
|
||||
if( pParse->explain ){
|
||||
pTrigger = pTrigger->pNext;
|
||||
}else{
|
||||
pTrigger = pTable->pTrigger;
|
||||
}
|
||||
}
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||
sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
|
||||
if( !pTable->isTemp ){
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
|
||||
sqliteChangeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+9, db->next_cookie);
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
if( !isView ){
|
||||
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp);
|
||||
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
@@ -1188,16 +1077,13 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
/* Move the table (and all its indices) to the pending DROP queue.
|
||||
** 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.
|
||||
/* Delete the in-memory description of the table.
|
||||
**
|
||||
** Exception: if the SQL statement began with the EXPLAIN keyword,
|
||||
** then no changes should be made.
|
||||
*/
|
||||
if( !pParse->explain ){
|
||||
sqlitePendingDropTable(db, pTable);
|
||||
sqliteUnlinkAndDeleteTable(db, pTable);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
sqliteViewResetAll(db);
|
||||
@@ -1264,7 +1150,7 @@ void sqliteCreateIndex(
|
||||
** Since its table has been suppressed, we need to also suppress the
|
||||
** index.
|
||||
*/
|
||||
if( pParse->initFlag && pTab->isTemp ){
|
||||
if( pParse->initFlag && !pParse->isTemp && pTab->isTemp ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
|
||||
@@ -1429,40 +1315,33 @@ void sqliteCreateIndex(
|
||||
if( v==0 ) goto exit_create_index;
|
||||
if( pTable!=0 ){
|
||||
sqliteBeginWriteOperation(pParse, 0);
|
||||
if( !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_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
sqliteOpenMasterTable(v, isTemp);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp);
|
||||
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER);
|
||||
pIndex->tnum = 0;
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
if( isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0);
|
||||
}else{
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
|
||||
}
|
||||
}
|
||||
if( !isTemp ){
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pStart && pEnd ){
|
||||
n = Addr(pEnd->z) - Addr(pStart->z) + 1;
|
||||
sqliteVdbeChangeP3(v, addr, pStart->z, n);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
|
||||
if( pStart && pEnd ){
|
||||
n = Addr(pEnd->z) - Addr(pStart->z) + 1;
|
||||
sqliteVdbeChangeP3(v, addr, pStart->z, n);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
|
||||
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum);
|
||||
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
@@ -1481,11 +1360,9 @@ void sqliteCreateIndex(
|
||||
}
|
||||
if( pTable!=0 ){
|
||||
if( !isTemp ){
|
||||
sqliteChangeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
}
|
||||
@@ -1523,42 +1400,35 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
static VdbeOp dropIndex[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, ADDR(10),0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 1 */
|
||||
{ OP_MemStore, 1, 1, 0},
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 4 */
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 3 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Eq, 0, ADDR(9), 0},
|
||||
{ OP_Next, 0, ADDR(4), 0},
|
||||
{ OP_Goto, 0, ADDR(10),0},
|
||||
{ OP_Delete, 0, 0, 0}, /* 9 */
|
||||
{ OP_Integer, 0, 0, 0}, /* 10 */
|
||||
{ OP_SetCookie, 0, 0, 0},
|
||||
{ OP_Close, 0, 0, 0},
|
||||
{ OP_Eq, 0, ADDR(8), 0},
|
||||
{ OP_Next, 0, ADDR(3), 0},
|
||||
{ OP_Goto, 0, ADDR(9), 0},
|
||||
{ OP_Delete, 0, 0, 0}, /* 8 */
|
||||
};
|
||||
int base;
|
||||
Table *pTab = pIndex->pTable;
|
||||
|
||||
sqliteBeginWriteOperation(pParse, 0);
|
||||
sqliteOpenMasterTable(v, pTab->isTemp);
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
|
||||
if( !pTab->isTemp ){
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
|
||||
sqliteChangeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+10, db->next_cookie);
|
||||
sqliteChangeCookie(db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
/* Move the index onto the pending DROP queue. Or, if the index was
|
||||
** 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.
|
||||
/* Delete the in-memory description of this index.
|
||||
*/
|
||||
if( !pParse->explain ){
|
||||
sqlitePendingDropIndex(db, pIndex);
|
||||
sqliteUnlinkAndDeleteIndex(db, pIndex);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
}
|
||||
|
365
src/main.c
365
src/main.c
@@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.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 "os.h"
|
||||
@@ -30,6 +30,7 @@
|
||||
** argv[1] = table or index name or meta statement type.
|
||||
** argv[2] = root page number for table or index. NULL for meta.
|
||||
** 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){
|
||||
@@ -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
|
||||
** when attempting to initialize from a corrupt database file. */
|
||||
|
||||
assert( argc==4 );
|
||||
assert( argc==5 );
|
||||
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 'i':
|
||||
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));
|
||||
sParse.db = db;
|
||||
sParse.initFlag = 1;
|
||||
sParse.isTemp = argv[4][0] - '0';
|
||||
sParse.newTnum = atoi(argv[2]);
|
||||
sqliteRunParser(&sParse, argv[3], 0);
|
||||
}else{
|
||||
@@ -120,15 +101,29 @@ int sqliteInitCallback(void *pDb, int argc, char **argv, char **azColName){
|
||||
** has the sqlite_master table locked) than another attempt
|
||||
** is made the first time the database is accessed.
|
||||
*/
|
||||
static int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
Vdbe *vdbe;
|
||||
int sqliteInit(sqlite *db, char **pzErrMsg){
|
||||
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
|
||||
*/
|
||||
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"
|
||||
" 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
|
||||
** structure holding the tables and indexes of the database.
|
||||
** The database contains a special table named "sqlite_master"
|
||||
** defined as follows:
|
||||
/* The following SQL will read the schema from the master tables.
|
||||
** The first version works with SQLite file formats 2 or greater.
|
||||
** The second version is for format 1 files.
|
||||
**
|
||||
** CREATE TABLE sqlite_master (
|
||||
** type text, -- Either "table" or "index" or "meta"
|
||||
** name text, -- Name of table or index
|
||||
** tbl_name text, -- Associated table
|
||||
** rootpage integer, -- The integer page number of root page
|
||||
** sql text -- The CREATE statement for this object
|
||||
** );
|
||||
**
|
||||
** The sqlite_master table contains a single entry for each table
|
||||
** 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.
|
||||
** Beginning with file format 2, the rowid for new table entries
|
||||
** (including entries in sqlite_master) is an increasing integer.
|
||||
** So for file format 2 and later, we can play back sqlite_master
|
||||
** and all the CREATE statements will appear in the right order.
|
||||
** But with file format 1, table entries were random and so we
|
||||
** 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
|
||||
** not exist then.)
|
||||
*/
|
||||
static VdbeOp initProg[] = {
|
||||
/* Send the file format to the callback routine
|
||||
*/
|
||||
{ OP_Open, 0, 2, 0},
|
||||
{ OP_String, 0, 0, "file-format"},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_String, 0, 0, 0},
|
||||
{ OP_ReadCookie, 0, 1, 0},
|
||||
{ OP_Callback, 4, 0, 0},
|
||||
static char init_script[] =
|
||||
"SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
|
||||
"UNION ALL "
|
||||
"SELECT type, name, rootpage, sql, 0 FROM sqlite_master";
|
||||
static char older_init_script[] =
|
||||
"SELECT type, name, rootpage, sql, 1 FROM sqlite_temp_master "
|
||||
"UNION ALL "
|
||||
"SELECT type, name, rootpage, sql, 0 FROM sqlite_master "
|
||||
"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
|
||||
*/
|
||||
{ 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.
|
||||
/* Construct the schema tables: sqlite_master and sqlite_temp_master
|
||||
*/
|
||||
vdbe = sqliteVdbeCreate(db);
|
||||
if( vdbe==0 ){
|
||||
sqliteSetString(pzErrMsg, "out of memory", 0);
|
||||
return SQLITE_NOMEM;
|
||||
azArg[0] = "table";
|
||||
azArg[1] = MASTER_NAME;
|
||||
azArg[2] = "2";
|
||||
azArg[3] = master_schema;
|
||||
azArg[4] = "0";
|
||||
azArg[5] = 0;
|
||||
sqliteInitCallback(db, 5, azArg, 0);
|
||||
pTab = sqliteFindTable(db, MASTER_NAME);
|
||||
if( pTab ){
|
||||
pTab->readOnly = 1;
|
||||
}
|
||||
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 ){
|
||||
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;
|
||||
}
|
||||
if( rc==SQLITE_OK && db->file_format>2 ){
|
||||
}else if( db->file_format>2 ){
|
||||
sqliteBtreeCloseCursor(curMain);
|
||||
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.
|
||||
/* Read the schema information out of the schema tables
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
Table *pTab;
|
||||
char *azArg[6];
|
||||
azArg[0] = "table";
|
||||
azArg[1] = MASTER_NAME;
|
||||
azArg[2] = "2";
|
||||
azArg[3] = master_schema;
|
||||
azArg[4] = 0;
|
||||
sqliteInitCallback(db, 4, azArg, 0);
|
||||
pTab = sqliteFindTable(db, MASTER_NAME);
|
||||
if( pTab ){
|
||||
pTab->readOnly = 1;
|
||||
}
|
||||
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;
|
||||
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->idxHash, 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);
|
||||
sqliteRegisterBuiltinFunctions(db);
|
||||
db->onError = OE_Default;
|
||||
@@ -377,74 +321,6 @@ no_mem_on_open:
|
||||
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
|
||||
*/
|
||||
@@ -467,8 +343,7 @@ void sqlite_close(sqlite *db){
|
||||
if( sqliteSafetyCheck(db) || sqliteSafetyOn(db) ){ return; }
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
sqliteBtreeClose(db->pBe);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
clearHashTable(db, 0);
|
||||
sqliteResetInternalSchema(db);
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeClose(db->pBeTemp);
|
||||
}
|
||||
@@ -638,11 +513,11 @@ int sqlite_exec(
|
||||
sqliteBtreeRollback(db->pBe);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
clearHashTable(db, 0);
|
||||
sqliteResetInternalSchema(db);
|
||||
}
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
clearHashTable(db, 1);
|
||||
sqliteResetInternalSchema(db);
|
||||
}
|
||||
db->recursionDepth--;
|
||||
if( sqliteSafetyOff(db) ) goto exec_misuse;
|
||||
|
10
src/parse.y
10
src/parse.y
@@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** 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_type {Token}
|
||||
@@ -65,9 +65,9 @@ input ::= cmdlist.
|
||||
cmdlist ::= ecmd.
|
||||
cmdlist ::= cmdlist ecmd.
|
||||
ecmd ::= explain cmd SEMI. {sqliteExec(pParse);}
|
||||
ecmd ::= cmd SEMI. {sqliteExec(pParse);}
|
||||
ecmd ::= SEMI.
|
||||
explain ::= EXPLAIN. {pParse->explain = 1;}
|
||||
explain ::= EXPLAIN. { sqliteBeginParse(pParse, 1); }
|
||||
explain ::= . { sqliteBeginParse(pParse, 0); }
|
||||
|
||||
///////////////////// Begin and end transactions. ////////////////////////////
|
||||
//
|
||||
@@ -87,8 +87,8 @@ create_table ::= CREATE(X) temp(T) TABLE ids(Y). {
|
||||
sqliteStartTable(pParse,&X,&Y,T);
|
||||
}
|
||||
%type temp {int}
|
||||
temp(A) ::= TEMP. {A = 1;}
|
||||
temp(A) ::= . {A = 0;}
|
||||
temp(A) ::= TEMP. {A = pParse->isTemp || !pParse->initFlag;}
|
||||
temp(A) ::= . {A = pParse->isTemp;}
|
||||
create_table_args ::= LP columnlist conslist_opt RP(X). {
|
||||
sqliteEndTable(pParse,&X,0);
|
||||
}
|
||||
|
46
src/shell.c
46
src/shell.c
@@ -12,7 +12,7 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** 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 <string.h>
|
||||
@@ -660,8 +660,11 @@ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
|
||||
sqlite_exec_printf(db,
|
||||
"SELECT name FROM sqlite_master "
|
||||
"WHERE type='index' AND tbl_name LIKE '%q' "
|
||||
"ORDER BY name",
|
||||
callback, &data, &zErrMsg, azArg[1]
|
||||
"UNION ALL "
|
||||
"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 ){
|
||||
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[1] = 0;
|
||||
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{
|
||||
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 "
|
||||
"ORDER BY type DESC, name",
|
||||
"ORDER BY substr(type,2,1), name",
|
||||
callback, &data, &zErrMsg, azArg[1]);
|
||||
}
|
||||
}else{
|
||||
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 "
|
||||
"ORDER BY tbl_name, type DESC, name",
|
||||
"ORDER BY substr(type,2,1), name",
|
||||
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,
|
||||
"SELECT name FROM sqlite_master "
|
||||
"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
|
||||
);
|
||||
}else{
|
||||
rc = sqlite_get_table_printf(db,
|
||||
"SELECT name FROM sqlite_master "
|
||||
"WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
|
||||
"ORDER BY name",
|
||||
&azResult, &nRow, 0, &zErrMsg, azArg[1]
|
||||
"UNION ALL "
|
||||
"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 ){
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** 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 "hash.h"
|
||||
@@ -145,7 +145,8 @@ extern int sqlite_iMallocFail; /* Fail sqliteMalloc() after this many calls */
|
||||
** is a special table that holds the names and attributes of all
|
||||
** 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
|
||||
@@ -202,8 +203,7 @@ struct sqlite {
|
||||
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
|
||||
Hash tblHash; /* All tables indexed by name */
|
||||
Hash idxHash; /* All (named) indices indexed by name */
|
||||
Hash tblDrop; /* Uncommitted DROP TABLEs */
|
||||
Hash idxDrop; /* Uncommitted DROP INDEXs */
|
||||
Hash trigHash; /* All triggers indexed by name */
|
||||
Hash aFunc; /* All functions that can be in SQL exprs */
|
||||
int lastRowid; /* ROWID of most recent insert */
|
||||
int priorNewRowid; /* Last randomly generated ROWID */
|
||||
@@ -211,9 +211,6 @@ struct sqlite {
|
||||
int magic; /* Magic number for detect library misuse */
|
||||
int nChange; /* Number of rows changed */
|
||||
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) */
|
||||
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 isCommit; /* True if creation of this table has been committed */
|
||||
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
|
||||
u8 isTransient; /* True if automatically deleted when VDBE finishes */
|
||||
u8 hasPrimKey; /* True if there exists a primary key */
|
||||
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
||||
|
||||
Trigger *pTrigger; /* List of SQL triggers on this table */
|
||||
};
|
||||
|
||||
@@ -386,8 +381,6 @@ struct Index {
|
||||
Table *pTable; /* The SQL table being indexed */
|
||||
int tnum; /* Page containing root of this index in database file */
|
||||
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 */
|
||||
Index *pNext; /* The next index associated with the same table */
|
||||
};
|
||||
@@ -648,10 +641,15 @@ struct Parse {
|
||||
Token sLastToken; /* The last token parsed */
|
||||
Table *pNewTable; /* A table being constructed by CREATE TABLE */
|
||||
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
||||
int colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */
|
||||
int explain; /* True if the EXPLAIN flag is found on the query */
|
||||
int initFlag; /* True if reparsing CREATE TABLEs */
|
||||
int nameClash; /* A permanent table name clashes with temp table name */
|
||||
u8 colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
u8 initFlag; /* True if reparsing CREATE TABLEs */
|
||||
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 nErr; /* Number of errors seen */
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
@@ -659,10 +657,6 @@ struct Parse {
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nAgg; /* Number 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;
|
||||
};
|
||||
|
||||
@@ -711,7 +705,6 @@ struct Trigger {
|
||||
TriggerStep *step_list; /* Link list of trigger program steps */
|
||||
char *strings; /* pointer to allocation of Token strings */
|
||||
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*);
|
||||
void sqliteExprListDelete(ExprList*);
|
||||
void sqlitePragma(Parse*,Token*,Token*,int);
|
||||
void sqliteCommitInternalChanges(sqlite*);
|
||||
void sqliteResetInternalSchema(sqlite*);
|
||||
int sqliteInit(sqlite*, char**);
|
||||
void sqliteBeginParse(Parse*,int);
|
||||
void sqliteRollbackInternalChanges(sqlite*);
|
||||
void sqliteCommitInternalChanges(sqlite*);
|
||||
Table *sqliteResultSetOfSelect(Parse*,char*,Select*);
|
||||
void sqliteOpenMasterTable(Vdbe *v, int);
|
||||
void sqliteStartTable(Parse*,Token*,Token*,int);
|
||||
void sqliteAddColumn(Parse*,Token*);
|
||||
void sqliteAddNotNull(Parse*, int);
|
||||
@@ -929,7 +926,7 @@ void sqliteRegisterBuiltinFunctions(sqlite*);
|
||||
int sqliteSafetyOn(sqlite*);
|
||||
int sqliteSafetyOff(sqlite*);
|
||||
int sqliteSafetyCheck(sqlite*);
|
||||
void sqliteChangeCookie(sqlite *);
|
||||
void sqliteChangeCookie(sqlite*, Vdbe*);
|
||||
void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*,
|
||||
int, Expr*, TriggerStep*, char const*,int);
|
||||
void sqliteDropTrigger(Parse*, Token*, int);
|
||||
|
@@ -70,6 +70,12 @@ void sqliteCreateTrigger(
|
||||
pParse->nErr++;
|
||||
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 ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
|
||||
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
|
||||
@@ -100,7 +106,6 @@ void sqliteCreateTrigger(
|
||||
nt->pColumns = pColumns;
|
||||
nt->foreach = foreach;
|
||||
nt->step_list = pStepList;
|
||||
nt->isCommit = 0;
|
||||
offset = (int)(nt->strings - zData);
|
||||
sqliteExprMoveStrings(nt->pWhen, offset);
|
||||
|
||||
@@ -119,20 +124,16 @@ void sqliteCreateTrigger(
|
||||
/* if we are not initializing, and this trigger is not on a TEMP table,
|
||||
** build the sqlite_master entry
|
||||
*/
|
||||
if( !pParse->initFlag && !tab->isTemp ){
|
||||
if( !pParse->initFlag ){
|
||||
static VdbeOp insertTrig[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_NewRecno, 0, 0, 0 },
|
||||
{ OP_String, 0, 0, "trigger" },
|
||||
{ OP_String, 0, 0, 0 }, /* 3: trigger name */
|
||||
{ OP_String, 0, 0, 0 }, /* 4: table name */
|
||||
{ OP_String, 0, 0, 0 }, /* 2: trigger name */
|
||||
{ OP_String, 0, 0, 0 }, /* 3: table name */
|
||||
{ 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_PutIntKey, 0, 0, 0 },
|
||||
{ OP_Integer, 0, 0, 0 }, /* 9: Next cookie */
|
||||
{ OP_SetCookie, 0, 0, 0 },
|
||||
{ OP_Close, 0, 0, 0 },
|
||||
};
|
||||
int addr;
|
||||
Vdbe *v;
|
||||
@@ -141,12 +142,17 @@ void sqliteCreateTrigger(
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto trigger_cleanup;
|
||||
sqliteBeginWriteOperation(pParse, 0);
|
||||
sqliteOpenMasterTable(v, tab->isTemp);
|
||||
addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqliteVdbeChangeP3(v, addr+3, nt->name, 0);
|
||||
sqliteVdbeChangeP3(v, addr+4, nt->table, 0);
|
||||
sqliteVdbeChangeP3(v, addr+6, nt->strings, 0);
|
||||
sqliteChangeCookie(pParse->db);
|
||||
sqliteVdbeChangeP1(v, addr+9, pParse->db->next_cookie);
|
||||
sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
|
||||
P3_STATIC);
|
||||
sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
|
||||
sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
|
||||
sqliteVdbeChangeP3(v, addr+5, nt->strings, 0);
|
||||
if( !tab->isTemp ){
|
||||
sqliteChangeCookie(pParse->db, v);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
@@ -312,11 +318,11 @@ void sqliteDeleteTrigger(Trigger *pTrigger){
|
||||
* table. This is so that the trigger can be restored into the database schema
|
||||
* if the transaction is rolled back.
|
||||
*/
|
||||
void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
|
||||
{
|
||||
void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
|
||||
char *zName;
|
||||
Trigger *pTrigger;
|
||||
Table *pTable;
|
||||
Vdbe *v;
|
||||
|
||||
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:
|
||||
* 1. Remove the trigger from its associated table structure
|
||||
* 2. Move the trigger from the trigHash hash to trigDrop
|
||||
* If this is not an "explain", then delete the trigger structure.
|
||||
*/
|
||||
if( !pParse->explain ){
|
||||
/* 1 */
|
||||
pTable = sqliteFindTable(pParse->db, pTrigger->table);
|
||||
assert(pTable);
|
||||
if( pTable->pTrigger == pTrigger ){
|
||||
@@ -351,46 +354,34 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested)
|
||||
}
|
||||
assert(cc);
|
||||
}
|
||||
|
||||
/* 2 */
|
||||
sqliteHashInsert(&(pParse->db->trigHash), zName,
|
||||
pName->n + 1, NULL);
|
||||
sqliteHashInsert(&(pParse->db->trigDrop), pTrigger->name,
|
||||
pName->n + 1, pTrigger);
|
||||
sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
|
||||
sqliteDeleteTrigger(pTrigger);
|
||||
}
|
||||
|
||||
/* Unless this is a trigger on a TEMP TABLE, generate code to destroy the
|
||||
* database record of the trigger */
|
||||
if( !pTable->isTemp ){
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static VdbeOp dropTrigger[] = {
|
||||
{ OP_OpenWrite, 0, 2, MASTER_NAME},
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 2 */
|
||||
{ OP_Rewind, 0, ADDR(8), 0},
|
||||
{ OP_String, 0, 0, 0}, /* 1 */
|
||||
{ OP_MemStore, 1, 1, 0},
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 4 */
|
||||
{ OP_MemLoad, 1, 0, 0}, /* 3 */
|
||||
{ OP_Column, 0, 1, 0},
|
||||
{ OP_Ne, 0, ADDR(8), 0},
|
||||
{ OP_Ne, 0, ADDR(7), 0},
|
||||
{ OP_Delete, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(4), 0}, /* 8 */
|
||||
{ OP_Integer, 0, 0, 0}, /* 9 */
|
||||
{ OP_SetCookie, 0, 0, 0},
|
||||
{ OP_Close, 0, 0, 0},
|
||||
{ OP_Next, 0, ADDR(3), 0}, /* 7 */
|
||||
};
|
||||
|
||||
if( !nested ){
|
||||
sqliteBeginWriteOperation(pParse, 0);
|
||||
}
|
||||
base = sqliteVdbeAddOpList(pParse->pVdbe,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0);
|
||||
sqliteEndWriteOperation(pParse);
|
||||
}
|
||||
|
||||
sqliteFree(zName);
|
||||
|
@@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.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 <ctype.h>
|
||||
@@ -3021,7 +3021,6 @@ case OP_Open: {
|
||||
case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break;
|
||||
case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break;
|
||||
}
|
||||
assert( pX!=0 );
|
||||
if( p2<=0 ){
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
Integerify(p, tos);
|
||||
@@ -3047,6 +3046,7 @@ case OP_Open: {
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
memset(&p->aCsr[i], 0, sizeof(Cursor));
|
||||
p->aCsr[i].nullRow = 1;
|
||||
if( pX==0 ) break;
|
||||
do{
|
||||
rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
|
||||
switch( rc ){
|
||||
|
@@ -13,7 +13,7 @@
|
||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||
** to generate VDBE code to evaluate expressions.
|
||||
**
|
||||
** $Id: where.c,v 1.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"
|
||||
|
||||
@@ -479,7 +479,6 @@ WhereInfo *sqliteWhereBegin(
|
||||
int inMask = 0; /* Index columns covered by an x IN .. term */
|
||||
int nEq, m, score;
|
||||
|
||||
if( pIdx->isDropped ) continue; /* Ignore dropped indices */
|
||||
if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
|
||||
for(j=0; j<nExpr; j++){
|
||||
if( aExpr[j].idxLeft==idx
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#
|
||||
# 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]
|
||||
source $testdir/tester.tcl
|
||||
@@ -115,7 +115,6 @@ do_test temptable-2.5 {
|
||||
lappend r $msg
|
||||
} {1 {no such table: t2}}
|
||||
|
||||
|
||||
# Make sure indices on temporary tables are also temporary.
|
||||
#
|
||||
do_test temptable-3.1 {
|
||||
|
@@ -160,4 +160,4 @@ catchsql { DROP TABLE tbl; }
|
||||
catchsql { DROP TABLE tbl2; }
|
||||
catchsql { DROP VIEW tbl_view; }
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -25,6 +25,19 @@ proc chng {date desc} {
|
||||
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)} {
|
||||
<li>The query optimizer now attempts to implement the ORDER BY clause
|
||||
using an index. Sorting is still used if not suitable index is
|
||||
|
17
www/faq.tcl
17
www/faq.tcl
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# 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>
|
||||
<head>
|
||||
@@ -276,8 +276,19 @@ ORDER BY name;
|
||||
using UPDATE, INSERT, or DELETE. The table is automatically updated by
|
||||
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
|
||||
there is no way to get a listing of temporary tables and indices.</p>
|
||||
<p>Temporary tables do not appear in the SQLITE_MASTER table. Temporary
|
||||
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 {
|
||||
|
12
www/lang.tcl
12
www/lang.tcl
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# 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>
|
||||
<head>
|
||||
@@ -236,7 +236,9 @@ See the section titled
|
||||
|
||||
<p>The exact text
|
||||
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
|
||||
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"
|
||||
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
|
||||
or a string. The only reserved table name is "<b>sqlite_master</b>" which
|
||||
is the name of the table that records the database schema.</p>
|
||||
or a string. Tables names that begin with "<b>sqlite_</b>" are reserved
|
||||
for use by the engine.</p>
|
||||
|
||||
<p>Each column definition is the name of the column followed by the
|
||||
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
|
||||
CREATE TABLE statement is synthesized and store in <b>sqlite_master</b>
|
||||
in place of the original command.
|
||||
The text of CREATE TEMPORARY TABLE statements are stored in the
|
||||
<b>sqlite_temp_master</b> table.
|
||||
</p>
|
||||
}
|
||||
Section {CREATE TRIGGER} createtrigger
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# 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>
|
||||
<head>
|
||||
@@ -117,6 +117,14 @@ indices from the database. You can not make manual changes
|
||||
to the sqlite_master table.
|
||||
</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>
|
||||
|
||||
<p>
|
||||
@@ -335,8 +343,8 @@ puts {
|
||||
executing the following query:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
SELECT name FROM sqlite_master
|
||||
WHERE type='table'
|
||||
SELECT name FROM sqlite_master WHERE type='table'
|
||||
UNION ALL SELECT name FROM sqlite_temp_master WHERE type='table'
|
||||
ORDER BY name;
|
||||
</pre></blockquote>
|
||||
|
||||
@@ -376,7 +384,9 @@ puts {
|
||||
list mode, then entering the following query:</p>
|
||||
|
||||
<blockquote><pre>
|
||||
SELECT sql FROM sqlite_master
|
||||
SELECT sql FROM
|
||||
(SELECT * FROM sqlite_master UNION ALL
|
||||
SELECT * FROM sqlite_temp_master)
|
||||
WHERE type!='meta'
|
||||
ORDER BY tbl_name, type DESC, name
|
||||
</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>
|
||||
|
||||
<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'
|
||||
ORDER BY type DESC, name
|
||||
</pre></blockquote>
|
||||
|
Reference in New Issue
Block a user