]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Experimental change to allow triggers in the temp schema to use fully qualified table...
authordan <Dan Kennedy>
Wed, 29 Oct 2025 20:57:44 +0000 (20:57 +0000)
committerdan <Dan Kennedy>
Wed, 29 Oct 2025 20:57:44 +0000 (20:57 +0000)
FossilOrigin-Name: 48e168007ceb1bdc54cf21a8e959a8e0f9ccdc478827db7a7a0518fc7a226401

12 files changed:
manifest
manifest.tags
manifest.uuid
src/alter.c
src/attach.c
src/fkey.c
src/parse.y
src/sqliteInt.h
src/trigger.c
test/altertrig.test
test/e_update.test
test/temptrigger.test

index dd2fce0a5e72acb6bc9b62bc9efb3f7a56d67833..6c087303bb0b54b89375e4012e74757823cb299f 100644 (file)
--- a/manifest
+++ b/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.
index bec971799ff1b8ee641c166c7aeb22d12c785393..ba33ad2c5bdf8ce912b043ec0b4c55e3775bb8bc 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch temp-trigger-refs
+tag temp-trigger-refs
index 7a12e4c45e4afdff38c52dc98125abe82cee524e..09a88d2afd681bbe12e36c3a0216bb37027c2888 100644 (file)
@@ -1 +1 @@
-095cc4f22e63c98cbb2acabdbcaf02e59e67ec6d3cc219b5f42a714e3d53a264
+48e168007ceb1bdc54cf21a8e959a8e0f9ccdc478827db7a7a0518fc7a226401
index a7255e75ef2da1e5df0e1c5c6570e1b6c26b386b..5cbb5c033acd112cb4429376d50acc1be80281a9 100644 (file)
@@ -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);
                   }
index 085e1b0ecc871045a61a762abcea0139461d23fd..f27c1e6be45f185ba507e8aa044312487454d48d 100644 (file)
@@ -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;
     }
index f1117a8845798937504d010ac0e629e48a377f61..5e0bc89c4ef85a560e7926cea523aa86e89eaf0b 100644 (file)
@@ -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);
index 617eb7303b6ee2f2293544a5cace5e4d95f908be..44613cdcacdeb98655369082ee7643173ceb9409 100644 (file)
@@ -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).
index 523bcfb3bd92c7ecff95e5f0b22384a0efc6252d..5ea057ad8e8bf26c17a905bedbc89f03fb7259ad 100644 (file)
@@ -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*);
index 799fbe57fa4fbfc619441f6c93c7a00d38d38bf4..bcec2bbeea36736c06847bda04023e5de0e7b9b4 100644 (file)
@@ -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);
index 556dc3fea4c21a440b2a2fb6df43f1ea716fd92b..223feaf8f08f638670caa4c2b5141dffcff07f84 100644 (file)
@@ -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;
 }
 
index a13b059b3292050e7725317970b3ea8db95072b5..2b3341dc7ef8da699dd4b4636c3197ef0f9c301b 100644 (file)
@@ -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
index e4277adf653b76b077126fec7177908eaf757e07..3ae4408ab4d362b9ad86aa54d3259eb373cd854a 100644 (file)
@@ -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