Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Do not use the one-pass optimization on an UPDATE if there is a subquery in the WHERE clause, since if the subquery is hidden behind a short-circuit operator, the subquery might not be evaluated until after one or more rows have been updated. Fix for the problem reported by forum post 0007d1fdb1. This is the same problem that was fixed by [73f0036f045bf371] only for UPDATE instead of DELETE. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
2c56b984a0bd3be5ec326a2109ea7b8f |
User & Date: | drh 2023-03-16 10:17:30 |
References
2023-08-01
| ||
00:34 | Restore part of the UPDATE one-pass optimization that was removed by check-in [2c56b984a0bd3be5]: only disable one-pass if the WHERE clause contains a subquery. Allow subqueries in the SET expressions. Fix for performance problem reported by forum post 8ab195fd44e75ed0. (check-in: 42916af9 user: drh tags: trunk) | |
Context
2023-03-16
| ||
11:50 | Update the tracing output for the query-invariant checker such that it shows the SQL that is run to verify that a found query-invariant discrepency is valid. Changes to testing logic only. (check-in: 8f45ad27 user: drh tags: trunk) | |
10:21 | Do not use the one-pass optimization on an UPDATE if there is a subquery in the WHERE clause, since if the subquery is hidden behind a short-circuit operator, the subquery might not be evaluated until after one or more rows have been updated. (check-in: b5d8a9a6 user: drh tags: branch-3.41) | |
10:17 | Do not use the one-pass optimization on an UPDATE if there is a subquery in the WHERE clause, since if the subquery is hidden behind a short-circuit operator, the subquery might not be evaluated until after one or more rows have been updated. Fix for the problem reported by forum post 0007d1fdb1. This is the same problem that was fixed by [73f0036f045bf371] only for UPDATE instead of DELETE. (check-in: 2c56b984 user: drh tags: trunk) | |
09:07 | Remove a NEVER() from btreeNext() that dbsqlfuzz 460aa158f9a2c41145831cc924296cde1f312b3f found could sometimes be reached. I will find a way to test that branch later. (check-in: 1dffeffe user: drh tags: trunk) | |
Changes
Changes to src/update.c.
︙ | ︙ | |||
723 724 725 726 727 728 729 | eOnePass = ONEPASS_SINGLE; sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); bFinishSeek = 0; }else{ /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if | > > > | > | < < > > | > > > > > > | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | eOnePass = ONEPASS_SINGLE; sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL); bFinishSeek = 0; }else{ /* Begin the database scan. ** ** Do not consider a single-pass strategy for a multi-row update if ** there is anything that might disrupt the cursor being used to do ** the UPDATE: ** (1) This is a nested UPDATE ** (2) There are triggers ** (3) There are FOREIGN KEY constraints ** (4) There are REPLACE conflict handlers ** (5) There are subqueries in the WHERE clause */ flags = WHERE_ONEPASS_DESIRED; if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace && (sNC.ncFlags & NC_Subquery)==0 ){ flags |= WHERE_ONEPASS_MULTIROW; } pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur); if( pWInfo==0 ) goto update_cleanup; /* A one-pass strategy that might update more than one row may not ** be used if any column of the index used for the scan is being |
︙ | ︙ |
Changes to test/corruptL.test.
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | | 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1 | 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1 | 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1.. | end crash-3afa1ca9e9c1bd.db }]} {} extra_schema_checks 0 | | | > > > | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 | | 4048: 37 20 31 0b 03 04 11 11 13 63 31 63 31 37 20 31 7 1......c1c17 1 | 4064: 0e 02 04 11 13 07 63 31 63 31 64 37 20 31 20 31 ......c1c1d7 1 1 | 4080: 0e 01 04 11 13 17 63 31 63 31 63 37 20 31 00 00 ......c1c1c7 1.. | end crash-3afa1ca9e9c1bd.db }]} {} extra_schema_checks 0 do_catchsql_test 15.1 { PRAGMA cell_size_check = 0; UPDATE c1 SET c= NOT EXISTS(SELECT 1 FROM c1 ORDER BY (SELECT 1 FROM c1 ORDER BY a)) +10 WHERE d BETWEEN 4 AND 7; } {1 {database disk image is malformed}} extra_schema_checks 1 do_execsql_test 15.2 { PRAGMA integrity_check; } {/in database main/} #------------------------------------------------------------------------- reset_db do_execsql_test 16.0 { CREATE TABLE t1(w, x, y, z, UNIQUE(w, x), UNIQUE(y, z)); INSERT INTO t1 VALUES(1, 1, 1, 1); |
︙ | ︙ |
Changes to test/delete.test.
︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 | # # When the WHERE clause of a DELETE statement contains a subquery # which uses the table that is being deleted from and there is a # short-circuit operator of some kind in the WHERE clause such that # the subquery might not run right away, then the subquery might # run after one or more rows have been deleted, which can change # the result of the subquery, and result in the wrong answer. # reset_db do_execsql_test delete-12.0 { CREATE TABLE t0(vkey INTEGER, pkey INTEGER,c1 INTEGER); INSERT INTO t0 VALUES(2,1,-20),(2,2,NULL),(2,3,0),(8,4,95); DELETE FROM t0 WHERE NOT ( (t0.vkey <= t0.c1) AND | > > > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | # # When the WHERE clause of a DELETE statement contains a subquery # which uses the table that is being deleted from and there is a # short-circuit operator of some kind in the WHERE clause such that # the subquery might not run right away, then the subquery might # run after one or more rows have been deleted, which can change # the result of the subquery, and result in the wrong answer. # # Similar problem for UPDATE tested by update-21.4 # https://sqlite.org/forum/forumpost/0007d1fdb1 # reset_db do_execsql_test delete-12.0 { CREATE TABLE t0(vkey INTEGER, pkey INTEGER,c1 INTEGER); INSERT INTO t0 VALUES(2,1,-20),(2,2,NULL),(2,3,0),(8,4,95); DELETE FROM t0 WHERE NOT ( (t0.vkey <= t0.c1) AND |
︙ | ︙ |
Changes to test/update.test.
︙ | ︙ | |||
727 728 729 730 731 732 733 734 735 | } {ok} do_catchsql_test update-20.20 { UPDATE t1 SET a=0; } {1 {constraint failed}} do_execsql_test update-20.30 { PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | } {ok} do_catchsql_test update-20.20 { UPDATE t1 SET a=0; } {1 {constraint failed}} do_execsql_test update-20.30 { PRAGMA integrity_check; } {ok} # 2023-03-16 https://sqlite.org/forum/forumpost/0007d1fdb1 # A subquery in the WHERE clause of an UPDATE and behind a # short-circuit evaluation caused problems because multi-row # single-pass was selected. # # Similar problem for DELETE tested by delete-12.0. # https://sqlite.org/src/info/73f0036f045bf371 # reset_db do_execsql_test update-21.1 { CREATE TABLE t1 (vkey INTEGER, c5 INTEGER); INSERT INTO t1 VALUES(3,NULL),(6,-54); } db null NULL do_execsql_test update-21.2 { BEGIN; UPDATE t1 SET vkey = 100 WHERE c5 is null; SELECT * FROM t1 ORDER BY vkey, c5; ROLLBACK; } {6 -54 100 NULL} do_execsql_test update-21.3 { BEGIN; UPDATE t1 SET vkey = 100 WHERE NOT (-10*(select min(vkey) from t1) >= c5); SELECT * FROM t1 ORDER BY vkey, c5; ROLLBACK; } {3 NULL 6 -54} do_execsql_test update-21.4 { BEGIN; UPDATE t1 SET vkey = 100 WHERE c5 is null OR NOT (-10*(select min(vkey) from t1) >= c5); SELECT * FROM t1 ORDER BY vkey, c5; ROLLBACK; } {6 -54 100 NULL} finish_test |