Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix the UPDATE-FROM logic so that it works the same as PostgreSQL when the FROM clause contains an outer join. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
98b3816bbaf539ea745456e1c0064e47 |
User & Date: | drh 2022-05-25 11:09:07.638 |
References
2022-05-28
| ||
14:03 | Apply the UPDATE-FROM file from check-in [98b3816bbaf539ea] to update-delete-limit builds. (check-in: 7e87892c24 user: drh tags: trunk) | |
2022-05-26
| ||
17:33 | Correct handling of outer joins in the FROM clause of an UPDATE statement that occurs inside of a trigger. Follow-on to [98b3816bbaf539ea]. (check-in: 664a49fa81 user: drh tags: trunk) | |
Context
2022-05-25
| ||
11:17 | Add in a VdbeCoverage() macro accidentally omitted from [d64ae49a1f251317]. (check-in: 18b5cea039 user: drh tags: trunk) | |
11:09 | Fix the UPDATE-FROM logic so that it works the same as PostgreSQL when the FROM clause contains an outer join. (check-in: 98b3816bba user: drh tags: trunk) | |
08:51 | Got the sqlite3-api JS bits wrapped up in deferred-load module. Whether that's going to be easier to use, in practice, remains to be seen. Consolidated two of the test-related JS files. (check-in: dd83cc05f2 user: stephan tags: trunk) | |
02:32 | An attempt to get UPDATE FROM working when the FROM clause contains a RIGHT or FULL JOIN. (Closed-Leaf check-in: a124e4f96f user: drh tags: update-from-right-join) | |
Changes
Changes to src/parse.y.
︙ | ︙ | |||
936 937 938 939 940 941 942 | sqlite3Update(pParse,X,Y,W,R,O,L,0); } %else cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); | > > > > > > > > > > | > | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | sqlite3Update(pParse,X,Y,W,R,O,L,0); } %else cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); if( F ){ SrcList *pFromClause = F; if( pFromClause->nSrc>1 ){ Select *pSubquery; Token as; pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); as.n = 0; as.z = 0; pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } X = sqlite3SrcListAppendList(pParse, X, pFromClause); } sqlite3Update(pParse,X,Y,W,R,0,0,0); } %endif %type setlist {ExprList*} |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 | SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } #endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** | > > > > > > > > > > > > > > > > > > > > > > > | 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 | SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } #endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ /* ** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same ** as pSrcItem but has the same alias as p0, then return true. ** Otherwise return false. */ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ int i; for(i=0; i<pSrc->nSrc; i++){ SrcItem *p1 = &pSrc->a[i]; if( p1==p0 ) continue; if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ return 1; } if( p1->pSelect && (p1->pSelect->selFlags & SF_NestedFrom)!=0 && sameSrcAlias(p0, p1->pSelect->pSrc) ){ return 1; } } return 0; } /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** |
︙ | ︙ | |||
6618 6619 6620 6621 6622 6623 6624 | ** ** Postgres disallows this case too. The reason is that some other ** systems handle this case differently, and not all the same way, ** which is just confusing. To avoid this, we follow PG's lead and ** disallow it altogether. */ if( p->selFlags & SF_UFSrcCheck ){ SrcItem *p0 = &p->pSrc->a[0]; | | < < | | | | | < | 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 | ** ** Postgres disallows this case too. The reason is that some other ** systems handle this case differently, and not all the same way, ** which is just confusing. To avoid this, we follow PG's lead and ** disallow it altogether. */ if( p->selFlags & SF_UFSrcCheck ){ SrcItem *p0 = &p->pSrc->a[0]; if( sameSrcAlias(p0, p->pSrc) ){ sqlite3ErrorMsg(pParse, "target object/alias may not appear in FROM clause: %s", p0->zAlias ? p0->zAlias : p0->pTab->zName ); goto select_end; } /* Clear the SF_UFSrcCheck flag. The check has already been performed, ** and leaving this flag set can cause errors if a compound sub-query ** in p->pSrc is flattened into this query and this function called ** again as part of compound SELECT processing. */ p->selFlags &= ~SF_UFSrcCheck; |
︙ | ︙ |
Added test/upfrom4.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # 2022-05-24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix upfrom4 do_execsql_test 100 { DROP TABLE IF EXISTS t5; DROP TABLE IF EXISTS m1; DROP TABLE IF EXISTS m2; CREATE TABLE t5(a INTEGER PRIMARY KEY, b TEXT, c TEXT); CREATE TABLE m1(x INTEGER PRIMARY KEY, y TEXT); CREATE TABLE m2(u INTEGER PRIMARY KEY, v TEXT); INSERT INTO t5 VALUES(1, 'one', 'ONE'); INSERT INTO t5 VALUES(2, 'two', 'TWO'); INSERT INTO t5 VALUES(3, 'three', 'THREE'); INSERT INTO t5 VALUES(4, 'four', 'FOUR'); INSERT INTO m1 VALUES(1, 'i'); INSERT INTO m1 VALUES(2, 'ii'); INSERT INTO m1 VALUES(3, 'iii'); INSERT INTO m2 VALUES(1, 'I'); INSERT INTO m2 VALUES(3, 'II'); INSERT INTO m2 VALUES(4, 'III'); SELECT * FROM t5; } {1 one ONE 2 two TWO 3 three THREE 4 four FOUR} do_execsql_test 110 { BEGIN; UPDATE t5 SET b=y, c=v FROM m1 LEFT JOIN m2 ON (x=u) WHERE x=a; SELECT * FROM t5 ORDER BY a; ROLLBACK; } {1 i I 2 ii {} 3 iii II 4 four FOUR} do_execsql_test 120 { BEGIN; UPDATE t5 SET b=y, c=v FROM m2 RIGHT JOIN m1 ON (x=u) WHERE x=a; SELECT * FROM t5 ORDER BY a; ROLLBACK; } {1 i I 2 ii {} 3 iii II 4 four FOUR} finish_test |