1
0
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:
dan
2025-10-29 20:57:44 +00:00
parent d443f0a95f
commit 11b6fc93f6
12 changed files with 240 additions and 166 deletions

View File

@@ -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.

View File

@@ -1,2 +1,2 @@
branch trunk
tag trunk
branch temp-trigger-refs
tag temp-trigger-refs

View File

@@ -1 +1 @@
095cc4f22e63c98cbb2acabdbcaf02e59e67ec6d3cc219b5f42a714e3d53a264
48e168007ceb1bdc54cf21a8e959a8e0f9ccdc478827db7a7a0518fc7a226401

View 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);
}

View 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;
}

View 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);

View 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).

View 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*);

View 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);

View 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;
}

View 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

View 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