1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Changes to the "sqlite" structure that allow simultaneous operations on

multiple database files.  Many regession tests pass - but not all of them.
Do not use this version except for debugging SQLite itself. (CVS 883)

FossilOrigin-Name: d2fb2bb50cf1e13feb90995079f291384abd6ba9
This commit is contained in:
drh
2003-03-27 12:51:24 +00:00
parent 84e6335c0c
commit d24cc427b7
14 changed files with 478 additions and 338 deletions

View File

@@ -1,5 +1,5 @@
C Re-generated.\s(CVS\s882) C Changes\sto\sthe\s"sqlite"\sstructure\sthat\sallow\ssimultaneous\soperations\son\nmultiple\sdatabase\sfiles.\s\sMany\sregession\stests\spass\s-\sbut\snot\sall\sof\sthem.\nDo\snot\suse\sthis\sversion\sexcept\sfor\sdebugging\sSQLite\sitself.\s(CVS\s883)
D 2003-03-24T09:42:16 D 2003-03-27T12:51:24
F Makefile.in 6917c2149a586f11b47c428f2ba748eb1da04f69 F Makefile.in 6917c2149a586f11b47c428f2ba748eb1da04f69
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -22,28 +22,28 @@ F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729 F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
F src/btree.c 327819bb858d534072f5004973f8bcdd50f133d6 F src/btree.c 327819bb858d534072f5004973f8bcdd50f133d6
F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095 F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095
F src/build.c a965338bee81ce20fb0ce38419e9a9d159e720f0 F src/build.c abd5da38923bba6c5dc14d0e24b8e05f68ff459b
F src/delete.c 96a0ae021f960a7f2dbb3d1456802624deacfd3c F src/delete.c e1552bd5a26418c32b8516cb5602bf5473651c68
F src/encode.c faf03741efe921755ec371cf4a6984536de00042 F src/encode.c faf03741efe921755ec371cf4a6984536de00042
F src/expr.c 8af430cdbcb6122dd0320c8860602bd4cc778486 F src/expr.c eae205a27ec45232f234f281f8827c3be58b303d
F src/func.c 90c583f0b91220f7cd411a2407deaf9327245d63 F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c 1f31bdec48bd3915615e7251b74c27dcfaee9b88 F src/insert.c 8d23a2d9995d5bee5b7eb44cb9dc354e0874e70a
F src/main.c 66cd7ff4fc9f43719aaa2bc22db5babd8f437a9f F src/main.c e0d9a86541f0644be5c875c6d8f5062c325c653d
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6 F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6
F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0 F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0
F src/pager.c dd1dfa4d929a58b44175f3117360ff1553671173 F src/pager.c dd1dfa4d929a58b44175f3117360ff1553671173
F src/pager.h 97d9a8cc5103750efd8037d71ebfb41849ef2f2f F src/pager.h 97d9a8cc5103750efd8037d71ebfb41849ef2f2f
F src/parse.y 7a9f333e7b09b0584fb4cc3799f8828f612e282e F src/parse.y 243cfc277d0e5ce87086c015e717dec98d6648a7
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c 06ddc007c20862b3beb8c1c2504db664335d6706 F src/select.c afdc06d4606d14ab5793ef480206def6b02a2f19
F src/shell.c 0d260a007e0668fc7dda2b0c89bd597ef2966ec6 F src/shell.c 0d260a007e0668fc7dda2b0c89bd597ef2966ec6
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 6f648803f2ffb9beb35cb1cfa42b323d55519171 F src/sqlite.h.in 6f648803f2ffb9beb35cb1cfa42b323d55519171
F src/sqliteInt.h ad95c947582d0584240ed413c5f1e9df71749ebe F src/sqliteInt.h c4338bc3c75784840d51fd8a744a63e444ec496d
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 8167d40fd34036701e07492d07a6f9e5c4015241 F src/tclsqlite.c 8167d40fd34036701e07492d07a6f9e5c4015241
F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8 F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8
@@ -51,12 +51,12 @@ F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728 F src/test3.c c12ea7f1c3fbbd58904e81e6cb10ad424e6fc728
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
F src/tokenize.c 675b4718d17c69fe7609dc8e85e426ef002be811 F src/tokenize.c 675b4718d17c69fe7609dc8e85e426ef002be811
F src/trigger.c aafc83ea108ec6a1b501b31b7fb6cebcd4725fd1 F src/trigger.c 578e9d07c5b0d07374f85d7f311126cf9c9d6bcf
F src/update.c 5c644629cc73993ba762bf186944816581213bd1 F src/update.c 785e0e1c8df2043dc96ad7c298fb11aaa3ebc8af
F src/util.c 73b668d1ed468df650dc00685a5e4ffa6887feb4 F src/util.c 73b668d1ed468df650dc00685a5e4ffa6887feb4
F src/vdbe.c 7171dbe873760f403b2501e96fd3d1bd852b3ce8 F src/vdbe.c 7171dbe873760f403b2501e96fd3d1bd852b3ce8
F src/vdbe.h ed43771f1dc2b994d5c484fdf2eab357c6ef0ee3 F src/vdbe.h ed43771f1dc2b994d5c484fdf2eab357c6ef0ee3
F src/where.c 3111c1c209023e4f6b7b7eb0df48cef0010967c3 F src/where.c e5733f7d5e9cc4ed3590dc3401f779e7b7bb8127
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
F test/auth.test 33e8b9680eb0ce521c54096fff1c9ab506c7dfb8 F test/auth.test 33e8b9680eb0ce521c54096fff1c9ab506c7dfb8
F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678 F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
@@ -156,7 +156,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P b1ca4e13dcab92cc532f4051f24bf5b1be251463 P f0c5bcf72cf393ea4c5cd126d085cb959eebd5f2
R e880aa98002065d15c576e440b78c820 R 6683142d762d7951c57ba32402494ae2
U a.rottmann U drh
Z f0092f1365d37d9048c83d0706e14c28 Z fa7baaef0faab26ced3760ebfbc99fb5

View File

@@ -1 +1 @@
f0c5bcf72cf393ea4c5cd126d085cb959eebd5f2 d2fb2bb50cf1e13feb90995079f291384abd6ba9

View File

