Support for temporary tables added. Still need more testing. (CVS 279)

FossilOrigin-Name: 9368c62e4097aae3081a325962c1dec167fd253d
This commit is contained in:
drh 2001-10-08 13:22:32 +00:00
parent 382c0247c7
commit f57b339988
18 changed files with 684 additions and 311 deletions

View File

@ -1,5 +1,5 @@
C Adding\stable\scolumn\squery\scapability\sto\ssupport\sODBC.\s(CVS\s278) C Support\sfor\stemporary\stables\sadded.\s\sStill\sneed\smore\stesting.\s(CVS\s279)
D 2001-10-06T16:33:02 D 2001-10-08T13:22:32
F Makefile.in 98d4627cb364537e4c3a29ee806171f3abf5211a F Makefile.in 98d4627cb364537e4c3a29ee806171f3abf5211a
F Makefile.template 1e54087c0390c4ce0bb5be43e14ba028283751e6 F Makefile.template 1e54087c0390c4ce0bb5be43e14ba028283751e6
F README 93d2977cc5c6595c448de16bdefc312b9d401533 F README 93d2977cc5c6595c448de16bdefc312b9d401533
@ -21,37 +21,37 @@ F publish.sh 502b907fa9e0214309406fa5f520b3d3c14f9c1d
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d
F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7 F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
F src/build.c 7cbac6c3a5d35e56f8d57bb6b07fba5e8a41c806 F src/build.c 55ca22cd7af59b7f8895c601ed9cf006adf50f05
F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2 F src/delete.c 93c9d5e160395020a25d59371625db74c97c7c4d
F src/expr.c 2f68829d983ec3f92eeb8b89ce4b9e5704169a80 F src/expr.c 2f68829d983ec3f92eeb8b89ce4b9e5704169a80
F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1 F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
F src/insert.c 01dd6ddee901a8a55c9b05a62b30023ec43de9ce F src/insert.c a48ba850461b203fb8dbc7add83fc6b6a9cf47f3
F src/main.c 6db4ba7ed8f1c1866b04eab6d0f9b46455e152c8 F src/main.c 87b2fca50cbe8b400e1443b2c73693e18d9911cb
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
F src/os.c 45376582c41dc8829330816d56b8e9e6cd1b7972 F src/os.c d3f435d89241e06d4230b6f79a4e9d49102eb0a4
F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d
F src/pager.c 592c16b06ad07c715240e382028e29b0e83378be F src/pager.c 3445bd7c18cbfdffd8d6d1077f0b2bdf788da4fe
F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
F src/parse.y fcd3452640cf5ae2304ce430668112e0da07745a F src/parse.y e88f1efe096a1a01c9076099fe1d81deedfa11de
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9 F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec
F src/select.c 0ef8ca1b7de2467fe082bcb35a5ab3b5be56153c F src/select.c 0ef8ca1b7de2467fe082bcb35a5ab3b5be56153c
F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76 F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11 F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11
F src/sqliteInt.h 78b1890c4b61d35f33941cf9a2aae366b32b3dd3 F src/sqliteInt.h d75506e003b508d8e2501217648f045496813f2c
F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac
F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96 F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
F src/tokenize.c 8a2aa0443f8bb1a02d021604377e2783e8e45f42 F src/tokenize.c 5bd2dd048d77f4c683f0551a73d2fa5e964b53f0
F src/update.c 0449af173b5f2f0b26e2f0e4545ee0e0429763cb F src/update.c 49a1edb1a3e44dfff3f799e00f2a3319f2393cd8
F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387 F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
F src/vdbe.c 5c865988f8b33dcb8c5282f24bde404ab5d96899 F src/vdbe.c 469c36ce2ef72a10447796dc5b5d61317e47fff2
F src/vdbe.h c543a58f52fb654c90dd31d0d0c31309f4d838de F src/vdbe.h 7eb7e9e6c58fe9430efab35e168f96cb4bd6cb45
F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87 F src/where.c b676765ad0360769173b09f46265ddec8d48367a
F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0 F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
@ -83,6 +83,7 @@ F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1 F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37 F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
F test/temptable.test 99611832cdef52a30e62b091eaf941dbc934f303
F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1 F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9 F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6 F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
@ -100,19 +101,19 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
F www/c_interface.tcl 8e8d9e66e8467c5751116c3427296bde77f474a6 F www/c_interface.tcl 8e8d9e66e8467c5751116c3427296bde77f474a6
F www/changes.tcl 8c2ecc905283cfe3221722d8e8bcb660af2297b2 F www/changes.tcl b42f68ebc6a590ab3dd4f16e389faad2a7f2d541
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60 F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
F www/index.tcl 68c815d64b35b2dcc4d4f6845827df71c6869f9f F www/index.tcl 68c815d64b35b2dcc4d4f6845827df71c6869f9f
F www/lang.tcl 33a74d727615ccbee8be7c8efd5876ce008c4b0e F www/lang.tcl 3a7900e3f80cab50f322d925e573bd9f0acd57e1
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60 F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
F www/opcode.tcl 4365ad9798872491dbd7d3071510ebe461785ac3 F www/opcode.tcl 4365ad9798872491dbd7d3071510ebe461785ac3
F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b
F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44 F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
P e4980849403a8d7bd63753c9b7f275519bd7df4f P b63b3f3684a3d584ef99f54cde76b6c483bbfef7
R 7502c066a19df2a451414aa8e23b0cac R 9a90e6e0cf1a1b0f9063fbb657761a98
U drh U drh
Z 47fec5ca7cd29a261f31f63e809cee33 Z 4e9556749f24d361b6f8c2df79fd7c4c

View File

@ -1 +1 @@
b63b3f3684a3d584ef99f54cde76b6c483bbfef7 9368c62e4097aae3081a325962c1dec167fd253d

View File

