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)
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

View File

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

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 ){

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 ){

View File

@@ -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

View File

@@ -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 {

View File

@@ -158,6 +158,6 @@ do_test trig-raise-7.3 {
catchsql { DROP TABLE tbl; }
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>"
}
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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>