@@ -25,7 +25,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.133 2003/03/20 01:16:58 drh Exp $ ** $Id: build.c,v 1.134 2003/03/27 12:51:24 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -113,9 +113,14 @@ void sqliteExec(Parse *pParse){
** 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, const char *zName){ Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
Table *p; Table *p = 0;
p = sqliteHashFind(&db->tblHash, zName, strlen(zName)+1); int i;
for(i=0; i<db->nDb; i++){
if( zDatabase!=0 && sqliteStrICmp(zDatabase, db->aDb[i].zName) ) continue;
p = sqliteHashFind(&db->aDb[i].tblHash, zName, strlen(zName)+1);
if( p ) break;
}
return p; return p;
} }
@@ -124,9 +129,14 @@ Table *sqliteFindTable(sqlite *db, const char *zName){
** a particular index given the name of that index. ** a particular index given the name of that index.
** Return NULL if not found. ** Return NULL if not found.
*/ */
Index *sqliteFindIndex(sqlite *db, const char *zName){ Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
Index *p; Index *p = 0;
p = sqliteHashFind(&db->idxHash, zName, strlen(zName)+1); int i;
for(i=0; i<db->nDb; i++){
if( zDb && sqliteStrICmp(zDb, db->aDb[i].zName) ) continue;
p = sqliteHashFind(&db->aDb[i].idxHash, zName, strlen(zName)+1);
if( p ) break;
}
return p; return p;
} }
@@ -140,10 +150,13 @@ Index *sqliteFindIndex(sqlite *db, const char *zName){
*/ */
static void sqliteDeleteIndex(sqlite *db, Index *p){ static void sqliteDeleteIndex(sqlite *db, Index *p){
Index *pOld; Index *pOld;
assert( db!=0 && p->zName!=0 ); assert( db!=0 && p->zName!=0 );
pOld = sqliteHashInsert(&db->idxHash, p->zName, strlen(p->zName)+1, 0); pOld = sqliteHashInsert(&db->aDb[p->iDb].idxHash, p->zName,
strlen(p->zName)+1, 0);
if( pOld!=0 && pOld!=p ){ if( pOld!=0 && pOld!=p ){
sqliteHashInsert(&db->idxHash, pOld->zName, strlen(pOld->zName)+1, pOld); sqliteHashInsert(&db->aDb[p->iDb].idxHash, pOld->zName,
strlen(pOld->zName)+1, pOld);
} }
sqliteFree(p); sqliteFree(p);
} }
@@ -176,23 +189,27 @@ void sqliteResetInternalSchema(sqlite *db){
HashElem *pElem; HashElem *pElem;
Hash temp1; Hash temp1;
Hash temp2; Hash temp2;
int i;
sqliteHashClear(&db->aFKey); for(i=0; i<db->nDb; i++){
temp1 = db->tblHash; Db *pDb = &db->aDb[i];
temp2 = db->trigHash; temp1 = pDb->tblHash;
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0); temp2 = pDb->trigHash;
sqliteHashClear(&db->idxHash); sqliteHashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ sqliteHashClear(&pDb->aFKey);
Trigger *pTrigger = sqliteHashData(pElem); sqliteHashClear(&pDb->idxHash);
sqliteDeleteTrigger(pTrigger); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
Trigger *pTrigger = sqliteHashData(pElem);
sqliteDeleteTrigger(pTrigger);
}
sqliteHashClear(&temp2);
sqliteHashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqliteDeleteTable(db, pTab);
}
sqliteHashClear(&temp1);
} }
sqliteHashClear(&temp2);
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqliteDeleteTable(db, pTab);
}
sqliteHashClear(&temp1);
db->flags &= ~(SQLITE_Initialized|SQLITE_InternChanges); db->flags &= ~(SQLITE_Initialized|SQLITE_InternChanges);
} }
@@ -241,6 +258,7 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
*/ */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext; pNext = pIndex->pNext;
assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) );
sqliteDeleteIndex(db, pIndex); sqliteDeleteIndex(db, pIndex);
} }
@@ -249,7 +267,9 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
*/ */
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
pNextFKey = pFKey->pNextFrom; pNextFKey = pFKey->pNextFrom;
assert( sqliteHashFind(&db->aFKey,pFKey->zTo,strlen(pFKey->zTo)+1)!=pFKey ); assert( pTable->iDb<db->nDb );
assert( sqliteHashFind(&db->aDb[pTable->iDb].aFKey,
pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey );
sqliteFree(pFKey); sqliteFree(pFKey);
} }
@@ -273,14 +293,15 @@ void sqliteDeleteTable(sqlite *db, Table *pTable){
static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){ static void sqliteUnlinkAndDeleteTable(sqlite *db, Table *p){
Table *pOld; Table *pOld;
FKey *pF1, *pF2; FKey *pF1, *pF2;
int i = p->iDb;
assert( db!=0 ); assert( db!=0 );
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, 0); pOld = sqliteHashInsert(&db->aDb[i].tblHash, p->zName, strlen(p->zName)+1, 0);
assert( pOld==0 || pOld==p ); assert( pOld==0 || pOld==p );
for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){
int nTo = strlen(pF1->zTo) + 1; int nTo = strlen(pF1->zTo) + 1;
pF2 = sqliteHashFind(&db->aFKey, pF1->zTo, nTo); pF2 = sqliteHashFind(&db->aDb[i].aFKey, pF1->zTo, nTo);
if( pF2==pF1 ){ if( pF2==pF1 ){
sqliteHashInsert(&db->aFKey, pF1->zTo, nTo, pF1->pNextTo); sqliteHashInsert(&db->aDb[i].aFKey, pF1->zTo, nTo, pF1->pNextTo);
}else{ }else{
while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; }
if( pF2 ){ if( pF2 ){
@@ -347,7 +368,9 @@ void sqliteStartTable(
pParse->sFirstToken = *pStart; pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return; if( zName==0 ) return;
if( pParse->iDb==1 ) isTemp = 1;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
assert( (isTemp & 1)==isTemp );
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0) ){ if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0) ){
sqliteFree(zName); sqliteFree(zName);
return; return;
@@ -378,7 +401,7 @@ void sqliteStartTable(
/* Before trying to create a temporary table, make sure the Btree for /* Before trying to create a temporary table, make sure the Btree for
** holding temporary tables is open. ** holding temporary tables is open.
*/ */
if( isTemp && db->aDb[1].pBt==0 ){ if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){
int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->aDb[1].pBt); int rc = sqliteBtreeOpen(0, 0, MAX_PAGES, &db->aDb[1].pBt);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database " sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
@@ -402,26 +425,18 @@ void sqliteStartTable(
** **
** If we are re-reading the sqlite_master table because of a schema ** 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 ** change and a new permanent table is found whose name collides with
** an existing temporary table, then ignore the new permanent table. ** an existing temporary table, that is not an error.
** 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, 0);
if( pTable!=0 ){ if( pTable!=0 && (pTable->iDb==isTemp || !pParse->initFlag) ){
if( pTable->isTemp && pParse->initFlag ){ sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
pParse->nameClash = 1; " already exists", 0, 0);
}else{ sqliteFree(zName);
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, pParse->nErr++;
" already exists", 0, 0); return;
sqliteFree(zName);
pParse->nErr++;
return;
}
}else{
pParse->nameClash = 0;
} }
if( (pIdx = sqliteFindIndex(db, zName))!=0 && if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 &&
(!pIdx->pTable->isTemp || !pParse->initFlag) ){ (pIdx->iDb==0 || !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);
@@ -438,7 +453,7 @@ void sqliteStartTable(
pTable->aCol = 0; pTable->aCol = 0;
pTable->iPKey = -1; pTable->iPKey = -1;
pTable->pIndex = 0; pTable->pIndex = 0;
pTable->isTemp = isTemp; pTable->iDb = isTemp ? 1 : pParse->iDb;
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable); if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable; pParse->pNewTable = pTable;
@@ -624,7 +639,7 @@ void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
pTab->iPKey = iCol; pTab->iPKey = iCol;
pTab->keyConf = onError; pTab->keyConf = onError;
}else{ }else{
sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0); sqliteCreateIndex(pParse, 0, 0, pList, onError, 0, 0, 0);
pList = 0; pList = 0;
} }
@@ -778,7 +793,7 @@ static char *createTableStmt(Table *p){
n += 35 + 6*p->nCol; n += 35 + 6*p->nCol;
zStmt = sqliteMallocRaw( n ); zStmt = sqliteMallocRaw( n );
if( zStmt==0 ) return 0; if( zStmt==0 ) return 0;
strcpy(zStmt, p->isTemp ? "CREATE TEMP TABLE " : "CREATE TABLE "); strcpy(zStmt, p->iDb==1 ? "CREATE TEMP TABLE " : "CREATE TABLE ");
k = strlen(zStmt); k = strlen(zStmt);
identPut(zStmt, &k, p->zName); identPut(zStmt, &k, p->zName);
zStmt[k++] = '('; zStmt[k++] = '(';
@@ -859,7 +874,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
if( v==0 ) return; if( v==0 ) return;
if( p->pSelect==0 ){ if( p->pSelect==0 ){
/* A regular table */ /* A regular table */
sqliteVdbeAddOp(v, OP_CreateTable, 0, p->isTemp); sqliteVdbeAddOp(v, OP_CreateTable, 0, p->iDb);
sqliteVdbeChangeP3(v, -1, (char *)&p->tnum, P3_POINTER); sqliteVdbeChangeP3(v, -1, (char *)&p->tnum, P3_POINTER);
}else{ }else{
/* A view */ /* A view */
@@ -891,12 +906,12 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
} }
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
if( !p->isTemp ){ if( !p->iDb ){
sqliteChangeCookie(db, v); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0);
if( pSelect ){ if( pSelect ){
sqliteVdbeAddOp(v, OP_Integer, p->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, p->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0); sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
pParse->nTab = 2; pParse->nTab = 2;
sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0); sqliteSelect(pParse, pSelect, SRT_Table, 1, 0, 0, 0);
@@ -906,19 +921,19 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
/* Add the table to the in-memory representation of the database. /* Add the table to the in-memory representation of the database.
*/ */
assert( pParse->nameClash==0 || pParse->initFlag==1 ); if( pParse->explain==0 && pParse->nErr==0 ){
if( pParse->explain==0 && pParse->nameClash==0 && pParse->nErr==0 ){
Table *pOld; Table *pOld;
FKey *pFKey; FKey *pFKey;
pOld = sqliteHashInsert(&db->tblHash, p->zName, strlen(p->zName)+1, p); pOld = sqliteHashInsert(&db->aDb[p->iDb].tblHash,
p->zName, strlen(p->zName)+1, p);
if( pOld ){ if( pOld ){
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
return; return;
} }
for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){
int nTo = strlen(pFKey->zTo) + 1; int nTo = strlen(pFKey->zTo) + 1;
pFKey->pNextTo = sqliteHashFind(&db->aFKey, pFKey->zTo, nTo); pFKey->pNextTo = sqliteHashFind(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo);
sqliteHashInsert(&db->aFKey, pFKey->zTo, nTo, pFKey); sqliteHashInsert(&db->aDb[p->iDb].aFKey, pFKey->zTo, nTo, pFKey);
} }
pParse->pNewTable = 0; pParse->pNewTable = 0;
db->nTable++; db->nTable++;
@@ -1038,7 +1053,7 @@ int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab->nCol = 0; pSelTab->nCol = 0;
pSelTab->aCol = 0; pSelTab->aCol = 0;
sqliteDeleteTable(0, pSelTab); sqliteDeleteTable(0, pSelTab);
pParse->db->flags |= SQLITE_UnresetViews; pParse->db->aDb[pTable->iDb].flags |= SQLITE_UnresetViews;
}else{ }else{
pTable->nCol = 0; pTable->nCol = 0;
nErr++; nErr++;
@@ -1074,16 +1089,16 @@ static void sqliteViewResetColumnNames(Table *pTable){
/* /*
** Clear the column names from every VIEW. ** Clear the column names from every VIEW.
*/ */
void sqliteViewResetAll(sqlite *db){ static void sqliteViewResetAll(sqlite *db, int idx){
HashElem *i; HashElem *i;
if( (db->flags & SQLITE_UnresetViews)==0 ) return; if( (db->aDb[idx].flags & SQLITE_UnresetViews)==0 ) return;
for(i=sqliteHashFirst(&db->tblHash); i; i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i); Table *pTab = sqliteHashData(i);
if( pTab->pSelect ){ if( pTab->pSelect ){
sqliteViewResetColumnNames(pTab); sqliteViewResetColumnNames(pTab);
} }
} }
db->flags &= ~SQLITE_UnresetViews; db->aDb[idx].flags &= ~SQLITE_UnresetViews;
} }
/* /*
@@ -1095,7 +1110,7 @@ Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
Table *pTab; Table *pTab;
zName = sqliteTableNameFromToken(pTok); zName = sqliteTableNameFromToken(pTok);
if( zName==0 ) return 0; if( zName==0 ) return 0;
pTab = sqliteFindTable(pParse->db, zName); pTab = sqliteFindTable(pParse->db, zName, 0);
sqliteFree(zName); sqliteFree(zName);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0, sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
@@ -1114,24 +1129,26 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
Vdbe *v; Vdbe *v;
int base; int base;
sqlite *db = pParse->db; sqlite *db = pParse->db;
int iDb;
if( pParse->nErr || sqlite_malloc_failed ) return; if( pParse->nErr || sqlite_malloc_failed ) return;
pTable = sqliteTableFromToken(pParse, pName); pTable = sqliteTableFromToken(pParse, pName);
if( pTable==0 ) return; if( pTable==0 ) return;
iDb = pTable->iDb;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->isTemp),0)){ if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0)){
return; return;
} }
{ {
int code; int code;
if( isView ){ if( isView ){
if( pTable->isTemp ){ if( iDb==1 ){
code = SQLITE_DROP_TEMP_VIEW; code = SQLITE_DROP_TEMP_VIEW;
}else{ }else{
code = SQLITE_DROP_VIEW; code = SQLITE_DROP_VIEW;
} }
}else{ }else{
if( pTable->isTemp ){ if( iDb==1 ){
code = SQLITE_DROP_TEMP_TABLE; code = SQLITE_DROP_TEMP_TABLE;
}else{ }else{
code = SQLITE_DROP_TABLE; code = SQLITE_DROP_TABLE;
@@ -1181,15 +1198,17 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
}; };
Index *pIdx; Index *pIdx;
Trigger *pTrigger; Trigger *pTrigger;
sqliteBeginWriteOperation(pParse, 0, pTable->isTemp); sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
sqliteOpenMasterTable(v, pTable->isTemp); sqliteOpenMasterTable(v, pTable->iDb);
/* Drop all triggers associated with the table being dropped */ /* Drop all triggers associated with the table being dropped */
pTrigger = pTable->pTrigger; pTrigger = pTable->pTrigger;
while( pTrigger ){ while( pTrigger ){
Token tt; SrcList *pNm;
tt.z = pTable->pTrigger->name; assert( pTrigger->iDb==pTable->iDb );
tt.n = strlen(pTable->pTrigger->name); pNm = sqliteSrcListAppend(0, 0, 0);
sqliteDropTrigger(pParse, &tt, 1); pNm->a[0].zName = sqliteStrDup(pTrigger->name);
pNm->a[0].zDatabase = sqliteStrDup(db->aDb[pTable->iDb].zName);
sqliteDropTrigger(pParse, pNm, 1);
if( pParse->explain ){ if( pParse->explain ){
pTrigger = pTrigger->pNext; pTrigger = pTrigger->pNext;
}else{ }else{
@@ -1198,14 +1217,14 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
} }
base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable); base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
sqliteVdbeChangeP3(v, base+1, pTable->zName, 0); sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
if( !pTable->isTemp ){ if( !pTable->iDb ){
sqliteChangeCookie(db, v); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0);
if( !isView ){ if( !isView ){
sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->isTemp); sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->isTemp); sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->iDb);
} }
} }
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
@@ -1220,7 +1239,7 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
sqliteUnlinkAndDeleteTable(db, pTable); sqliteUnlinkAndDeleteTable(db, pTable);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
sqliteViewResetAll(db); sqliteViewResetAll(db, iDb);
} }
/* /*
@@ -1403,9 +1422,10 @@ void sqliteDeferForeignKey(Parse *pParse, int isDeferred){
void sqliteCreateIndex( void sqliteCreateIndex(
Parse *pParse, /* All information about this parse */ Parse *pParse, /* All information about this parse */
Token *pName, /* Name of the index. May be NULL */ Token *pName, /* Name of the index. May be NULL */
Token *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */ SrcList *pTable, /* Name of the table to index. Use pParse->pNewTable if 0 */
IdList *pList, /* A list of columns to be indexed */ IdList *pList, /* A list of columns to be indexed */
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
int isTemp, /* True if this is a temporary index */
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
Token *pEnd /* The ")" that closes the CREATE INDEX statement */ Token *pEnd /* The ")" that closes the CREATE INDEX statement */
){ ){
@@ -1415,7 +1435,6 @@ void sqliteCreateIndex(
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;
@@ -1424,15 +1443,17 @@ void sqliteCreateIndex(
*/ */
if( pTable!=0 ){ if( pTable!=0 ){
assert( pName!=0 ); assert( pName!=0 );
pTab = sqliteTableFromToken(pParse, pTable); assert( pTable->nSrc==1 );
pTab = sqliteTableNameToTable(pParse,
pTable->a[0].zName, pTable->a[0].zDatabase);
}else{ }else{
assert( pName==0 ); assert( pName==0 );
pTab = pParse->pNewTable; pTab = pParse->pNewTable;
} }
if( pTab==0 || pParse->nErr ) goto exit_create_index; if( pTab==0 || pParse->nErr ) goto exit_create_index;
if( pTab->readOnly ){ if( !isTemp && (pTab->readOnly || pTab->iDb>=2) ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not have new indices added", 0); " may not have non-temporary indices added", 0);
pParse->nErr++; pParse->nErr++;
goto exit_create_index; goto exit_create_index;
} }
@@ -1441,7 +1462,12 @@ void sqliteCreateIndex(
pParse->nErr++; pParse->nErr++;
goto exit_create_index; goto exit_create_index;
} }
if( pTab->iDb==1 ){
isTemp = 1;
}
#if 0
/* If this index is created while re-reading the schema from sqlite_master /* 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 ** but the table associated with this index is a temporary table, it can
** only mean that the table that this index is really associated with is ** only mean that the table that this index is really associated with is
@@ -1449,9 +1475,10 @@ void sqliteCreateIndex(
** Since its table has been suppressed, we need to also suppress the ** Since its table has been suppressed, we need to also suppress the
** index. ** index.
*/ */
if( pParse->initFlag && !pParse->isTemp && pTab->isTemp ){ if( pParse->initFlag && !pParse->isTemp && pTab->iDb ){
goto exit_create_index; goto exit_create_index;
} }
#endif
/* /*
** 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
@@ -1460,40 +1487,30 @@ void sqliteCreateIndex(
** Exception: If we are reading the names of permanent indices from the ** Exception: If we are reading the names of permanent indices from the
** sqlite_master table (because some other process changed the schema) and ** 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 ** 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 ** index, then we will continue to process this index.
** store its name in the hash table. Set the hideName flag to accomplish
** this.
** **
** If pName==0 it means that we are ** 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 && !pParse->initFlag ){
Index *pISameName; /* Another index with the same name */ Index *pISameName; /* Another index with the same name */
Table *pTSameName; /* A table with same name as the index */ Table *pTSameName; /* A table with same name as the index */
zName = sqliteTableNameFromToken(pName); zName = sqliteStrNDup(pName->z, pName->n);
if( zName==0 ) goto exit_create_index; if( zName==0 ) goto exit_create_index;
if( (pISameName = sqliteFindIndex(db, zName))!=0 ){ if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){
if( pISameName->pTable->isTemp && pParse->initFlag ){ sqliteSetString(&pParse->zErrMsg, "index ", zName,
hideName = 1; " already exists", 0);
}else{ pParse->nErr++;
sqliteSetString(&pParse->zErrMsg, "index ", zName, goto exit_create_index;
" already exists", 0);
pParse->nErr++;
goto exit_create_index;
}
} }
if( (pTSameName = sqliteFindTable(db, zName))!=0 ){ if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){
if( pTSameName->isTemp && pParse->initFlag ){ sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
hideName = 1; zName, 0);
}else{ pParse->nErr++;
sqliteSetString(&pParse->zErrMsg, "there is already a table named ", goto exit_create_index;
zName, 0);
pParse->nErr++;
goto exit_create_index;
}
} }
}else{ }else if( pName==0 ){
char zBuf[30]; char zBuf[30];
int n; int n;
Index *pLoop; Index *pLoop;
@@ -1502,17 +1519,20 @@ void sqliteCreateIndex(
zName = 0; zName = 0;
sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0); sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0);
if( zName==0 ) goto exit_create_index; if( zName==0 ) goto exit_create_index;
hideName = sqliteFindIndex(db, zName)!=0; }else{
zName = sqliteStrNDup(pName->z, pName->n);
} }
/* Check for authorization to create an index. /* Check for authorization to create an index.
*/ */
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->isTemp), 0) ){ assert( isTemp==0 || isTemp==1 );
assert( pTab->iDb==pParse->iDb || isTemp==1 );
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0) ){
goto exit_create_index; goto exit_create_index;
} }
i = SQLITE_CREATE_INDEX; i = SQLITE_CREATE_INDEX;
if( pTab->isTemp ) i = SQLITE_CREATE_TEMP_INDEX; if( isTemp ) i = SQLITE_CREATE_TEMP_INDEX;
if( sqliteAuthCheck(pParse, i, zName, pTab->zName) ){ if( sqliteAuthCheck(pParse, i, zName, pTab->zName) ){
goto exit_create_index; goto exit_create_index;
} }
@@ -1542,6 +1562,7 @@ void sqliteCreateIndex(
pIndex->nColumn = pList->nId; pIndex->nColumn = pList->nId;
pIndex->onError = pIndex->isUnique = onError; pIndex->onError = pIndex->isUnique = onError;
pIndex->autoIndex = pName==0; pIndex->autoIndex = pName==0;
pIndex->iDb = isTemp ? 1 : pParse->iDb;
/* Scan the names of the columns of the table to be indexed and /* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error ** load the column indices into the Index structure. Report an error
@@ -1564,9 +1585,10 @@ void sqliteCreateIndex(
/* Link the new Index structure to its table and to the other /* Link the new Index structure to its table and to the other
** in-memory database structures. ** in-memory database structures.
*/ */
if( !pParse->explain && !hideName ){ if( !pParse->explain ){
Index *p; Index *p;
p = sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex); p = sqliteHashInsert(&db->aDb[isTemp].idxHash,
pIndex->zName, strlen(zName)+1, pIndex);
if( p ){ if( p ){
assert( p==pIndex ); /* Malloc must have failed */ assert( p==pIndex ); /* Malloc must have failed */
sqliteFree(pIndex); sqliteFree(pIndex);
@@ -1622,7 +1644,6 @@ 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;
@@ -1653,7 +1674,7 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, OP_Integer, isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
lbl2 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v);
@@ -1683,6 +1704,7 @@ void sqliteCreateIndex(
/* Clean up before exiting */ /* Clean up before exiting */
exit_create_index: exit_create_index:
sqliteIdListDelete(pList); sqliteIdListDelete(pList);
sqliteSrcListDelete(pTable);
sqliteFree(zName); sqliteFree(zName);
return; return;
} }
@@ -1691,39 +1713,41 @@ exit_create_index:
** This routine will drop an existing named index. This routine ** This routine will drop an existing named index. This routine
** implements the DROP INDEX statement. ** implements the DROP INDEX statement.
*/ */
void sqliteDropIndex(Parse *pParse, Token *pName){ void sqliteDropIndex(Parse *pParse, SrcList *pName){
Index *pIndex; Index *pIndex;
char *zName;
Vdbe *v; Vdbe *v;
sqlite *db = pParse->db; sqlite *db = pParse->db;
if( pParse->nErr || sqlite_malloc_failed ) return; if( pParse->nErr || sqlite_malloc_failed ) return;
zName = sqliteTableNameFromToken(pName); assert( pName->nSrc==1 );
if( zName==0 ) return; pIndex = sqliteFindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
pIndex = sqliteFindIndex(db, zName);
sqliteFree(zName);
if( pIndex==0 ){ if( pIndex==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such index: ", 0, sqliteSetString(&pParse->zErrMsg, "no such index: ", pName->a[0].zName, 0);
pName->z, pName->n, 0);
pParse->nErr++; pParse->nErr++;
return; goto exit_drop_index;
} }
if( pIndex->autoIndex ){ if( pIndex->autoIndex ){
sqliteSetString(&pParse->zErrMsg, "index associated with UNIQUE " sqliteSetString(&pParse->zErrMsg, "index associated with UNIQUE "
"or PRIMARY KEY constraint cannot be dropped", 0); "or PRIMARY KEY constraint cannot be dropped", 0);
pParse->nErr++; pParse->nErr++;
return; goto exit_drop_index;
}
if( pIndex->iDb>1 ){
sqliteSetString(&pParse->zErrMsg, "cannot alter schema of attached "
"databases", 0);
pParse->nErr++;
goto exit_drop_index;
} }
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
{ {
int code = SQLITE_DROP_INDEX; int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable; Table *pTab = pIndex->pTable;
if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTab->isTemp), 0) ){ if( sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pIndex->iDb), 0) ){
return; goto exit_drop_index;
} }
if( pTab->isTemp ) code = SQLITE_DROP_TEMP_INDEX; if( pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX;
if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName) ){ if( sqliteAuthCheck(pParse, code, pIndex->zName, pTab->zName) ){
return; goto exit_drop_index;
} }
} }
#endif #endif
@@ -1743,17 +1767,16 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
{ OP_Delete, 0, 0, 0}, /* 8 */ { OP_Delete, 0, 0, 0}, /* 8 */
}; };
int base; int base;
Table *pTab = pIndex->pTable;
sqliteBeginWriteOperation(pParse, 0, pTab->isTemp); sqliteBeginWriteOperation(pParse, 0, pIndex->iDb);
sqliteOpenMasterTable(v, pTab->isTemp); sqliteOpenMasterTable(v, pIndex->iDb);
base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex); base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0); sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
if( !pTab->isTemp ){ if( pIndex->iDb==0 ){
sqliteChangeCookie(db, v); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pTab->isTemp); sqliteVdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
@@ -1763,6 +1786,9 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
sqliteUnlinkAndDeleteIndex(db, pIndex); sqliteUnlinkAndDeleteIndex(db, pIndex);
db->flags |= SQLITE_InternChanges; db->flags |= SQLITE_InternChanges;
} }
exit_drop_index:
sqliteSrcListDelete(pName);
} }
/* /*
@@ -1943,13 +1969,12 @@ void sqliteSrcListDelete(SrcList *pList){
*/ */
void sqliteCopy( void sqliteCopy(
Parse *pParse, /* The parser context */ Parse *pParse, /* The parser context */
Token *pTableName, /* The name of the table into which we will insert */ SrcList *pTableName, /* The name of the table into which we will insert */
Token *pFilename, /* The file from which to obtain information */ Token *pFilename, /* The file from which to obtain information */
Token *pDelimiter, /* Use this as the field delimiter */ Token *pDelimiter, /* Use this as the field delimiter */
int onError /* What to do if a constraint fails */ int onError /* What to do if a constraint fails */
){ ){
Table *pTab; Table *pTab;
char *zTab;
int i; int i;
Vdbe *v; Vdbe *v;
int addr, end; int addr, end;
@@ -1958,10 +1983,10 @@ void sqliteCopy(
sqlite *db = pParse->db; sqlite *db = pParse->db;
zTab = sqliteTableNameFromToken(pTableName); if( sqlite_malloc_failed ) goto copy_cleanup;
if( sqlite_malloc_failed || zTab==0 ) goto copy_cleanup; assert( pTableName->nSrc==1 );
pTab = sqliteTableNameToTable(pParse, zTab); pTab = sqliteTableNameToTable(pParse, pTableName->a[0].zName,
sqliteFree(zTab); pTableName->a[0].zDatabase);
if( pTab==0 ) goto copy_cleanup; if( pTab==0 ) goto copy_cleanup;
zFile = sqliteStrNDup(pFilename->z, pFilename->n); zFile = sqliteStrNDup(pFilename->z, pFilename->n);
sqliteDequote(zFile); sqliteDequote(zFile);
@@ -1971,15 +1996,16 @@ void sqliteCopy(
} }
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v ){ if( v ){
sqliteBeginWriteOperation(pParse, 1, pTab->isTemp); sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1);
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0); addr = sqliteVdbeAddOp(v, OP_FileOpen, 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_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
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_Integer, pTab->isTemp, 0); assert( pIdx->iDb==1 || pIdx->iDb==pTab->iDb );
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
} }
@@ -2026,6 +2052,7 @@ void sqliteCopy(
} }
copy_cleanup: copy_cleanup:
sqliteSrcListDelete(pTableName);
sqliteFree(zFile); sqliteFree(zFile);
return; return;
} }
@@ -2487,7 +2514,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( sqliteStrICmp(zLeft, "table_info")==0 ){ if( sqliteStrICmp(zLeft, "table_info")==0 ){
Table *pTab; Table *pTab;
pTab = sqliteFindTable(db, zRight); pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){ if( pTab ){
static VdbeOp tableInfoPreface[] = { static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "cid"}, { OP_ColumnName, 0, 0, "cid"},
@@ -2517,7 +2544,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( sqliteStrICmp(zLeft, "index_info")==0 ){ if( sqliteStrICmp(zLeft, "index_info")==0 ){
Index *pIdx; Index *pIdx;
Table *pTab; Table *pTab;
pIdx = sqliteFindIndex(db, zRight); pIdx = sqliteFindIndex(db, zRight, 0);
if( pIdx ){ if( pIdx ){
static VdbeOp tableInfoPreface[] = { static VdbeOp tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "seqno"}, { OP_ColumnName, 0, 0, "seqno"},
@@ -2542,7 +2569,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( sqliteStrICmp(zLeft, "index_list")==0 ){ if( sqliteStrICmp(zLeft, "index_list")==0 ){
Index *pIdx; Index *pIdx;
Table *pTab; Table *pTab;
pTab = sqliteFindTable(db, zRight); pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){ if( pTab ){
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
pIdx = pTab->pIndex; pIdx = pTab->pIndex;

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.47 2003/03/20 01:16:59 drh Exp $ ** $Id: delete.c,v 1.48 2003/03/27 12:51:24 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -22,11 +22,15 @@
** table is writeable. Generate an error and return NULL if not. If ** table is writeable. Generate an error and return NULL if not. If
** everything checks out, return a pointer to the Table structure. ** everything checks out, return a pointer to the Table structure.
*/ */
Table *sqliteTableNameToTable(Parse *pParse, const char *zTab){ Table *sqliteTableNameToTable(Parse *pParse, const char *zTab, const char *zDb){
Table *pTab; Table *pTab;
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(pParse->db, zTab, zDb);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0); if( zDb==0 || zDb[0]==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0);
}else{
sqliteSetString(&pParse->zErrMsg, "no such table: ", zDb, ".", zTab, 0);
}
pParse->nErr++; pParse->nErr++;
return 0; return 0;
} }
@@ -52,6 +56,7 @@ void sqliteDeleteFrom(
Vdbe *v; /* The virtual database engine */ Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */ Table *pTab; /* The table from which records will be deleted */
char *zTab; /* Name of the table from which we are deleting */ char *zTab; /* Name of the table from which we are deleting */
char *zDb; /* Name of database containing table zTab */
int end, addr; /* A couple addresses of generated code */ int end, addr; /* A couple addresses of generated code */
int i; /* Loop counter */ int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */ WhereInfo *pWInfo; /* Information about the WHERE clause */
@@ -73,8 +78,9 @@ void sqliteDeleteFrom(
** defined ** defined
*/ */
zTab = pTabList->a[0].zName; zTab = pTabList->a[0].zName;
zDb = pTabList->a[0].zDatabase;
if( zTab != 0 ){ if( zTab != 0 ){
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(pParse->db, zTab, zDb);
if( pTab ){ if( pTab ){
row_triggers_exist = row_triggers_exist =
sqliteTriggersExist(pParse, pTab->pTrigger, sqliteTriggersExist(pParse, pTab->pTrigger,
@@ -95,7 +101,7 @@ void sqliteDeleteFrom(
** will be calling are designed to work with multiple tables and expect ** will be calling are designed to work with multiple tables and expect
** an SrcList* parameter instead of just a Table* parameter. ** an SrcList* parameter instead of just a Table* parameter.
*/ */
pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab); pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab, zDb);
if( pTab==0 ){ if( pTab==0 ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
@@ -129,7 +135,7 @@ void sqliteDeleteFrom(
goto delete_from_cleanup; goto delete_from_cleanup;
} }
sqliteBeginWriteOperation(pParse, row_triggers_exist, sqliteBeginWriteOperation(pParse, row_triggers_exist,
!row_triggers_exist && pTab->isTemp); !row_triggers_exist && pTab->iDb==1);
/* Initialize the counter of the number of rows deleted, if /* Initialize the counter of the number of rows deleted, if
** we are counting rows. ** we are counting rows.
@@ -148,7 +154,7 @@ void sqliteDeleteFrom(
** entries in the table. */ ** entries in the table. */
int endOfLoop = sqliteVdbeMakeLabel(v); int endOfLoop = sqliteVdbeMakeLabel(v);
int addr; int addr;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2); sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2);
addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0); addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
@@ -156,9 +162,9 @@ void sqliteDeleteFrom(
sqliteVdbeResolveLabel(v, endOfLoop); sqliteVdbeResolveLabel(v, endOfLoop);
sqliteVdbeAddOp(v, OP_Close, base, 0); sqliteVdbeAddOp(v, OP_Close, base, 0);
} }
sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->isTemp); sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pTab->isTemp); sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
} }
} }
@@ -195,7 +201,7 @@ void sqliteDeleteFrom(
if( row_triggers_exist ){ if( row_triggers_exist ){
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end); addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeAddOp(v, OP_MoveTo, base, 0); sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
@@ -225,10 +231,10 @@ void sqliteDeleteFrom(
** cursors are opened only once on the outside the loop. ** cursors are opened only once on the outside the loop.
*/ */
pParse->nTab = base + 1; pParse->nTab = base + 1;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
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_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
} }

View File

@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and ** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite. ** for generating VDBE code that evaluates expressions in SQLite.
** **
** $Id: expr.c,v 1.89 2003/03/20 01:16:59 drh Exp $ ** $Id: expr.c,v 1.90 2003/03/27 12:51:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -493,16 +493,29 @@ int sqliteExprResolveIds(
break; break;
} }
/* A table name and column name: ID.ID */ /* A table name and column name: ID.ID
** Or a database, table and column: ID.ID.ID
*/
case TK_DOT: { case TK_DOT: {
int cnt = 0; /* Number of matches */ int cnt = 0; /* Number of matches */
int cntTab = 0; /* Number of matching tables */ int cntTab = 0; /* Number of matching tables */
int i; /* Loop counter */ int i; /* Loop counter */
Expr *pLeft, *pRight; /* Left and right subbranches of the expr */ Expr *pLeft, *pRight; /* Left and right subbranches of the expr */
char *zLeft, *zRight; /* Text of an identifier */ char *zLeft, *zRight; /* Text of an identifier */
char *zDb; /* Name of database holding table */
sqlite *db = pParse->db;
pLeft = pExpr->pLeft;
pRight = pExpr->pRight; pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
pLeft = pExpr->pLeft;
zDb = 0;
}else{
Expr *pDb = pExpr->pLeft;
assert( pDb && pDb->op==TK_ID && pDb->token.z );
zDb = sqliteStrNDup(pDb->token.z, pDb->token.n);
pLeft = pRight->pLeft;
pRight = pRight->pRight;
}
assert( pLeft && pLeft->op==TK_ID && pLeft->token.z ); assert( pLeft && pLeft->op==TK_ID && pLeft->token.z );
assert( pRight && pRight->op==TK_ID && pRight->token.z ); assert( pRight && pRight->op==TK_ID && pRight->token.z );
zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n); zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
@@ -510,8 +523,10 @@ int sqliteExprResolveIds(
if( zLeft==0 || zRight==0 ){ if( zLeft==0 || zRight==0 ){
sqliteFree(zLeft); sqliteFree(zLeft);
sqliteFree(zRight); sqliteFree(zRight);
sqliteFree(zDb);
return 1; return 1;
} }
sqliteDequote(zDb);
sqliteDequote(zLeft); sqliteDequote(zLeft);
sqliteDequote(zRight); sqliteDequote(zRight);
pExpr->iTable = -1; pExpr->iTable = -1;
@@ -523,10 +538,14 @@ int sqliteExprResolveIds(
assert( pTab->nCol>0 ); assert( pTab->nCol>0 );
if( pTabList->a[i].zAlias ){ if( pTabList->a[i].zAlias ){
zTab = pTabList->a[i].zAlias; zTab = pTabList->a[i].zAlias;
if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
}else{ }else{
zTab = pTab->zName; zTab = pTab->zName;
if( zTab==0 || sqliteStrICmp(zTab, zLeft)!=0 ) continue;
if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
continue;
}
} }
if( zTab==0 || sqliteStrICmp(zTab, zLeft)!=0 ) continue;
if( 0==(cntTab++) ) pExpr->iTable = i + base; if( 0==(cntTab++) ) pExpr->iTable = i + base;
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){ if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
@@ -577,6 +596,7 @@ int sqliteExprResolveIds(
pExpr->iColumn = -1; pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM; pExpr->dataType = SQLITE_SO_NUM;
} }
sqliteFree(zDb);
sqliteFree(zLeft); sqliteFree(zLeft);
sqliteFree(zRight); sqliteFree(zRight);
if( cnt==0 ){ if( cnt==0 ){
@@ -592,9 +612,9 @@ int sqliteExprResolveIds(
pParse->nErr++; pParse->nErr++;
return 1; return 1;
} }
sqliteExprDelete(pLeft); sqliteExprDelete(pExpr->pLeft);
pExpr->pLeft = 0; pExpr->pLeft = 0;
sqliteExprDelete(pRight); sqliteExprDelete(pExpr->pRight);
pExpr->pRight = 0; pExpr->pRight = 0;
pExpr->op = TK_COLUMN; pExpr->op = TK_COLUMN;
sqliteAuthRead(pParse, pExpr, pTabList, base); sqliteAuthRead(pParse, pExpr, pTabList, base);

View File

@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope. ** All other code has file scope.
** **
** $Id: func.c,v 1.23 2002/11/04 19:32:25 drh Exp $ ** $Id: func.c,v 1.24 2003/03/27 12:51:25 drh Exp $
*/ */
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
@@ -255,6 +255,46 @@ static void versionFunc(sqlite_func *context, int argc, const char **argv){
sqlite_set_result_string(context, sqlite_version, -1); sqlite_set_result_string(context, sqlite_version, -1);
} }
#ifdef SQLITE_SOUNDEX
/*
** Compute the soundex encoding of a word.
*/
static void soundexFunc(sqlite_func *context, int argc, const char **argv){
char zResult[8];
const char *zIn;
int i, j;
static const unsigned char iCode[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0,
1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
};
assert( argc==1 );
zIn = argv[0];
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){
zResult[0] = toupper(zIn[i]);
for(j=1; j<4 && zIn[i]; i++){
int code = iCode[zIn[i]&0x7f];
if( code>0 ){
zResult[j++] = code + '0';
}
}
while( j<4 ){
zResult[j++] = '0';
}
zResult[j] = 0;
sqlite_set_result_string(context, zResult, 4);
}else{
sqlite_set_result_string(context, zResult, "?000", 4);
}
}
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
/* /*
** This function generates a string of random characters. Used for ** This function generates a string of random characters. Used for
@@ -490,6 +530,9 @@ void sqliteRegisterBuiltinFunctions(sqlite *db){
{ "glob", 2, SQLITE_NUMERIC, globFunc }, { "glob", 2, SQLITE_NUMERIC, globFunc },
{ "nullif", 2, SQLITE_ARGS, nullifFunc }, { "nullif", 2, SQLITE_ARGS, nullifFunc },
{ "sqlite_version",0,SQLITE_TEXT, versionFunc}, { "sqlite_version",0,SQLITE_TEXT, versionFunc},
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, SQLITE_TEXT, soundexFunc},
#endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
{ "randstr", 2, SQLITE_TEXT, randStr }, { "randstr", 2, SQLITE_TEXT, randStr },
#endif #endif

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.74 2003/03/20 01:16:59 drh Exp $ ** $Id: insert.c,v 1.75 2003/03/27 12:51:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -93,6 +93,7 @@ void sqliteInsert(
){ ){
Table *pTab; /* The table to insert into */ Table *pTab; /* The table to insert into */
char *zTab; /* Name of the table into which we are inserting */ char *zTab; /* Name of the table into which we are inserting */
char *zDb; /* Name of the database holding zTab */
int i, j, idx; /* Loop counters */ int i, j, idx; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */ Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */ Index *pIdx; /* For looping over indices of the table */
@@ -120,10 +121,9 @@ void sqliteInsert(
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
zTab = pTabList->a[0].zName; zTab = pTabList->a[0].zName;
if( zTab==0 ) goto insert_cleanup; if( zTab==0 ) goto insert_cleanup;
pTab = sqliteFindTable(pParse->db, zTab); zDb = pTabList->a[0].zDatabase;
pTab = sqliteTableNameToTable(pParse, zTab, zDb);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", zTab, 0);
pParse->nErr++;
goto insert_cleanup; goto insert_cleanup;
} }
if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){ if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0) ){
@@ -162,7 +162,7 @@ void sqliteInsert(
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto insert_cleanup; if( v==0 ) goto insert_cleanup;
sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist,
!row_triggers_exist && pTab->isTemp); !row_triggers_exist && pTab->iDb==1);
/* if there are row triggers, allocate a temp table for new.* references. */ /* if there are row triggers, allocate a temp table for new.* references. */
if( row_triggers_exist ){ if( row_triggers_exist ){
@@ -196,7 +196,7 @@ void sqliteInsert(
** should be written into a temporary table. Set to FALSE if each ** should be written into a temporary table. Set to FALSE if each
** row of the SELECT can be written directly into the result table. ** row of the SELECT can be written directly into the result table.
*/ */
opCode = pTab->isTemp ? OP_OpenTemp : OP_OpenRead; opCode = pTab->iDb==1 ? OP_OpenTemp : OP_OpenRead;
useTempTable = row_triggers_exist || sqliteVdbeFindOp(v,opCode,pTab->tnum); useTempTable = row_triggers_exist || sqliteVdbeFindOp(v,opCode,pTab->tnum);
if( useTempTable ){ if( useTempTable ){
@@ -327,11 +327,11 @@ void sqliteInsert(
/* Open tables and indices if there are no row triggers */ /* Open tables and indices if there are no row triggers */
if( !row_triggers_exist ){ if( !row_triggers_exist ){
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
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_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
} }
@@ -389,11 +389,11 @@ void sqliteInsert(
/* Open the tables and indices for the INSERT */ /* Open the tables and indices for the INSERT */
if( !pTab->pSelect ){ if( !pTab->pSelect ){
base = pParse->nTab; base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
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_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
} }

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.116 2003/03/20 01:16:59 drh Exp $ ** $Id: main.c,v 1.117 2003/03/27 12:51:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -67,7 +67,7 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = pData->db; sParse.db = pData->db;
sParse.initFlag = 1; sParse.initFlag = 1;
sParse.isTemp = argv[4][0] - '0'; sParse.iDb = atoi(argv[4]);
sParse.newTnum = atoi(argv[2]); sParse.newTnum = atoi(argv[2]);
sParse.useCallback = 1; sParse.useCallback = 1;
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg); sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
@@ -78,7 +78,12 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
** been created when we processed the CREATE TABLE. All we have ** been created when we processed the CREATE TABLE. All we have
** to do here is record the root page number for that index. ** to do here is record the root page number for that index.
*/ */
Index *pIndex = sqliteFindIndex(pData->db, argv[1]); int iDb;
Index *pIndex;
iDb = atoi(argv[4]);
assert( iDb>=0 && iDb<pData->db->nDb );
pIndex = sqliteFindIndex(pData->db, argv[1], pData->db->aDb[iDb].zName);
if( pIndex==0 || pIndex->tnum!=0 ){ if( pIndex==0 || pIndex->tnum!=0 ){
/* This can occur if there exists an index on a TEMP table which /* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since ** has the same name as another index on a permanent index. Since
@@ -118,7 +123,7 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
Trigger *pTrig; Trigger *pTrig;
char *zErr = 0; char *zErr = 0;
pTab = sqliteFindTable(pData->db, argv[0]); pTab = sqliteFindTable(pData->db, argv[0], 0);
assert( pTab!=0 ); assert( pTab!=0 );
assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
if( pTab ){ if( pTab ){
@@ -141,7 +146,7 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
** cause the structure that pTab points to be deleted. In case that ** cause the structure that pTab points to be deleted. In case that
** happened, we need to refetch pTab. ** happened, we need to refetch pTab.
*/ */
pTab = sqliteFindTable(pData->db, argv[0]); pTab = sqliteFindTable(pData->db, argv[0], 0);
if( pTab ){ if( pTab ){
assert( sqliteStrICmp(pTab->zName, argv[0])==0 ); assert( sqliteStrICmp(pTab->zName, argv[0])==0 );
pTab->pTrigger = pTrig; /* Re-enable triggers */ pTab->pTrigger = pTrig; /* Re-enable triggers */
@@ -234,7 +239,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
initData.db = db; initData.db = db;
initData.pzErrMsg = pzErrMsg; initData.pzErrMsg = pzErrMsg;
sqliteInitCallback(&initData, 5, azArg, 0); sqliteInitCallback(&initData, 5, azArg, 0);
pTab = sqliteFindTable(db, MASTER_NAME); pTab = sqliteFindTable(db, MASTER_NAME, "main");
if( pTab ){ if( pTab ){
pTab->readOnly = 1; pTab->readOnly = 1;
} }
@@ -242,7 +247,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
azArg[3] = temp_master_schema; azArg[3] = temp_master_schema;
azArg[4] = "1"; azArg[4] = "1";
sqliteInitCallback(&initData, 5, azArg, 0); sqliteInitCallback(&initData, 5, azArg, 0);
pTab = sqliteFindTable(db, TEMP_MASTER_NAME); pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp");
if( pTab ){ if( pTab ){
pTab->readOnly = 1; pTab->readOnly = 1;
} }
@@ -347,22 +352,24 @@ const char sqlite_encoding[] = "iso8859";
*/ */
sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
sqlite *db; sqlite *db;
int rc; int rc, i;
/* Allocate the sqlite data structure */ /* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite) ); db = sqliteMalloc( sizeof(sqlite) );
if( pzErrMsg ) *pzErrMsg = 0; if( pzErrMsg ) *pzErrMsg = 0;
if( db==0 ) goto no_mem_on_open; if( db==0 ) goto no_mem_on_open;
sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->trigHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
sqliteHashInit(&db->aFKey, SQLITE_HASH_STRING, 1);
db->onError = OE_Default; db->onError = OE_Default;
db->priorNewRowid = 0; db->priorNewRowid = 0;
db->magic = SQLITE_MAGIC_BUSY; db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2; db->nDb = 2;
db->aDb = db->aDbStatic; db->aDb = db->aDbStatic;
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
for(i=0; i<db->nDb; i++){
sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
sqliteHashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
}
/* Open the backend database driver */ /* Open the backend database driver */
rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->aDb[0].pBt); rc = sqliteBtreeOpen(zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
@@ -486,7 +493,6 @@ void sqlite_close(sqlite *db){
} }
} }
sqliteHashClear(&db->aFunc); sqliteHashClear(&db->aFunc);
sqliteHashClear(&db->aFKey);
sqliteFree(db); sqliteFree(db);
} }

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.92 2003/03/20 01:16:59 drh Exp $ ** @(#) $Id: parse.y,v 1.93 2003/03/27 12:51:25 drh Exp $
*/ */
%token_prefix TK_ %token_prefix TK_
%token_type {Token} %token_type {Token}
@@ -96,8 +96,8 @@ create_table ::= CREATE(X) temp(T) TABLE nm(Y). {
sqliteStartTable(pParse,&X,&Y,T,0); sqliteStartTable(pParse,&X,&Y,T,0);
} }
%type temp {int} %type temp {int}
temp(A) ::= TEMP. {A = pParse->isTemp || !pParse->initFlag;} temp(A) ::= TEMP. {A = 1;}
temp(A) ::= . {A = pParse->isTemp;} 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,0); sqliteEndTable(pParse,&X,0);
} }
@@ -176,7 +176,7 @@ carg ::= DEFAULT NULL.
ccons ::= NULL onconf. ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqliteAddNotNull(pParse, R);} ccons ::= NOT NULL onconf(R). {sqliteAddNotNull(pParse, R);}
ccons ::= PRIMARY KEY sortorder onconf(R). {sqliteAddPrimaryKey(pParse,0,R);} ccons ::= PRIMARY KEY sortorder onconf(R). {sqliteAddPrimaryKey(pParse,0,R);}
ccons ::= UNIQUE onconf(R). {sqliteCreateIndex(pParse,0,0,0,R,0,0);} ccons ::= UNIQUE onconf(R). {sqliteCreateIndex(pParse,0,0,0,R,0,0,0);}
ccons ::= CHECK LP expr RP onconf. ccons ::= CHECK LP expr RP onconf.
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
{sqliteCreateForeignKey(pParse,0,&T,TA,R);} {sqliteCreateForeignKey(pParse,0,&T,TA,R);}
@@ -223,7 +223,7 @@ tcons ::= CONSTRAINT nm.
tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R). tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R).
{sqliteAddPrimaryKey(pParse,X,R);} {sqliteAddPrimaryKey(pParse,X,R);}
tcons ::= UNIQUE LP idxlist(X) RP onconf(R). tcons ::= UNIQUE LP idxlist(X) RP onconf(R).
{sqliteCreateIndex(pParse,0,0,X,R,0,0);} {sqliteCreateIndex(pParse,0,0,X,R,0,0,0);}
tcons ::= CHECK expr onconf. tcons ::= CHECK expr onconf.
tcons ::= FOREIGN KEY LP idxlist(FA) RP tcons ::= FOREIGN KEY LP idxlist(FA) RP
REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). { REFERENCES nm(T) idxlist_opt(TA) refargs(R) defer_subclause_opt(D). {
@@ -528,6 +528,13 @@ expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y); Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y);
A = sqliteExpr(TK_DOT, temp1, temp2, 0); A = sqliteExpr(TK_DOT, temp1, temp2, 0);
} }
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqliteExpr(TK_ID, 0, 0, &X);
Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y);
Expr *temp3 = sqliteExpr(TK_ID, 0, 0, &Z);
Expr *temp4 = sqliteExpr(TK_DOT, temp2, temp3, 0);
A = sqliteExpr(TK_DOT, temp1, temp4, 0);
}
expr(A) ::= expr(B) ORACLE_OUTER_JOIN. expr(A) ::= expr(B) ORACLE_OUTER_JOIN.
{A = B; ExprSetProperty(A,EP_Oracle8Join);} {A = B; ExprSetProperty(A,EP_Oracle8Join);}
expr(A) ::= INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);} expr(A) ::= INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);}
@@ -692,11 +699,12 @@ expritem(A) ::= . {A = 0;}
///////////////////////////// The CREATE INDEX command /////////////////////// ///////////////////////////// The CREATE INDEX command ///////////////////////
// //
cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) cmd ::= CREATE(S) temp(T) uniqueflag(U) INDEX nm(X)
ON nm(Y) LP idxlist(Z) RP(E) onconf(R). { ON nm(Y) dbnm(D) LP idxlist(Z) RP(E) onconf(R). {
SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
if( U!=OE_None ) U = R; if( U!=OE_None ) U = R;
if( U==OE_Default) U = OE_Abort; if( U==OE_Default) U = OE_Abort;
sqliteCreateIndex(pParse, &X, &Y, Z, U, &S, &E); sqliteCreateIndex(pParse, &X, pSrc, Z, U, T, &S, &E);
} }
%type uniqueflag {int} %type uniqueflag {int}
@@ -718,15 +726,17 @@ idxitem(A) ::= nm(X). {A = X;}
///////////////////////////// The DROP INDEX command ///////////////////////// ///////////////////////////// The DROP INDEX command /////////////////////////
// //
cmd ::= DROP INDEX nm(X). {sqliteDropIndex(pParse, &X);} cmd ::= DROP INDEX nm(X) dbnm(Y). {
sqliteDropIndex(pParse, sqliteSrcListAppend(0,&X,&Y));
}
///////////////////////////// The COPY command /////////////////////////////// ///////////////////////////// The COPY command ///////////////////////////////
// //
cmd ::= COPY orconf(R) nm(X) FROM nm(Y) USING DELIMITERS STRING(Z). cmd ::= COPY orconf(R) nm(X) dbnm(D) FROM nm(Y) USING DELIMITERS STRING(Z).
{sqliteCopy(pParse,&X,&Y,&Z,R);} {sqliteCopy(pParse,sqliteSrcListAppend(0,&X,&D),&Y,&Z,R);}
cmd ::= COPY orconf(R) nm(X) FROM nm(Y). cmd ::= COPY orconf(R) nm(X) dbnm(D) FROM nm(Y).
{sqliteCopy(pParse,&X,&Y,0,R);} {sqliteCopy(pParse,sqliteSrcListAppend(0,&X,&D),&Y,0,R);}
///////////////////////////// The VACUUM command ///////////////////////////// ///////////////////////////// The VACUUM command /////////////////////////////
// //
@@ -749,13 +759,15 @@ plus_opt ::= PLUS.
plus_opt ::= . plus_opt ::= .
//////////////////////////// The CREATE TRIGGER command ///////////////////// //////////////////////////// The CREATE TRIGGER command /////////////////////
cmd ::= CREATE(A) TRIGGER nm(B) trigger_time(C) trigger_event(D) ON nm(E) cmd ::= CREATE(A) TRIGGER nm(B) trigger_time(C) trigger_event(D)
ON nm(E) dbnm(DB)
foreach_clause(F) when_clause(G) foreach_clause(F) when_clause(G)
BEGIN trigger_cmd_list(S) END(Z). { BEGIN trigger_cmd_list(S) END(Z). {
SrcList *pTab = sqliteSrcListAppend(0, &E, &DB);
Token all; Token all;
all.z = A.z; all.z = A.z;
all.n = (Z.z - A.z) + Z.n; all.n = (Z.z - A.z) + Z.n;
sqliteCreateTrigger(pParse, &B, C, D.a, D.b, &E, F, G, S, &all); sqliteCreateTrigger(pParse, &B, C, D.a, D.b, pTab, F, G, S, &all);
} }
%type trigger_time {int} %type trigger_time {int}
@@ -828,8 +840,8 @@ expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y). {
} }
//////////////////////// DROP TRIGGER statement ////////////////////////////// //////////////////////// DROP TRIGGER statement //////////////////////////////
cmd ::= DROP TRIGGER nm(X). { cmd ::= DROP TRIGGER nm(X) dbnm(D). {
sqliteDropTrigger(pParse,&X,0); sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D),0);
} }
//////////////////////// ATTACH DATABASE file AS name ///////////////////////// //////////////////////// ATTACH DATABASE file AS name /////////////////////////

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 SELECT statements in SQLite. ** to handle SELECT statements in SQLite.
** **
** $Id: select.c,v 1.127 2003/03/19 03:14:02 drh Exp $ ** $Id: select.c,v 1.128 2003/03/27 12:51:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -912,7 +912,8 @@ static int fillInColumnList(Parse *pParse, Select *p){
}else{ }else{
/* An ordinary table or view name in the FROM clause */ /* An ordinary table or view name in the FROM clause */
pTabList->a[i].pTab = pTab = pTabList->a[i].pTab = pTab =
sqliteFindTable(pParse->db, pTabList->a[i].zName); sqliteFindTable(pParse->db, pTabList->a[i].zName,
pTabList->a[i].zDatabase);
if( pTab==0 ){ if( pTab==0 ){
sqliteSetString(&pParse->zErrMsg, "no such table: ", sqliteSetString(&pParse->zErrMsg, "no such table: ",
pTabList->a[i].zName, 0); pTabList->a[i].zName, 0);
@@ -1830,13 +1831,13 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
sqliteCodeVerifySchema(pParse); sqliteCodeVerifySchema(pParse);
} }
base = p->base; base = p->base;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
if( pIdx==0 ){ if( pIdx==0 ){
sqliteVdbeAddOp(v, seekOp, base, 0); sqliteVdbeAddOp(v, seekOp, base, 0);
}else{ }else{
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, seekOp, base+1, 0); sqliteVdbeAddOp(v, seekOp, base+1, 0);

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.164 2003/03/20 01:16:59 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.165 2003/03/27 12:51:25 drh Exp $
*/ */
#include "config.h" #include "config.h"
#include "sqlite.h" #include "sqlite.h"
@@ -200,7 +200,12 @@ struct Db {
char *zName; /* Name of this database */ char *zName; /* Name of this database */
Btree *pBt; /* The B*Tree structure for this database file */ Btree *pBt; /* The B*Tree structure for this database file */
int schema_cookie; /* Database schema version number for this file */ int schema_cookie; /* Database schema version number for this file */
Hash tblHash; /* All tables indexed by name */
Hash idxHash; /* All (named) indices indexed by name */
Hash trigHash; /* All triggers indexed by name */
Hash aFKey; /* Foreign keys indexed by to-table */
u8 inTrans; /* True if a transaction is underway for this backend */ u8 inTrans; /* True if a transaction is underway for this backend */
u16 flags; /* Flags associated with this database */
}; };
/* /*
@@ -231,11 +236,7 @@ struct sqlite {
int nTable; /* Number of tables in the database */ int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */ void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
Hash tblHash; /* All tables indexed by name */
Hash idxHash; /* All (named) indices indexed by name */
Hash trigHash; /* All triggers indexed by name */
Hash aFunc; /* All functions that can be in SQL exprs */ Hash aFunc; /* All functions that can be in SQL exprs */
Hash aFKey; /* Foreign keys indexed by to-table */
int lastRowid; /* ROWID of most recent insert */ int lastRowid; /* ROWID of most recent insert */
int priorNewRowid; /* Last randomly generated ROWID */ int priorNewRowid; /* Last randomly generated ROWID */
int onError; /* Default conflict algorithm */ int onError; /* Default conflict algorithm */
@@ -329,26 +330,27 @@ struct Column {
** Each SQL table is represented in memory by an instance of the ** Each SQL table is represented in memory by an instance of the
** following structure. ** following structure.
** **
** Expr.zName is the name of the table. The case of the original ** Table.zName is the name of the table. The case of the original
** CREATE TABLE statement is stored, but case is not significant for ** CREATE TABLE statement is stored, but case is not significant for
** comparisons. ** comparisons.
** **
** Expr.nCol is the number of columns in this table. Expr.aCol is a ** Table.nCol is the number of columns in this table. Table.aCol is a
** pointer to an array of Column structures, one for each column. ** pointer to an array of Column structures, one for each column.
** **
** If the table has an INTEGER PRIMARY KEY, then Expr.iPKey is the index of ** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of
** the column that is that key. Otherwise Expr.iPKey is negative. Note ** the column that is that key. Otherwise Table.iPKey is negative. Note
** that the datatype of the PRIMARY KEY must be INTEGER for this field to ** that the datatype of the PRIMARY KEY must be INTEGER for this field to
** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of ** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of
** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid ** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid
** is generated for each row of the table. Expr.hasPrimKey is true if ** is generated for each row of the table. Table.hasPrimKey is true if
** the table has any PRIMARY KEY, INTEGER or otherwise. ** the table has any PRIMARY KEY, INTEGER or otherwise.
** **
** Expr.tnum is the page number for the root BTree page of the table in the ** Table.tnum is the page number for the root BTree page of the table in the
** database file. If Expr.isTemp is true, then this page occurs in the ** database file. If Table.iDb is the index of the database table backend
** auxiliary database file, not the main database file. If Expr.isTransient ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that
** holds temporary tables and indices. If Table.isTransient
** is true, then the table is stored in a file that is automatically deleted ** is true, then the table is stored in a file that is automatically deleted
** when the VDBE cursor to the table is closed. In this case Expr.tnum ** when the VDBE cursor to the table is closed. In this case Table.tnum
** refers VDBE cursor number that holds the table open, not to the root ** refers VDBE cursor number that holds the table open, not to the root
** page number. Transient tables are used to hold the results of a ** page number. Transient tables are used to hold the results of a
** sub-query that appears instead of a real table name in the FROM clause ** sub-query that appears instead of a real table name in the FROM clause
@@ -363,7 +365,7 @@ struct Table {
int tnum; /* Root BTree node for this table (see note above) */ int tnum; /* Root BTree node for this table (see note above) */
Select *pSelect; /* NULL for tables. Points to definition if a view. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */
u8 readOnly; /* True if this table should not be written by the user */ u8 readOnly; /* True if this table should not be written by the user */
u8 isTemp; /* Index into sqlite.aDb[] of the backend for this table */ u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */
u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 isTransient; /* True if automatically deleted when VDBE finishes */
u8 hasPrimKey; /* True if there exists a primary key */ u8 hasPrimKey; /* True if there exists a primary key */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
@@ -479,6 +481,7 @@ struct Index {
u8 isUnique; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 isUnique; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */
Index *pNext; /* The next index associated with the same table */ Index *pNext; /* The next index associated with the same table */
}; };
@@ -604,6 +607,12 @@ struct IdList {
** The following structure describes the FROM clause of a SELECT statement. ** The following structure describes the FROM clause of a SELECT statement.
** Each table or subquery in the FROM clause is a separate element of ** Each table or subquery in the FROM clause is a separate element of
** the SrcList.a[] array. ** the SrcList.a[] array.
**
** With the addition of multiple database support, the following structure
** can also be used to describe a particular table such as the table that
** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
** such a table must be a simple name: ID. But in SQLite, the table can
** now be identified by a database name, a dot, then the table name: ID.ID.
*/ */
struct SrcList { struct SrcList {
int nSrc; /* Number of tables or subqueries in the FROM clause */ int nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -765,7 +774,7 @@ struct Parse {
** while generating expressions. Normally false */ ** while generating expressions. Normally false */
u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace u8 schemaVerified; /* True if an OP_VerifySchema has been coded someplace
** other than after an OP_Transaction */ ** other than after an OP_Transaction */
u8 isTemp; /* True if parsing temporary tables */ u8 iDb; /* Index of database whose schema is being parsed */
u8 useCallback; /* True if callbacks should be used to report results */ u8 useCallback; /* True if callbacks should be used to report results */
int newTnum; /* Table number to use when reparsing CREATE TABLEs */ int newTnum; /* Table number to use when reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
@@ -807,6 +816,7 @@ struct Parse {
struct Trigger { struct Trigger {
char *name; /* The name of the trigger */ char *name; /* The name of the trigger */
char *table; /* The table or view to which the trigger applies */ char *table; /* The table or view to which the trigger applies */
int iDb; /* Database containing this trigger */
int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */ int op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
int tr_tm; /* One of TK_BEFORE, TK_AFTER */ int tr_tm; /* One of TK_BEFORE, TK_AFTER */
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */ Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
@@ -973,7 +983,6 @@ void sqliteAddCollateType(Parse*, int);
void sqliteEndTable(Parse*,Token*,Select*); void sqliteEndTable(Parse*,Token*,Select*);
void sqliteCreateView(Parse*,Token*,Token*,Select*,int); void sqliteCreateView(Parse*,Token*,Token*,Select*,int);
int sqliteViewGetColumnNames(Parse*,Table*); int sqliteViewGetColumnNames(Parse*,Table*);
void sqliteViewResetAll(sqlite*);
void sqliteDropTable(Parse*, Token*, int); void sqliteDropTable(Parse*, Token*, int);
void sqliteDeleteTable(sqlite*, Table*); void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, SrcList*, ExprList*, Select*, IdList*, int); void sqliteInsert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
@@ -983,8 +992,8 @@ SrcList *sqliteSrcListAppend(SrcList*, Token*, Token*);
void sqliteSrcListAddAlias(SrcList*, Token*); void sqliteSrcListAddAlias(SrcList*, Token*);
void sqliteIdListDelete(IdList*); void sqliteIdListDelete(IdList*);
void sqliteSrcListDelete(SrcList*); void sqliteSrcListDelete(SrcList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*); void sqliteCreateIndex(Parse*,Token*,SrcList*,IdList*,int,int,Token*,Token*);
void sqliteDropIndex(Parse*, Token*); void sqliteDropIndex(Parse*, SrcList*);
void sqliteAddKeyType(Vdbe*, ExprList*); void sqliteAddKeyType(Vdbe*, ExprList*);
void sqliteAddIdxKeyType(Vdbe*, Index*); void sqliteAddIdxKeyType(Vdbe*, Index*);
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*); int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
@@ -992,7 +1001,7 @@ Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
int,int,int); int,int,int);
void sqliteSelectDelete(Select*); void sqliteSelectDelete(Select*);
void sqliteSelectUnbind(Select*); void sqliteSelectUnbind(Select*);
Table *sqliteTableNameToTable(Parse*, const char*); Table *sqliteTableNameToTable(Parse*, const char*, const char*);
void sqliteDeleteFrom(Parse*, SrcList*, Expr*); void sqliteDeleteFrom(Parse*, SrcList*, Expr*);
void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int); void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**); WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int, ExprList**);
@@ -1000,10 +1009,10 @@ void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*); void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int, int); void sqliteExprIfTrue(Parse*, Expr*, int, int);
void sqliteExprIfFalse(Parse*, Expr*, int, int); void sqliteExprIfFalse(Parse*, Expr*, int, int);
Table *sqliteFindTable(sqlite*,const char*); Table *sqliteFindTable(sqlite*,const char*, const char*);
Index *sqliteFindIndex(sqlite*,const char*); Index *sqliteFindIndex(sqlite*,const char*, const char*);
void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*);
void sqliteCopy(Parse*, Token*, Token*, Token*, int); void sqliteCopy(Parse*, SrcList*, Token*, Token*, int);
void sqliteVacuum(Parse*, Token*); void sqliteVacuum(Parse*, Token*);
int sqliteGlobCompare(const unsigned char*,const unsigned char*); int sqliteGlobCompare(const unsigned char*,const unsigned char*);
int sqliteLikeCompare(const unsigned char*,const unsigned char*); int sqliteLikeCompare(const unsigned char*,const unsigned char*);
@@ -1043,9 +1052,9 @@ int sqliteSafetyOn(sqlite*);
int sqliteSafetyOff(sqlite*); int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*); int sqliteSafetyCheck(sqlite*);
void sqliteChangeCookie(sqlite*, Vdbe*); void sqliteChangeCookie(sqlite*, Vdbe*);
void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*, void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, SrcList*,
int, Expr*, TriggerStep*, Token*); int, Expr*, TriggerStep*, Token*);
void sqliteDropTrigger(Parse*, Token*, int); void sqliteDropTrigger(Parse*, SrcList*, int);
int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*); int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
int, int); int, int);