@ -25,7 +25,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.44 2001/10/06 16:33:03 drh Exp $ ** $Id: build.c,v 1.45 2001/10/08 13:22:32 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -65,7 +65,9 @@ void sqliteExec(Parse *pParse){
} }
/* /*
** Construct a new expression node and return a pointer to it. ** Construct a new expression node and return a pointer to it. Memory
** for this node is obtained from sqliteMalloc(). The calling function
** is responsible for making sure the node eventually gets freed.
*/ */
Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
Expr *pNew; Expr *pNew;
@ -131,8 +133,8 @@ void sqliteExprDelete(Expr *p){
} }
/* /*
** Locate the in-memory structure that describes the ** Locate the in-memory structure that describes
** format of a particular database table given the name ** a particular database table given the name
** of that table. Return NULL if not found. ** of that table. Return NULL if not found.
*/ */
Table *sqliteFindTable(sqlite *db, char *zName){ Table *sqliteFindTable(sqlite *db, char *zName){
@ -141,9 +143,9 @@ Table *sqliteFindTable(sqlite *db, char *zName){
} }
/* /*
** Locate the in-memory structure that describes the ** Locate the in-memory structure that describes
** format of a particular index given the name ** a particular index given the name of that index.
** of that index. Return NULL if not found. ** Return NULL if not found.
*/ */
Index *sqliteFindIndex(sqlite *db, char *zName){ Index *sqliteFindIndex(sqlite *db, char *zName){
Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1); Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
@ -155,7 +157,7 @@ Index *sqliteFindIndex(sqlite *db, char *zName){
** its memory structures. ** its memory structures.
** **
** The index is removed from the database hash table if db!=NULL. ** The index is removed from the database hash table if db!=NULL.
** But it is not unlinked from the Table that is being indexed. ** But the index is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function. ** Unlinking from the Table must be done by the calling function.
*/ */
static void sqliteDeleteIndex(sqlite *db, Index *pIndex){ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
@ -167,7 +169,7 @@ static void sqliteDeleteIndex(sqlite *db, Index *pIndex){
/* /*
** Unlink the given index from its table, then remove ** Unlink the given index from its table, then remove
** the index from the index hash table, and free its memory ** the index from the index hash table and free its memory
** structures. ** structures.
*/ */
static void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){ static void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
@ -276,7 +278,7 @@ void sqliteCommitInternalChanges(sqlite *db){
/* /*
** This routine runs when one or more CREATE TABLE, CREATE INDEX, ** This routine runs when one or more CREATE TABLE, CREATE INDEX,
** DROP TABLE, or DROP INDEX statements get rolled back. The ** DROP TABLE, or DROP INDEX statements gets rolled back. The
** additions or deletions of Table and Index structures in the ** additions or deletions of Table and Index structures in the
** internal hash tables are undone. ** internal hash tables are undone.
** **
@ -334,14 +336,19 @@ char *sqliteTableNameFromToken(Token *pName){
** the first of several action routines that get called in response ** the first of several action routines that get called in response
** to a CREATE TABLE statement. In particular, this routine is called ** to a CREATE TABLE statement. In particular, this routine is called
** after seeing tokens "CREATE" and "TABLE" and the table name. The ** after seeing tokens "CREATE" and "TABLE" and the table name. The
** pStart token is the CREATE and pName is the table name. ** 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
** CREATE and TABLE.
** **
** The new table is constructed in fields of the pParse structure. As ** The new table record is initialized and put in pParse->pNewTable.
** more of the CREATE TABLE statement is parsed, additional action ** As more of the CREATE TABLE statement is parsed, additional action
** routines are called to build up more of the table. ** routines will be called to add more information to this record.
** At the end of the CREATE TABLE statement, the sqliteEndTable() routine
** is called to complete the construction of the new table record.
*/ */
void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
Table *pTable; Table *pTable;
Index *pIdx;
char *zName; char *zName;
sqlite *db = pParse->db; sqlite *db = pParse->db;
Vdbe *v; Vdbe *v;
@ -349,15 +356,54 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
pParse->sFirstToken = *pStart; pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return; if( zName==0 ) return;
/* Before trying to create a temporary table, make sure the Btree for
** holding temporary tables is open.
*/
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 "
"file for storing temporary tables", 0);
pParse->nErr++;
return;
}
if( db->flags & SQLITE_InTrans ){
rc = sqliteBtreeBeginTrans(db->pBeTemp);
if( rc!=SQLITE_OK ){
sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on "
"the temporary datbase file", 0);
pParse->nErr++;
return;
}
}
}
/* Make sure the new table name does not collide with an existing
** index or table name. Issue an error message if it does.
**
** If we are re-reading the sqlite_master table because of a schema
** change and a new permanent table is found whose name collides with
** an existing temporary table, then ignore the new permanent table.
** We will continue parsing, but the pParse->nameClash flag will be set
** so we will know to discard the table record once parsing has finished.
*/
pTable = sqliteFindTable(db, zName); pTable = sqliteFindTable(db, zName);
if( pTable!=0 ){ if( pTable!=0 ){
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, if( pTable->isTemp && pParse->initFlag ){
" already exists", 0, 0); pParse->nameClash = 1;
sqliteFree(zName); }else{
pParse->nErr++; sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
return; " already exists", 0, 0);
sqliteFree(zName);
pParse->nErr++;
return;
}
}else{
pParse->nameClash = 0;
} }
if( sqliteFindIndex(db, zName) ){ if( (pIdx = sqliteFindIndex(db, zName))!=0 &&
(!pIdx->pTable->isTemp || !pParse->initFlag) ){
sqliteSetString(&pParse->zErrMsg, "there is already an index named ", sqliteSetString(&pParse->zErrMsg, "there is already an index named ",
zName, 0); zName, 0);
sqliteFree(zName); sqliteFree(zName);
@ -370,6 +416,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
pTable->nCol = 0; pTable->nCol = 0;
pTable->aCol = 0; pTable->aCol = 0;
pTable->pIndex = 0; pTable->pIndex = 0;
pTable->isTemp = isTemp;
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable; pParse->pNewTable = pTable;
if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
@ -378,7 +425,9 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1; pParse->schemaVerified = 1;
} }
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); if( !isTemp ){
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
}
} }
} }
@ -418,7 +467,7 @@ void sqliteAddNotNull(Parse *pParse){
int i; int i;
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1; i = p->nCol-1;
p->aCol[i].notNull = 1; if( i>=0 ) p->aCol[i].notNull = 1;
} }
/* /*
@ -437,10 +486,12 @@ void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
char *z, **pz; char *z, **pz;
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1; i = p->nCol-1;
if( i<0 ) return;
pz = &p->aCol[i].zType; pz = &p->aCol[i].zType;
n = pLast->n + ((int)pLast->z) - (int)pFirst->z; n = pLast->n + ((int)pLast->z) - (int)pFirst->z;
sqliteSetNString(pz, pFirst->z, n, 0); sqliteSetNString(pz, pFirst->z, n, 0);
z = *pz; z = *pz;
if( z==0 ) return;
for(i=j=0; z[i]; i++){ for(i=j=0; z[i]; i++){
int c = z[i]; int c = z[i];
if( isspace(c) ) continue; if( isspace(c) ) continue;
@ -463,6 +514,7 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
char **pz; char **pz;
if( (p = pParse->pNewTable)==0 ) return; if( (p = pParse->pNewTable)==0 ) return;
i = p->nCol-1; i = p->nCol-1;
if( i<0 ) return;
pz = &p->aCol[i].zDflt; pz = &p->aCol[i].zDflt;
if( minusFlag ){ if( minusFlag ){
sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0); sqliteSetNString(pz, "-", 1, pVal->z, pVal->n, 0);
@ -500,13 +552,16 @@ static void changeCookie(sqlite *db){
** This routine is called to report the final ")" that terminates ** This routine is called to report the final ")" that terminates
** a CREATE TABLE statement. ** a CREATE TABLE statement.
** **
** The table structure is added to the internal hash tables. ** The table structure that other action routines have been building
** is added to the internal hash tables, assuming no errors have
** occurred.
** **
** An entry for the table is made in the master table on disk, ** An entry for the table is made in the master table on disk,
** unless initFlag==1. When initFlag==1, it means we are reading ** unless this is a temporary table or initFlag==1. When initFlag==1,
** the master table because we just connected to the database, so ** it means we are reading the sqlite_master table because we just
** the entry for this table already exists in the master table. ** connected to the database or because the sqlite_master table has
** We do not want to create it again. ** recently changes, so the entry for this table already exists in
** the sqlite_master table. We do not want to create it again.
*/ */
void sqliteEndTable(Parse *pParse, Token *pEnd){ void sqliteEndTable(Parse *pParse, Token *pEnd){
Table *p; Table *p;
@ -516,9 +571,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
p = pParse->pNewTable; p = pParse->pNewTable;
if( p==0 ) return; if( p==0 ) return;
/* Add the table to the in-memory representation of the database /* Add the table to the in-memory representation of the database.
*/ */
if( pParse->explain==0 ){ assert( pParse->nameClash==0 || pParse->initFlag==0 );
if( pParse->explain==0 && pParse->nameClash==0 ){
sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p);
pParse->pNewTable = 0; pParse->pNewTable = 0;
db->nTable++; db->nTable++;
@ -537,6 +593,9 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
/* If not initializing, then create a record for the new table /* If not initializing, then create a record for the new table
** in the SQLITE_MASTER table of the database. ** in the SQLITE_MASTER table of the database.
**
** If this is a TEMPORARY table, then just create the table. Do not
** make an entry in SQLITE_MASTER.
*/ */
if( !pParse->initFlag ){ if( !pParse->initFlag ){
int n, addr; int n, addr;
@ -545,20 +604,24 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) return; if( v==0 ) return;
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1; n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); if( !p->isTemp ){
sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
}
addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0); addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1); sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1);
p->tnum = 0; p->tnum = 0;
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); if( !p->isTemp ){
sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n); addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0); sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n);
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
changeCookie(db); sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); changeCookie(db);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
}
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }
@ -619,8 +682,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
{ OP_Ne, 0, ADDR(3), 0}, { OP_Ne, 0, ADDR(3), 0},
{ OP_Delete, 0, 0, 0}, { OP_Delete, 0, 0, 0},
{ OP_Goto, 0, ADDR(3), 0}, { OP_Goto, 0, ADDR(3), 0},
{ OP_Destroy, 0, 0, 0}, /* 9 */ { OP_SetCookie, 0, 0, 0}, /* 9 */
{ OP_SetCookie, 0, 0, 0}, /* 10 */
{ OP_Close, 0, 0, 0}, { OP_Close, 0, 0, 0},
}; };
Index *pIdx; Index *pIdx;
@ -629,13 +691,15 @@ void sqliteDropTable(Parse *pParse, Token *pName){
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1; pParse->schemaVerified = 1;
} }
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); if( !pTable->isTemp ){
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP1(v, base+9, pTable->tnum); sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
changeCookie(db); changeCookie(db);
sqliteVdbeChangeP1(v, base+10, db->next_cookie); sqliteVdbeChangeP1(v, base+9, db->next_cookie);
}
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp, 0, 0);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0); sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp, 0, 0);
} }
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
@ -679,8 +743,9 @@ void sqliteCreateIndex(
Index *pIndex; /* The index to be created */ Index *pIndex; /* The index to be created */
char *zName = 0; char *zName = 0;
int i, j; int i, j;
Token nullId; /* Fake token for an empty ID list */ Token nullId; /* Fake token for an empty ID list */
sqlite *db = pParse->db; sqlite *db = pParse->db;
int hideName = 0; /* Do not put table name in the hash table */
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
@ -702,26 +767,56 @@ void sqliteCreateIndex(
goto exit_create_index; goto exit_create_index;
} }
/* If this index is created while re-reading the schema from sqlite_master
** but the table associated with this index is a temporary table, it can
** only mean that the table this index is really associated with is one
** whose name is hidden behind a temporary table with the same name.
** Since its table has been suppressed, we need to also suppress the
** index.
*/
if( pParse->initFlag && pTab->isTemp ){
goto exit_create_index;
}
/* /*
** Find the name of the index. Make sure there is not already another ** Find the name of the index. Make sure there is not already another
** index or table with the same name. If pName==0 it means that we are ** index or table with the same name.
**
** Exception: If we are reading the names of permanent indices from the
** sqlite_master table (because some other process changed the schema) and
** one of the index names collides with the name of a temporary table or
** index, then we will continue to process this index, but we will not
** store its name in the hash table. Set the hideName flag to accomplish
** this.
**
** If pName==0 it means that we are
** dealing with a primary key or UNIQUE constraint. We have to invent our ** dealing with a primary key or UNIQUE constraint. We have to invent our
** own name. ** own name.
*/ */
if( pName ){ if( pName ){
Index *pISameName; /* Another index with the same name */
Table *pTSameName; /* A table with same name as the index */
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) goto exit_create_index; if( zName==0 ) goto exit_create_index;
if( sqliteFindIndex(db, zName) ){ if( (pISameName = sqliteFindIndex(db, zName))!=0 ){
sqliteSetString(&pParse->zErrMsg, "index ", zName, if( pISameName->pTable->isTemp && pParse->initFlag ){
" already exists", 0); hideName = 1;
pParse->nErr++; }else{
goto exit_create_index; sqliteSetString(&pParse->zErrMsg, "index ", zName,
" already exists", 0);
pParse->nErr++;
goto exit_create_index;
}
} }
if( sqliteFindTable(db, zName) ){ if( (pTSameName = sqliteFindTable(db, zName))!=0 ){
sqliteSetString(&pParse->zErrMsg, "there is already a table named ", if( pTSameName->isTemp && pParse->initFlag ){
zName, 0); hideName = 1;
pParse->nErr++; }else{
goto exit_create_index; sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
zName, 0);
pParse->nErr++;
goto exit_create_index;
}
} }
}else{ }else{
char zBuf[30]; char zBuf[30];
@ -781,7 +876,7 @@ void sqliteCreateIndex(
*/ */
pIndex->pNext = pTab->pIndex; pIndex->pNext = pTab->pIndex;
pTab->pIndex = pIndex; pTab->pIndex = pIndex;
if( !pParse->explain ){ if( !pParse->explain && !hideName ){
sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex); sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
@ -815,6 +910,7 @@ void sqliteCreateIndex(
int lbl1, lbl2; int lbl1, lbl2;
int i; int i;
int addr; int addr;
int isTemp = pTab->isTemp;
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto exit_create_index; if( v==0 ) goto exit_create_index;
@ -824,28 +920,39 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1; pParse->schemaVerified = 1;
} }
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0); if( !isTemp ){
sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
}
} }
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0); if( !isTemp ){
sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0); sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0);
sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0);
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0);
}
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp, 0, 0);
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, -1); sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, -1);
pIndex->tnum = 0; pIndex->tnum = 0;
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0); if( isTemp ){
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0); sqliteVdbeAddOp(v, OP_OpenWrAux, 1, 0, 0, 0);
}else{
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0);
}
} }
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0); if( !isTemp ){
if( pStart && pEnd ){ addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
n = (int)pEnd->z - (int)pStart->z + 1; if( pStart && pEnd ){
sqliteVdbeChangeP3(v, addr, pStart->z, n); n = (int)pEnd->z - (int)pStart->z + 1;
sqliteVdbeChangeP3(v, addr, pStart->z, n);
}
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
} }
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, OP_Open, 2, pTab->tnum, pTab->zName, 0); sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open,
2, pTab->tnum, pTab->zName, 0);
lbl1 = sqliteVdbeMakeLabel(v); lbl1 = sqliteVdbeMakeLabel(v);
lbl2 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, 2, 0, 0, 0); sqliteVdbeAddOp(v, OP_Rewind, 2, 0, 0, 0);
@ -859,12 +966,14 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0); sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2); sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
sqliteVdbeAddOp(v, OP_Close, 2, 0, 0, 0); sqliteVdbeAddOp(v, OP_Close, 2, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
} }
sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
if( pTable!=0 ){ if( pTable!=0 ){
changeCookie(db); if( !isTemp ){
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0); changeCookie(db);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
}
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }
@ -916,17 +1025,20 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
{ OP_Close, 0, 0, 0}, { OP_Close, 0, 0, 0},
}; };
int base; int base;
Table *pTab = pIndex->pTable;
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1; pParse->schemaVerified = 1;
} }
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); if( !pTab->isTemp ){
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0); base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP1(v, base+8, pIndex->tnum); sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
changeCookie(db); changeCookie(db);
sqliteVdbeChangeP1(v, base+9, db->next_cookie); sqliteVdbeChangeP1(v, base+9, db->next_cookie);
}
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp, 0, 0);
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
} }
@ -1091,6 +1203,7 @@ void sqliteCopy(
} }
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
int openOp;
if( (db->flags & SQLITE_InTrans)==0 ){ if( (db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
@ -1099,9 +1212,10 @@ void sqliteCopy(
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0); addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n); sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr); sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum, pTab->zName, 0); openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
sqliteVdbeAddOp(v, openOp, 0, pTab->tnum, pTab->zName, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum, pIdx->zName, 0); sqliteVdbeAddOp(v, openOp, i, pIdx->tnum, pIdx->zName, 0);
} }
end = sqliteVdbeMakeLabel(v); end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0); addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end, 0, 0);
@ -1374,6 +1488,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
}else }else
#endif #endif
if( zLeft ) sqliteFree(zLeft); {}
if( zRight ) sqliteFree(zRight); sqliteFree(zLeft);
sqliteFree(zRight);
} }

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements. ** to handle DELETE FROM statements.
** **
** $Id: delete.c,v 1.15 2001/09/23 02:35:53 drh Exp $ ** $Id: delete.c,v 1.16 2001/10/08 13:22:32 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -91,9 +91,9 @@ void sqliteDeleteFrom(
** It is easier just to erase the whole table. ** It is easier just to erase the whole table.
*/ */
if( pWhere==0 ){ if( pWhere==0 ){
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, 0, 0, 0); sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->isTemp, 0, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, 0, 0, 0); sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pTab->isTemp, 0, 0);
} }
} }
@ -101,6 +101,8 @@ void sqliteDeleteFrom(
** the table an pick which records to delete. ** the table an pick which records to delete.
*/ */
else{ else{
int openOp;
/* Begin the database scan /* Begin the database scan
*/ */
sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
@ -121,9 +123,10 @@ void sqliteDeleteFrom(
*/ */
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0); openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
sqliteVdbeAddOp(v, openOp, base, pTab->tnum, 0, 0);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_OpenWrite, base+i, pIdx->tnum, 0, 0); sqliteVdbeAddOp(v, openOp, base+i, pIdx->tnum, 0, 0);
} }
end = sqliteVdbeMakeLabel(v); end = sqliteVdbeMakeLabel(v);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** to handle INSERT statements in SQLite.
** **
** $Id: insert.c,v 1.21 2001/10/06 16:33:03 drh Exp $ ** $Id: insert.c,v 1.22 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -48,6 +48,7 @@ void sqliteInsert(
int base; /* First available cursor */ int base; /* First available cursor */
int iCont, iBreak; /* Beginning and end of the loop over srcTab */ int iCont, iBreak; /* Beginning and end of the loop over srcTab */
sqlite *db; /* The main database structure */ sqlite *db; /* The main database structure */
int openOp; /* Opcode used to open cursors */
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup; if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
db = pParse->db; db = pParse->db;
@ -155,9 +156,10 @@ void sqliteInsert(
** all indices of that table. ** all indices of that table.
*/ */
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, 0); openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
sqliteVdbeAddOp(v, openOp, base, pTab->tnum, pTab->zName, 0);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){ for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum, pIdx->zName, 0); sqliteVdbeAddOp(v, openOp, idx+base, pIdx->tnum, pIdx->zName, 0);
} }
/* If the data source is a SELECT statement, then we have to create /* If the data source is a SELECT statement, then we have to create

View File

@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.43 2001/10/06 16:33:03 drh Exp $ ** $Id: main.c,v 1.44 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@ -309,7 +309,9 @@ no_mem_on_open:
} }
/* /*
** Erase all schema information from the schema hash table. ** Erase all schema information from the schema hash table. Except
** tables that are created using CREATE TEMPORARY TABLE are preserved
** if the preserverTemps flag is true.
** **
** The database schema is normally read in once when the database ** The database schema is normally read in once when the database
** is first opened and stored in a hash table in the sqlite structure. ** is first opened and stored in a hash table in the sqlite structure.
@ -317,15 +319,24 @@ no_mem_on_open:
** either the database is being closed or because some other process ** either the database is being closed or because some other process
** changed the schema and this process needs to reread it. ** changed the schema and this process needs to reread it.
*/ */
static void clearHashTable(sqlite *db){ static void clearHashTable(sqlite *db, int preserveTemps){
HashElem *pElem; HashElem *pElem;
Hash temp1; Hash temp1;
temp1 = db->tblHash; temp1 = db->tblHash;
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
sqliteHashClear(&db->idxHash); sqliteHashClear(&db->idxHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTbl = sqliteHashData(pElem); Table *pTab = sqliteHashData(pElem);
sqliteDeleteTable(db, pTbl); if( preserveTemps && pTab->isTemp ){
Index *pIdx;
sqliteHashInsert(&db->tblHash, pTab->zName, strlen(pTab->zName)+1, pTab);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int n = strlen(pIdx->zName)+1;
sqliteHashInsert(&db->idxHash, pIdx->zName, n, pIdx);
}
}else{
sqliteDeleteTable(db, pTab);
}
} }
sqliteHashClear(&temp1); sqliteHashClear(&temp1);
db->flags &= ~SQLITE_Initialized; db->flags &= ~SQLITE_Initialized;
@ -336,7 +347,10 @@ static void clearHashTable(sqlite *db){
*/ */
void sqlite_close(sqlite *db){ void sqlite_close(sqlite *db){
sqliteBtreeClose(db->pBe); sqliteBtreeClose(db->pBe);
clearHashTable(db); clearHashTable(db, 0);
if( db->pBeTemp ){
sqliteBtreeClose(db->pBeTemp);
}
sqliteFree(db); sqliteFree(db);
} }
@ -429,7 +443,7 @@ int sqlite_exec(
} }
sqliteStrRealloc(pzErrMsg); sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){ if( sParse.rc==SQLITE_SCHEMA ){
clearHashTable(db); clearHashTable(db, 1);
} }
return sParse.rc; return sParse.rc;
} }

