mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
Experimental change to allow triggers in the temp schema to use fully qualified table names in INSERT/UPDATE/DELETE statements.
FossilOrigin-Name: 48e168007ceb1bdc54cf21a8e959a8e0f9ccdc478827db7a7a0518fc7a226401
This commit is contained in:
33
manifest
33
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\slogic\serror\sintroduced\sby\s[cea8bf79e18d55a8]\swhich\scaused\n"0\sOR\s2"\sto\sbe\sevaluated\sas\s"2"\sinstead\sof\sas\s"1".\s\sProblem\sreported\sat\n[forum:/forumpost/d5f32040c5d50d2d|forum\spost\sd5f32040c].
|
||||
D 2025-10-29T20:47:01.603
|
||||
C Experimental\schange\sto\sallow\striggers\sin\sthe\stemp\sschema\sto\suse\sfully\squalified\stable\snames\sin\sINSERT/UPDATE/DELETE\sstatements.
|
||||
D 2025-10-29T20:57:44.300
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -668,9 +668,9 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
|
||||
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
|
||||
F src/alter.c fc7bbbeb9e89c7124bf5772ce474b333b7bdc18d6e080763211a40fde69fb1da
|
||||
F src/alter.c a02edd673c242698f42eecf150a0c6eef11d1cc8ebf555d5c0e9f2847c0e9e9d
|
||||
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
|
||||
F src/attach.c 9af61b63b10ee702b1594ecd24fb8cea0839cfdb6addee52fba26fa879f5db9d
|
||||
F src/attach.c 7cf07d4fa42b9fc8662237c60c40b730326c30aa90ae5fffc0b18b2d726ebf61
|
||||
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
|
||||
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
|
||||
F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
|
||||
@@ -688,7 +688,7 @@ F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
|
||||
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
|
||||
F src/expr.c 17b0cbe08e004c1653030f5de9b6b050e84feaa112239f7f576af2dc5e53a5fb
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 928ed2517e8732113d2b9821aa37af639688d752f4ea9ac6e0e393d713eeb76f
|
||||
F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531
|
||||
F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
|
||||
F src/global.c a19e4b1ca1335f560e9560e590fc13081e21f670643367f99cb9e8f9dc7d615b
|
||||
F src/hash.c 73934a7f7ab1cb110614a9388cb516893b0cf5b7b69e4fd1a0780ac4ce166be7
|
||||
@@ -725,7 +725,7 @@ F src/os_win.c 27617f334168644b542c9d58ac6e5f051b318136273e78d243384b4eca2df6b3
|
||||
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
|
||||
F src/pager.c 113f9149092ccff6cf90e97c2611200e5a237f13d26c394bc9fd933377852764
|
||||
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
|
||||
F src/parse.y 619c3e92a54686c5e47923688c4b9bf7ec534a4690db5677acc28b299c403250
|
||||
F src/parse.y 5ba60bd246219225ccb32c15bf692124327810f00128dd779155185848369865
|
||||
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
|
||||
@@ -740,7 +740,7 @@ F src/shell.c.in ce9953719b1e544e71cc47f3b9b699440e4f441418506c0913484c58a27b36b
|
||||
F src/sqlite.h.in f7944026ee89ea348f89aec56372d6d25b6cafc1d89df741278d6917e86326a3
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 7f236ca1b175ffe03316d974ef57df79b3938466c28d2f95caef5e08c57f3a52
|
||||
F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59aa
|
||||
F src/sqliteInt.h 89e84b1a2e9de855282f2d7fc415105edc284529bad6bbe54018eef0c4e15456
|
||||
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
|
||||
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -796,7 +796,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c cb3294cf23c11106b50d9af6998a6c1bf389b52e15b17698c9fab97bbaa9b37f
|
||||
F src/treeview.c 3ce7ac9835d2d70cc1c868b01b747ae8a062322e155701e58e3d62ca79aada7a
|
||||
F src/trigger.c d5cf2541ff048f30b6a0507eb3d1ec4e695c53584e3b2298a5bf248714fe185e
|
||||
F src/trigger.c 4328fb185c81889299f41734b64ba59f25b571effa0d2f6ea284c611dca685bc
|
||||
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
|
||||
F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1
|
||||
F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
|
||||
@@ -850,7 +850,7 @@ F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834
|
||||
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
|
||||
F test/altertab2.test 0889ba0700cc1cdb7bc7d25975aa61fece34f621de963d0886e2395716b38576
|
||||
F test/altertab3.test 471b8898d10bbc6488db9c23dc76811f405de6707d2d342b1b8b6fd1f13cd3c8
|
||||
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
|
||||
F test/altertrig.test b1590647076add5a47aea0f2236c609ca0bc8a7a2462463edd3e5882c7894802
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
|
||||
F test/analyze3.test c5156cef33f04b90a6b9e9d5d0bbc273a0fb44147d4508407bf1080811e2c6c8
|
||||
@@ -1072,7 +1072,7 @@ F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||
F test/e_select.test 327a15f14068bbd6f647cedc67210f8680fcb2f05e481a0a855fccd2abfa1292
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
F test/e_update.test 9f8bb82b8760ac66f2c9c2aadb78a418bd639d22f041d712570c9db56f20afda
|
||||
F test/e_uri.test 86564382132d9c453845eeb5293c7e375487b625900ab56c181a0464908417d8
|
||||
F test/e_vacuum.test 89fc48e8beee2f9dfd6de1fbb2edea6542dae9121dc0fbe6313764169e742104
|
||||
F test/e_wal.test db7c33642711cf3c7959714b5f012aca08cacfa78da0382f95e849eb3ba66aa4
|
||||
@@ -1690,7 +1690,7 @@ F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d1631311a16
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/temptrigger.test 62c0d29ff3fb7fa40c136dcfac3d992c5a6d3b1699459e65a4c1d0feb1258120
|
||||
F test/tester.tcl 463ae33b8bf75ac77451df19bd65e7c415c2e9891227c7c9e657d0a2d8e1074a
|
||||
F test/testloadext.c 862b848783eaed9985fbce46c65cd214664376b549fae252b364d5d1ef350a27
|
||||
F test/testrunner.tcl 9da764507f6bc752961555c0beb58eb6584b9fb0f989342c7eaab3336380f560 x
|
||||
@@ -2171,8 +2171,11 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P e2c20aa5929e5b79aabca8a51fb3e32e0533526d64d7576d3caf1c847fff58b4
|
||||
R 1a124afdb2635430b3fd6e2b8b70ff33
|
||||
U drh
|
||||
Z 0a36ac0dd51fe98fcc08d99ab2c27dbd
|
||||
P 095cc4f22e63c98cbb2acabdbcaf02e59e67ec6d3cc219b5f42a714e3d53a264
|
||||
R 85cd0d1d042f2b81ef8d0010c49c6487
|
||||
T *branch * temp-trigger-refs
|
||||
T *sym-temp-trigger-refs *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 89ba63f7a028e73214265366183a56b0
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
branch trunk
|
||||
tag trunk
|
||||
branch temp-trigger-refs
|
||||
tag temp-trigger-refs
|
||||
|
||||
@@ -1 +1 @@
|
||||
095cc4f22e63c98cbb2acabdbcaf02e59e67ec6d3cc219b5f42a714e3d53a264
|
||||
48e168007ceb1bdc54cf21a8e959a8e0f9ccdc478827db7a7a0518fc7a226401
|
||||
|
||||
36
src/alter.c
36
src/alter.c
@@ -1346,8 +1346,8 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
|
||||
if( pParse->nErr ) rc = pParse->rc;
|
||||
}
|
||||
if( rc==SQLITE_OK && pStep->zTarget ){
|
||||
SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
|
||||
if( rc==SQLITE_OK && pStep->pSrc ){
|
||||
SrcList *pSrc = sqlite3SrcListDup(db, pStep->pSrc, 0);
|
||||
if( pSrc ){
|
||||
Select *pSel = sqlite3SelectNew(
|
||||
pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0
|
||||
@@ -1375,10 +1375,10 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
pSel->pSrc = 0;
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
if( pStep->pSrc ){
|
||||
int i;
|
||||
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
|
||||
SrcItem *p = &pStep->pFrom->a[i];
|
||||
for(i=0; i<pStep->pSrc->nSrc && rc==SQLITE_OK; i++){
|
||||
SrcItem *p = &pStep->pSrc->a[i];
|
||||
if( p->fg.isSubquery ){
|
||||
assert( p->u4.pSubq!=0 );
|
||||
sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
|
||||
@@ -1447,13 +1447,13 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
|
||||
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
|
||||
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
if( pStep->pSrc ){
|
||||
int i;
|
||||
SrcList *pFrom = pStep->pFrom;
|
||||
for(i=0; i<pFrom->nSrc; i++){
|
||||
if( pFrom->a[i].fg.isSubquery ){
|
||||
assert( pFrom->a[i].u4.pSubq!=0 );
|
||||
sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
|
||||
SrcList *pSrc = pStep->pSrc;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
if( pSrc->a[i].fg.isSubquery ){
|
||||
assert( pSrc->a[i].u4.pSubq!=0 );
|
||||
sqlite3WalkSelect(pWalker, pSrc->a[i].u4.pSubq->pSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1624,8 +1624,8 @@ static void renameColumnFunc(
|
||||
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
||||
|
||||
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget ){
|
||||
Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
|
||||
if( pStep->pSrc ){
|
||||
Table *pTarget = sqlite3LocateTableItem(&sParse, 0, &pStep->pSrc->a[0]);
|
||||
if( pTarget==pTab ){
|
||||
if( pStep->pUpsert ){
|
||||
ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet;
|
||||
@@ -1637,7 +1637,6 @@ static void renameColumnFunc(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Find tokens to edit in UPDATE OF clause */
|
||||
if( sParse.pTriggerTab==pTab ){
|
||||
renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);
|
||||
@@ -1839,13 +1838,10 @@ static void renameTableFunc(
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
if( pStep->pSrc ){
|
||||
int i;
|
||||
for(i=0; i<pStep->pFrom->nSrc; i++){
|
||||
SrcItem *pItem = &pStep->pFrom->a[i];
|
||||
for(i=0; i<pStep->pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &pStep->pSrc->a[i];
|
||||
if( 0==sqlite3_stricmp(pItem->zName, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pItem->zName);
|
||||
}
|
||||
|
||||
@@ -596,7 +596,7 @@ int sqlite3FixTriggerStep(
|
||||
if( sqlite3WalkSelect(&pFix->w, pStep->pSelect)
|
||||
|| sqlite3WalkExpr(&pFix->w, pStep->pWhere)
|
||||
|| sqlite3WalkExprList(&pFix->w, pStep->pExprList)
|
||||
|| sqlite3FixSrcList(pFix, pStep->pFrom)
|
||||
|| sqlite3FixSrcList(pFix, pStep->pSrc)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
|
||||
11
src/fkey.c
11
src/fkey.c
@@ -688,6 +688,7 @@ FKey *sqlite3FkReferences(Table *pTab){
|
||||
static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
||||
if( p ){
|
||||
TriggerStep *pStep = p->step_list;
|
||||
sqlite3SrcListDelete(dbMem, pStep->pSrc);
|
||||
sqlite3ExprDelete(dbMem, pStep->pWhere);
|
||||
sqlite3ExprListDelete(dbMem, pStep->pExprList);
|
||||
sqlite3SelectDelete(dbMem, pStep->pSelect);
|
||||
@@ -1354,14 +1355,14 @@ static Trigger *fkActionTrigger(
|
||||
|
||||
pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
||||
sizeof(Trigger) + /* struct Trigger */
|
||||
sizeof(TriggerStep) + /* Single step in trigger program */
|
||||
nFrom + 1 /* Space for pStep->zTarget */
|
||||
sizeof(TriggerStep) /* Single step in trigger program */
|
||||
);
|
||||
if( pTrigger ){
|
||||
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
||||
pStep->zTarget = (char *)&pStep[1];
|
||||
memcpy((char *)pStep->zTarget, zFrom, nFrom);
|
||||
|
||||
pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pStep->pSrc ){
|
||||
pStep->pSrc->a[0].zName = sqlite3DbStrNDup(db, zFrom, nFrom);
|
||||
}
|
||||
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
||||
pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
||||
|
||||
42
src/parse.y
42
src/parse.y
@@ -816,17 +816,10 @@ fullname(A) ::= nm(X) DOT nm(Y). {
|
||||
|
||||
%type xfullname {SrcList*}
|
||||
%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);}
|
||||
xfullname(A) ::= nm(X).
|
||||
{A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/}
|
||||
xfullname(A) ::= nm(X) DOT nm(Y).
|
||||
{A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/}
|
||||
xfullname(A) ::= nm(X) DOT nm(Y) AS nm(Z). {
|
||||
A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/
|
||||
if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z);
|
||||
}
|
||||
xfullname(A) ::= nm(X) AS nm(Z). {
|
||||
A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/
|
||||
if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z);
|
||||
xfullname(A) ::= fullname(X). { A=X; }
|
||||
xfullname(A) ::= fullname(X) AS nm(Z). {
|
||||
X->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z);
|
||||
A = X;
|
||||
}
|
||||
|
||||
%type joinop {int}
|
||||
@@ -1707,28 +1700,13 @@ when_clause(A) ::= WHEN expr(X). { A = X; }
|
||||
%type trigger_cmd_list {TriggerStep*}
|
||||
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
|
||||
trigger_cmd_list(A) ::= trigger_cmd_list(A) trigger_cmd(X) SEMI. {
|
||||
assert( A!=0 );
|
||||
A->pLast->pNext = X;
|
||||
A->pLast = X;
|
||||
}
|
||||
trigger_cmd_list(A) ::= trigger_cmd(A) SEMI. {
|
||||
assert( A!=0 );
|
||||
A->pLast = A;
|
||||
}
|
||||
|
||||
// Disallow qualified table names on INSERT, UPDATE, and DELETE statements
|
||||
// within a trigger. The table to INSERT, UPDATE, or DELETE is always in
|
||||
// the same database as the table that the trigger fires on.
|
||||
//
|
||||
%type trnm {Token}
|
||||
trnm(A) ::= nm(A).
|
||||
trnm(A) ::= nm DOT nm(X). {
|
||||
A = X;
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
|
||||
"statements within triggers");
|
||||
}
|
||||
|
||||
// Disallow the INDEX BY and NOT INDEXED clauses on UPDATE and DELETE
|
||||
// statements within triggers. We make a specific error message for this
|
||||
// since it is an exception to the default grammar rules.
|
||||
@@ -1751,17 +1729,17 @@ tridxby ::= NOT INDEXED. {
|
||||
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
|
||||
// UPDATE
|
||||
trigger_cmd(A) ::=
|
||||
UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E).
|
||||
{A = sqlite3TriggerUpdateStep(pParse, &X, F, Y, Z, R, B.z, E);}
|
||||
UPDATE(B) orconf(R) xfullname(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E).
|
||||
{A = sqlite3TriggerUpdateStep(pParse, X, F, Y, Z, R, B.z, E);}
|
||||
|
||||
// INSERT
|
||||
trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
|
||||
trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). {
|
||||
A = sqlite3TriggerInsertStep(pParse,&X,F,S,R,U,B,Z);/*A-overwrites-R*/
|
||||
xfullname(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). {
|
||||
A = sqlite3TriggerInsertStep(pParse,X,F,S,R,U,B,Z);/*A-overwrites-R*/
|
||||
}
|
||||
// DELETE
|
||||
trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E).
|
||||
{A = sqlite3TriggerDeleteStep(pParse, &X, Y, B.z, E);}
|
||||
trigger_cmd(A) ::= DELETE(B) FROM xfullname(X) tridxby where_opt(Y) scanpt(E).
|
||||
{A = sqlite3TriggerDeleteStep(pParse, X, Y, B.z, E);}
|
||||
|
||||
// SELECT
|
||||
trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E).
|
||||
|
||||
@@ -4152,19 +4152,19 @@ struct Trigger {
|
||||
** orconf -> stores the ON CONFLICT algorithm
|
||||
** pSelect -> The content to be inserted - either a SELECT statement or
|
||||
** a VALUES clause.
|
||||
** zTarget -> Dequoted name of the table to insert into.
|
||||
** pSrc -> Table to insert into.
|
||||
** pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
||||
** statement, then this stores the column-names to be
|
||||
** inserted into.
|
||||
** pUpsert -> The ON CONFLICT clauses for an Upsert
|
||||
**
|
||||
** (op == TK_DELETE)
|
||||
** zTarget -> Dequoted name of the table to delete from.
|
||||
** pSrc -> Table to delete from
|
||||
** pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
||||
** Otherwise NULL.
|
||||
**
|
||||
** (op == TK_UPDATE)
|
||||
** zTarget -> Dequoted name of the table to update.
|
||||
** pSrc -> Table to update, followed by any FROM clause tables.
|
||||
** pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
||||
** Otherwise NULL.
|
||||
** pExprList -> A list of the columns to update and the expressions to update
|
||||
@@ -4184,8 +4184,7 @@ struct TriggerStep {
|
||||
u8 orconf; /* OE_Rollback etc. */
|
||||
Trigger *pTrig; /* The trigger that this step is a part of */
|
||||
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
|
||||
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
||||
SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
|
||||
SrcList *pSrc; /* Table to insert/update/delete */
|
||||
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
||||
ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */
|
||||
IdList *pIdList; /* Column names for INSERT */
|
||||
@@ -5251,17 +5250,16 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
|
||||
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
|
||||
TriggerStep *sqlite3TriggerInsertStep(Parse*,SrcList*, IdList*,
|
||||
Select*,u8,Upsert*,
|
||||
const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*,
|
||||
TriggerStep *sqlite3TriggerUpdateStep(Parse*,SrcList*,SrcList*,ExprList*,
|
||||
Expr*, u8, const char*,const char*);
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
|
||||
TriggerStep *sqlite3TriggerDeleteStep(Parse*,SrcList*, Expr*,
|
||||
const char*,const char*);
|
||||
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
||||
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
|
||||
SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*);
|
||||
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
|
||||
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
|
||||
#else
|
||||
@@ -5275,7 +5273,6 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
||||
# define sqlite3ParseToplevel(p) p
|
||||
# define sqlite3IsToplevel(p) 1
|
||||
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
|
||||
# define sqlite3TriggerStepSrc(A,B) 0
|
||||
#endif
|
||||
|
||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||
|
||||
128
src/trigger.c
128
src/trigger.c
@@ -26,7 +26,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
|
||||
sqlite3SelectDelete(db, pTmp->pSelect);
|
||||
sqlite3IdListDelete(db, pTmp->pIdList);
|
||||
sqlite3UpsertDelete(db, pTmp->pUpsert);
|
||||
sqlite3SrcListDelete(db, pTmp->pFrom);
|
||||
sqlite3SrcListDelete(db, pTmp->pSrc);
|
||||
sqlite3DbFree(db, pTmp->zSpan);
|
||||
|
||||
sqlite3DbFree(db, pTmp);
|
||||
@@ -365,12 +365,12 @@ void sqlite3FinishTrigger(
|
||||
if( sqlite3ReadOnlyShadowTables(db) ){
|
||||
TriggerStep *pStep;
|
||||
for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget!=0
|
||||
&& sqlite3ShadowTableName(db, pStep->zTarget)
|
||||
if( pStep->pSrc!=0
|
||||
&& sqlite3ShadowTableName(db, pStep->pSrc->a[0].zName)
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"trigger \"%s\" may not write to shadow table \"%s\"",
|
||||
pTrig->zName, pStep->zTarget);
|
||||
pTrig->zName, pStep->pSrc->a[0].zName);
|
||||
goto triggerfinish_cleanup;
|
||||
}
|
||||
}
|
||||
@@ -461,26 +461,39 @@ TriggerStep *sqlite3TriggerSelectStep(
|
||||
static TriggerStep *triggerStepAllocate(
|
||||
Parse *pParse, /* Parser context */
|
||||
u8 op, /* Trigger opcode */
|
||||
Token *pName, /* The target name */
|
||||
SrcList *pTabList, /* Target table */
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
){
|
||||
Trigger *pNew = pParse->pNewTrigger;
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
TriggerStep *pTriggerStep = 0;
|
||||
|
||||
if( pParse->nErr ) return 0;
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
|
||||
if( pTriggerStep ){
|
||||
char *z = (char*)&pTriggerStep[1];
|
||||
memcpy(z, pName->z, pName->n);
|
||||
sqlite3Dequote(z);
|
||||
pTriggerStep->zTarget = z;
|
||||
pTriggerStep->op = op;
|
||||
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
|
||||
if( pParse->nErr==0 ){
|
||||
if( pNew
|
||||
&& pNew->pSchema!=db->aDb[1].pSchema
|
||||
&& pTabList->a[0].u4.zDatabase
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
|
||||
"statements within triggers");
|
||||
}else{
|
||||
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
|
||||
if( pTriggerStep ){
|
||||
pTriggerStep->pSrc = sqlite3SrcListDup(db, pTabList, EXPRDUP_REDUCE);
|
||||
pTriggerStep->op = op;
|
||||
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse,
|
||||
pTriggerStep->pSrc->a[0].zName,
|
||||
pTabList->a[0].zName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3SrcListDelete(db, pTabList);
|
||||
return pTriggerStep;
|
||||
}
|
||||
|
||||
@@ -493,7 +506,7 @@ static TriggerStep *triggerStepAllocate(
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerInsertStep(
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table into which we insert */
|
||||
SrcList *pTabList, /* Table to INSERT into */
|
||||
IdList *pColumn, /* List of columns in pTableName to insert into */
|
||||
Select *pSelect, /* A SELECT statement that supplies values */
|
||||
u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
|
||||
@@ -506,7 +519,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
|
||||
assert(pSelect != 0 || db->mallocFailed);
|
||||
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTabList, zStart, zEnd);
|
||||
if( pTriggerStep ){
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pSelect = pSelect;
|
||||
@@ -538,7 +551,7 @@ TriggerStep *sqlite3TriggerInsertStep(
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerUpdateStep(
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* Name of the table to be updated */
|
||||
SrcList *pTabList, /* Name of the table to be updated */
|
||||
SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */
|
||||
ExprList *pEList, /* The SET clause: list of column and new values */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
@@ -549,21 +562,34 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTabList, zStart, zEnd);
|
||||
if( pTriggerStep ){
|
||||
SrcList *pFromDup = 0;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pExprList = pEList;
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
pTriggerStep->pFrom = pFrom;
|
||||
pFromDup = pFrom;
|
||||
pEList = 0;
|
||||
pWhere = 0;
|
||||
pFrom = 0;
|
||||
}else{
|
||||
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
||||
pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
|
||||
pFromDup = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
|
||||
}
|
||||
pTriggerStep->orconf = orconf;
|
||||
|
||||
if( pFromDup && !IN_RENAME_OBJECT){
|
||||
Select *pSub;
|
||||
Token as = {0, 0};
|
||||
pSub = sqlite3SelectNew(pParse, 0, pFromDup, 0,0,0,0, SF_NestedFrom, 0);
|
||||
pFromDup = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &as, pSub ,0);
|
||||
}
|
||||
if( pFromDup ){
|
||||
pTriggerStep->pSrc = sqlite3SrcListAppendList(
|
||||
pParse, pTriggerStep->pSrc, pFromDup
|
||||
);
|
||||
}
|
||||
}
|
||||
sqlite3ExprListDelete(db, pEList);
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
@@ -578,7 +604,7 @@ TriggerStep *sqlite3TriggerUpdateStep(
|
||||
*/
|
||||
TriggerStep *sqlite3TriggerDeleteStep(
|
||||
Parse *pParse, /* Parser */
|
||||
Token *pTableName, /* The table from which rows are deleted */
|
||||
SrcList *pTabList, /* The table from which rows are deleted */
|
||||
Expr *pWhere, /* The WHERE clause */
|
||||
const char *zStart, /* Start of SQL text */
|
||||
const char *zEnd /* End of SQL text */
|
||||
@@ -586,7 +612,7 @@ TriggerStep *sqlite3TriggerDeleteStep(
|
||||
sqlite3 *db = pParse->db;
|
||||
TriggerStep *pTriggerStep;
|
||||
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
|
||||
pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTabList, zStart, zEnd);
|
||||
if( pTriggerStep ){
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pTriggerStep->pWhere = pWhere;
|
||||
@@ -848,52 +874,6 @@ Trigger *sqlite3TriggersExist(
|
||||
return triggersReallyExist(pParse,pTab,op,pChanges,pMask);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert the pStep->zTarget string 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.
|
||||
*/
|
||||
SrcList *sqlite3TriggerStepSrc(
|
||||
Parse *pParse, /* The parsing context */
|
||||
TriggerStep *pStep /* The trigger containing the target token */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
SrcList *pSrc; /* SrcList to be returned */
|
||||
char *zName = sqlite3DbStrDup(db, pStep->zTarget);
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
assert( pSrc==0 || pSrc->nSrc==1 );
|
||||
assert( zName || pSrc==0 );
|
||||
if( pSrc ){
|
||||
Schema *pSchema = pStep->pTrig->pSchema;
|
||||
pSrc->a[0].zName = zName;
|
||||
if( pSchema!=db->aDb[1].pSchema ){
|
||||
assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
|
||||
pSrc->a[0].u4.pSchema = pSchema;
|
||||
pSrc->a[0].fg.fixedSchema = 1;
|
||||
}
|
||||
if( pStep->pFrom ){
|
||||
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
|
||||
if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
|
||||
Select *pSubquery;
|
||||
Token as;
|
||||
pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0);
|
||||
as.n = 0;
|
||||
as.z = 0;
|
||||
pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
|
||||
}
|
||||
pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, zName);
|
||||
}
|
||||
return pSrc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the pExpr term from the RETURNING clause argument
|
||||
** list is of the form "*". Raise an error if the terms if of the
|
||||
@@ -1159,7 +1139,7 @@ static int codeTriggerProgram(
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
sqlite3Update(pParse,
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3SrcListDup(db, pStep->pSrc, 0),
|
||||
sqlite3ExprListDup(db, pStep->pExprList, 0),
|
||||
sqlite3ExprDup(db, pStep->pWhere, 0),
|
||||
pParse->eOrconf, 0, 0, 0
|
||||
@@ -1169,7 +1149,7 @@ static int codeTriggerProgram(
|
||||
}
|
||||
case TK_INSERT: {
|
||||
sqlite3Insert(pParse,
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3SrcListDup(db, pStep->pSrc, 0),
|
||||
sqlite3SelectDup(db, pStep->pSelect, 0),
|
||||
sqlite3IdListDup(db, pStep->pIdList),
|
||||
pParse->eOrconf,
|
||||
@@ -1180,7 +1160,7 @@ static int codeTriggerProgram(
|
||||
}
|
||||
case TK_DELETE: {
|
||||
sqlite3DeleteFrom(pParse,
|
||||
sqlite3TriggerStepSrc(pParse, pStep),
|
||||
sqlite3SrcListDup(db, pStep->pSrc, 0),
|
||||
sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
|
||||
);
|
||||
sqlite3VdbeAddOp0(v, OP_ResetCount);
|
||||
|
||||
@@ -41,7 +41,7 @@ do_execsql_test 1.0 {
|
||||
CREATE TABLE t4(a);
|
||||
|
||||
CREATE TRIGGER r1 INSERT ON t1 BEGIN
|
||||
UPDATE t1 SET d='xyz' FROM t2, t3;
|
||||
UPDATE t1 SET d='xyz' FROM t2, t3;
|
||||
END;
|
||||
}
|
||||
|
||||
|
||||
@@ -325,6 +325,8 @@ foreach {tn sql error ac data } {
|
||||
# EVIDENCE-OF: R-43190-62442 In other words, the schema-name. prefix on
|
||||
# the table name of the UPDATE is not allowed within triggers.
|
||||
#
|
||||
# Update: Unless the trigger is in the temp schema.
|
||||
#
|
||||
do_update_tests e_update-2.1 -error {
|
||||
qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers
|
||||
} {
|
||||
@@ -339,12 +341,14 @@ do_update_tests e_update-2.1 -error {
|
||||
UPDATE aux.t1 SET a=1, b=2;
|
||||
END;
|
||||
} {}
|
||||
}
|
||||
|
||||
3 {
|
||||
CREATE TRIGGER tr1 AFTER DELETE ON t4 BEGIN
|
||||
UPDATE main.t1 SET a=1, b=2;
|
||||
END;
|
||||
} {}
|
||||
# Qualified table name is allowed as t4 is a temp table.
|
||||
do_execsql_test e_update-2.1.3 {
|
||||
CREATE TRIGGER tr1 AFTER DELETE ON t4 BEGIN
|
||||
UPDATE main.t1 SET a=1, b=2;
|
||||
END;
|
||||
DROP TRIGGER tr1;
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-06085-13761 Unless the table to which the trigger is
|
||||
|
||||
@@ -276,4 +276,119 @@ do_catchsql_test 6.3 {
|
||||
} {1 error}
|
||||
db2 close
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
|
||||
do_execsql_test 7.0 {
|
||||
CREATE TABLE m1(a, b);
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.a1(c, d);
|
||||
}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TEMP TRIGGER tr1 AFTER INSERT ON m1 BEGIN
|
||||
INSERT INTO a1 VALUES(new.a, new.b);
|
||||
END;
|
||||
|
||||
INSERT INTO m1 VALUES(5, 6);
|
||||
SELECT * FROM aux.a1;
|
||||
} {5 6}
|
||||
|
||||
do_execsql_test 7.2 {
|
||||
CREATE TABLE a1(e, f);
|
||||
INSERT INTO m1 VALUES(7, 8);
|
||||
}
|
||||
|
||||
do_execsql_test 7.3.1 { SELECT * FROM main.a1 } {7 8}
|
||||
do_execsql_test 7.3.2 { SELECT * FROM aux.a1 } {5 6}
|
||||
|
||||
do_execsql_test 7.4 {
|
||||
DROP TRIGGER tr1;
|
||||
CREATE TEMP TRIGGER tr1 AFTER INSERT ON m1 BEGIN
|
||||
INSERT INTO a1 SELECT d, c FROM aux.a1;
|
||||
END;
|
||||
|
||||
DELETE FROM aux.a1;
|
||||
DELETE FROM main.a1;
|
||||
INSERT INTO aux.a1 VALUES('hello', 'world');
|
||||
}
|
||||
|
||||
do_execsql_test 7.5 {
|
||||
INSERT INTO m1 VALUES(9, 10);
|
||||
SELECT * FROM main.a1;
|
||||
} {world hello}
|
||||
|
||||
do_catchsql_test 7.6 {
|
||||
DROP TRIGGER tr1;
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON m1 BEGIN
|
||||
INSERT INTO a1 SELECT d, c FROM aux.a1;
|
||||
END;
|
||||
} {1 {trigger tr1 cannot reference objects in database aux}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that temp triggers may INSERT/UPDATE/DELETE to fully qualified
|
||||
# table names.
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 8.0 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE TABLE aux.t1(e, f);
|
||||
CREATE TABLE aux.t2(g, h);
|
||||
}
|
||||
|
||||
do_catchsql_test 8.1.1 {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t2 BEGIN
|
||||
INSERT INTO aux.t1 VALUES(new.c, new.d);
|
||||
END;
|
||||
} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}}
|
||||
|
||||
do_execsql_test 8.1.2 {
|
||||
CREATE TEMP TRIGGER tr1 AFTER INSERT ON t2 BEGIN
|
||||
INSERT INTO aux.t1 VALUES(new.c, new.d);
|
||||
END;
|
||||
|
||||
INSERT INTO main.t2 VALUES('x', 'y');
|
||||
SELECT * FROM aux.t1;
|
||||
} {x y}
|
||||
|
||||
do_execsql_test 8.1.3 { SELECT * FROM t1 } {}
|
||||
|
||||
do_catchsql_test 8.2.1 {
|
||||
CREATE TRIGGER aux.tr2 AFTER UPDATE ON aux.t1 BEGIN
|
||||
UPDATE main.t2 SET c=new.e, d=new.f;
|
||||
END;
|
||||
} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}}
|
||||
|
||||
do_execsql_test 8.2.2 {
|
||||
CREATE TEMP TRIGGER tr2 AFTER UPDATE ON aux.t1 BEGIN
|
||||
UPDATE main.t2 SET c=new.e, d=new.f;
|
||||
END;
|
||||
|
||||
UPDATE aux.t1 SET e=1, f=2;
|
||||
SELECT * FROM t2;
|
||||
} {1 2}
|
||||
|
||||
do_execsql_test 8.2.3 { SELECT * FROM aux.t2 } {}
|
||||
|
||||
do_catchsql_test 8.3.1 {
|
||||
CREATE TRIGGER tr3 AFTER DELETE ON t2 BEGIN
|
||||
DELETE FROM aux.t1;
|
||||
END;
|
||||
} {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}}
|
||||
|
||||
do_execsql_test 8.3.2 {
|
||||
INSERT INTO main.t1 VALUES('a', 'b');
|
||||
CREATE TEMP TRIGGER tr3 AFTER DELETE ON t2 BEGIN
|
||||
DELETE FROM aux.t1;
|
||||
END;
|
||||
|
||||
DELETE FROM main.t2;
|
||||
SELECT * FROM aux.t1;
|
||||
} {}
|
||||
|
||||
do_execsql_test 8.3.3 { SELECT * FROM t1 } {a b}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user