View File

@@ -41,7 +41,7 @@ void sqliteCreateTrigger(
int tr_tm, /* One of TK_BEFORE, TK_AFTER , TK_INSTEAD */ int tr_tm, /* One of TK_BEFORE, TK_AFTER , TK_INSTEAD */
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */ IdList *pColumns, /* column list if this is an UPDATE OF trigger */
Token *pTableName, /* The name of the table/view the trigger applies to */ SrcList *pTableName,/* The name of the table/view the trigger applies to */
int foreach, /* One of TK_ROW or TK_STATEMENT */ int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */ Expr *pWhen, /* WHEN clause */
TriggerStep *pStepList, /* The triggered program */ TriggerStep *pStepList, /* The triggered program */
@@ -50,6 +50,7 @@ void sqliteCreateTrigger(
Trigger *nt; Trigger *nt;
Table *tab; Table *tab;
char *zName = 0; /* Name of the trigger */ char *zName = 0; /* Name of the trigger */
sqlite *db = pParse->db;
/* Check that: /* Check that:
** 1. the trigger name does not already exist. ** 1. the trigger name does not already exist.
@@ -58,60 +59,55 @@ void sqliteCreateTrigger(
** 4. That we are not trying to create an INSTEAD OF trigger on a table. ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
*/ */
if( sqlite_malloc_failed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
tab = sqliteTableNameToTable(pParse, pTableName->a[0].zName,
pTableName->a[0].zDatabase);
if( !tab ){
goto trigger_cleanup;
}
if( tab->iDb>=2 ){
sqliteSetString(&pParse->zErrMsg, "triggers may not be added to "
"auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0);
pParse->nErr++;
goto trigger_cleanup;
}
zName = sqliteStrNDup(pName->z, pName->n); zName = sqliteStrNDup(pName->z, pName->n);
if( sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1) ){ if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){
sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
pName->z, pName->n, " already exists", -1, 0); pName->z, pName->n, " already exists", -1, 0);
pParse->nErr++; pParse->nErr++;
goto trigger_cleanup; goto trigger_cleanup;
} }
{ if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n); sqliteSetString(&pParse->zErrMsg,"cannot create trigger on system table",0);
if( tmp_str==0 ) goto trigger_cleanup; pParse->nErr++;
tab = sqliteFindTable(pParse->db, tmp_str); goto trigger_cleanup;
sqliteFree(tmp_str);
if( !tab ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
pTableName->z, pTableName->n, 0);
pParse->nErr++;
goto trigger_cleanup;
}
if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){
sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
"table: " MASTER_NAME, 0);
pParse->nErr++;
goto trigger_cleanup;
}
if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){
sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
"table: " TEMP_MASTER_NAME, 0);
pParse->nErr++;
goto trigger_cleanup;
}
if( tab->pSelect && tr_tm != TK_INSTEAD ){
sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
, pTableName->z, pTableName->n, 0);
goto trigger_cleanup;
}
if( !tab->pSelect && tr_tm == TK_INSTEAD ){
sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF", -1,
" trigger on table: ", -1, pTableName->z, pTableName->n, 0);
goto trigger_cleanup;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
if( tab->isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
goto trigger_cleanup;
}
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->isTemp), 0)){
goto trigger_cleanup;
}
}
#endif
} }
if( tab->pSelect && tr_tm != TK_INSTEAD ){
sqliteSetNString(&pParse->zErrMsg, "cannot create ",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", " trigger on view: ",
pTableName->a[0].zName, 0);
goto trigger_cleanup;
}
if( !tab->pSelect && tr_tm == TK_INSTEAD ){
sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF",
" trigger on table: ", pTableName->a[0].zName);
goto trigger_cleanup;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
goto trigger_cleanup;
}
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){
goto trigger_cleanup;
}
}
#endif
if (tr_tm == TK_INSTEAD){ if (tr_tm == TK_INSTEAD){
tr_tm = TK_BEFORE; tr_tm = TK_BEFORE;
@@ -122,8 +118,9 @@ void sqliteCreateTrigger(
if( nt==0 ) goto trigger_cleanup; if( nt==0 ) goto trigger_cleanup;
nt->name = zName; nt->name = zName;
zName = 0; zName = 0;
nt->table = sqliteStrNDup(pTableName->z, pTableName->n); nt->table = sqliteStrDup(pTableName->a[0].zName);
if( sqlite_malloc_failed ) goto trigger_cleanup; if( sqlite_malloc_failed ) goto trigger_cleanup;
nt->iDb = tab->iDb;
nt->op = op; nt->op = op;
nt->tr_tm = tr_tm; nt->tr_tm = tr_tm;
nt->pWhen = sqliteExprDup(pWhen); nt->pWhen = sqliteExprDup(pWhen);
@@ -154,15 +151,15 @@ void sqliteCreateTrigger(
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto trigger_cleanup; if( v==0 ) goto trigger_cleanup;
sqliteBeginWriteOperation(pParse, 0, 0); sqliteBeginWriteOperation(pParse, 0, 0);
sqliteOpenMasterTable(v, tab->isTemp); sqliteOpenMasterTable(v, tab->iDb);
addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME, sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME,
P3_STATIC); P3_STATIC);
sqliteVdbeChangeP3(v, addr+2, nt->name, 0); sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
sqliteVdbeChangeP3(v, addr+3, nt->table, 0); sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
if( !tab->isTemp ){ if( tab->iDb==0 ){
sqliteChangeCookie(pParse->db, v); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
@@ -170,7 +167,7 @@ void sqliteCreateTrigger(
if( !pParse->explain ){ if( !pParse->explain ){
/* Stick it in the hash-table */ /* Stick it in the hash-table */
sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt); sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt);
/* Attach it to the table object */ /* Attach it to the table object */
nt->pNext = tab->pTrigger; nt->pNext = tab->pTrigger;
@@ -185,6 +182,7 @@ void sqliteCreateTrigger(
trigger_cleanup: trigger_cleanup:
sqliteFree(zName); sqliteFree(zName);
sqliteSrcListDelete(pTableName);
sqliteIdListDelete(pColumns); sqliteIdListDelete(pColumns);
sqliteExprDelete(pWhen); sqliteExprDelete(pWhen);
sqliteDeleteTriggerStep(pStepList); sqliteDeleteTriggerStep(pStepList);
@@ -342,31 +340,46 @@ void sqliteDeleteTrigger(Trigger *pTrigger){
* table. This is so that the trigger can be restored into the database schema * table. This is so that the trigger can be restored into the database schema
* if the transaction is rolled back. * if the transaction is rolled back.
*/ */
void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
char *zName;
Trigger *pTrigger; Trigger *pTrigger;
Table *pTable; Table *pTable;
Vdbe *v; Vdbe *v;
int i;
const char *zDb;
const char *zName;
int nName;
sqlite *db = pParse->db;
zName = sqliteStrNDup(pName->z, pName->n); if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
assert( pName->nSrc==1 );
/* ensure that the trigger being dropped exists */ zDb = pName->a[0].zDatabase;
pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1); zName = pName->a[0].zName;
if( !pTrigger ){ nName = strlen(zName);
sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1, for(i=0; i<db->nDb; i++){
zName, -1, 0); if( zDb && sqliteStrICmp(db->aDb[i].zName, zDb) ) continue;
sqliteFree(zName); pTrigger = sqliteHashFind(&(db->aDb[i].trigHash), zName, nName+1);
return; if( pTrigger ) break;
} }
pTable = sqliteFindTable(pParse->db, pTrigger->table); if( !pTrigger ){
sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0);
goto drop_trigger_cleanup;
}
assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );
if( pTrigger->iDb>=2 ){
sqliteSetString(&pParse->zErrMsg, "triggers may not be removed from "
"auxiliary database \"", db->aDb[pTrigger->iDb].zName, "\"", 0);
pParse->nErr++;
goto drop_trigger_cleanup;
}
pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName);
assert(pTable); assert(pTable);
assert( pTable->iDb==pTrigger->iDb );
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
{ {
int code = SQLITE_DROP_TRIGGER; int code = SQLITE_DROP_TRIGGER;
if( pTable->isTemp ) code = SQLITE_DROP_TEMP_TRIGGER; if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->isTemp),0) ){ sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){
sqliteFree(zName);
return; return;
} }
} }
@@ -389,7 +402,7 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
} }
assert(cc); assert(cc);
} }
sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL); sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
sqliteDeleteTrigger(pTrigger); sqliteDeleteTrigger(pTrigger);
} }
@@ -409,17 +422,18 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
}; };
sqliteBeginWriteOperation(pParse, 0, 0); sqliteBeginWriteOperation(pParse, 0, 0);
sqliteOpenMasterTable(v, pTable->isTemp); sqliteOpenMasterTable(v, pTable->iDb);
base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
sqliteVdbeChangeP3(v, base+1, zName, 0); sqliteVdbeChangeP3(v, base+1, zName, 0);
if( !pTable->isTemp ){ if( pTable->iDb==0 ){
sqliteChangeCookie(pParse->db, v); sqliteChangeCookie(db, v);
} }
sqliteVdbeAddOp(v, OP_Close, 0, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0);
sqliteEndWriteOperation(pParse); sqliteEndWriteOperation(pParse);
} }
sqliteFree(zName); drop_trigger_cleanup:
sqliteSrcListDelete(pName);
} }
/* /*

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.55 2003/03/20 01:16:59 drh Exp $ ** $Id: update.c,v 1.56 2003/03/27 12:51:25 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -28,6 +28,7 @@ void sqliteUpdate(
){ ){
int i, j; /* Loop counters */ int i, j; /* Loop counters */
char *zTab; /* Name of the table to be updated */ char *zTab; /* Name of the table to be updated */
char *zDb; /* Name of the database holding zTab */
Table *pTab; /* The table to be updated */ Table *pTab; /* The table to be updated */
int addr; /* VDBE instruction address of the start of the loop */ int addr; /* VDBE instruction address of the start of the loop */
WhereInfo *pWInfo; /* Information about the WHERE clause */ WhereInfo *pWInfo; /* Information about the WHERE clause */
@@ -59,8 +60,9 @@ void sqliteUpdate(
* defined * defined
*/ */
zTab = pTabList->a[0].zName; zTab = pTabList->a[0].zName;
zDb = pTabList->a[0].zDatabase;
if( zTab != 0 ){ if( zTab != 0 ){
pTab = sqliteFindTable(pParse->db, zTab); pTab = sqliteFindTable(pParse->db, zTab, zDb);
if( pTab ){ if( pTab ){
row_triggers_exist = row_triggers_exist =
sqliteTriggersExist(pParse, pTab->pTrigger, sqliteTriggersExist(pParse, pTab->pTrigger,
@@ -82,7 +84,7 @@ void sqliteUpdate(
** will be calling are designed to work with multiple tables and expect ** will be calling are designed to work with multiple tables and expect
** an SrcList* parameter instead of just a Table* parameter. ** an SrcList* parameter instead of just a Table* parameter.
*/ */
pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab); pTab = pTabList->a[0].pTab = sqliteTableNameToTable(pParse, zTab, zDb);
if( pTab==0 ) goto update_cleanup; if( pTab==0 ) goto update_cleanup;
assert( pTab->pSelect==0 ); /* This table is not a VIEW */ assert( pTab->pSelect==0 ); /* This table is not a VIEW */
aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
@@ -197,7 +199,7 @@ void sqliteUpdate(
*/ */
v = sqliteGetVdbe(pParse); v = sqliteGetVdbe(pParse);
if( v==0 ) goto update_cleanup; if( v==0 ) goto update_cleanup;
sqliteBeginWriteOperation(pParse, 1, !row_triggers_exist && pTab->isTemp); sqliteBeginWriteOperation(pParse, 1, !row_triggers_exist && pTab->iDb==1);
/* Begin the database scan /* Begin the database scan
*/ */
@@ -229,7 +231,7 @@ void sqliteUpdate(
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0); sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeAddOp(v, OP_MoveTo, base, 0); sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
@@ -275,7 +277,7 @@ void sqliteUpdate(
** action, then we need to open all indices because we might need ** action, then we need to open all indices because we might need
** to be deleting some records. ** to be deleting some records.
*/ */
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
if( onError==OE_Replace ){ if( onError==OE_Replace ){
openAll = 1; openAll = 1;
@@ -290,7 +292,7 @@ void sqliteUpdate(
} }
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
if( openAll || aIdxUsed[i] ){ if( openAll || aIdxUsed[i] ){
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum); sqliteVdbeAddOp(v, OP_OpenWrite, base+i+1, pIdx->tnum);
assert( pParse->nTab>base+i+1 ); assert( pParse->nTab>base+i+1 );
} }

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.73 2003/03/19 03:14:03 drh Exp $ ** $Id: where.c,v 1.74 2003/03/27 12:51:26 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -640,7 +640,7 @@ WhereInfo *sqliteWhereBegin(
pTab = pTabList->a[i].pTab; pTab = pTabList->a[i].pTab;
if( pTab->isTransient || pTab->pSelect ) continue; if( pTab->isTransient || pTab->pSelect ) continue;
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base+i, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, base+i, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
if( i==0 && !pParse->schemaVerified && if( i==0 && !pParse->schemaVerified &&
@@ -648,7 +648,7 @@ WhereInfo *sqliteWhereBegin(
sqliteCodeVerifySchema(pParse); sqliteCodeVerifySchema(pParse);
} }
if( pWInfo->a[i].pIdx!=0 ){ if( pWInfo->a[i].pIdx!=0 ){
sqliteVdbeAddOp(v, OP_Integer, pTab->isTemp, 0); sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, sqliteVdbeAddOp(v, OP_OpenRead,
pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum); pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);