View File

@ -397,6 +397,9 @@ int sqliteOsLock(OsFile id, int wrlock){
lock.l_whence = SEEK_SET; lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L; lock.l_start = lock.l_len = 0L;
rc = fcntl(id, F_SETLK, &lock); rc = fcntl(id, F_SETLK, &lock);
if( rc ){
fcntl(id, F_GETLK, &lock); /* For debugging */
}
return rc==0 ? SQLITE_OK : SQLITE_BUSY; return rc==0 ? SQLITE_OK : SQLITE_BUSY;
#endif #endif
#if OS_WIN #if OS_WIN

View File

@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.25 2001/10/06 16:33:03 drh Exp $ ** @(#) $Id: pager.c,v 1.26 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "pager.h" #include "pager.h"
@ -640,12 +640,16 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* If a journal file exists, try to play it back. /* If a journal file exists, try to play it back.
*/ */
if( sqliteOsFileExists(pPager->zJournal) ){ if( sqliteOsFileExists(pPager->zJournal) ){
int rc; int rc, dummy;
/* Open the journal for exclusive access. Return SQLITE_BUSY if /* Open the journal for exclusive access. Return SQLITE_BUSY if
** we cannot get exclusive access to the journal file ** we cannot get exclusive access to the journal file.
**
** Even though we will only be reading from the journal, not writing,
** we have to open the journal for writing in order to obtain an
** exclusive access lock.
*/ */
rc = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd); rc = sqliteOsOpenReadWrite(pPager->zJournal, &pPager->jfd, &dummy);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pPager->journalOpen = 1; pPager->journalOpen = 1;
} }

View File

@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing ** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens. ** numeric codes for all of the tokens.
** **
** @(#) $Id: parse.y,v 1.34 2001/10/06 16:33:03 drh Exp $ ** @(#) $Id: parse.y,v 1.35 2001/10/08 13:22:33 drh Exp $
*/ */
%token_prefix TK_ %token_prefix TK_
%token_type {Token} %token_type {Token}
@ -62,7 +62,11 @@ cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);}
///////////////////// The CREATE TABLE statement //////////////////////////// ///////////////////// The CREATE TABLE statement ////////////////////////////
// //
cmd ::= create_table create_table_args. cmd ::= create_table create_table_args.
create_table ::= CREATE(X) TABLE ids(Y). {sqliteStartTable(pParse,&X,&Y);} 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;}
create_table_args ::= LP columnlist conslist_opt RP(X). create_table_args ::= LP columnlist conslist_opt RP(X).
{sqliteEndTable(pParse,&X);} {sqliteEndTable(pParse,&X);}
columnlist ::= columnlist COMMA column. columnlist ::= columnlist COMMA column.
@ -91,6 +95,7 @@ id(A) ::= END(X). {A = X;}
id(A) ::= PRAGMA(X). {A = X;} id(A) ::= PRAGMA(X). {A = X;}
id(A) ::= CLUSTER(X). {A = X;} id(A) ::= CLUSTER(X). {A = X;}
id(A) ::= ID(X). {A = X;} id(A) ::= ID(X). {A = X;}
id(A) ::= TEMP(X). {A = X;}
// And "ids" is an identifer-or-string. // And "ids" is an identifer-or-string.
// //

