Support for temporary tables added. Still need more testing. (CVS 279)
FossilOrigin-Name: 9368c62e4097aae3081a325962c1dec167fd253d
This commit is contained in:
parent
382c0247c7
commit
f57b339988
41
manifest
41
manifest
@ -1,5 +1,5 @@
|
||||
C Adding\stable\scolumn\squery\scapability\sto\ssupport\sODBC.\s(CVS\s278)
|
||||
D 2001-10-06T16:33:02
|
||||
C Support\sfor\stemporary\stables\sadded.\s\sStill\sneed\smore\stesting.\s(CVS\s279)
|
||||
D 2001-10-08T13:22:32
|
||||
F Makefile.in 98d4627cb364537e4c3a29ee806171f3abf5211a
|
||||
F Makefile.template 1e54087c0390c4ce0bb5be43e14ba028283751e6
|
||||
F README 93d2977cc5c6595c448de16bdefc312b9d401533
|
||||
@ -21,37 +21,37 @@ F publish.sh 502b907fa9e0214309406fa5f520b3d3c14f9c1d
|
||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||
F src/btree.c 7e9c33a714ed1630562f89ad19847f5f28bd6d4d
|
||||
F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
|
||||
F src/build.c 7cbac6c3a5d35e56f8d57bb6b07fba5e8a41c806
|
||||
F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2
|
||||
F src/build.c 55ca22cd7af59b7f8895c601ed9cf006adf50f05
|
||||
F src/delete.c 93c9d5e160395020a25d59371625db74c97c7c4d
|
||||
F src/expr.c 2f68829d983ec3f92eeb8b89ce4b9e5704169a80
|
||||
F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
|
||||
F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
|
||||
F src/insert.c 01dd6ddee901a8a55c9b05a62b30023ec43de9ce
|
||||
F src/main.c 6db4ba7ed8f1c1866b04eab6d0f9b46455e152c8
|
||||
F src/insert.c a48ba850461b203fb8dbc7add83fc6b6a9cf47f3
|
||||
F src/main.c 87b2fca50cbe8b400e1443b2c73693e18d9911cb
|
||||
F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
|
||||
F src/os.c 45376582c41dc8829330816d56b8e9e6cd1b7972
|
||||
F src/os.c d3f435d89241e06d4230b6f79a4e9d49102eb0a4
|
||||
F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d
|
||||
F src/pager.c 592c16b06ad07c715240e382028e29b0e83378be
|
||||
F src/pager.c 3445bd7c18cbfdffd8d6d1077f0b2bdf788da4fe
|
||||
F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
|
||||
F src/parse.y fcd3452640cf5ae2304ce430668112e0da07745a
|
||||
F src/parse.y e88f1efe096a1a01c9076099fe1d81deedfa11de
|
||||
F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
|
||||
F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec
|
||||
F src/select.c 0ef8ca1b7de2467fe082bcb35a5ab3b5be56153c
|
||||
F src/shell.c cb8c41f1b2173efd212dab3f35f1fc6bf32ead76
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in b95c161abf1d58bceb05290fa3f657d8f388fc11
|
||||
F src/sqliteInt.h 78b1890c4b61d35f33941cf9a2aae366b32b3dd3
|
||||
F src/sqliteInt.h d75506e003b508d8e2501217648f045496813f2c
|
||||
F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
|
||||
F src/tclsqlite.c 765599686c19ed777ac379928d732c8bfc63ebac
|
||||
F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
|
||||
F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
|
||||
F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
|
||||
F src/tokenize.c 8a2aa0443f8bb1a02d021604377e2783e8e45f42
|
||||
F src/update.c 0449af173b5f2f0b26e2f0e4545ee0e0429763cb
|
||||
F src/tokenize.c 5bd2dd048d77f4c683f0551a73d2fa5e964b53f0
|
||||
F src/update.c 49a1edb1a3e44dfff3f799e00f2a3319f2393cd8
|
||||
F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
|
||||
F src/vdbe.c 5c865988f8b33dcb8c5282f24bde404ab5d96899
|
||||
F src/vdbe.h c543a58f52fb654c90dd31d0d0c31309f4d838de
|
||||
F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
|
||||
F src/vdbe.c 469c36ce2ef72a10447796dc5b5d61317e47fff2
|
||||
F src/vdbe.h 7eb7e9e6c58fe9430efab35e168f96cb4bd6cb45
|
||||
F src/where.c b676765ad0360769173b09f46265ddec8d48367a
|
||||
F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
|
||||
F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
|
||||
F test/btree.test 47952c7a0c22660566264c68c0664592b7da85ce
|
||||
@ -83,6 +83,7 @@ F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
|
||||
F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
|
||||
F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
|
||||
F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
|
||||
F test/temptable.test 99611832cdef52a30e62b091eaf941dbc934f303
|
||||
F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
|
||||
F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
|
||||
F test/unique.test ef1f67607a7109e9c0842cd8557550fb121d7ec6
|
||||
@ -100,19 +101,19 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
|
||||
F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
|
||||
F www/arch.tcl 03b521d252575f93b9c52f7c8b0007011512fcfb
|
||||
F www/c_interface.tcl 8e8d9e66e8467c5751116c3427296bde77f474a6
|
||||
F www/changes.tcl 8c2ecc905283cfe3221722d8e8bcb660af2297b2
|
||||
F www/changes.tcl b42f68ebc6a590ab3dd4f16e389faad2a7f2d541
|
||||
F www/crosscompile.tcl c99efacb3aefaa550c6e80d91b240f55eb9fd33e
|
||||
F www/download.tcl 3e51c9ff1326b0a182846134987301310dff7d60
|
||||
F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c
|
||||
F www/index.tcl 68c815d64b35b2dcc4d4f6845827df71c6869f9f
|
||||
F www/lang.tcl 33a74d727615ccbee8be7c8efd5876ce008c4b0e
|
||||
F www/lang.tcl 3a7900e3f80cab50f322d925e573bd9f0acd57e1
|
||||
F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
|
||||
F www/opcode.tcl 4365ad9798872491dbd7d3071510ebe461785ac3
|
||||
F www/speed.tcl ab7d6d3bc898472bd94320a5d3c63de928d4804b
|
||||
F www/sqlite.tcl 6a21242a272e9c0939a04419a51c3d50cae33e3e
|
||||
F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
|
||||
F www/vdbe.tcl bb7d620995f0a987293e9d4fb6185a3b077e9b44
|
||||
P e4980849403a8d7bd63753c9b7f275519bd7df4f
|
||||
R 7502c066a19df2a451414aa8e23b0cac
|
||||
P b63b3f3684a3d584ef99f54cde76b6c483bbfef7
|
||||
R 9a90e6e0cf1a1b0f9063fbb657761a98
|
||||
U drh
|
||||
Z 47fec5ca7cd29a261f31f63e809cee33
|
||||
Z 4e9556749f24d361b6f8c2df79fd7c4c
|
||||
|
@ -1 +1 @@
|
||||
b63b3f3684a3d584ef99f54cde76b6c483bbfef7
|
||||
9368c62e4097aae3081a325962c1dec167fd253d
|
295
src/build.c
295
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** 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 <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 *pNew;
|
||||
@ -131,8 +133,8 @@ void sqliteExprDelete(Expr *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate the in-memory structure that describes the
|
||||
** format of a particular database table given the name
|
||||
** Locate the in-memory structure that describes
|
||||
** a particular database table given the name
|
||||
** of that table. Return NULL if not found.
|
||||
*/
|
||||
Table *sqliteFindTable(sqlite *db, char *zName){
|
||||
@ -141,9 +143,9 @@ Table *sqliteFindTable(sqlite *db, char *zName){
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate the in-memory structure that describes the
|
||||
** format of a particular index given the name
|
||||
** of that index. Return NULL if not found.
|
||||
** Locate the in-memory structure that describes
|
||||
** a particular index given the name of that index.
|
||||
** Return NULL if not found.
|
||||
*/
|
||||
Index *sqliteFindIndex(sqlite *db, char *zName){
|
||||
Index *p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1);
|
||||
@ -155,7 +157,7 @@ Index *sqliteFindIndex(sqlite *db, char *zName){
|
||||
** its memory structures.
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
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
|
||||
** the index from the index hash table, and free its memory
|
||||
** the index from the index hash table and free its memory
|
||||
** structures.
|
||||
*/
|
||||
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,
|
||||
** 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
|
||||
** internal hash tables are undone.
|
||||
**
|
||||
@ -334,14 +336,19 @@ char *sqliteTableNameFromToken(Token *pName){
|
||||
** 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.
|
||||
** 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
|
||||
** more of the CREATE TABLE statement is parsed, additional action
|
||||
** routines are called to build up more of the table.
|
||||
** The new table record is initialized and put in pParse->pNewTable.
|
||||
** As more of the CREATE TABLE statement is parsed, additional action
|
||||
** 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;
|
||||
Index *pIdx;
|
||||
char *zName;
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v;
|
||||
@ -349,15 +356,54 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
|
||||
pParse->sFirstToken = *pStart;
|
||||
zName = sqliteTableNameFromToken(pName);
|
||||
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);
|
||||
if( pTable!=0 ){
|
||||
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
|
||||
" already exists", 0, 0);
|
||||
sqliteFree(zName);
|
||||
pParse->nErr++;
|
||||
return;
|
||||
if( pTable->isTemp && pParse->initFlag ){
|
||||
pParse->nameClash = 1;
|
||||
}else{
|
||||
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
|
||||
" 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 ",
|
||||
zName, 0);
|
||||
sqliteFree(zName);
|
||||
@ -370,6 +416,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
|
||||
pTable->nCol = 0;
|
||||
pTable->aCol = 0;
|
||||
pTable->pIndex = 0;
|
||||
pTable->isTemp = isTemp;
|
||||
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
|
||||
pParse->pNewTable = pTable;
|
||||
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);
|
||||
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;
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
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;
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
i = p->nCol-1;
|
||||
if( i<0 ) return;
|
||||
pz = &p->aCol[i].zType;
|
||||
n = pLast->n + ((int)pLast->z) - (int)pFirst->z;
|
||||
sqliteSetNString(pz, pFirst->z, n, 0);
|
||||
z = *pz;
|
||||
if( z==0 ) return;
|
||||
for(i=j=0; z[i]; i++){
|
||||
int c = z[i];
|
||||
if( isspace(c) ) continue;
|
||||
@ -463,6 +514,7 @@ void sqliteAddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
|
||||
char **pz;
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
i = p->nCol-1;
|
||||
if( i<0 ) return;
|
||||
pz = &p->aCol[i].zDflt;
|
||||
if( minusFlag ){
|
||||
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
|
||||
** 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,
|
||||
** unless initFlag==1. When initFlag==1, it means we are reading
|
||||
** the master table because we just connected to the database, so
|
||||
** the entry for this table already exists in the master table.
|
||||
** We do not want to create it again.
|
||||
** unless this is a temporary table or initFlag==1. When initFlag==1,
|
||||
** it means we are reading the sqlite_master table because we just
|
||||
** connected to the database or because the sqlite_master table has
|
||||
** 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){
|
||||
Table *p;
|
||||
@ -516,9 +571,10 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
p = pParse->pNewTable;
|
||||
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);
|
||||
pParse->pNewTable = 0;
|
||||
db->nTable++;
|
||||
@ -537,6 +593,9 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
|
||||
/* If not initializing, then create a record for the new table
|
||||
** 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 ){
|
||||
int n, addr;
|
||||
@ -545,20 +604,24 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 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);
|
||||
if( !p->isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 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);
|
||||
}
|
||||
addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1);
|
||||
p->tnum = 0;
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
if( !p->isTemp ){
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
|
||||
sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n);
|
||||
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
}
|
||||
if( (db->flags & SQLITE_InTrans)==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_Delete, 0, 0, 0},
|
||||
{ OP_Goto, 0, ADDR(3), 0},
|
||||
{ OP_Destroy, 0, 0, 0}, /* 9 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 10 */
|
||||
{ OP_SetCookie, 0, 0, 0}, /* 9 */
|
||||
{ OP_Close, 0, 0, 0},
|
||||
};
|
||||
Index *pIdx;
|
||||
@ -629,13 +691,15 @@ void sqliteDropTable(Parse *pParse, Token *pName){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
|
||||
sqliteVdbeChangeP1(v, base+9, pTable->tnum);
|
||||
changeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+10, db->next_cookie);
|
||||
if( !pTable->isTemp ){
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
|
||||
sqliteVdbeChangeP3(v, base+2, pTable->zName, 0);
|
||||
changeCookie(db);
|
||||
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){
|
||||
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 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
@ -679,8 +743,9 @@ void sqliteCreateIndex(
|
||||
Index *pIndex; /* The index to be created */
|
||||
char *zName = 0;
|
||||
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;
|
||||
int hideName = 0; /* Do not put table name in the hash table */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
|
||||
|
||||
@ -702,26 +767,56 @@ void sqliteCreateIndex(
|
||||
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
|
||||
** 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
|
||||
** own name.
|
||||
*/
|
||||
if( pName ){
|
||||
Index *pISameName; /* Another index with the same name */
|
||||
Table *pTSameName; /* A table with same name as the index */
|
||||
zName = sqliteTableNameFromToken(pName);
|
||||
if( zName==0 ) goto exit_create_index;
|
||||
if( sqliteFindIndex(db, zName) ){
|
||||
sqliteSetString(&pParse->zErrMsg, "index ", zName,
|
||||
" already exists", 0);
|
||||
pParse->nErr++;
|
||||
goto exit_create_index;
|
||||
if( (pISameName = sqliteFindIndex(db, zName))!=0 ){
|
||||
if( pISameName->pTable->isTemp && pParse->initFlag ){
|
||||
hideName = 1;
|
||||
}else{
|
||||
sqliteSetString(&pParse->zErrMsg, "index ", zName,
|
||||
" already exists", 0);
|
||||
pParse->nErr++;
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
if( sqliteFindTable(db, zName) ){
|
||||
sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
|
||||
zName, 0);
|
||||
pParse->nErr++;
|
||||
goto exit_create_index;
|
||||
if( (pTSameName = sqliteFindTable(db, zName))!=0 ){
|
||||
if( pTSameName->isTemp && pParse->initFlag ){
|
||||
hideName = 1;
|
||||
}else{
|
||||
sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
|
||||
zName, 0);
|
||||
pParse->nErr++;
|
||||
goto exit_create_index;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
char zBuf[30];
|
||||
@ -781,7 +876,7 @@ void sqliteCreateIndex(
|
||||
*/
|
||||
pIndex->pNext = pTab->pIndex;
|
||||
pTab->pIndex = pIndex;
|
||||
if( !pParse->explain ){
|
||||
if( !pParse->explain && !hideName ){
|
||||
sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
@ -815,6 +910,7 @@ void sqliteCreateIndex(
|
||||
int lbl1, lbl2;
|
||||
int i;
|
||||
int addr;
|
||||
int isTemp = pTab->isTemp;
|
||||
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v==0 ) goto exit_create_index;
|
||||
@ -824,28 +920,39 @@ void sqliteCreateIndex(
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
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);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0);
|
||||
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0);
|
||||
if( !isTemp ){
|
||||
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0);
|
||||
sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 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);
|
||||
pIndex->tnum = 0;
|
||||
if( pTable ){
|
||||
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0);
|
||||
if( isTemp ){
|
||||
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( pStart && pEnd ){
|
||||
n = (int)pEnd->z - (int)pStart->z + 1;
|
||||
sqliteVdbeChangeP3(v, addr, pStart->z, n);
|
||||
if( !isTemp ){
|
||||
addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
|
||||
if( pStart && pEnd ){
|
||||
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 ){
|
||||
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);
|
||||
lbl2 = sqliteVdbeMakeLabel(v);
|
||||
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_Noop, 0, 0, 0, lbl2);
|
||||
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 ){
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
if( !isTemp ){
|
||||
changeCookie(db);
|
||||
sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
|
||||
}
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
@ -916,17 +1025,20 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
|
||||
{ OP_Close, 0, 0, 0},
|
||||
};
|
||||
int base;
|
||||
Table *pTab = pIndex->pTable;
|
||||
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
|
||||
sqliteVdbeChangeP1(v, base+8, pIndex->tnum);
|
||||
changeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+9, db->next_cookie);
|
||||
if( !pTab->isTemp ){
|
||||
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
|
||||
sqliteVdbeChangeP3(v, base+2, pIndex->zName, 0);
|
||||
changeCookie(db);
|
||||
sqliteVdbeChangeP1(v, base+9, db->next_cookie);
|
||||
}
|
||||
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp, 0, 0);
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
|
||||
}
|
||||
@ -1091,6 +1203,7 @@ void sqliteCopy(
|
||||
}
|
||||
v = sqliteGetVdbe(pParse);
|
||||
if( v ){
|
||||
int openOp;
|
||||
if( (db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_Transaction, 0, 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);
|
||||
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
|
||||
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++){
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum, pIdx->zName, 0);
|
||||
sqliteVdbeAddOp(v, openOp, i, pIdx->tnum, pIdx->zName, 0);
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
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
|
||||
#endif
|
||||
|
||||
if( zLeft ) sqliteFree(zLeft);
|
||||
if( zRight ) sqliteFree(zRight);
|
||||
{}
|
||||
sqliteFree(zLeft);
|
||||
sqliteFree(zRight);
|
||||
}
|
||||
|
13
src/delete.c
13
src/delete.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** 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"
|
||||
|
||||
@ -91,9 +91,9 @@ void sqliteDeleteFrom(
|
||||
** It is easier just to erase the whole table.
|
||||
*/
|
||||
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){
|
||||
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.
|
||||
*/
|
||||
else{
|
||||
int openOp;
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
|
||||
@ -121,9 +123,10 @@ void sqliteDeleteFrom(
|
||||
*/
|
||||
base = pParse->nTab;
|
||||
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){
|
||||
sqliteVdbeAddOp(v, OP_OpenWrite, base+i, pIdx->tnum, 0, 0);
|
||||
sqliteVdbeAddOp(v, openOp, base+i, pIdx->tnum, 0, 0);
|
||||
}
|
||||
end = sqliteVdbeMakeLabel(v);
|
||||
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** 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"
|
||||
|
||||
@ -48,6 +48,7 @@ void sqliteInsert(
|
||||
int base; /* First available cursor */
|
||||
int iCont, iBreak; /* Beginning and end of the loop over srcTab */
|
||||
sqlite *db; /* The main database structure */
|
||||
int openOp; /* Opcode used to open cursors */
|
||||
|
||||
if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
|
||||
db = pParse->db;
|
||||
@ -155,9 +156,10 @@ void sqliteInsert(
|
||||
** all indices of that table.
|
||||
*/
|
||||
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++){
|
||||
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
|
||||
|
28
src/main.c
28
src/main.c
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.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 "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
|
||||
** 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
|
||||
** changed the schema and this process needs to reread it.
|
||||
*/
|
||||
static void clearHashTable(sqlite *db){
|
||||
static void clearHashTable(sqlite *db, int preserveTemps){
|
||||
HashElem *pElem;
|
||||
Hash temp1;
|
||||
temp1 = db->tblHash;
|
||||
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqliteHashClear(&db->idxHash);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTbl = sqliteHashData(pElem);
|
||||
sqliteDeleteTable(db, pTbl);
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
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);
|
||||
db->flags &= ~SQLITE_Initialized;
|
||||
@ -336,7 +347,10 @@ static void clearHashTable(sqlite *db){
|
||||
*/
|
||||
void sqlite_close(sqlite *db){
|
||||
sqliteBtreeClose(db->pBe);
|
||||
clearHashTable(db);
|
||||
clearHashTable(db, 0);
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeClose(db->pBeTemp);
|
||||
}
|
||||
sqliteFree(db);
|
||||
}
|
||||
|
||||
@ -429,7 +443,7 @@ int sqlite_exec(
|
||||
}
|
||||
sqliteStrRealloc(pzErrMsg);
|
||||
if( sParse.rc==SQLITE_SCHEMA ){
|
||||
clearHashTable(db);
|
||||
clearHashTable(db, 1);
|
||||
}
|
||||
return sParse.rc;
|
||||
}
|
||||
|
3
src/os.c
3
src/os.c
@ -397,6 +397,9 @@ int sqliteOsLock(OsFile id, int wrlock){
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = lock.l_len = 0L;
|
||||
rc = fcntl(id, F_SETLK, &lock);
|
||||
if( rc ){
|
||||
fcntl(id, F_GETLK, &lock); /* For debugging */
|
||||
}
|
||||
return rc==0 ? SQLITE_OK : SQLITE_BUSY;
|
||||
#endif
|
||||
#if OS_WIN
|
||||
|
12
src/pager.c
12
src/pager.c
@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** 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 "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( sqliteOsFileExists(pPager->zJournal) ){
|
||||
int rc;
|
||||
int rc, dummy;
|
||||
|
||||
/* 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 ){
|
||||
pPager->journalOpen = 1;
|
||||
}
|
||||
|
@ -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.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_type {Token}
|
||||
@ -62,7 +62,11 @@ cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);}
|
||||
///////////////////// The CREATE TABLE statement ////////////////////////////
|
||||
//
|
||||
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).
|
||||
{sqliteEndTable(pParse,&X);}
|
||||
columnlist ::= columnlist COMMA column.
|
||||
@ -91,6 +95,7 @@ id(A) ::= END(X). {A = X;}
|
||||
id(A) ::= PRAGMA(X). {A = X;}
|
||||
id(A) ::= CLUSTER(X). {A = X;}
|
||||
id(A) ::= ID(X). {A = X;}
|
||||
id(A) ::= TEMP(X). {A = X;}
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** 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 "hash.h"
|
||||
@ -139,6 +139,7 @@ typedef struct AggExpr AggExpr;
|
||||
*/
|
||||
struct sqlite {
|
||||
Btree *pBe; /* The B*Tree backend */
|
||||
Btree *pBeTemp; /* Backend for session temporary tables */
|
||||
int flags; /* Miscellanous flags. See below */
|
||||
int file_format; /* What file format version is this database? */
|
||||
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 isCommit; /* True if creation of this table has been committed */
|
||||
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 {
|
||||
sqlite *db; /* The main database structure */
|
||||
@ -372,8 +376,8 @@ struct Parse {
|
||||
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 */
|
||||
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 nTab; /* Number of previously allocated cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
@ -423,7 +427,7 @@ void sqliteExprListDelete(ExprList*);
|
||||
void sqlitePragma(Parse*,Token*,Token*,int);
|
||||
void sqliteCommitInternalChanges(sqlite*);
|
||||
void sqliteRollbackInternalChanges(sqlite*);
|
||||
void sqliteStartTable(Parse*,Token*,Token*);
|
||||
void sqliteStartTable(Parse*,Token*,Token*,int);
|
||||
void sqliteAddColumn(Parse*,Token*);
|
||||
void sqliteAddNotNull(Parse*);
|
||||
void sqliteAddColumnType(Parse*,Token*,Token*);
|
||||
|
@ -15,7 +15,7 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** 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 <ctype.h>
|
||||
@ -84,6 +84,8 @@ static Keyword aKeywordTable[] = {
|
||||
{ "SELECT", 0, TK_SELECT, 0 },
|
||||
{ "SET", 0, TK_SET, 0 },
|
||||
{ "TABLE", 0, TK_TABLE, 0 },
|
||||
{ "TEMP", 0, TK_TEMP, 0 },
|
||||
{ "TEMPORARY", 0, TK_TEMP, 0 },
|
||||
{ "TRANSACTION", 0, TK_TRANSACTION, 0 },
|
||||
{ "UNION", 0, TK_UNION, 0 },
|
||||
{ "UNIQUE", 0, TK_UNIQUE, 0 },
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** 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"
|
||||
|
||||
@ -39,6 +39,7 @@ void sqliteUpdate(
|
||||
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
|
||||
** an expression for the i-th column of the table.
|
||||
** 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;
|
||||
db = pParse->db;
|
||||
@ -159,9 +160,10 @@ void sqliteUpdate(
|
||||
*/
|
||||
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
|
||||
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++){
|
||||
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
|
||||
|
169
src/vdbe.c
169
src/vdbe.c
@ -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.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 <ctype.h>
|
||||
@ -793,30 +793,31 @@ void sqliteVdbeDelete(Vdbe *p){
|
||||
static char *zOpName[] = { 0,
|
||||
"Transaction", "Commit", "Rollback", "ReadCookie",
|
||||
"SetCookie", "VerifyCookie", "Open", "OpenTemp",
|
||||
"OpenWrite", "Close", "MoveTo", "Fcnt",
|
||||
"NewRecno", "Put", "Distinct", "Found",
|
||||
"NotFound", "Delete", "Column", "KeyAsData",
|
||||
"Recno", "FullKey", "Rewind", "Next",
|
||||
"Destroy", "Clear", "CreateIndex", "CreateTable",
|
||||
"Reorganize", "BeginIdx", "NextIdx", "PutIdx",
|
||||
"DeleteIdx", "MemLoad", "MemStore", "ListOpen",
|
||||
"ListWrite", "ListRewind", "ListRead", "ListClose",
|
||||
"SortOpen", "SortPut", "SortMakeRec", "SortMakeKey",
|
||||
"Sort", "SortNext", "SortKey", "SortCallback",
|
||||
"SortClose", "FileOpen", "FileRead", "FileColumn",
|
||||
"FileClose", "AggReset", "AggFocus", "AggIncr",
|
||||
"AggNext", "AggSet", "AggGet", "SetInsert",
|
||||
"SetFound", "SetNotFound", "SetClear", "MakeRecord",
|
||||
"MakeKey", "MakeIdxKey", "Goto", "If",
|
||||
"Halt", "ColumnCount", "ColumnName", "Callback",
|
||||
"Integer", "String", "Null", "Pop",
|
||||
"Dup", "Pull", "Add", "AddImm",
|
||||
"Subtract", "Multiply", "Divide", "Min",
|
||||
"Max", "Like", "Glob", "Eq",
|
||||
"Ne", "Lt", "Le", "Gt",
|
||||
"Ge", "IsNull", "NotNull", "Negative",
|
||||
"And", "Or", "Not", "Concat",
|
||||
"Noop", "Strlen", "Substr",
|
||||
"OpenWrite", "OpenAux", "OpenWrAux", "Close",
|
||||
"MoveTo", "Fcnt", "NewRecno", "Put",
|
||||
"Distinct", "Found", "NotFound", "Delete",
|
||||
"Column", "KeyAsData", "Recno", "FullKey",
|
||||
"Rewind", "Next", "Destroy", "Clear",
|
||||
"CreateIndex", "CreateTable", "Reorganize", "BeginIdx",
|
||||
"NextIdx", "PutIdx", "DeleteIdx", "MemLoad",
|
||||
"MemStore", "ListOpen", "ListWrite", "ListRewind",
|
||||
"ListRead", "ListClose", "SortOpen", "SortPut",
|
||||
"SortMakeRec", "SortMakeKey", "Sort", "SortNext",
|
||||
"SortKey", "SortCallback", "SortClose", "FileOpen",
|
||||
"FileRead", "FileColumn", "FileClose", "AggReset",
|
||||
"AggFocus", "AggIncr", "AggNext", "AggSet",
|
||||
"AggGet", "SetInsert", "SetFound", "SetNotFound",
|
||||
"SetClear", "MakeRecord", "MakeKey", "MakeIdxKey",
|
||||
"Goto", "If", "Halt", "ColumnCount",
|
||||
"ColumnName", "Callback", "Integer", "String",
|
||||
"Null", "Pop", "Dup", "Pull",
|
||||
"Add", "AddImm", "Subtract", "Multiply",
|
||||
"Divide", "Min", "Max", "Like",
|
||||
"Glob", "Eq", "Ne", "Lt",
|
||||
"Le", "Gt", "Ge", "IsNull",
|
||||
"NotNull", "Negative", "And", "Or",
|
||||
"Not", "Concat", "Noop", "Strlen",
|
||||
"Substr",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1920,6 +1921,12 @@ case OP_MakeIdxKey: {
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
int busy = 0;
|
||||
if( db->pBeTemp ){
|
||||
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
do{
|
||||
rc = sqliteBtreeBeginTrans(pBt);
|
||||
switch( rc ){
|
||||
@ -1951,7 +1958,9 @@ case OP_Transaction: {
|
||||
** A read lock continues to be held if there are still cursors open.
|
||||
*/
|
||||
case OP_Commit: {
|
||||
rc = sqliteBtreeCommit(pBt);
|
||||
if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
|
||||
rc = sqliteBtreeCommit(pBt);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteCommitInternalChanges(db);
|
||||
}else{
|
||||
@ -1971,6 +1980,9 @@ case OP_Commit: {
|
||||
** the read and write locks on the database.
|
||||
*/
|
||||
case OP_Rollback: {
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeRollback(db->pBeTemp);
|
||||
}
|
||||
rc = sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
break;
|
||||
@ -2065,6 +2077,16 @@ case OP_VerifyCookie: {
|
||||
** The P3 value is not actually used by this opcode and may be
|
||||
** omitted. But the code generator usually inserts the index or
|
||||
** 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
|
||||
**
|
||||
@ -2074,13 +2096,33 @@ case OP_VerifyCookie: {
|
||||
** 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
|
||||
** 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_Open: {
|
||||
int busy = 0;
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
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( tos<0 ) goto not_enough_stack;
|
||||
Integerify(p, tos);
|
||||
@ -2105,8 +2147,7 @@ case OP_Open: {
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
memset(&p->aCsr[i], 0, sizeof(Cursor));
|
||||
do{
|
||||
int wrFlag = pOp->opcode==OP_OpenWrite;
|
||||
rc = sqliteBtreeCursor(pBt, p2, wrFlag, &p->aCsr[i].pCursor);
|
||||
rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
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
|
||||
** database is read-only. The temporary file is deleted when the
|
||||
** 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: {
|
||||
int i = pOp->p1;
|
||||
@ -2765,34 +2813,43 @@ case OP_DeleteIdx: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Destroy P1 * *
|
||||
/* Opcode: Destroy P1 P2 *
|
||||
**
|
||||
** Delete an entire database table or index whose root page in the database
|
||||
** 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
|
||||
*/
|
||||
case OP_Destroy: {
|
||||
sqliteBtreeDropTable(pBt, pOp->p1);
|
||||
sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Clear P1 * *
|
||||
/* Opcode: Clear P1 P2 *
|
||||
**
|
||||
** 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
|
||||
** 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
|
||||
*/
|
||||
case OP_Clear: {
|
||||
sqliteBtreeClearTable(pBt, pOp->p1);
|
||||
sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
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.
|
||||
**
|
||||
** The root page number is also written to a memory location that P3
|
||||
@ -2802,39 +2859,20 @@ case OP_Clear: {
|
||||
**
|
||||
** 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: {
|
||||
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 ){
|
||||
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);
|
||||
rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
aStack[i].flags = STK_Int;
|
||||
@ -3164,6 +3202,7 @@ case OP_SortNext: {
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/* Opcode: SortKey P1 * *
|
||||
**
|
||||
** Push the key for the topmost element of the sorter onto the stack.
|
||||
@ -3182,6 +3221,7 @@ case OP_SortKey: {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* NOT USED */
|
||||
|
||||
/* Opcode: SortCallback P1 P2 *
|
||||
**
|
||||
@ -3245,6 +3285,7 @@ case OP_FileOpen: {
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/* Opcode: FileClose * * *
|
||||
**
|
||||
** Close a file previously opened using FileOpen. This is a no-op
|
||||
@ -3267,6 +3308,7 @@ case OP_FileClose: {
|
||||
p->nLineAlloc = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: FileRead P1 P2 P3
|
||||
**
|
||||
@ -3597,6 +3639,7 @@ case OP_AggNext: {
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/* Opcode: SetClear P1 * *
|
||||
**
|
||||
** Remove all elements from the P1-th Set.
|
||||
@ -3608,6 +3651,7 @@ case OP_SetClear: {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* NOT USED */
|
||||
|
||||
/* Opcode: SetInsert P1 * P3
|
||||
**
|
||||
@ -3874,6 +3918,7 @@ cleanup:
|
||||
if( rc!=SQLITE_OK ){
|
||||
closeAllCursors(p);
|
||||
sqliteBtreeRollback(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
}
|
||||
|
194
src/vdbe.h
194
src/vdbe.h
@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** 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_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -71,116 +71,118 @@ typedef struct VdbeOp VdbeOp;
|
||||
#define OP_Open 7
|
||||
#define OP_OpenTemp 8
|
||||
#define OP_OpenWrite 9
|
||||
#define OP_Close 10
|
||||
#define OP_MoveTo 11
|
||||
#define OP_Fcnt 12
|
||||
#define OP_NewRecno 13
|
||||
#define OP_Put 14
|
||||
#define OP_Distinct 15
|
||||
#define OP_Found 16
|
||||
#define OP_NotFound 17
|
||||
#define OP_Delete 18
|
||||
#define OP_Column 19
|
||||
#define OP_KeyAsData 20
|
||||
#define OP_Recno 21
|
||||
#define OP_FullKey 22
|
||||
#define OP_Rewind 23
|
||||
#define OP_Next 24
|
||||
#define OP_OpenAux 10
|
||||
#define OP_OpenWrAux 11
|
||||
#define OP_Close 12
|
||||
#define OP_MoveTo 13
|
||||
#define OP_Fcnt 14
|
||||
#define OP_NewRecno 15
|
||||
#define OP_Put 16
|
||||
#define OP_Distinct 17
|
||||
#define OP_Found 18
|
||||
#define OP_NotFound 19
|
||||
#define OP_Delete 20
|
||||
#define OP_Column 21
|
||||
#define OP_KeyAsData 22
|
||||
#define OP_Recno 23
|
||||
#define OP_FullKey 24
|
||||
#define OP_Rewind 25
|
||||
#define OP_Next 26
|
||||
|
||||
#define OP_Destroy 25
|
||||
#define OP_Clear 26
|
||||
#define OP_CreateIndex 27
|
||||
#define OP_CreateTable 28
|
||||
#define OP_Reorganize 29
|
||||
#define OP_Destroy 27
|
||||
#define OP_Clear 28
|
||||
#define OP_CreateIndex 29
|
||||
#define OP_CreateTable 30
|
||||
#define OP_Reorganize 31
|
||||
|
||||
#define OP_BeginIdx 30
|
||||
#define OP_NextIdx 31
|
||||
#define OP_PutIdx 32
|
||||
#define OP_DeleteIdx 33
|
||||
#define OP_BeginIdx 32
|
||||
#define OP_NextIdx 33
|
||||
#define OP_PutIdx 34
|
||||
#define OP_DeleteIdx 35
|
||||
|
||||
#define OP_MemLoad 34
|
||||
#define OP_MemStore 35
|
||||
#define OP_MemLoad 36
|
||||
#define OP_MemStore 37
|
||||
|
||||
#define OP_ListOpen 36
|
||||
#define OP_ListWrite 37
|
||||
#define OP_ListRewind 38
|
||||
#define OP_ListRead 39
|
||||
#define OP_ListClose 40
|
||||
#define OP_ListOpen 38
|
||||
#define OP_ListWrite 39
|
||||
#define OP_ListRewind 40
|
||||
#define OP_ListRead 41
|
||||
#define OP_ListClose 42
|
||||
|
||||
#define OP_SortOpen 41
|
||||
#define OP_SortPut 42
|
||||
#define OP_SortMakeRec 43
|
||||
#define OP_SortMakeKey 44
|
||||
#define OP_Sort 45
|
||||
#define OP_SortNext 46
|
||||
#define OP_SortKey 47
|
||||
#define OP_SortCallback 48
|
||||
#define OP_SortClose 49
|
||||
#define OP_SortOpen 43
|
||||
#define OP_SortPut 44
|
||||
#define OP_SortMakeRec 45
|
||||
#define OP_SortMakeKey 46
|
||||
#define OP_Sort 47
|
||||
#define OP_SortNext 48
|
||||
#define OP_SortKey 49
|
||||
#define OP_SortCallback 50
|
||||
#define OP_SortClose 51
|
||||
|
||||
#define OP_FileOpen 50
|
||||
#define OP_FileRead 51
|
||||
#define OP_FileColumn 52
|
||||
#define OP_FileClose 53
|
||||
#define OP_FileOpen 52
|
||||
#define OP_FileRead 53
|
||||
#define OP_FileColumn 54
|
||||
#define OP_FileClose 55
|
||||
|
||||
#define OP_AggReset 54
|
||||
#define OP_AggFocus 55
|
||||
#define OP_AggIncr 56
|
||||
#define OP_AggNext 57
|
||||
#define OP_AggSet 58
|
||||
#define OP_AggGet 59
|
||||
#define OP_AggReset 56
|
||||
#define OP_AggFocus 57
|
||||
#define OP_AggIncr 58
|
||||
#define OP_AggNext 59
|
||||
#define OP_AggSet 60
|
||||
#define OP_AggGet 61
|
||||
|
||||
#define OP_SetInsert 60
|
||||
#define OP_SetFound 61
|
||||
#define OP_SetNotFound 62
|
||||
#define OP_SetClear 63
|
||||
#define OP_SetInsert 62
|
||||
#define OP_SetFound 63
|
||||
#define OP_SetNotFound 64
|
||||
#define OP_SetClear 65
|
||||
|
||||
#define OP_MakeRecord 64
|
||||
#define OP_MakeKey 65
|
||||
#define OP_MakeIdxKey 66
|
||||
#define OP_MakeRecord 66
|
||||
#define OP_MakeKey 67
|
||||
#define OP_MakeIdxKey 68
|
||||
|
||||
#define OP_Goto 67
|
||||
#define OP_If 68
|
||||
#define OP_Halt 69
|
||||
#define OP_Goto 69
|
||||
#define OP_If 70
|
||||
#define OP_Halt 71
|
||||
|
||||
#define OP_ColumnCount 70
|
||||
#define OP_ColumnName 71
|
||||
#define OP_Callback 72
|
||||
#define OP_ColumnCount 72
|
||||
#define OP_ColumnName 73
|
||||
#define OP_Callback 74
|
||||
|
||||
#define OP_Integer 73
|
||||
#define OP_String 74
|
||||
#define OP_Null 75
|
||||
#define OP_Pop 76
|
||||
#define OP_Dup 77
|
||||
#define OP_Pull 78
|
||||
#define OP_Integer 75
|
||||
#define OP_String 76
|
||||
#define OP_Null 77
|
||||
#define OP_Pop 78
|
||||
#define OP_Dup 79
|
||||
#define OP_Pull 80
|
||||
|
||||
#define OP_Add 79
|
||||
#define OP_AddImm 80
|
||||
#define OP_Subtract 81
|
||||
#define OP_Multiply 82
|
||||
#define OP_Divide 83
|
||||
#define OP_Min 84
|
||||
#define OP_Max 85
|
||||
#define OP_Like 86
|
||||
#define OP_Glob 87
|
||||
#define OP_Eq 88
|
||||
#define OP_Ne 89
|
||||
#define OP_Lt 90
|
||||
#define OP_Le 91
|
||||
#define OP_Gt 92
|
||||
#define OP_Ge 93
|
||||
#define OP_IsNull 94
|
||||
#define OP_NotNull 95
|
||||
#define OP_Negative 96
|
||||
#define OP_And 97
|
||||
#define OP_Or 98
|
||||
#define OP_Not 99
|
||||
#define OP_Concat 100
|
||||
#define OP_Noop 101
|
||||
#define OP_Add 81
|
||||
#define OP_AddImm 82
|
||||
#define OP_Subtract 83
|
||||
#define OP_Multiply 84
|
||||
#define OP_Divide 85
|
||||
#define OP_Min 86
|
||||
#define OP_Max 87
|
||||
#define OP_Like 88
|
||||
#define OP_Glob 89
|
||||
#define OP_Eq 90
|
||||
#define OP_Ne 91
|
||||
#define OP_Lt 92
|
||||
#define OP_Le 93
|
||||
#define OP_Gt 94
|
||||
#define OP_Ge 95
|
||||
#define OP_IsNull 96
|
||||
#define OP_NotNull 97
|
||||
#define OP_Negative 98
|
||||
#define OP_And 99
|
||||
#define OP_Or 100
|
||||
#define OP_Not 101
|
||||
#define OP_Concat 102
|
||||
#define OP_Noop 103
|
||||
|
||||
#define OP_Strlen 102
|
||||
#define OP_Substr 103
|
||||
#define OP_Strlen 104
|
||||
#define OP_Substr 105
|
||||
|
||||
#define OP_MAX 103
|
||||
#define OP_MAX 105
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
12
src/where.c
12
src/where.c
@ -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.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"
|
||||
|
||||
@ -285,15 +285,19 @@ WhereInfo *sqliteWhereBegin(
|
||||
/* Open all tables in the pTabList and all indices in aIdx[].
|
||||
*/
|
||||
for(i=0; i<pTabList->nId; i++){
|
||||
sqliteVdbeAddOp(v, OP_Open, base+i, pTabList->a[i].pTab->tnum,
|
||||
pTabList->a[i].pTab->zName, 0);
|
||||
int openOp;
|
||||
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 &&
|
||||
(pParse->db->flags & SQLITE_InTrans)==0 ){
|
||||
sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0, 0, 0);
|
||||
pParse->schemaVerified = 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
124
test/temptable.test
Normal file
124
test/temptable.test
Normal 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
|
@ -20,8 +20,10 @@ proc chng {date desc} {
|
||||
chng {2001 Oct ? (2.0.2)} {
|
||||
<li>Removed some unused "#include <unistd.h>" that were causing problems
|
||||
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
|
||||
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)} {
|
||||
|
59
www/lang.tcl
59
www/lang.tcl
@ -1,7 +1,7 @@
|
||||
#
|
||||
# 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>
|
||||
<head>
|
||||
@ -119,15 +119,14 @@ ROLLBACK [TRANSACTION [<name>]]
|
||||
puts {
|
||||
<p>Beginning in version 2.0, SQLite supports transactions with
|
||||
rollback and atomic commit. However, only a single level of
|
||||
transaction is allowed. In other words, transactions
|
||||
may not be nested.
|
||||
transaction is allowed. Transactions may not be nested.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
No changes can be made to the database except within a transaction.
|
||||
Any command that changes the database (basically, any SQL command
|
||||
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.
|
||||
</p>
|
||||
|
||||
@ -206,7 +205,7 @@ SQLite's internal representation of the index layout.</p>
|
||||
Section {CREATE TABLE} {createtable}
|
||||
|
||||
Syntax {sql-command} {
|
||||
CREATE TABLE <table-name> (
|
||||
CREATE [TEMP | TEMPORARY] TABLE <table-name> (
|
||||
<column-def> [, <column-def>]*
|
||||
[, <constraint>]*
|
||||
)
|
||||
@ -246,6 +245,13 @@ The DEFAULT constraint
|
||||
specifies a default value to use when doing an INSERT.
|
||||
</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
|
||||
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>
|
||||
@ -579,20 +585,55 @@ puts {
|
||||
<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
|
||||
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>
|
||||
}
|
||||
|
||||
Section PRAGMA pragma
|
||||
|
||||
Syntax {sql-statement} {
|
||||
PRAGMA <name> = <value>
|
||||
PRAGMA <name> = <value> |
|
||||
PRAGMA <function>(<arg>)
|
||||
}
|
||||
|
||||
puts {
|
||||
<p>The PRAGMA command is used to modify the operation of the SQLite library.
|
||||
Additional documentation on the PRAMGA statement is forthcoming.
|
||||
</p>
|
||||
The pragma command is experimental and specific pragma statements may
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user