mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Tighter binding of views, triggers, and indices to their respective
databases. Ticket #323. Much more testing needs to be done to the sqliteFix...() routines in attach.c. (CVS 990) FossilOrigin-Name: 7202d4f1a8853368954a967b7ccca9d8a6645a2e
This commit is contained in:
32
manifest
32
manifest
@ -1,5 +1,5 @@
|
|||||||
C Change\sthe\srow-size\slimit\sback\sto\s1MB.\s\sIt\swas\stemporarily\sraised\sto\s16MB.\nWe'll\sprobably\smove\sit\sto\s16MB\seventually,\sbut\snot\sjust\syet.\s(CVS\s989)
|
C Tighter\sbinding\sof\sviews,\striggers,\sand\sindices\sto\stheir\srespective\ndatabases.\s\sTicket\s#323.\s\sMuch\smore\stesting\sneeds\sto\sbe\sdone\sto\sthe\nsqliteFix...()\sroutines\sin\sattach.c.\s(CVS\s990)
|
||||||
D 2003-05-29T17:50:55
|
D 2003-05-31T16:21:12
|
||||||
F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43
|
F Makefile.in 1ff85c27d4350c74118341024e8a4fb2a04a3a43
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -19,21 +19,21 @@ F publish.sh 86b5e8535830a2588f62ce1d5d1ef00e1dede23a
|
|||||||
F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
|
F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
|
||||||
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
||||||
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||||
F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
|
F src/attach.c 4f0aa5add0fb3c11b6a2130a1c8593bb5063b6d4
|
||||||
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
||||||
F src/btree.c 8092dca45dcdb69c61273db0213cbb85760673c7
|
F src/btree.c 8092dca45dcdb69c61273db0213cbb85760673c7
|
||||||
F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
|
F src/btree.h 23c50e00709de16a5dce1fcea9c0429cc955ff0e
|
||||||
F src/btree_rb.c 1d809e703aab8bef916ebb0b6ba9254a1c36d9a6
|
F src/btree_rb.c 1d809e703aab8bef916ebb0b6ba9254a1c36d9a6
|
||||||
F src/build.c 3f5d1798e40020e3a038dbe058406f665b4a51a4
|
F src/build.c 936d10b33b326546280690bee7f20efaf19a6fe8
|
||||||
F src/copy.c 5e5d558d283536592cd67b5dc1519c3152bd7e20
|
F src/copy.c 5e5d558d283536592cd67b5dc1519c3152bd7e20
|
||||||
F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc
|
F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc
|
||||||
F src/encode.c ed720e54ec4ef4d4de651592f1dd1c74d422bbd2
|
F src/encode.c ed720e54ec4ef4d4de651592f1dd1c74d422bbd2
|
||||||
F src/expr.c a666ef5220ca90ebcf40c8ccc783966a345a7616
|
F src/expr.c ebdb0f3ee039c8030de25935ce2df030966540a6
|
||||||
F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2
|
F src/func.c 33bbce6acaf9578ac99aa1f689968ccaf2ce43a2
|
||||||
F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3
|
F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3
|
||||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||||
F src/insert.c 2f26b95cc1055062411cbdea06e2e1b40a8b0d8d
|
F src/insert.c 2f26b95cc1055062411cbdea06e2e1b40a8b0d8d
|
||||||
F src/main.c 717aaf32d468667dabeaec80054e11bfdb6309b6
|
F src/main.c d299e896377001823e610c0a75d28d1e7adf104e
|
||||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||||
F src/os.c 080238f03015057879cdf53bc4af9e497f2ba724
|
F src/os.c 080238f03015057879cdf53bc4af9e497f2ba724
|
||||||
F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
|
F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
|
||||||
@ -43,11 +43,11 @@ F src/parse.y 917250e5d86bdee752355e6617ea2e8ee12438bf
|
|||||||
F src/pragma.c ec64704e61286948f39157617f1ce2f506dd1b74
|
F src/pragma.c ec64704e61286948f39157617f1ce2f506dd1b74
|
||||||
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
||||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||||
F src/select.c 15d921308065c9320363af6f43c01d9f09ea7118
|
F src/select.c 76b3a5cda76421cfe82d6a96c72308c2518cb2f9
|
||||||
F src/shell.c b63089a91d6584df06eaa2e53ea1150c68ab1e61
|
F src/shell.c b63089a91d6584df06eaa2e53ea1150c68ab1e61
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
|
F src/sqlite.h.in eec06462cba262c0ee03f38462a18a4bc66dda4e
|
||||||
F src/sqliteInt.h db9d8883896fa2be7afe13da8bf9c67b39313a6d
|
F src/sqliteInt.h ad7895b4cd9ae7fed25d98ee6f91d7d4774fdc84
|
||||||
F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95
|
F src/table.c 4301926464d88d2c2c7cd21c3360aa75bf068b95
|
||||||
F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
|
F src/tclsqlite.c 9e25f98f1765afa0716144ef57abda75c88f688d
|
||||||
F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
|
F src/test1.c 4596acd9d9f2a49fda0160a8a6dee5bfc7c6c325
|
||||||
@ -55,7 +55,7 @@ F src/test2.c 5014337d8576b731cce5b5a14bec4f0daf432700
|
|||||||
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
|
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
|
||||||
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
F src/threadtest.c d641a5219e718e18a1a80a50eb9bb549f451f42e
|
||||||
F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3
|
F src/tokenize.c 2ba93fe10d5f57f0cc20b07417c3244a30c324b3
|
||||||
F src/trigger.c 7607b209e6de07371e94f3266a850562f522297e
|
F src/trigger.c 5caf7697e6cd4cfaf38d55bff31580f4124d836f
|
||||||
F src/update.c 8e657c7b3d27b5592d8caa362d9c4765e0b3cd6a
|
F src/update.c 8e657c7b3d27b5592d8caa362d9c4765e0b3cd6a
|
||||||
F src/util.c 8065b78806a5132119452d9e0417cf071e6f02f9
|
F src/util.c 8065b78806a5132119452d9e0417cf071e6f02f9
|
||||||
F src/vacuum.c 0820984615786c9ccdaad8032a792309b354a8eb
|
F src/vacuum.c 0820984615786c9ccdaad8032a792309b354a8eb
|
||||||
@ -63,7 +63,7 @@ F src/vdbe.c 81b9868acd7e7d54ddd26af4ffe8442c312ad374
|
|||||||
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
|
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
|
||||||
F src/where.c 1e645d430cb4b347159c28c6085e9801160f2099
|
F src/where.c 1e645d430cb4b347159c28c6085e9801160f2099
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
F test/attach.test 20b35533a5460e1a1ed518948233f870c31ba824
|
F test/attach.test f050eebbb7e45c0796add92fa3f9154d68d7a01a
|
||||||
F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
|
F test/auth.test dee78be1f4f920bd6b15c4c947ce4d01bfe2826d
|
||||||
F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
|
F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
@ -119,15 +119,15 @@ F test/tclsqlite.test d9bdfc0afca9ee605c50ecb39e94ae4dea8c222b
|
|||||||
F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
|
F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692
|
||||||
F test/tester.tcl d7a5835edaf118539241145d8188f0822b673488
|
F test/tester.tcl d7a5835edaf118539241145d8188f0822b673488
|
||||||
F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d
|
F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d
|
||||||
F test/trigger1.test 589fb8f3015613b1158736e9a29771efbbe989dd
|
F test/trigger1.test 8e6c11a1b7962ae9dd89c124d36667f52568a4ac
|
||||||
F test/trigger2.test 00ceb8aff6bddd511bbac7c837af2863fa0c9cb4
|
F test/trigger2.test 00ceb8aff6bddd511bbac7c837af2863fa0c9cb4
|
||||||
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
|
F test/trigger3.test 870afef7997a5b86bf3ea893ce0c2e85d6356c72
|
||||||
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
|
F test/trigger4.test f0092c8580cce3c7119b17eefd3cc766a7579557
|
||||||
F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
|
F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
|
||||||
F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
|
F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
|
||||||
F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258
|
F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258
|
||||||
F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
|
F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
|
||||||
F test/view.test 408fa464da35cf9c1fd9054c988f7e755a1cb0b6
|
F test/view.test 1ee12c6f8f4791a2c0655120d5562a49400cfe53
|
||||||
F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
|
F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
|
||||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||||
F tool/lemon.c 93db920de9479657d04ca73e9368db7fc2969990
|
F tool/lemon.c 93db920de9479657d04ca73e9368db7fc2969990
|
||||||
@ -165,7 +165,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
|
|||||||
F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125
|
F www/sqlite.tcl 4bd1729e320f5fa9125f0022b281fbe839192125
|
||||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 8c402db7e0745622d9950e5ca5d4d8e933da436c
|
P b84c4035c6b06469055798cf412fa4da8b50fa17
|
||||||
R fbd5748bc942b5aae6db8b32fa7c1886
|
R fe41e9ac0f03f80478d135d39a06e3d3
|
||||||
U drh
|
U drh
|
||||||
Z 9cd0279506dec2db43f72b462a03f9b3
|
Z 1e8087bb88b82d343bca83c3daf989ca
|
||||||
|
@ -1 +1 @@
|
|||||||
b84c4035c6b06469055798cf412fa4da8b50fa17
|
7202d4f1a8853368954a967b7ccca9d8a6645a2e
|
135
src/attach.c
135
src/attach.c
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||||
**
|
**
|
||||||
** $Id: attach.c,v 1.3 2003/04/15 19:22:23 drh Exp $
|
** $Id: attach.c,v 1.4 2003/05/31 16:21:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -128,3 +128,136 @@ void sqliteDetach(Parse *pParse, Token *pDbname){
|
|||||||
sqliteResetInternalSchema(db, i);
|
sqliteResetInternalSchema(db, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Initialize a DbFixer structure. This routine must be called prior
|
||||||
|
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
||||||
|
**
|
||||||
|
** The return value indicates whether or not fixation is required. TRUE
|
||||||
|
** means we do need to fix the database references, FALSE means we do not.
|
||||||
|
*/
|
||||||
|
int sqliteFixInit(
|
||||||
|
DbFixer *pFix, /* The fixer to be initialized */
|
||||||
|
Parse *pParse, /* Error messages will be written here */
|
||||||
|
int iDb, /* This is the database that must must be used */
|
||||||
|
const char *zType, /* "view", "trigger", or "index" */
|
||||||
|
const Token *pName /* Name of the view, trigger, or index */
|
||||||
|
){
|
||||||
|
sqlite *db;
|
||||||
|
|
||||||
|
if( iDb<0 || iDb==1 ) return 0;
|
||||||
|
db = pParse->db;
|
||||||
|
assert( db->nDb>iDb );
|
||||||
|
pFix->zDb = db->aDb[iDb].zName;
|
||||||
|
pFix->zType = zType;
|
||||||
|
pFix->pName = pName;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following set of routines walk through the parse tree and assign
|
||||||
|
** a specific database to all table references where the database name
|
||||||
|
** was left unspecified in the original SQL statement. The pFix structure
|
||||||
|
** must have been initialized by a prior call to sqliteFixInit().
|
||||||
|
**
|
||||||
|
** These routines are used to make sure that an index, trigger, or
|
||||||
|
** view in one database does not refer to objects in a different database.
|
||||||
|
** (Exception: indices, triggers, and views in the TEMP database are
|
||||||
|
** allowed to refer to anything.) If a reference is explicitly made
|
||||||
|
** to an object in a different database, an error message is added to
|
||||||
|
** pParse->zErrMsg and these routines return non-zero. If everything
|
||||||
|
** checks out, these routines return 0.
|
||||||
|
*/
|
||||||
|
int sqliteFixSrcList(
|
||||||
|
DbFixer *pFix, /* Context of the fixation */
|
||||||
|
SrcList *pList /* The Source list to check and modify */
|
||||||
|
){
|
||||||
|
int i;
|
||||||
|
const char *zDb;
|
||||||
|
|
||||||
|
if( pList==0 ) return 0;
|
||||||
|
zDb = pFix->zDb;
|
||||||
|
for(i=0; i<pList->nSrc; i++){
|
||||||
|
if( pList->a[i].zDatabase==0 ){
|
||||||
|
pList->a[i].zDatabase = sqliteStrDup(zDb);
|
||||||
|
}else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){
|
||||||
|
sqliteErrorMsg(pFix->pParse,
|
||||||
|
"%s %.*s cannot reference objects in database %s",
|
||||||
|
pFix->zType, pFix->pName->n, pFix->pName->z, pList->a[i].zDatabase);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1;
|
||||||
|
if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int sqliteFixSelect(
|
||||||
|
DbFixer *pFix, /* Context of the fixation */
|
||||||
|
Select *pSelect /* The SELECT statement to be fixed to one database */
|
||||||
|
){
|
||||||
|
while( pSelect ){
|
||||||
|
if( sqliteFixExprList(pFix, pSelect->pEList) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixSrcList(pFix, pSelect->pSrc) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExpr(pFix, pSelect->pWhere) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExpr(pFix, pSelect->pHaving) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pSelect = pSelect->pPrior;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int sqliteFixExpr(
|
||||||
|
DbFixer *pFix, /* Context of the fixation */
|
||||||
|
Expr *pExpr /* The expression to be fixed to one database */
|
||||||
|
){
|
||||||
|
while( pExpr ){
|
||||||
|
if( sqliteFixSelect(pFix, pExpr->pSelect) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExprList(pFix, pExpr->pList) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExpr(pFix, pExpr->pRight) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pExpr = pExpr->pLeft;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int sqliteFixExprList(
|
||||||
|
DbFixer *pFix, /* Context of the fixation */
|
||||||
|
ExprList *pList /* The expression to be fixed to one database */
|
||||||
|
){
|
||||||
|
int i;
|
||||||
|
if( pList==0 ) return 0;
|
||||||
|
for(i=0; i<pList->nExpr; i++){
|
||||||
|
if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int sqliteFixTriggerStep(
|
||||||
|
DbFixer *pFix, /* Context of the fixation */
|
||||||
|
TriggerStep *pStep /* The trigger step be fixed to one database */
|
||||||
|
){
|
||||||
|
while( pStep ){
|
||||||
|
if( sqliteFixSelect(pFix, pStep->pSelect) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExpr(pFix, pStep->pWhere) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( sqliteFixExprList(pFix, pStep->pExprList) ){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pStep = pStep->pNext;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
62
src/build.c
62
src/build.c
@ -23,7 +23,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.154 2003/05/17 19:04:04 drh Exp $
|
** $Id: build.c,v 1.155 2003/05/31 16:21:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -118,6 +118,12 @@ void sqliteExec(Parse *pParse){
|
|||||||
** of that table and (optionally) the name of the database
|
** of that table and (optionally) the name of the database
|
||||||
** containing the table. Return NULL if not found.
|
** containing the table. Return NULL if not found.
|
||||||
**
|
**
|
||||||
|
** If zDatabase is 0, all databases are searched for the
|
||||||
|
** table and the first matching table is returned. (No checking
|
||||||
|
** for duplicate table names is done.) The search order is
|
||||||
|
** TEMP first, then MAIN, then any auxiliary databases added
|
||||||
|
** using the ATTACH command.
|
||||||
|
**
|
||||||
** See also sqliteLocateTable().
|
** See also sqliteLocateTable().
|
||||||
*/
|
*/
|
||||||
Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
|
Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
|
||||||
@ -137,38 +143,22 @@ Table *sqliteFindTable(sqlite *db, const char *zName, const char *zDatabase){
|
|||||||
** a particular database table given the name
|
** a particular database table given the name
|
||||||
** of that table and (optionally) the name of the database
|
** of that table and (optionally) the name of the database
|
||||||
** containing the table. Return NULL if not found.
|
** containing the table. Return NULL if not found.
|
||||||
|
** Also leave an error message in pParse->zErrMsg.
|
||||||
**
|
**
|
||||||
** If pParse->useDb is not negative, then the table must be
|
** The difference between this routine and sqliteFindTable()
|
||||||
** located in that database. If a different database is specified,
|
** is that this routine leaves an error message in pParse->zErrMsg
|
||||||
** an error message is generated into pParse->zErrMsg.
|
** where sqliteFindTable() does not.
|
||||||
*/
|
*/
|
||||||
Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){
|
Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){
|
||||||
sqlite *db;
|
|
||||||
const char *zUse;
|
|
||||||
Table *p;
|
Table *p;
|
||||||
db = pParse->db;
|
|
||||||
if( pParse->useDb<0 ){
|
p = sqliteFindTable(pParse->db, zName, zDbase);
|
||||||
p = sqliteFindTable(db, zName, zDbase);
|
|
||||||
}else {
|
|
||||||
assert( pParse->useDb<db->nDb );
|
|
||||||
assert( db->aDb[pParse->useDb].pBt!=0 );
|
|
||||||
zUse = db->aDb[pParse->useDb].zName;
|
|
||||||
if( zDbase && pParse->useDb!=1 && sqliteStrICmp(zDbase, zUse)!=0 ){
|
|
||||||
sqliteErrorMsg(pParse,"cannot use database %s in this context", zDbase);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
p = sqliteFindTable(db, zName, zUse);
|
|
||||||
if( p==0 && pParse->useDb==1 && zDbase==0 ){
|
|
||||||
p = sqliteFindTable(db, zName, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( p==0 ){
|
if( p==0 ){
|
||||||
if( zDbase ){
|
if( zDbase ){
|
||||||
sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
|
sqliteErrorMsg(pParse, "no such table: %s.%s", zDbase, zName);
|
||||||
}else if( (pParse->useDb==0 || pParse->useDb>=2)
|
}else if( sqliteFindTable(pParse->db, zName, 0)!=0 ){
|
||||||
&& sqliteFindTable(db, zName, 0)!=0 ){
|
|
||||||
sqliteErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
|
sqliteErrorMsg(pParse, "table \"%s\" is not in database \"%s\"",
|
||||||
zName, zUse);
|
zName, zDbase);
|
||||||
}else{
|
}else{
|
||||||
sqliteErrorMsg(pParse, "no such table: %s", zName);
|
sqliteErrorMsg(pParse, "no such table: %s", zName);
|
||||||
}
|
}
|
||||||
@ -181,6 +171,12 @@ Table *sqliteLocateTable(Parse *pParse, const char *zName, const char *zDbase){
|
|||||||
** a particular index given the name of that index
|
** a particular index given the name of that index
|
||||||
** and the name of the database that contains the index.
|
** and the name of the database that contains the index.
|
||||||
** Return NULL if not found.
|
** Return NULL if not found.
|
||||||
|
**
|
||||||
|
** If zDatabase is 0, all databases are searched for the
|
||||||
|
** table and the first matching index is returned. (No checking
|
||||||
|
** for duplicate index names is done.) The search order is
|
||||||
|
** TEMP first, then MAIN, then any auxiliary databases added
|
||||||
|
** using the ATTACH command.
|
||||||
*/
|
*/
|
||||||
Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
|
Index *sqliteFindIndex(sqlite *db, const char *zName, const char *zDb){
|
||||||
Index *p = 0;
|
Index *p = 0;
|
||||||
@ -1046,6 +1042,7 @@ void sqliteCreateView(
|
|||||||
int n;
|
int n;
|
||||||
const char *z;
|
const char *z;
|
||||||
Token sEnd;
|
Token sEnd;
|
||||||
|
DbFixer sFix;
|
||||||
|
|
||||||
sqliteStartTable(pParse, pBegin, pName, isTemp, 1);
|
sqliteStartTable(pParse, pBegin, pName, isTemp, 1);
|
||||||
p = pParse->pNewTable;
|
p = pParse->pNewTable;
|
||||||
@ -1053,6 +1050,12 @@ void sqliteCreateView(
|
|||||||
sqliteSelectDelete(pSelect);
|
sqliteSelectDelete(pSelect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if( sqliteFixInit(&sFix, pParse, p->iDb, "view", pName)
|
||||||
|
&& sqliteFixSelect(&sFix, pSelect)
|
||||||
|
){
|
||||||
|
sqliteSelectDelete(pSelect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make a copy of the entire SELECT statement that defines the view.
|
/* Make a copy of the entire SELECT statement that defines the view.
|
||||||
** This will force all the Expr.token.z values to be dynamically
|
** This will force all the Expr.token.z values to be dynamically
|
||||||
@ -1534,10 +1537,17 @@ void sqliteCreateIndex(
|
|||||||
Index *pIndex; /* The index to be created */
|
Index *pIndex; /* The index to be created */
|
||||||
char *zName = 0;
|
char *zName = 0;
|
||||||
int i, j;
|
int i, j;
|
||||||
Token nullId; /* Fake token for an empty ID list */
|
Token nullId; /* Fake token for an empty ID list */
|
||||||
|
DbFixer sFix; /* For assigning database names to pTable */
|
||||||
sqlite *db = pParse->db;
|
sqlite *db = pParse->db;
|
||||||
|
|
||||||
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
|
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
|
||||||
|
if( !isTemp && pParse->initFlag
|
||||||
|
&& sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName)
|
||||||
|
&& sqliteFixSrcList(&sFix, pTable)
|
||||||
|
){
|
||||||
|
goto exit_create_index;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Find the table that is to be indexed. Return early if not found.
|
** Find the table that is to be indexed. Return early if not found.
|
||||||
|
@ -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.95 2003/05/02 14:32:13 drh Exp $
|
** $Id: expr.c,v 1.96 2003/05/31 16:21:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -191,6 +191,7 @@ SrcList *sqliteSrcListDup(SrcList *p){
|
|||||||
if( pNew==0 ) return 0;
|
if( pNew==0 ) return 0;
|
||||||
pNew->nSrc = p->nSrc;
|
pNew->nSrc = p->nSrc;
|
||||||
for(i=0; i<p->nSrc; i++){
|
for(i=0; i<p->nSrc; i++){
|
||||||
|
pNew->a[i].zDatabase = sqliteStrDup(p->a[i].zDatabase);
|
||||||
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
||||||
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
|
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
|
||||||
pNew->a[i].jointype = p->a[i].jointype;
|
pNew->a[i].jointype = p->a[i].jointype;
|
||||||
|
@ -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.131 2003/05/17 17:35:12 drh Exp $
|
** $Id: main.c,v 1.132 2003/05/31 16:21:12 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@ -80,7 +80,6 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
|
|||||||
sParse.db = pData->db;
|
sParse.db = pData->db;
|
||||||
sParse.initFlag = 1;
|
sParse.initFlag = 1;
|
||||||
sParse.iDb = atoi(argv[4]);
|
sParse.iDb = atoi(argv[4]);
|
||||||
sParse.useDb = -1;
|
|
||||||
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);
|
||||||
@ -332,7 +331,6 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
|
|||||||
sParse.xCallback = sqliteInitCallback;
|
sParse.xCallback = sqliteInitCallback;
|
||||||
sParse.pArg = (void*)&initData;
|
sParse.pArg = (void*)&initData;
|
||||||
sParse.initFlag = 1;
|
sParse.initFlag = 1;
|
||||||
sParse.useDb = -1;
|
|
||||||
sParse.useCallback = 1;
|
sParse.useCallback = 1;
|
||||||
if( iDb==0 ){
|
if( iDb==0 ){
|
||||||
sqliteRunParser(&sParse,
|
sqliteRunParser(&sParse,
|
||||||
@ -623,7 +621,6 @@ static int sqliteMain(
|
|||||||
sParse.db = db;
|
sParse.db = db;
|
||||||
sParse.xCallback = xCallback;
|
sParse.xCallback = xCallback;
|
||||||
sParse.pArg = pArg;
|
sParse.pArg = pArg;
|
||||||
sParse.useDb = -1;
|
|
||||||
sParse.useCallback = ppVm==0;
|
sParse.useCallback = ppVm==0;
|
||||||
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
|
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
|
||||||
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
sqliteRunParser(&sParse, zSql, pzErrMsg);
|
||||||
|
@ -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.139 2003/05/17 17:35:12 drh Exp $
|
** $Id: select.c,v 1.140 2003/05/31 16:21:13 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -1657,6 +1657,7 @@ static int flattenSubquery(
|
|||||||
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
|
if( pSrc->a[iFrom].pTab && pSrc->a[iFrom].pTab->isTransient ){
|
||||||
sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
|
sqliteDeleteTable(0, pSrc->a[iFrom].pTab);
|
||||||
}
|
}
|
||||||
|
sqliteFree(pSrc->a[iFrom].zDatabase);
|
||||||
sqliteFree(pSrc->a[iFrom].zName);
|
sqliteFree(pSrc->a[iFrom].zName);
|
||||||
sqliteFree(pSrc->a[iFrom].zAlias);
|
sqliteFree(pSrc->a[iFrom].zAlias);
|
||||||
if( nSubSrc>1 ){
|
if( nSubSrc>1 ){
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.188 2003/05/29 17:50:55 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.189 2003/05/31 16:21:13 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
@ -857,7 +857,6 @@ struct Parse {
|
|||||||
** while generating expressions. Normally false */
|
** while generating expressions. Normally false */
|
||||||
u8 iDb; /* Index of database whose schema is being parsed */
|
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 useDb; /* Restrict references to tables in this database */
|
|
||||||
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 */
|
||||||
int nTab; /* Number of previously allocated VDBE cursors */
|
int nTab; /* Number of previously allocated VDBE cursors */
|
||||||
@ -905,6 +904,7 @@ struct Trigger {
|
|||||||
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
|
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
|
||||||
the <column-list> is stored here */
|
the <column-list> is stored here */
|
||||||
int foreach; /* One of TK_ROW or TK_STATEMENT */
|
int foreach; /* One of TK_ROW or TK_STATEMENT */
|
||||||
|
Token *pNameToken; /* Token containing zName. Use during parsing only */
|
||||||
|
|
||||||
TriggerStep *step_list; /* Link list of trigger program steps */
|
TriggerStep *step_list; /* Link list of trigger program steps */
|
||||||
Trigger *pNext; /* Next trigger associated with the table */
|
Trigger *pNext; /* Next trigger associated with the table */
|
||||||
@ -1001,6 +1001,19 @@ struct TriggerStack {
|
|||||||
TriggerStack *pNext; /* Next trigger down on the trigger stack */
|
TriggerStack *pNext; /* Next trigger down on the trigger stack */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following structure contains information used by the sqliteFix...
|
||||||
|
** routines as they walk the parse tree to make database references
|
||||||
|
** explicit.
|
||||||
|
*/
|
||||||
|
typedef struct DbFixer DbFixer;
|
||||||
|
struct DbFixer {
|
||||||
|
Parse *pParse; /* The parsing context. Error messages written here */
|
||||||
|
const char *zDb; /* Make sure all objects are contained in this database */
|
||||||
|
const char *zType; /* Type of the container - used for error messages */
|
||||||
|
const Token *pName; /* Name of the container - used for error messages */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This global flag is set for performance testing of triggers. When it is set
|
* This global flag is set for performance testing of triggers. When it is set
|
||||||
* SQLite will perform the overhead of building new and old trigger references
|
* SQLite will perform the overhead of building new and old trigger references
|
||||||
@ -1171,3 +1184,9 @@ void sqliteAttach(Parse*, Token*, Token*);
|
|||||||
void sqliteDetach(Parse*, Token*);
|
void sqliteDetach(Parse*, Token*);
|
||||||
int sqliteBtreeFactory(const sqlite *db, const char *zFilename,
|
int sqliteBtreeFactory(const sqlite *db, const char *zFilename,
|
||||||
int mode, int nPg, Btree **ppBtree);
|
int mode, int nPg, Btree **ppBtree);
|
||||||
|
int sqliteFixInit(DbFixer*, Parse*, int, const char*, const Token*);
|
||||||
|
int sqliteFixSrcList(DbFixer*, SrcList*);
|
||||||
|
int sqliteFixSelect(DbFixer*, Select*);
|
||||||
|
int sqliteFixExpr(DbFixer*, Expr*);
|
||||||
|
int sqliteFixExprList(DbFixer*, ExprList*);
|
||||||
|
int sqliteFixTriggerStep(DbFixer*, TriggerStep*);
|
||||||
|
@ -64,7 +64,12 @@ void sqliteBeginTrigger(
|
|||||||
*/
|
*/
|
||||||
if( sqlite_malloc_failed ) goto trigger_cleanup;
|
if( sqlite_malloc_failed ) goto trigger_cleanup;
|
||||||
assert( pTableName->nSrc==1 );
|
assert( pTableName->nSrc==1 );
|
||||||
|
assert( pTableName->a[0].zDatabase==0 );
|
||||||
|
if( pParse->initFlag ){
|
||||||
|
pTableName->a[0].zDatabase = db->aDb[pParse->iDb].zName;
|
||||||
|
}
|
||||||
tab = sqliteSrcListLookup(pParse, pTableName);
|
tab = sqliteSrcListLookup(pParse, pTableName);
|
||||||
|
pTableName->a[0].zDatabase = 0;
|
||||||
if( !tab ){
|
if( !tab ){
|
||||||
goto trigger_cleanup;
|
goto trigger_cleanup;
|
||||||
}
|
}
|
||||||
@ -133,6 +138,7 @@ void sqliteBeginTrigger(
|
|||||||
nt->pWhen = sqliteExprDup(pWhen);
|
nt->pWhen = sqliteExprDup(pWhen);
|
||||||
nt->pColumns = sqliteIdListDup(pColumns);
|
nt->pColumns = sqliteIdListDup(pColumns);
|
||||||
nt->foreach = foreach;
|
nt->foreach = foreach;
|
||||||
|
nt->pNameToken = pName;
|
||||||
assert( pParse->pNewTrigger==0 );
|
assert( pParse->pNewTrigger==0 );
|
||||||
pParse->pNewTrigger = nt;
|
pParse->pNewTrigger = nt;
|
||||||
|
|
||||||
@ -152,8 +158,9 @@ void sqliteFinishTrigger(
|
|||||||
TriggerStep *pStepList, /* The triggered program */
|
TriggerStep *pStepList, /* The triggered program */
|
||||||
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
Token *pAll /* Token that describes the complete CREATE TRIGGER */
|
||||||
){
|
){
|
||||||
Trigger *nt; /* The trigger whose construction is finishing up */
|
Trigger *nt = 0; /* The trigger whose construction is finishing up */
|
||||||
sqlite *db = pParse->db; /* The database */
|
sqlite *db = pParse->db; /* The database */
|
||||||
|
DbFixer sFix;
|
||||||
|
|
||||||
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
|
if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
|
||||||
nt = pParse->pNewTrigger;
|
nt = pParse->pNewTrigger;
|
||||||
@ -163,6 +170,11 @@ void sqliteFinishTrigger(
|
|||||||
pStepList->pTrig = nt;
|
pStepList->pTrig = nt;
|
||||||
pStepList = pStepList->pNext;
|
pStepList = pStepList->pNext;
|
||||||
}
|
}
|
||||||
|
if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", nt->pNameToken)
|
||||||
|
&& sqliteFixTriggerStep(&sFix, nt->step_list) ){
|
||||||
|
goto triggerfinish_cleanup;
|
||||||
|
}
|
||||||
|
nt->pNameToken = 0;
|
||||||
|
|
||||||
/* if we are not initializing, and this trigger is not on a TEMP table,
|
/* if we are not initializing, and this trigger is not on a TEMP table,
|
||||||
** build the sqlite_master entry
|
** build the sqlite_master entry
|
||||||
@ -201,15 +213,15 @@ void sqliteFinishTrigger(
|
|||||||
Table *pTab;
|
Table *pTab;
|
||||||
sqliteHashInsert(&db->aDb[nt->iDb].trigHash,
|
sqliteHashInsert(&db->aDb[nt->iDb].trigHash,
|
||||||
nt->name, strlen(nt->name)+1, nt);
|
nt->name, strlen(nt->name)+1, nt);
|
||||||
pTab = sqliteLocateTable(pParse, nt->table, 0);
|
pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
|
||||||
assert( pTab!=0 );
|
assert( pTab!=0 );
|
||||||
nt->pNext = pTab->pTrigger;
|
nt->pNext = pTab->pTrigger;
|
||||||
pTab->pTrigger = nt;
|
pTab->pTrigger = nt;
|
||||||
}else{
|
nt = 0;
|
||||||
sqliteDeleteTrigger(nt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerfinish_cleanup:
|
triggerfinish_cleanup:
|
||||||
|
sqliteDeleteTrigger(nt);
|
||||||
sqliteDeleteTrigger(pParse->pNewTrigger);
|
sqliteDeleteTrigger(pParse->pNewTrigger);
|
||||||
pParse->pNewTrigger = 0;
|
pParse->pNewTrigger = 0;
|
||||||
sqliteDeleteTriggerStep(pStepList);
|
sqliteDeleteTriggerStep(pStepList);
|
||||||
@ -547,6 +559,36 @@ int sqliteTriggersExist(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert the pStep->target token into a SrcList and return a pointer
|
||||||
|
** to that SrcList.
|
||||||
|
**
|
||||||
|
** This routine adds a specific database name, if needed, to the target when
|
||||||
|
** forming the SrcList. This prevents a trigger in one database from
|
||||||
|
** referring to a target in another database. An exception is when the
|
||||||
|
** trigger is in TEMP in which case it can refer to any other database it
|
||||||
|
** wants.
|
||||||
|
*/
|
||||||
|
static SrcList *targetSrcList(
|
||||||
|
Parse *pParse, /* The parsing context */
|
||||||
|
TriggerStep *pStep /* The trigger containing the target token */
|
||||||
|
){
|
||||||
|
Token sDb; /* Dummy database name token */
|
||||||
|
int iDb; /* Index of the database to use */
|
||||||
|
SrcList *pSrc; /* SrcList to be returned */
|
||||||
|
|
||||||
|
iDb = pStep->pTrig->iDb;
|
||||||
|
if( iDb==0 || iDb>=2 ){
|
||||||
|
assert( iDb<pParse->db->nDb );
|
||||||
|
sDb.z = pParse->db->aDb[iDb].zName;
|
||||||
|
sDb.n = strlen(sDb.z);
|
||||||
|
pSrc = sqliteSrcListAppend(0, &sDb, &pStep->target);
|
||||||
|
} else {
|
||||||
|
pSrc = sqliteSrcListAppend(0, &pStep->target, 0);
|
||||||
|
}
|
||||||
|
return pSrc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate VDBE code for zero or more statements inside the body of a
|
** Generate VDBE code for zero or more statements inside the body of a
|
||||||
** trigger.
|
** trigger.
|
||||||
@ -561,11 +603,9 @@ static int codeTriggerProgram(
|
|||||||
|
|
||||||
while( pTriggerStep ){
|
while( pTriggerStep ){
|
||||||
int saveNTab = pParse->nTab;
|
int saveNTab = pParse->nTab;
|
||||||
int saveUseDb = pParse->useDb;
|
|
||||||
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
|
||||||
pParse->trigStack->orconf = orconf;
|
pParse->trigStack->orconf = orconf;
|
||||||
pParse->useDb = pTriggerStep->pTrig->iDb;
|
|
||||||
if( pParse->useDb==1 ) pParse->useDb = -1;
|
|
||||||
switch( pTriggerStep->op ){
|
switch( pTriggerStep->op ){
|
||||||
case TK_SELECT: {
|
case TK_SELECT: {
|
||||||
Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
|
Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
|
||||||
@ -577,7 +617,7 @@ static int codeTriggerProgram(
|
|||||||
}
|
}
|
||||||
case TK_UPDATE: {
|
case TK_UPDATE: {
|
||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
||||||
sqliteUpdate(pParse, pSrc,
|
sqliteUpdate(pParse, pSrc,
|
||||||
sqliteExprListDup(pTriggerStep->pExprList),
|
sqliteExprListDup(pTriggerStep->pExprList),
|
||||||
@ -587,7 +627,7 @@ static int codeTriggerProgram(
|
|||||||
}
|
}
|
||||||
case TK_INSERT: {
|
case TK_INSERT: {
|
||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqliteInsert(pParse, pSrc,
|
sqliteInsert(pParse, pSrc,
|
||||||
sqliteExprListDup(pTriggerStep->pExprList),
|
sqliteExprListDup(pTriggerStep->pExprList),
|
||||||
sqliteSelectDup(pTriggerStep->pSelect),
|
sqliteSelectDup(pTriggerStep->pSelect),
|
||||||
@ -597,7 +637,7 @@ static int codeTriggerProgram(
|
|||||||
case TK_DELETE: {
|
case TK_DELETE: {
|
||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
|
||||||
pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
|
pSrc = targetSrcList(pParse, pTriggerStep);
|
||||||
sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
|
sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
|
||||||
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
|
sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
|
||||||
break;
|
break;
|
||||||
@ -606,7 +646,6 @@ static int codeTriggerProgram(
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
pParse->nTab = saveNTab;
|
pParse->nTab = saveNTab;
|
||||||
pParse->useDb = saveUseDb;
|
|
||||||
pTriggerStep = pTriggerStep->pNext;
|
pTriggerStep = pTriggerStep->pNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
test/attach.test
103
test/attach.test
@ -12,7 +12,7 @@
|
|||||||
# focus of this script is testing the ATTACH and DETACH commands
|
# focus of this script is testing the ATTACH and DETACH commands
|
||||||
# and related functionality.
|
# and related functionality.
|
||||||
#
|
#
|
||||||
# $Id: attach.test,v 1.5 2003/05/17 19:23:52 drh Exp $
|
# $Id: attach.test,v 1.6 2003/05/31 16:21:13 drh Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
@ -369,6 +369,107 @@ do_test attach-3.14 {
|
|||||||
execsql {SELECT * FROM t1}
|
execsql {SELECT * FROM t1}
|
||||||
} {1 2 3 4}
|
} {1 2 3 4}
|
||||||
|
|
||||||
|
# Ticket #323
|
||||||
|
do_test attach-4.1 {
|
||||||
|
execsql {DETACH db2}
|
||||||
|
db2 close
|
||||||
|
sqlite db2 test2.db
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t3(x,y);
|
||||||
|
CREATE UNIQUE INDEX t3i1 ON t3(x);
|
||||||
|
INSERT INTO t3 VALUES(1,2);
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2;
|
||||||
|
} {1 2}
|
||||||
|
do_test attach-4.2 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t3(a,b);
|
||||||
|
CREATE UNIQUE INDEX t3i1b ON t3(a);
|
||||||
|
INSERT INTO t3 VALUES(9,10);
|
||||||
|
SELECT * FROM t3;
|
||||||
|
}
|
||||||
|
} {9 10}
|
||||||
|
do_test attach-4.3 {
|
||||||
|
execsql {
|
||||||
|
ATTACH DATABASE 'test2.db' AS db2;
|
||||||
|
SELECT * FROM db2.t3;
|
||||||
|
}
|
||||||
|
} {1 2}
|
||||||
|
do_test attach-4.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM main.t3;
|
||||||
|
}
|
||||||
|
} {9 10}
|
||||||
|
do_test attach-4.5 {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO db2.t3 VALUES(9,10);
|
||||||
|
SELECT * FROM db2.t3;
|
||||||
|
}
|
||||||
|
} {1 2 9 10}
|
||||||
|
do_test attach-4.6 {
|
||||||
|
execsql {
|
||||||
|
DETACH db2;
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t4(x);
|
||||||
|
CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN
|
||||||
|
INSERT INTO t4 VALUES('db2.' || NEW.x);
|
||||||
|
END;
|
||||||
|
INSERT INTO t3 VALUES(6,7);
|
||||||
|
SELECT * FROM t4;
|
||||||
|
} db2
|
||||||
|
} {db2.6}
|
||||||
|
do_test attach-4.7 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE t4(y);
|
||||||
|
CREATE TRIGGER t3r3 AFTER INSERT ON t3 BEGIN
|
||||||
|
INSERT INTO t4 VALUES('main.' || NEW.a);
|
||||||
|
END;
|
||||||
|
INSERT INTO main.t3 VALUES(11,12);
|
||||||
|
SELECT * FROM main.t4;
|
||||||
|
}
|
||||||
|
} {main.11}
|
||||||
|
do_test attach-4.8 {
|
||||||
|
execsql {
|
||||||
|
ATTACH DATABASE 'test2.db' AS db2;
|
||||||
|
INSERT INTO db2.t3 VALUES(13,14);
|
||||||
|
SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
|
||||||
|
}
|
||||||
|
} {db2.6 db2.13 main.11}
|
||||||
|
do_test attach-4.9 {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO main.t3 VALUES(15,16);
|
||||||
|
SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
|
||||||
|
}
|
||||||
|
} {db2.6 db2.13 main.11 main.15}
|
||||||
|
do_test attach-4.10 {
|
||||||
|
execsql {
|
||||||
|
DETACH DATABASE db2;
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
|
CREATE VIEW v3 AS SELECT x*100+y FROM t3;
|
||||||
|
SELECT * FROM v3;
|
||||||
|
} db2
|
||||||
|
} {102 910 607 1314}
|
||||||
|
do_test attach-4.11 {
|
||||||
|
execsql {
|
||||||
|
CREATE VIEW v3 AS SELECT a*100+b FROM t3;
|
||||||
|
SELECT * FROM v3;
|
||||||
|
}
|
||||||
|
} {910 1112 1516}
|
||||||
|
do_test attach-4.12 {
|
||||||
|
execsql {
|
||||||
|
ATTACH DATABASE 'test2.db' AS db2;
|
||||||
|
SELECT * FROM db2.v3;
|
||||||
|
}
|
||||||
|
} {102 910 607 1314}
|
||||||
|
do_test attach-4.13 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM main.v3;
|
||||||
|
}
|
||||||
|
} {910 1112 1516}
|
||||||
|
|
||||||
|
|
||||||
for {set i 2} {$i<=15} {incr i} {
|
for {set i 2} {$i<=15} {incr i} {
|
||||||
catch {db$i close}
|
catch {db$i close}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ do_test trigger-3.2 {
|
|||||||
INSERT INTO t1 VALUES(1,2);
|
INSERT INTO t1 VALUES(1,2);
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
}
|
}
|
||||||
} {1 {table "t2" is not in database "main"}}
|
} {1 {no such table: main.t2}}
|
||||||
do_test trigger-3.3 {
|
do_test trigger-3.3 {
|
||||||
db close
|
db close
|
||||||
set rc [catch {sqlite db test.db} err]
|
set rc [catch {sqlite db test.db} err]
|
||||||
@ -234,14 +234,14 @@ do_test trigger-3.4 {
|
|||||||
INSERT INTO t1 VALUES(1,2);
|
INSERT INTO t1 VALUES(1,2);
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
}
|
}
|
||||||
} {1 {no such table: t2}}
|
} {1 {no such table: main.t2}}
|
||||||
do_test trigger-3.5 {
|
do_test trigger-3.5 {
|
||||||
catchsql {
|
catchsql {
|
||||||
CREATE TEMP TABLE t2(x,y);
|
CREATE TEMP TABLE t2(x,y);
|
||||||
INSERT INTO t1 VALUES(1,2);
|
INSERT INTO t1 VALUES(1,2);
|
||||||
SELECT * FROM t2;
|
SELECT * FROM t2;
|
||||||
}
|
}
|
||||||
} {1 {table "t2" is not in database "main"}}
|
} {1 {no such table: main.t2}}
|
||||||
do_test trigger-3.6 {
|
do_test trigger-3.6 {
|
||||||
catchsql {
|
catchsql {
|
||||||
DROP TRIGGER r1;
|
DROP TRIGGER r1;
|
||||||
|
@ -83,19 +83,19 @@ do_test trigger4-3.1 {
|
|||||||
drop table test2;
|
drop table test2;
|
||||||
insert into test values(7,8,9);
|
insert into test values(7,8,9);
|
||||||
}
|
}
|
||||||
} {1 {no such table: test2}}
|
} {1 {no such table: main.test2}}
|
||||||
do_test trigger4-3.2 {
|
do_test trigger4-3.2 {
|
||||||
db close
|
db close
|
||||||
sqlite db test.db
|
sqlite db test.db
|
||||||
catchsql {
|
catchsql {
|
||||||
insert into test values(7,8,9);
|
insert into test values(7,8,9);
|
||||||
}
|
}
|
||||||
} {1 {no such table: test2}}
|
} {1 {no such table: main.test2}}
|
||||||
do_test trigger4-3.3 {
|
do_test trigger4-3.3 {
|
||||||
catchsql {
|
catchsql {
|
||||||
update test set a=222 where id=1;
|
update test set a=222 where id=1;
|
||||||
}
|
}
|
||||||
} {1 {no such table: test2}}
|
} {1 {no such table: main.test2}}
|
||||||
do_test trigger4-3.4 {
|
do_test trigger4-3.4 {
|
||||||
execsql {
|
execsql {
|
||||||
select * from test1;
|
select * from test1;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing VIEW statements.
|
# focus of this file is testing VIEW statements.
|
||||||
#
|
#
|
||||||
# $Id: view.test,v 1.15 2003/05/02 16:04:17 drh Exp $
|
# $Id: view.test,v 1.16 2003/05/31 16:21:13 drh Exp $
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ do_test view-1.6 {
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SELECT * FROM v1 ORDER BY a;
|
SELECT * FROM v1 ORDER BY a;
|
||||||
}
|
}
|
||||||
} {1 {no such table: t1}}
|
} {1 {no such table: main.t1}}
|
||||||
do_test view-1.7 {
|
do_test view-1.7 {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE t1(x,a,b,c);
|
CREATE TABLE t1(x,a,b,c);
|
||||||
|
Reference in New Issue
Block a user