View File

@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.57 2001/10/06 16:33:03 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.58 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqlite.h" #include "sqlite.h"
#include "hash.h" #include "hash.h"
@ -139,6 +139,7 @@ typedef struct AggExpr AggExpr;
*/ */
struct sqlite { struct sqlite {
Btree *pBe; /* The B*Tree backend */ Btree *pBe; /* The B*Tree backend */
Btree *pBeTemp; /* Backend for session temporary tables */
int flags; /* Miscellanous flags. See below */ int flags; /* Miscellanous flags. See below */
int file_format; /* What file format version is this database? */ int file_format; /* What file format version is this database? */
int schema_cookie; /* Magic number that changes with the schema */ int schema_cookie; /* Magic number that changes with the schema */
@ -195,6 +196,7 @@ struct Table {
u8 readOnly; /* True if this table should not be written by the user */ u8 readOnly; /* True if this table should not be written by the user */
u8 isCommit; /* True if creation of this table has been committed */ u8 isCommit; /* True if creation of this table has been committed */
u8 isDelete; /* True if this table is being deleted */ u8 isDelete; /* True if this table is being deleted */
u8 isTemp; /* True if stored in db->pBeTemp instead of db->pBe */
}; };
/* /*
@ -355,7 +357,9 @@ struct AggExpr {
}; };
/* /*
** An SQL parser context ** An SQL parser context. A copy of this structure is passed through
** the parser and down into all the parser action routine in order to
** carry around information that is global to the entire parse.
*/ */
struct Parse { struct Parse {
sqlite *db; /* The main database structure */ sqlite *db; /* The main database structure */
@ -372,8 +376,8 @@ struct Parse {
int colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */ int colNamesSet; /* TRUE after OP_ColumnCount has been issued to pVdbe */
int explain; /* True if the EXPLAIN flag is found on the query */ int explain; /* True if the EXPLAIN flag is found on the query */
int initFlag; /* True if reparsing CREATE TABLEs */ int initFlag; /* True if reparsing CREATE TABLEs */
int nameClash; /* A permanent table name clashes with temp table name */
int newTnum; /* Table number to use when reparsing CREATE TABLEs */ int newTnum; /* Table number to use when reparsing CREATE TABLEs */
int newKnum; /* Primary key number when reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated cursors */ int nTab; /* Number of previously allocated cursors */
int nMem; /* Number of memory cells used so far */ int nMem; /* Number of memory cells used so far */
@ -423,7 +427,7 @@ void sqliteExprListDelete(ExprList*);
void sqlitePragma(Parse*,Token*,Token*,int); void sqlitePragma(Parse*,Token*,Token*,int);
void sqliteCommitInternalChanges(sqlite*); void sqliteCommitInternalChanges(sqlite*);
void sqliteRollbackInternalChanges(sqlite*); void sqliteRollbackInternalChanges(sqlite*);
void sqliteStartTable(Parse*,Token*,Token*); void sqliteStartTable(Parse*,Token*,Token*,int);
void sqliteAddColumn(Parse*,Token*); void sqliteAddColumn(Parse*,Token*);
void sqliteAddNotNull(Parse*); void sqliteAddNotNull(Parse*);
void sqliteAddColumnType(Parse*,Token*,Token*); void sqliteAddColumnType(Parse*,Token*,Token*);

View File

@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the ** individual tokens and sends those tokens one-by-one over to the
** parser for analysis. ** parser for analysis.
** **
** $Id: tokenize.c,v 1.24 2001/10/06 16:33:03 drh Exp $ ** $Id: tokenize.c,v 1.25 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -84,6 +84,8 @@ static Keyword aKeywordTable[] = {
{ "SELECT", 0, TK_SELECT, 0 }, { "SELECT", 0, TK_SELECT, 0 },
{ "SET", 0, TK_SET, 0 }, { "SET", 0, TK_SET, 0 },
{ "TABLE", 0, TK_TABLE, 0 }, { "TABLE", 0, TK_TABLE, 0 },
{ "TEMP", 0, TK_TEMP, 0 },
{ "TEMPORARY", 0, TK_TEMP, 0 },
{ "TRANSACTION", 0, TK_TRANSACTION, 0 }, { "TRANSACTION", 0, TK_TRANSACTION, 0 },
{ "UNION", 0, TK_UNION, 0 }, { "UNION", 0, TK_UNION, 0 },
{ "UNIQUE", 0, TK_UNIQUE, 0 }, { "UNIQUE", 0, TK_UNIQUE, 0 },

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle UPDATE statements. ** to handle UPDATE statements.
** **
** $Id: update.c,v 1.16 2001/09/27 03:22:34 drh Exp $ ** $Id: update.c,v 1.17 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -39,6 +39,7 @@ void sqliteUpdate(
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table. ** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */ ** aXRef[i]==-1 if the i-th column is not changed. */
int openOp; /* Opcode used to open tables */
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup; if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
db = pParse->db; db = pParse->db;
@ -159,9 +160,10 @@ void sqliteUpdate(
*/ */
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0); sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum, 0, 0); openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
sqliteVdbeAddOp(v, openOp, base, pTab->tnum, 0, 0);
for(i=0; i<nIdx; i++){ for(i=0; i<nIdx; i++){
sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, apIdx[i]->tnum, 0, 0); sqliteVdbeAddOp(v, openOp, base+i+1, apIdx[i]->tnum, 0, 0);
} }
/* Loop over every record that needs updating. We have to load /* Loop over every record that needs updating. We have to load

View File

@ -30,7 +30,7 @@
** But other routines are also provided to help in building up ** But other routines are also provided to help in building up
** a program instruction by instruction. ** a program instruction by instruction.
** **
** $Id: vdbe.c,v 1.80 2001/10/06 16:33:03 drh Exp $ ** $Id: vdbe.c,v 1.81 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@ -793,30 +793,31 @@ void sqliteVdbeDelete(Vdbe *p){
static char *zOpName[] = { 0, static char *zOpName[] = { 0,
"Transaction", "Commit", "Rollback", "ReadCookie", "Transaction", "Commit", "Rollback", "ReadCookie",
"SetCookie", "VerifyCookie", "Open", "OpenTemp", "SetCookie", "VerifyCookie", "Open", "OpenTemp",
"OpenWrite", "Close", "MoveTo", "Fcnt", "OpenWrite", "OpenAux", "OpenWrAux", "Close",
"NewRecno", "Put", "Distinct", "Found", "MoveTo", "Fcnt", "NewRecno", "Put",
"NotFound", "Delete", "Column", "KeyAsData", "Distinct", "Found", "NotFound", "Delete",
"Recno", "FullKey", "Rewind", "Next", "Column", "KeyAsData", "Recno", "FullKey",
"Destroy", "Clear", "CreateIndex", "CreateTable", "Rewind", "Next", "Destroy", "Clear",
"Reorganize", "BeginIdx", "NextIdx", "PutIdx", "CreateIndex", "CreateTable", "Reorganize", "BeginIdx",
"DeleteIdx", "MemLoad", "MemStore", "ListOpen", "NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
"ListWrite", "ListRewind", "ListRead", "ListClose", "MemStore", "ListOpen", "ListWrite", "ListRewind",
"SortOpen", "SortPut", "SortMakeRec", "SortMakeKey", "ListRead", "ListClose", "SortOpen", "SortPut",
"Sort", "SortNext", "SortKey", "SortCallback", "SortMakeRec", "SortMakeKey", "Sort", "SortNext",
"SortClose", "FileOpen", "FileRead", "FileColumn", "SortKey", "SortCallback", "SortClose", "FileOpen",
"FileClose", "AggReset", "AggFocus", "AggIncr", "FileRead", "FileColumn", "FileClose", "AggReset",
"AggNext", "AggSet", "AggGet", "SetInsert", "AggFocus", "AggIncr", "AggNext", "AggSet",
"SetFound", "SetNotFound", "SetClear", "MakeRecord", "AggGet", "SetInsert", "SetFound", "SetNotFound",
"MakeKey", "MakeIdxKey", "Goto", "If", "SetClear", "MakeRecord", "MakeKey", "MakeIdxKey",
"Halt", "ColumnCount", "ColumnName", "Callback", "Goto", "If", "Halt", "ColumnCount",
"Integer", "String", "Null", "Pop", "ColumnName", "Callback", "Integer", "String",
"Dup", "Pull", "Add", "AddImm", "Null", "Pop", "Dup", "Pull",
"Subtract", "Multiply", "Divide", "Min", "Add", "AddImm", "Subtract", "Multiply",
"Max", "Like", "Glob", "Eq", "Divide", "Min", "Max", "Like",
"Ne", "Lt", "Le", "Gt", "Glob", "Eq", "Ne", "Lt",
"Ge", "IsNull", "NotNull", "Negative", "Le", "Gt", "Ge", "IsNull",
"And", "Or", "Not", "Concat", "NotNull", "Negative", "And", "Or",
"Noop", "Strlen", "Substr", "Not", "Concat", "Noop", "Strlen",
"Substr",
}; };
/* /*
@ -1920,6 +1921,12 @@ case OP_MakeIdxKey: {
*/ */
case OP_Transaction: { case OP_Transaction: {
int busy = 0; int busy = 0;
if( db->pBeTemp ){
rc = sqliteBtreeBeginTrans(db->pBeTemp);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}
do{ do{
rc = sqliteBtreeBeginTrans(pBt); rc = sqliteBtreeBeginTrans(pBt);
switch( rc ){ switch( rc ){
@ -1951,7 +1958,9 @@ case OP_Transaction: {
** A read lock continues to be held if there are still cursors open. ** A read lock continues to be held if there are still cursors open.
*/ */
case OP_Commit: { case OP_Commit: {
rc = sqliteBtreeCommit(pBt); if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
rc = sqliteBtreeCommit(pBt);
}
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqliteCommitInternalChanges(db); sqliteCommitInternalChanges(db);
}else{ }else{
@ -1971,6 +1980,9 @@ case OP_Commit: {
** the read and write locks on the database. ** the read and write locks on the database.
*/ */
case OP_Rollback: { case OP_Rollback: {
if( db->pBeTemp ){
sqliteBtreeRollback(db->pBeTemp);
}
rc = sqliteBtreeRollback(pBt); rc = sqliteBtreeRollback(pBt);
sqliteRollbackInternalChanges(db); sqliteRollbackInternalChanges(db);
break; break;
@ -2065,6 +2077,16 @@ case OP_VerifyCookie: {
** The P3 value is not actually used by this opcode and may be ** The P3 value is not actually used by this opcode and may be
** omitted. But the code generator usually inserts the index or ** omitted. But the code generator usually inserts the index or
** table name into P3 to make the code easier to read. ** table name into P3 to make the code easier to read.
**
** See also OpenAux and OpenWrite.
*/
/* Opcode: OpenAux P1 P2 P3
**
** Open a read-only cursor in the auxiliary table set. This opcode
** works exactly like OP_Open except that it opens the cursor on the
** auxiliary table set (the file used to store tables created using
** CREATE TEMPORARY TABLE) instead of in the main database file.
** See OP_Open for additional information.
*/ */
/* Opcode: OpenWrite P1 P2 P3 /* Opcode: OpenWrite P1 P2 P3
** **
@ -2074,13 +2096,33 @@ case OP_VerifyCookie: {
** This instruction works just like Open except that it opens the cursor ** This instruction works just like Open except that it opens the cursor
** in read/write mode. For a given table, there can be one or more read-only ** in read/write mode. For a given table, there can be one or more read-only
** cursors or a single read/write cursor but not both. ** cursors or a single read/write cursor but not both.
**
** See also OpWrAux.
*/ */
/* Opcode: OpenWrAux P1 P2 P3
**
** Open a read/write cursor in the auxiliary table set. This opcode works
** just like OpenWrite except that the auxiliary table set (the file used
** to store tables created using CREATE TEMPORARY TABLE) is used in place
** of the main database file.
*/
case OP_OpenAux:
case OP_OpenWrAux:
case OP_OpenWrite: case OP_OpenWrite:
case OP_Open: { case OP_Open: {
int busy = 0; int busy = 0;
int i = pOp->p1; int i = pOp->p1;
int tos = p->tos; int tos = p->tos;
int p2 = pOp->p2; int p2 = pOp->p2;
int wrFlag;
Btree *pX;
switch( pOp->opcode ){
case OP_Open: wrFlag = 0; pX = pBt; break;
case OP_OpenWrite: wrFlag = 1; pX = pBt; break;
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( p2<=0 ){
if( tos<0 ) goto not_enough_stack; if( tos<0 ) goto not_enough_stack;
Integerify(p, tos); Integerify(p, tos);
@ -2105,8 +2147,7 @@ case OP_Open: {
cleanupCursor(&p->aCsr[i]); cleanupCursor(&p->aCsr[i]);
memset(&p->aCsr[i], 0, sizeof(Cursor)); memset(&p->aCsr[i], 0, sizeof(Cursor));
do{ do{
int wrFlag = pOp->opcode==OP_OpenWrite; rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
rc = sqliteBtreeCursor(pBt, p2, wrFlag, &p->aCsr[i].pCursor);
switch( rc ){ switch( rc ){
case SQLITE_BUSY: { case SQLITE_BUSY: {
if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){ if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
@ -2133,6 +2174,13 @@ case OP_Open: {
** file. The temporary file is opened read/write even if the main ** file. The temporary file is opened read/write even if the main
** database is read-only. The temporary file is deleted when the ** database is read-only. The temporary file is deleted when the
** cursor is closed. ** cursor is closed.
**
** This opcode is used for tables that exist for the duration of a single
** SQL statement only. Tables created using CREATE TEMPORARY TABLE
** are opened using OP_OpenAux or OP_OpenWrAux. "Temporary" in the
** context of this opcode means for the duration of a single SQL statement
** whereas "Temporary" in the context of CREATE TABLE means for the duration
** of the connection to the database. Same word; different meanings.
*/ */
case OP_OpenTemp: { case OP_OpenTemp: {
int i = pOp->p1; int i = pOp->p1;
@ -2765,34 +2813,43 @@ case OP_DeleteIdx: {
break; break;
} }
/* Opcode: Destroy P1 * * /* Opcode: Destroy P1 P2 *
** **
** Delete an entire database table or index whose root page in the database ** Delete an entire database table or index whose root page in the database
** file is given by P1. ** file is given by P1.
** **
** The table being destroyed is in the main database file if P2==0. If
** P2==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** See also: Clear ** See also: Clear
*/ */
case OP_Destroy: { case OP_Destroy: {
sqliteBtreeDropTable(pBt, pOp->p1); sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
break; break;
} }
/* Opcode: Clear P1 * * /* Opcode: Clear P1 P2 *
** **
** Delete all contents of the database table or index whose root page ** Delete all contents of the database table or index whose root page
** in the database file is given by P1. But, unlike Destroy, do not ** in the database file is given by P1. But, unlike Destroy, do not
** remove the table or index from the database file. ** remove the table or index from the database file.
** **
** The table being clear is in the main database file if P2==0. If
** P2==1 then the table to be clear is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** See also: Destroy ** See also: Destroy
*/ */
case OP_Clear: { case OP_Clear: {
sqliteBtreeClearTable(pBt, pOp->p1); sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
break; break;
} }
/* Opcode: CreateTable * * P3 /* Opcode: CreateTable * P2 P3
** **
** Allocate a new table in the main database file. Push the page number ** Allocate a new table in the main database file if P2==0 or in the
** auxiliary database file if P2==1. Push the page number
** for the root page of the new table onto the stack. ** for the root page of the new table onto the stack.
** **
** The root page number is also written to a memory location that P3 ** The root page number is also written to a memory location that P3
@ -2802,39 +2859,20 @@ case OP_Clear: {
** **
** See also: CreateIndex ** See also: CreateIndex
*/ */
/* Opcode: CreateIndex * P2 P3
**
** This instruction does exactly the same thing as CreateTable. It
** has a different name for historical reasons.
**
** See also: CreateTable
*/
case OP_CreateIndex:
case OP_CreateTable: { case OP_CreateTable: {
int i = ++p->tos; int i = ++p->tos;
int pgno; int pgno;
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
assert( pOp->p3!=0 && pOp->p3dyn==0 ); assert( pOp->p3!=0 && pOp->p3dyn==0 );
rc = sqliteBtreeCreateTable(pBt, &pgno); rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
if( rc==SQLITE_OK ){
aStack[i].i = pgno;
aStack[i].flags = STK_Int;
*(u32*)pOp->p3 = pgno;
pOp->p3 = 0;
}
break;
}
/* Opcode: CreateIndex * * P3
**
** Allocate a new Index in the main database file. Push the page number
** for the root page of the new table onto the stack.
**
** The root page number is also written to a memory location that P3
** points to. This is the mechanism is used to write the root page
** number into the parser's internal data structures that describe the
** new index.
**
** See also: CreateTable
*/
case OP_CreateIndex: {
int i = ++p->tos;
int pgno;
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
assert( pOp->p3!=0 && pOp->p3dyn==0 );
rc = sqliteBtreeCreateTable(pBt, &pgno);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
aStack[i].i = pgno; aStack[i].i = pgno;
aStack[i].flags = STK_Int; aStack[i].flags = STK_Int;
@ -3164,6 +3202,7 @@ case OP_SortNext: {
break; break;
} }
#if 0 /* NOT USED */
/* Opcode: SortKey P1 * * /* Opcode: SortKey P1 * *
** **
** Push the key for the topmost element of the sorter onto the stack. ** Push the key for the topmost element of the sorter onto the stack.
@ -3182,6 +3221,7 @@ case OP_SortKey: {
} }
break; break;
} }
#endif /* NOT USED */
/* Opcode: SortCallback P1 P2 * /* Opcode: SortCallback P1 P2 *
** **
@ -3245,6 +3285,7 @@ case OP_FileOpen: {
break; break;
} }
#if 0 /* NOT USED */
/* Opcode: FileClose * * * /* Opcode: FileClose * * *
** **
** Close a file previously opened using FileOpen. This is a no-op ** Close a file previously opened using FileOpen. This is a no-op
@ -3267,6 +3308,7 @@ case OP_FileClose: {
p->nLineAlloc = 0; p->nLineAlloc = 0;
break; break;
} }
#endif
/* Opcode: FileRead P1 P2 P3 /* Opcode: FileRead P1 P2 P3
** **
@ -3597,6 +3639,7 @@ case OP_AggNext: {
break; break;
} }
#if 0 /* NOT USED */
/* Opcode: SetClear P1 * * /* Opcode: SetClear P1 * *
** **
** Remove all elements from the P1-th Set. ** Remove all elements from the P1-th Set.
@ -3608,6 +3651,7 @@ case OP_SetClear: {
} }
break; break;
} }
#endif /* NOT USED */
/* Opcode: SetInsert P1 * P3 /* Opcode: SetInsert P1 * P3
** **
@ -3874,6 +3918,7 @@ cleanup:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
closeAllCursors(p); closeAllCursors(p);
sqliteBtreeRollback(pBt); sqliteBtreeRollback(pBt);
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
sqliteRollbackInternalChanges(db); sqliteRollbackInternalChanges(db);
db->flags &= ~SQLITE_InTrans; db->flags &= ~SQLITE_InTrans;
} }

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a ** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database. ** simple program to access and modify the underlying database.
** **
** $Id: vdbe.h,v 1.25 2001/09/27 15:11:55 drh Exp $ ** $Id: vdbe.h,v 1.26 2001/10/08 13:22:33 drh Exp $
*/ */
#ifndef _SQLITE_VDBE_H_ #ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_
@ -71,116 +71,118 @@ typedef struct VdbeOp VdbeOp;
#define OP_Open 7 #define OP_Open 7
#define OP_OpenTemp 8 #define OP_OpenTemp 8
#define OP_OpenWrite 9 #define OP_OpenWrite 9
#define OP_Close 10 #define OP_OpenAux 10
#define OP_MoveTo 11 #define OP_OpenWrAux 11
#define OP_Fcnt 12 #define OP_Close 12
#define OP_NewRecno 13 #define OP_MoveTo 13
#define OP_Put 14 #define OP_Fcnt 14
#define OP_Distinct 15 #define OP_NewRecno 15
#define OP_Found 16 #define OP_Put 16
#define OP_NotFound 17 #define OP_Distinct 17
#define OP_Delete 18 #define OP_Found 18
#define OP_Column 19 #define OP_NotFound 19
#define OP_KeyAsData 20 #define OP_Delete 20
#define OP_Recno 21 #define OP_Column 21
#define OP_FullKey 22 #define OP_KeyAsData 22
#define OP_Rewind 23 #define OP_Recno 23
#define OP_Next 24 #define OP_FullKey 24
#define OP_Rewind 25
#define OP_Next 26
#define OP_Destroy 25 #define OP_Destroy 27
#define OP_Clear 26 #define OP_Clear 28
#define OP_CreateIndex 27 #define OP_CreateIndex 29
#define OP_CreateTable 28 #define OP_CreateTable 30
#define OP_Reorganize 29 #define OP_Reorganize 31
#define OP_BeginIdx 30 #define OP_BeginIdx 32
#define OP_NextIdx 31 #define OP_NextIdx 33
#define OP_PutIdx 32 #define OP_PutIdx 34
#define OP_DeleteIdx 33 #define OP_DeleteIdx 35
#define OP_MemLoad 34 #define OP_MemLoad 36
#define OP_MemStore 35 #define OP_MemStore 37
#define OP_ListOpen 36 #define OP_ListOpen 38
#define OP_ListWrite 37 #define OP_ListWrite 39
#define OP_ListRewind 38 #define OP_ListRewind 40
#define OP_ListRead 39 #define OP_ListRead 41
#define OP_ListClose 40 #define OP_ListClose 42
#define OP_SortOpen 41 #define OP_SortOpen 43
#define OP_SortPut 42 #define OP_SortPut 44
#define OP_SortMakeRec 43 #define OP_SortMakeRec 45
#define OP_SortMakeKey 44 #define OP_SortMakeKey 46
#define OP_Sort 45 #define OP_Sort 47
#define OP_SortNext 46 #define OP_SortNext 48
#define OP_SortKey 47 #define OP_SortKey 49
#define OP_SortCallback 48 #define OP_SortCallback 50
#define OP_SortClose 49 #define OP_SortClose 51
#define OP_FileOpen 50 #define OP_FileOpen 52
#define OP_FileRead 51 #define OP_FileRead 53
#define OP_FileColumn 52 #define OP_FileColumn 54
#define OP_FileClose 53 #define OP_FileClose 55
#define OP_AggReset 54 #define OP_AggReset 56
#define OP_AggFocus 55 #define OP_AggFocus 57
#define OP_AggIncr 56 #define OP_AggIncr 58
#define OP_AggNext 57 #define OP_AggNext 59
#define OP_AggSet 58 #define OP_AggSet 60
#define OP_AggGet 59 #define OP_AggGet 61
#define OP_SetInsert 60 #define OP_SetInsert 62
#define OP_SetFound 61 #define OP_SetFound 63
#define OP_SetNotFound 62 #define OP_SetNotFound 64
#define OP_SetClear 63 #define OP_SetClear 65
#define OP_MakeRecord 64 #define OP_MakeRecord 66
#define OP_MakeKey 65 #define OP_MakeKey 67
#define OP_MakeIdxKey 66 #define OP_MakeIdxKey 68
#define OP_Goto 67 #define OP_Goto 69
#define OP_If 68 #define OP_If 70
#define OP_Halt 69 #define OP_Halt 71
#define OP_ColumnCount 70 #define OP_ColumnCount 72
#define OP_ColumnName 71 #define OP_ColumnName 73
#define OP_Callback 72 #define OP_Callback 74
#define OP_Integer 73 #define OP_Integer 75
#define OP_String 74 #define OP_String 76
#define OP_Null 75 #define OP_Null 77
#define OP_Pop 76 #define OP_Pop 78
#define OP_Dup 77 #define OP_Dup 79
#define OP_Pull 78 #define OP_Pull 80
#define OP_Add 79 #define OP_Add 81
#define OP_AddImm 80 #define OP_AddImm 82
#define OP_Subtract 81 #define OP_Subtract 83
#define OP_Multiply 82 #define OP_Multiply 84
#define OP_Divide 83 #define OP_Divide 85
#define OP_Min 84 #define OP_Min 86
#define OP_Max 85 #define OP_Max 87
#define OP_Like 86 #define OP_Like 88
#define OP_Glob 87 #define OP_Glob 89
#define OP_Eq 88 #define OP_Eq 90
#define OP_Ne 89 #define OP_Ne 91
#define OP_Lt 90 #define OP_Lt 92
#define OP_Le 91 #define OP_Le 93
#define OP_Gt 92 #define OP_Gt 94
#define OP_Ge 93 #define OP_Ge 95
#define OP_IsNull 94 #define OP_IsNull 96
#define OP_NotNull 95 #define OP_NotNull 97
#define OP_Negative 96 #define OP_Negative 98
#define OP_And 97 #define OP_And 99
#define OP_Or 98 #define OP_Or 100
#define OP_Not 99 #define OP_Not 101
#define OP_Concat 100 #define OP_Concat 102
#define OP_Noop 101 #define OP_Noop 103
#define OP_Strlen 102 #define OP_Strlen 104
#define OP_Substr 103 #define OP_Substr 105
#define OP_MAX 103 #define OP_MAX 105
/* /*
** Prototypes for the VDBE interface. See comments on the implementation ** Prototypes for the VDBE interface. See comments on the implementation

View File

@ -13,7 +13,7 @@
** the WHERE clause of SQL statements. Also found here are subroutines ** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions. ** to generate VDBE code to evaluate expressions.
** **
** $Id: where.c,v 1.21 2001/09/18 02:02:23 drh Exp $ ** $Id: where.c,v 1.22 2001/10/08 13:22:33 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@ -285,15 +285,19 @@ WhereInfo *sqliteWhereBegin(
/* Open all tables in the pTabList and all indices in aIdx[]. /* Open all tables in the pTabList and all indices in aIdx[].
*/ */
for(i=0; i<pTabList->nId; i++){ for(i=0; i<pTabList->nId; i++){
sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum, int openOp;
pTabList->a[i].pTab->zName, 0); Table *pTab;
pTab = pTabList->a[i].pTab;
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
sqliteVdbeAddOp(v, openOp, base+i, pTab->tnum, pTab->zName, 0);
if( i==0 && !pParse->schemaVerified && if( i==0 && !pParse->schemaVerified &&
(pParse->db->flags & SQLITE_InTrans)==0 ){ (pParse->db->flags & SQLITE_InTrans)==0 ){
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0); sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
pParse->schemaVerified = 1; pParse->schemaVerified = 1;
} }
if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){ if( i<ARRAYSIZE(aIdx) && aIdx[i]!=0 ){
sqliteVdbeAddOp(v, OP_Open, base+pTabList->nId+i, aIdx[i]->tnum, sqliteVdbeAddOp(v, openOp, base+pTabList->nId+i, aIdx[i]->tnum,
aIdx[i]->zName, 0); aIdx[i]->zName, 0);
} }
} }

124
test/temptable.test Normal file
View File

@ -0,0 +1,124 @@
# 2001 October 7
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for temporary tables and indices.
#
# $Id: temptable.test,v 1.1 2001/10/08 13:22:33 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Create an alternative connection to the database
#
do_test temptable-1.0 {
sqlite db2 ./test.db
} {}
# Create a permanent table.
#
do_test temptable-1.1 {
execsql {CREATE TABLE t1(a,b,c);}
execsql {INSERT INTO t1 VALUES(1,2,3);}
execsql {SELECT * FROM t1}
} {1 2 3}
do_test temptable-1.2 {
catch {db2 eval {SELECT * FROM sqlite_master}}
db2 eval {SELECT * FROM t1}
} {1 2 3}
do_test testtable-1.3 {
execsql {SELECT name FROM sqlite_master}
} {t1}
do_test testtable-1.4 {
db2 eval {SELECT name FROM sqlite_master}
} {t1}
# Create a temporary table. Verify that only one of the two
# processes can see it.
#
do_test testtable-1.5 {
db2 eval {
CREATE TEMP TABLE t2(x,y,z);
INSERT INTO t2 VALUES(4,5,6);
}
db2 eval {SELECT * FROM t2}
} {4 5 6}
do_test testtable-1.6 {
catch {execsql {SELECT * FROM sqlite_master}}
catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test testtable-1.7 {
catchsql {INSERT INTO t2 VALUES(8,9,0);}
} {1 {no such table: t2}}
do_test testtable-1.8 {
db2 eval {INSERT INTO t2 VALUES(8,9,0);}
db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6 8 9 0}
do_test testtable-1.9 {
db2 eval {DELETE FROM t2 WHERE x==8}
db2 eval {SELECT * FROM t2 ORDER BY x}
} {4 5 6}
do_test testtable-1.10 {
db2 eval {DELETE FROM t2}
db2 eval {SELECT * FROM t2}
} {}
do_test testtable-1.11 {
db2 eval {
INSERT INTO t2 VALUES(7,6,5);
INSERT INTO t2 VALUES(4,3,2);
SELECT * FROM t2 ORDER BY x;
}
} {4 3 2 7 6 5}
do_test testtable-1.12 {
db2 eval {DROP TABLE t2;}
set r [catch {db2 eval {SELECT * FROM t2}} msg]
lappend r $msg
} {1 {no such table: t2}}
# Make sure temporary tables work with transactions
#
do_test testtable-2.1 {
execsql {
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t2(x,y);
INSERT INTO t2 VALUES(1,2);
SELECT * FROM t2;
}
} {1 2}
do_test testtable-2.2 {
execsql {ROLLBACK}
catchsql {SELECT * FROM t2}
} {1 {no such table: t2}}
do_test testtable-2.3 {
execsql {
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t2(x,y);
INSERT INTO t2 VALUES(1,2);
SELECT * FROM t2;
}
} {1 2}
do_test testtable-2.4 {
execsql {COMMIT}
catchsql {SELECT * FROM t2}
} {0 {1 2}}
do_test testtable-2.5 {
set r [catch {db2 eval {SELECT * FROM t2}} msg]
lappend r $msg
} {1 {no such table: t2}}
# Check for correct name collision processing. A name collision can
# occur when process A creates a temporary table T then process B
# creates a permanent table also named T. The temp table in process A
# hides the existance of the permanent table.
#
finish_test

View File

@ -20,8 +20,10 @@ proc chng {date desc} {
chng {2001 Oct ? (2.0.2)} { chng {2001 Oct ? (2.0.2)} {
<li>Removed some unused "#include <unistd.h>" that were causing problems <li>Removed some unused "#include <unistd.h>" that were causing problems
for VC++.</li> for VC++.</li>
<li>Fixed <b>sqlite.h</b> so that it is usable from C++</li>
<li>Added the FULL_COLUMN_NAMES pragma. When set to "ON", the names of <li>Added the FULL_COLUMN_NAMES pragma. When set to "ON", the names of
columns are reported back as TABLE.COLUMN instead of just COLUMN.</li> columns are reported back as TABLE.COLUMN instead of just COLUMN.</li>
<li>Added support for TEMPORARY tables and indices.</li>
} }
chng {2001 Oct 2 (2.0.1)} { chng {2001 Oct 2 (2.0.1)} {

View File

@ -1,7 +1,7 @@
# #
# Run this Tcl script to generate the sqlite.html file. # Run this Tcl script to generate the sqlite.html file.
# #
set rcsid {$Id: lang.tcl,v 1.10 2001/09/28 17:47:14 drh Exp $} set rcsid {$Id: lang.tcl,v 1.11 2001/10/08 13:22:33 drh Exp $}
puts {<html> puts {<html>
<head> <head>
@ -119,15 +119,14 @@ ROLLBACK [TRANSACTION [<name>]]
puts { puts {
<p>Beginning in version 2.0, SQLite supports transactions with <p>Beginning in version 2.0, SQLite supports transactions with
rollback and atomic commit. However, only a single level of rollback and atomic commit. However, only a single level of
transaction is allowed. In other words, transactions transaction is allowed. Transactions may not be nested.
may not be nested.
</p> </p>
<p> <p>
No changes can be made to the database except within a transaction. No changes can be made to the database except within a transaction.
Any command that changes the database (basically, any SQL command Any command that changes the database (basically, any SQL command
other than SELECT) will automatically starts a transaction if other than SELECT) will automatically starts a transaction if
when is not already in effect. Automatically stared transactions one is not already in effect. Automatically stared transactions
are committed at the conclusion of the command. are committed at the conclusion of the command.
</p> </p>
@ -206,7 +205,7 @@ SQLite's internal representation of the index layout.</p>
Section {CREATE TABLE} {createtable} Section {CREATE TABLE} {createtable}
Syntax {sql-command} { Syntax {sql-command} {
CREATE TABLE <table-name> ( CREATE [TEMP | TEMPORARY] TABLE <table-name> (
<column-def> [, <column-def>]* <column-def> [, <column-def>]*
[, <constraint>]* [, <constraint>]*
) )
@ -246,6 +245,13 @@ The DEFAULT constraint
specifies a default value to use when doing an INSERT. specifies a default value to use when doing an INSERT.
</p> </p>
<p>If the "TEMP" or "TEMPORARY" keyword occurs in between "CREATE"
and "TABLE" then the table that is created is only visible to the
process that opened the database and is automatically deleted when
the database is closed. Any indices created on a temporary table
are also temporary. Temporary tables and indices are stored in a
separate file distinct from the main database file.</p>
<p>There are no arbitrary limits on the number <p>There are no arbitrary limits on the number
of columns or on the number of constraints in a table. of columns or on the number of constraints in a table.
The total amount of data in a single row is limited to 65535 bytes.</p> The total amount of data in a single row is limited to 65535 bytes.</p>
@ -579,20 +585,55 @@ puts {
<p>The VACUUM command is an SQLite extension modelled after a similar <p>The VACUUM command is an SQLite extension modelled after a similar
command found in PostgreSQL. If VACUUM is invoked with the name of a command found in PostgreSQL. If VACUUM is invoked with the name of a
table or index then it is suppose to clean up the named table or index. table or index then it is suppose to clean up the named table or index.
In the current implementation, VACUUM is a no-op. In version 1.0 of SQLite, the VACUUM command would invoke
<b>gdbm_reorganize()</b> to clean up the backend database file.
Beginning with version 2.0 of SQLite, GDBM is no longer used for
the database backend and VACUUM has become a no-op.
</p> </p>
} }
Section PRAGMA pragma Section PRAGMA pragma
Syntax {sql-statement} { Syntax {sql-statement} {
PRAGMA <name> = <value> PRAGMA <name> = <value> |
PRAGMA <function>(<arg>)
} }
puts { puts {
<p>The PRAGMA command is used to modify the operation of the SQLite library. <p>The PRAGMA command is used to modify the operation of the SQLite library.
Additional documentation on the PRAMGA statement is forthcoming. The pragma command is experimental and specific pragma statements may
</p> removed or added in future releases of SQLite. Use this command
with caution.</p>
<p>The current implementation supports the following pragmas:</p>
<ul>
<li><p><b>PRAGMA cache_size = </b><i>Number-of-pages</i><b>;</b></p>
<p>Change the maximum number of database disk pages that SQLite
will hold in memory at once. Each page uses about 1.5K of RAM.
The default cache size is 100. If you are doing UPDATEs or DELETEs
that change many rows of a database and you do not mind if SQLite
uses more memory, you can increase the cache size for a possible speed
improvement.</p></li>
<li><p><b>PRAGMA full_column_names = ON;
<br>PRAGMA full_column_names = OFF;</b></p>
<p>The column names reported in an SQLite callback are normally just
the name of the column itself, except for joins when "TABLE.COLUMN"
is used. But when full_column_names is turned on, column names are
always reported as "TABLE.COLUMN" even for simple queries.</p></li>
<li><p><b>PRAGMA vdbe_trace = ON;<br>PRAGMA vdbe_trace = OFF;</b></p>
<p>Turn tracing of the virtual database engine inside of the
SQLite library on and off. This is used for debugging.</p></li>
<li><p><b>PRAGMA parser_trace = ON;<br>PRAGMA parser_trace = OFF;</b></p>
<p>Turn tracing of the SQL parser inside of the
SQLite library on and off. This is used for debugging.</p></li>
</ul>
<p>No error message is generated if an unknown pragma is issued.
Unknown pragmas are ignored.</p>
} }
puts { puts {