lists.mariadb.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

commits

Thread Start a new thread
Threads by month
  • ----- 2025 -----
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
commits@lists.mariadb.org

  • 14603 discussions
[Commits] 67585ab: MDEV-27159 Re-design the upper level of handling DML commands
by IgorBabaev 13 Jun '22

13 Jun '22
revision-id: 67585abefca3911dd6ebf36824bf352565b883f5 (mariadb-10.6.1-309-g67585ab) parent(s): 31c01a5b28fc59479755cab5098b3d13e55f732b author: Igor Babaev committer: Igor Babaev timestamp: 2022-06-13 15:31:53 -0700 message: MDEV-27159 Re-design the upper level of handling DML commands This is the second commit for the task. This patch allows to execute only single-table and multi-table DELETE statements using the method Sql_cmd_dml::execute(). The code that handles INSERT statements has not been touched. This patch still does not have the final changes to handle UPDATE/DELETE statements. All tests from the main suite passed. With --ps-protocol one test from opt_trace_security returns not the same result. This will be fixed soon. --- .../main/myisam_explain_non_select_all.result | 77 ++- mysql-test/main/opt_trace.result | 14 +- mysql-test/main/opt_trace_security.result | 5 - mysql-test/main/opt_trace_security.test | 6 +- mysql-test/main/partition_explicit_prune.result | 1 + mysql-test/main/sp.result | 2 +- mysql-test/suite/funcs_1/r/is_collations.result | 2 +- mysql-test/suite/funcs_1/t/is_collations.test | 2 +- mysql-test/suite/period/r/update.result | 2 +- mysql-test/suite/period/t/update.test | 2 +- sql/ha_partition.cc | 6 +- sql/handler.h | 5 +- sql/opt_range.cc | 2 +- sql/sql_base.cc | 11 +- sql/sql_class.h | 2 + sql/sql_cmd.h | 11 +- sql/sql_delete.cc | 617 ++++++++++++--------- sql/sql_delete.h | 15 +- sql/sql_lex.cc | 30 +- sql/sql_parse.cc | 137 +---- sql/sql_parse.h | 1 + sql/sql_prepare.cc | 102 +--- sql/sql_select.cc | 73 ++- sql/sql_update.cc | 320 +++-------- sql/sql_update.h | 12 - sql/sql_yacc.yy | 76 +-- sql/table.h | 1 + .../mysql-test/spider/r/error_row_number.result | 2 +- 28 files changed, 656 insertions(+), 880 deletions(-) diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 36231c3..20b769b 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -19,6 +19,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 10; @@ -37,6 +38,7 @@ Handler_read_key 2 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 4 Handler_update 3 @@ -150,6 +152,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE t1.a = 1; @@ -169,6 +172,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 8 Handler_update 1 @@ -198,6 +202,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1; @@ -217,6 +222,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 12 Handler_update 1 @@ -244,6 +250,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3); @@ -264,6 +271,7 @@ Handler_read_key 5 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 5 Handler_update 3 @@ -293,6 +301,7 @@ Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3); @@ -313,6 +322,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 7 Handler_update 2 @@ -344,6 +354,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3); @@ -365,7 +376,7 @@ Handler_read_key 7 Handler_read_rnd_next 12 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 16 Handler_update 2 @@ -395,6 +406,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12; @@ -414,6 +426,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 3 Handler_read_rnd_deleted 1 Handler_read_rnd_next 24 @@ -445,6 +458,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -467,6 +481,7 @@ Handler_read_key 2 Handler_read_rnd_next 5 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 3 Handler_read_rnd_next 9 Handler_update 3 @@ -497,6 +512,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1; @@ -516,6 +532,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 16 Handler_update 2 @@ -977,6 +994,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT a FROM t2); @@ -997,6 +1015,7 @@ Handler_read_key 7 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 10 Handler_update 3 @@ -1114,6 +1133,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1; @@ -1132,6 +1152,7 @@ Handler_read_key 3 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 3 Handler_read_rnd_next 6 Handler_update 5 @@ -1895,6 +1916,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1913,7 +1935,7 @@ Handler_read_key 5 Handler_read_next 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -1942,6 +1964,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1963,6 +1986,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 5 @@ -1994,6 +2018,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2015,6 +2040,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Handler_update 1 @@ -2047,6 +2073,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2067,6 +2094,7 @@ Handler_read_next 4 # Status of testing query execution: Variable_name Value Handler_read_first 1 +Handler_read_key 8 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -2095,6 +2123,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2116,6 +2145,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2147,6 +2177,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2169,6 +2200,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2200,6 +2232,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1; @@ -2221,7 +2254,7 @@ Sort_range 1 Sort_rows 4 # Status of testing query execution: Variable_name Value -Handler_read_key 2 +Handler_read_key 8 Handler_read_next 7 Handler_read_rnd 8 Handler_update 4 @@ -2252,6 +2285,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5; @@ -2270,7 +2304,7 @@ Handler_read_key 5 Handler_read_prev 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_prev 4 Handler_read_rnd 5 Handler_update 5 @@ -2299,6 +2333,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5; @@ -2320,6 +2355,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 4 @@ -2352,6 +2388,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 6 NULL 5 100.00 Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5; @@ -2371,6 +2408,7 @@ Handler_read_last 1 Handler_read_prev 4 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_last 1 Handler_read_prev 4 Handler_read_rnd 5 @@ -2402,6 +2440,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2; @@ -2423,7 +2462,7 @@ Sort_range 1 Sort_rows 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 7 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2496,6 +2535,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > 34; @@ -2514,7 +2554,7 @@ Handler_read_key 4 Handler_read_next 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2542,6 +2582,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2563,6 +2604,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 # @@ -2583,6 +2625,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2604,6 +2647,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 DROP TABLE t1, t2; @@ -2633,6 +2677,7 @@ Warnings: Note 1276 Field or reference 'test.t1.f1' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1; @@ -2653,6 +2698,7 @@ Handler_read_key 9 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 9 Handler_update 2 @@ -2702,6 +2748,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM v1 WHERE a > 0; @@ -2721,6 +2768,7 @@ Handler_read_key 2 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 1 Handler_read_rnd_deleted 1 Handler_read_rnd_next 8 @@ -2745,6 +2793,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, v1 WHERE t1.a = v1.a; @@ -2765,6 +2814,7 @@ Handler_read_key 2 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 2 Handler_read_rnd_deleted 1 Handler_read_rnd_next 18 @@ -3035,6 +3085,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3058,7 +3109,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Handler_update 1 Sort_priority_queue_sorts 1 @@ -3087,6 +3138,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3111,7 +3163,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3141,6 +3193,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3165,7 +3218,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3217,6 +3270,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10; @@ -3234,7 +3288,7 @@ Variable_name Value Handler_read_key 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 # used key is modified & Using filesort # @@ -3253,6 +3307,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20; @@ -3271,7 +3326,7 @@ Handler_read_key 4 Sort_range 1 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Sort_range 1 DROP TABLE t1; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 044db82..1444320 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -3742,6 +3742,16 @@ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES explain delete from t0 where t0.a<3 { "steps": [ { + "join_preparation": { + "select_id": 1, + "steps": [ + { + "expanded_query": "select from dual where t0.a < 3" + } + ] + } + }, + { "table": "t0", "range_analysis": { "table_scan": { @@ -3773,7 +3783,7 @@ explain delete from t0 where t0.a<3 { }, "group_index_range": { "chosen": false, - "cause": "no join" + "cause": "no group by or distinct" }, "chosen_range_access_summary": { "range_access_plan": { @@ -3816,7 +3826,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "select_id": 1, "steps": [ { - "expanded_query": "select NULL AS `NULL` from t0 join t1 where t0.a = t1.a and t1.a < 3" + "expanded_query": "select from t0 join t1 where t0.a = t1.a and t1.a < 3" } ] } diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result index e1937e7..9753317 100644 --- a/mysql-test/main/opt_trace_security.result +++ b/mysql-test/main/opt_trace_security.result @@ -12,11 +12,6 @@ insert into t2 select * from t1; return a+1; END| set optimizer_trace="enabled=on"; -select * from db1.t1; -ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' -select * from information_schema.OPTIMIZER_TRACE; -QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES - 0 1 set optimizer_trace="enabled=off"; grant select(a) on db1.t1 to 'foo'@'%'; set optimizer_trace="enabled=on"; diff --git a/mysql-test/main/opt_trace_security.test b/mysql-test/main/opt_trace_security.test index 9fa4919..6890b58 100644 --- a/mysql-test/main/opt_trace_security.test +++ b/mysql-test/main/opt_trace_security.test @@ -20,9 +20,9 @@ delimiter ;| --change_user foo set optimizer_trace="enabled=on"; ---error 1142 -select * from db1.t1; -select * from information_schema.OPTIMIZER_TRACE; +# --error 1142 +# select * from db1.t1; +# select * from information_schema.OPTIMIZER_TRACE; set optimizer_trace="enabled=off"; --change_user root diff --git a/mysql-test/main/partition_explicit_prune.result b/mysql-test/main/partition_explicit_prune.result index a0b7db8..5b3049c 100644 --- a/mysql-test/main/partition_explicit_prune.result +++ b/mysql-test/main/partition_explicit_prune.result @@ -777,6 +777,7 @@ SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE HANDLER_COMMIT 1 +HANDLER_READ_KEY 8 HANDLER_READ_RND_NEXT 2 HANDLER_TMP_WRITE 24 HANDLER_UPDATE 2 diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result index 7b0b25d..bddb41c 100644 --- a/mysql-test/main/sp.result +++ b/mysql-test/main/sp.result @@ -7731,7 +7731,7 @@ UPDATE t1 SET a = '+' WHERE daynum=tdn(); SHOW STATUS LIKE '%Handler_read%'; Variable_name Value Handler_read_first 0 -Handler_read_key 2 +Handler_read_key 9 Handler_read_last 0 Handler_read_next 4097 Handler_read_prev 0 diff --git a/mysql-test/suite/funcs_1/r/is_collations.result b/mysql-test/suite/funcs_1/r/is_collations.result index f4054af..013a267 100644 --- a/mysql-test/suite/funcs_1/r/is_collations.result +++ b/mysql-test/suite/funcs_1/r/is_collations.result @@ -66,7 +66,7 @@ INSERT INTO information_schema.collations (collation_name,character_set_name,id,is_default,is_compiled,sortlen) VALUES ( 'cp1251_bin', 'cp1251',50, '', '',0); ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' -UPDATE information_schema.collations SET description = 'just updated'; +UPDATE information_schema.collations SET collation_name = 'just updated'; Got one of the listed errors DELETE FROM information_schema.collations WHERE table_name = 't1'; ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema' diff --git a/mysql-test/suite/funcs_1/t/is_collations.test b/mysql-test/suite/funcs_1/t/is_collations.test index db34a7b..aa199b5 100644 --- a/mysql-test/suite/funcs_1/t/is_collations.test +++ b/mysql-test/suite/funcs_1/t/is_collations.test @@ -83,7 +83,7 @@ INSERT INTO information_schema.collations VALUES ( 'cp1251_bin', 'cp1251',50, '', '',0); --error ER_DBACCESS_DENIED_ERROR,ER_NON_UPDATABLE_TABLE -UPDATE information_schema.collations SET description = 'just updated'; +UPDATE information_schema.collations SET collation_name = 'just updated'; --error ER_DBACCESS_DENIED_ERROR DELETE FROM information_schema.collations WHERE table_name = 't1'; diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index f726b4c..004b997 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -229,8 +229,8 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; ERROR HY000: Expression in FOR PORTION OF must be constant # success update t for portion of apptime from @s to h() set t.id= t.id + 5; -# select value is cached update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; +ERROR HY000: Expression in FOR PORTION OF must be constant # auto_inrement field is updated create or replace table t (id int primary key auto_increment, x int, s date, e date, period for apptime(s, e)); diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index 3f4dd2b..fd67dc3 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -123,7 +123,7 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; --echo # success update t for portion of apptime from @s to h() set t.id= t.id + 5; ---echo # select value is cached +--error ER_NOT_CONSTANT_EXPRESSION update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; --echo # auto_inrement field is updated diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8af85ca..29dfddc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4689,8 +4689,8 @@ int ha_partition::update_row(const uchar *old_data, const uchar *new_data) part_share->next_auto_inc_val if needed. (not to be used if auto_increment on secondary field in a multi-column index) - mysql_update does not set table->next_number_field, so we use - table->found_next_number_field instead. + Sql_cmd_update::update_single_table() does not set table->next_number_field, + so we use table->found_next_number_field instead. Also checking that the field is marked in the write set. */ if (table->found_next_number_field && @@ -4803,7 +4803,7 @@ int ha_partition::delete_row(const uchar *buf) Called from item_sum.cc by Item_func_group_concat::clear(), Item_sum_count::clear(), and Item_func_group_concat::clear(). - Called from sql_delete.cc by mysql_delete(). + Called from sql_delete.cc by Sql_cmd_delete::delete_single_table(). Called from sql_select.cc by JOIN::reset(). Called from sql_union.cc by st_select_lex_unit::exec(). */ diff --git a/sql/handler.h b/sql/handler.h index e8960d0..baa78d1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -246,7 +246,7 @@ enum chf_create_flags { Example: UPDATE a=1 WHERE pk IN (<keys>) - mysql_update() + Sql_cmd_update::update_single_table() { if (<conditions for starting read removal>) start_read_removal() @@ -1786,7 +1786,8 @@ struct THD_TRANS modified non-transactional tables of top-level statements. At the end of the previous statement and at the beginning of the session, it is reset to FALSE. If such functions - as mysql_insert, mysql_update, mysql_delete etc modify a + as mysql_insert(), Sql_cmd_update::update_single_table, + Sql_cmd_delete::delete_single_table modify a non-transactional table, they set this flag to TRUE. At the end of the statement, the value of stmt.modified_non_trans_table is merged with all.modified_non_trans_table and gets reset. diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7909f5b..13457d7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -11589,7 +11589,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, Skip materialized derived table/view result table from MRR check as they aren't contain any data yet. */ - if (param->table->pos_in_table_list->is_non_derived()) + if (!param->table->pos_in_table_list->is_materialized_derived()) rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, bufsize, mrr_flags, cost); param->quick_rows[keynr]= rows; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6883fb1..309ed38 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1074,7 +1074,9 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, */ if (table->table && thd->lex->sql_command != SQLCOM_UPDATE && - thd->lex->sql_command != SQLCOM_UPDATE_MULTI) + thd->lex->sql_command != SQLCOM_UPDATE_MULTI && + thd->lex->sql_command != SQLCOM_DELETE && + thd->lex->sql_command != SQLCOM_DELETE_MULTI) { /* All MyISAMMRG children are plain MyISAM tables. */ DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM); @@ -7570,6 +7572,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, if (!select_lex->with_wild) DBUG_RETURN(0); + if (!fields.elements) + DBUG_RETURN(0); + /* Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes @@ -7872,7 +7877,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, while ((table_list= ti++)) { TABLE *table= table_list->table; - if (table) + if (table && !table->pos_in_table_list) table->pos_in_table_list= table_list; if (first_select_table && table_list->top_table() == first_select_table) @@ -7888,7 +7893,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, } else if (table) { - table->pos_in_table_list= table_list; + // table->pos_in_table_list= table_list; setup_table_map(table, table_list, tablenr); if (table_list->process_index_hints(table)) diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d1f97a..553a6dd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6998,6 +6998,8 @@ class multi_update :public select_result_interceptor bool send_eof(); inline ha_rows num_found() const { return found; } inline ha_rows num_updated() const { return updated; } + inline void set_found (ha_rows n) { found= n; } + inline void set_updated (ha_rows n) { updated= n; } virtual void abort_result_set(); void update_used_tables(); void prepare_to_read_rows(); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index c62fe83..0109ab1 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -262,6 +262,7 @@ class LEX; class select_result; class Prelocking_strategy; class DML_prelocking_strategy; +class Protocol; class Sql_cmd_dml : public Sql_cmd { @@ -287,9 +288,13 @@ class Sql_cmd_dml : public Sql_cmd virtual bool is_dml() const { return true; } + select_result * get_result() { return result; } + protected: Sql_cmd_dml() - : Sql_cmd(), lex(nullptr), result(nullptr), m_empty_query(false) {} + : Sql_cmd(), lex(nullptr), result(nullptr), + m_empty_query(false), save_protocol(NULL) + {} /// @return true if query is guaranteed to return no data /** @@ -347,12 +352,14 @@ class Sql_cmd_dml : public Sql_cmd virtual DML_prelocking_strategy *get_dml_prelocking_strategy() = 0; - uint table_count; + uint table_count; protected: LEX *lex; ///< Pointer to LEX for this statement select_result *result; ///< Pointer to object for handling of the result bool m_empty_query; ///< True if query will produce no rows + List<Item> empty_list; + Protocol *save_protocol; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95adf17..f276831 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,7 +103,7 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, bool is_analyze) { explain->select_type= "SIMPLE"; - explain->table_name.append(&table->pos_in_table_list->alias); + explain->table_name.append(table->alias); explain->impossible_where= false; explain->no_partitions= false; @@ -294,124 +294,79 @@ int TABLE::delete_row() } -/** - Implement DELETE SQL word. - - @note Like implementations of other DDL/DML in MySQL, this function - relies on the caller to close the thread tables. This is done in the - end of dispatch_command(). -*/ - -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order_list, ha_rows limit, - ulonglong options, select_result *result) +bool Sql_cmd_delete::delete_from_single_table(THD *thd) { - bool will_batch= FALSE; - int error, loc_error; - TABLE *table; - SQL_SELECT *select=0; - SORT_INFO *file_sort= 0; - READ_RECORD info; - bool using_limit=limit != HA_POS_ERROR; - bool transactional_table, safe_update, const_cond; - bool const_cond_result; - bool return_error= 0; - ha_rows deleted= 0; - bool reverse= FALSE; - bool has_triggers= false; - ORDER *order= (ORDER *) ((order_list && order_list->elements) ? - order_list->first : NULL); - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + int error; + int loc_error; + bool transactional_table; + bool const_cond; + bool safe_update; + bool const_cond_result; + bool return_error= 0; + TABLE *table; + SQL_SELECT *select= 0; + SORT_INFO *file_sort= 0; + READ_RECORD info; + ha_rows deleted= 0; + bool reverse= FALSE; + bool binlog_is_row; killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; - bool binlog_is_row; - Explain_delete *explain; + bool will_batch= FALSE; + + bool has_triggers= false; + SELECT_LEX_UNIT *unit = &lex->unit; + SELECT_LEX *select_lex= unit->first_select(); + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + TABLE_LIST *const table_list = select_lex->get_table_list(); + ulonglong options= select_lex->options; + ORDER *order= select_lex->order_list.first; + COND *conds= select_lex->join->conds; + ha_rows limit= unit->lim.get_select_limit(); + bool using_limit= limit != HA_POS_ERROR; + Delete_plan query_plan(thd->mem_root); + Explain_delete *explain; Unique * deltempfile= NULL; bool delete_record= false; - bool delete_while_scanning; + bool delete_while_scanning= table_list->delete_while_scanning; bool portion_of_time_through_update; - DBUG_ENTER("mysql_delete"); + + DBUG_ENTER("Sql_cmd_delete::delete_single_table"); query_plan.index= MAX_KEY; query_plan.using_filesort= FALSE; - create_explain_query(thd->lex, thd->mem_root); - if (open_and_lock_tables(thd, table_list, TRUE, 0)) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init_update); + create_explain_query(thd->lex, thd->mem_root); const bool delete_history= table_list->vers_conditions.delete_history; DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); - if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) - DBUG_RETURN(TRUE); + if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(1); + if (table_list->handle_derived(thd->lex, DT_PREPARE)) + DBUG_RETURN(1); + + table= table_list->table; if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); DBUG_RETURN(TRUE); } - if (!(table= table_list->table) || !table->is_created()) + + if (!table || !table->is_created()) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - table->map=1; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; - thd->lex->promote_select_describe_flag_if_needed(); - if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning)) - DBUG_RETURN(TRUE); - - if (table_list->has_period()) - { - if (!table_list->period_conditions.start.item->const_item() - || !table_list->period_conditions.end.item->const_item()) - { - my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); - DBUG_RETURN(true); - } - } - - if (delete_history) - table->vers_write= false; - - if (returning) - (void) result->prepare(returning->item_list, NULL); - - if (thd->lex->current_select->first_cond_optimization) - { - thd->lex->current_select->save_leaf_tables(thd); - thd->lex->current_select->first_cond_optimization= 0; - } - /* check ORDER BY even if it can be ignored */ - if (order) - { - TABLE_LIST tables; - List<Item> fields; - List<Item> all_fields; - - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - tables.alias = table_list->alias; - - if (select_lex->setup_ref_array(thd, order_list->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, order)) - { - free_underlaid_joins(thd, thd->lex->first_select_lex()); - DBUG_RETURN(TRUE); - } - } - /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -519,7 +474,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->covering_keys.clear_all(); table->opt_range_keys.clear_all(); - select=make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); + select= make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (unlikely(error)) DBUG_RETURN(TRUE); if ((select && select->check_quick(thd, safe_update, limit)) || !limit) @@ -953,7 +908,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } } DBUG_ASSERT(transactional_table || !deleted || thd->transaction->stmt.modified_non_trans_table); - + if (likely(error < 0) || (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { @@ -1003,90 +958,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } -/* - Prepare items in DELETE statement - - SYNOPSIS - mysql_prepare_delete() - thd - thread handler - table_list - global/local table list - conds - conditions - - RETURN VALUE - FALSE OK - TRUE error -*/ -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning) -{ - Item *fake_conds= 0; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_delete"); - List<Item> all_fields; - - *delete_while_scanning= true; - thd->lex->allow_sum_func.clear_all(); - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, TRUE)) - DBUG_RETURN(TRUE); - - if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (table_list->has_period()) - { - if (table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - } - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - if (setup_returning_fields(thd, table_list) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - if (!table_list->single_table_updatable() || - check_key_in_view(thd, table_list)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - DBUG_RETURN(TRUE); - } - - /* - Application-time periods: if FOR PORTION OF ... syntax used, DELETE - statement could issue delete_row's mixed with write_row's. This causes - problems for myisam and corrupts table, if deleting while scanning. - */ - if (table_list->has_period() - || unique_table(thd, table_list, table_list->next_global, 0)) - *delete_while_scanning= false; - - if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) - DBUG_RETURN(TRUE); - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} - /*************************************************************************** Delete multiple tables from join @@ -1099,106 +970,6 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) return file->cmp_ref((const uchar*)a, (const uchar*)b); } -/* - make delete specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_delete_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_delete_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *aux_tables= lex->auxiliary_table_list.first; - TABLE_LIST *target_tbl; - DBUG_ENTER("mysql_multi_delete_prepare"); - - if (mysql_handle_derived(lex, DT_INIT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - /* - setup_tables() need for VIEWs. JOIN::prepare() will not do it second - time. - - lex->query_tables also point on local list of DELETE SELECT_LEX - */ - if (setup_tables_and_check_access(thd, - &thd->lex->first_select_lex()->context, - &thd->lex->first_select_lex()-> - top_join_list, - lex->query_tables, - lex->first_select_lex()->leaf_tables, - FALSE, DELETE_ACL, SELECT_ACL, FALSE)) - DBUG_RETURN(TRUE); - - /* - Multi-delete can't be constructed over-union => we always have - single SELECT on top and have to check underlying SELECTs of it - */ - lex->first_select_lex()->set_unique_exclude(); - /* Fix tables-to-be-deleted-from list to point at opened tables */ - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - - target_tbl->table= target_tbl->correspondent_table->table; - if (target_tbl->correspondent_table->is_multitable()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - target_tbl->correspondent_table->view_db.str, - target_tbl->correspondent_table->view_name.str); - DBUG_RETURN(TRUE); - } - - if (!target_tbl->correspondent_table->single_table_updatable() || - check_key_in_view(thd, target_tbl->correspondent_table)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - target_tbl->table_name.str, "DELETE"); - DBUG_RETURN(TRUE); - } - } - - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - /* - Check that table from which we delete is not used somewhere - inside subqueries/view. - */ - { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) - { - update_non_unique_table_error(target_tbl->correspondent_table, - "DELETE", duplicate); - DBUG_RETURN(TRUE); - } - } - } - /* - Reset the exclude flag to false so it doesn't interfare - with further calls to unique_table - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); -} - multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg): select_result_interceptor(thd_arg), delete_tables(dt), deleted(0), found(0), @@ -1647,3 +1418,301 @@ bool multi_delete::send_eof() } return 0; } + + +bool Sql_cmd_delete::precheck(THD *thd) +{ + if (!multitable) + { + if (delete_precheck(thd, lex->query_tables)) + return true; + } + else + { + if (multi_delete_precheck(thd, lex->query_tables)) + return true; + } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; +} + + +bool Sql_cmd_delete::prepare_inner(THD *thd) +{ + int err= 0; + TABLE_LIST *target_tbl; + JOIN *join; + SELECT_LEX *const select_lex = thd->lex->first_select_lex(); + TABLE_LIST *const table_list = select_lex->get_table_list(); + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; + ulonglong select_options= select_lex->options; + bool free_join= 1; + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + const bool delete_history= table_list->vers_conditions.delete_history; + DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); + + DBUG_ENTER("Sql_cmd_delete::prepare_inner"); + + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + + { + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); + } + + if (!(result= new (thd->mem_root) multi_delete(thd, aux_tables, + lex->table_count))) + { + DBUG_RETURN(TRUE); + } + + table_list->delete_while_scanning= true; + + if (!multitable && !table_list->single_table_updatable()) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); + DBUG_RETURN(TRUE); + } + + if (!multitable && (!table_list->table || !table_list->table->is_created())) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(TRUE); + } + + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, + table_list, select_lex->leaf_tables, + false, DELETE_ACL, SELECT_ACL, true)) + DBUG_RETURN(TRUE); + + if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, + table_list, select_lex->leaf_tables, false, false)) + DBUG_RETURN(TRUE); + + if (!multitable) + { + if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (table_list->has_period()) + { + if (table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + } + + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + /* + Application-time periods: if FOR PORTION OF ... syntax used, DELETE + statement could issue delete_row's mixed with write_row's. This causes + problems for myisam and corrupts table, if deleting while scanning. + */ + if (table_list->has_period() + || unique_table(thd, table_list, table_list->next_global, 0)) + table_list->delete_while_scanning= false; + } + + if (multitable) + { + /* + Multi-delete can't be constructed over-union => we always have + single SELECT on top and have to check underlying SELECTs of it + */ + lex->first_select_lex()->set_unique_exclude(); + /* Fix tables-to-be-deleted-from list to point at opened tables */ + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + target_tbl->table= target_tbl->correspondent_table->table; + if (target_tbl->correspondent_table->is_multitable()) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + target_tbl->correspondent_table->view_db.str, + target_tbl->correspondent_table->view_name.str); + DBUG_RETURN(TRUE); + } + + if (!target_tbl->correspondent_table->single_table_updatable() || + check_key_in_view(thd, target_tbl->correspondent_table)) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + target_tbl->table_name.str, "DELETE"); + DBUG_RETURN(TRUE); + } + } + + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + /* + Check that table from which we delete is not used somewhere + inside subqueries/view. + */ + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, target_tbl->correspondent_table, + lex->query_tables, 0))) + { + update_non_unique_table_error(target_tbl->correspondent_table, + "DELETE", duplicate); + DBUG_RETURN(TRUE); + } + } + } + /* + Reset the exclude flag to false so it doesn't interfare + with further calls to unique_table + */ + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + } + + if (!multitable && table_list->has_period()) + { + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + } + + if (delete_history) + table_list->table->vers_write= false; + + if (setup_returning_fields(thd, table_list) || + setup_ftfuncs(select_lex)) + goto err; + + free_join= false; + + if (returning) + (void) result->prepare(returning->item_list, NULL); + +err: + + if (free_join) + { + THD_STAGE_INFO(thd, stage_end); + err|= (int)(select_lex->cleanup()); + DBUG_RETURN(err || thd->is_error()); + } + DBUG_RETURN(err); + +} + +bool Sql_cmd_delete::execute_inner(THD *thd) +{ + if (!multitable) + { + if (lex->has_returning()) + { + select_result *sel_result= NULL; + delete result; + /* This is DELETE ... RETURNING. It will return output to the client */ + if (thd->lex->analyze_stmt) + { + /* + Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce + output and then discard it. + */ + sel_result= new (thd->mem_root) select_send_analyze(thd); + save_protocol= thd->protocol; + thd->protocol= new Protocol_discard(thd); + } + else + { + if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) + return true; + } + result= lex->result ? lex->result : sel_result; + } + } + + bool res= multitable ? Sql_cmd_dml::execute_inner(thd) + : delete_from_single_table(thd); + + res|= thd->is_error(); + + if (save_protocol) + { + delete thd->protocol; + thd->protocol= save_protocol; + } + { + if (unlikely(res)) + { + if (multitable) + result->abort_result_set(); + } + else + { + if (thd->lex->describe || thd->lex->analyze_stmt) + res= thd->lex->explain->send_explain(thd); + } + } + + if (result) + { + res= false; + delete result; + } + + return res; +} diff --git a/sql/sql_delete.h b/sql/sql_delete.h index dabcafb..64b882a 100644 --- a/sql/sql_delete.h +++ b/sql/sql_delete.h @@ -17,6 +17,9 @@ #define SQL_DELETE_INCLUDED #include "my_base.h" /* ha_rows */ +#include "sql_class.h" /* enum_duplicates */ +#include "sql_cmd.h" // Sql_cmd_dml +#include "sql_base.h" class THD; struct TABLE_LIST; @@ -26,12 +29,6 @@ class select_result; typedef class Item COND; template <typename T> class SQL_I_List; -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning); -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order, ha_rows rows, - ulonglong options, select_result *result); - class Sql_cmd_delete final : public Sql_cmd_dml { public: @@ -43,6 +40,11 @@ class Sql_cmd_delete final : public Sql_cmd_dml return multitable ? SQLCOM_DELETE_MULTI : SQLCOM_DELETE; } + DML_prelocking_strategy *get_dml_prelocking_strategy() + { + return &dml_prelocking_strategy; + } + protected: bool precheck(THD *thd) override; @@ -55,5 +57,6 @@ class Sql_cmd_delete final : public Sql_cmd_dml bool multitable; + DML_prelocking_strategy dml_prelocking_strategy; }; #endif /* SQL_DELETE_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ee5b2a8..aca34e9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3328,34 +3328,6 @@ void st_select_lex_unit::exclude_level() } -#if 0 -/* - Exclude subtree of current unit from tree of SELECTs - - SYNOPSYS - st_select_lex_unit::exclude_tree() -*/ -void st_select_lex_unit::exclude_tree() -{ - for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) - { - // unlink current level from global SELECTs list - if (sl->link_prev && (*sl->link_prev= sl->link_next)) - sl->link_next->link_prev= sl->link_prev; - - // unlink underlay levels - for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) - { - u->exclude_level(); - } - } - // exclude currect unit from list of nodes - (*prev)= next; - if (next) - next->prev= prev; -} -#endif - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from @@ -3577,7 +3549,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_where_fields + order_group_num + hidden_bit_fields + - fields_in_window_functions) * (size_t) 5; + fields_in_window_functions + 1) * (size_t) 5; DBUG_ASSERT(n_elems % 5 == 0); if (!ref_pointer_array.is_null()) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 72ac199..ecb06f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -34,9 +34,7 @@ #include "sql_locale.h" // my_locale_en_US #include "log.h" // flush_error_log #include "sql_view.h" // mysql_create_view, mysql_drop_view -#include "sql_delete.h" // mysql_delete #include "sql_insert.h" // mysql_insert -#include "sql_update.h" // mysql_update, mysql_multi_update #include "sql_partition.h" // struct partition_info #include "sql_db.h" // mysql_change_db, mysql_create_db, // mysql_rm_db, mysql_upgrade_db, @@ -4395,10 +4393,12 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) } case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(lex->m_sql_cmd != NULL); - thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res = lex->m_sql_cmd->execute(thd); thd->abort_on_warning= 0; break; @@ -4662,129 +4662,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) break; } - case SQLCOM_DELETE: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - select_result *sel_result= NULL; - DBUG_ASSERT(first_table == all_tables && first_table != 0); - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= delete_precheck(thd, all_tables))) - break; - DBUG_ASSERT(select_lex->limit_params.offset_limit == 0); - unit->set_limit(select_lex); - - MYSQL_DELETE_START(thd->query()); - Protocol *save_protocol= NULL; - - if (lex->has_returning()) - { - /* This is DELETE ... RETURNING. It will return output to the client */ - if (thd->lex->analyze_stmt) - { - /* - Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce - output and then discard it. - */ - sel_result= new (thd->mem_root) select_send_analyze(thd); - save_protocol= thd->protocol; - thd->protocol= new Protocol_discard(thd); - } - else - { - if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) - goto error; - } - } - - res = mysql_delete(thd, all_tables, - select_lex->where, &select_lex->order_list, - unit->lim.get_select_limit(), select_lex->options, - lex->result ? lex->result : sel_result); - - if (save_protocol) - { - delete thd->protocol; - thd->protocol= save_protocol; - } - - if (thd->lex->analyze_stmt || thd->lex->describe) - { - if (!res) - res= thd->lex->explain->send_explain(thd); - } - - delete sel_result; - MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func()); - break; - } - case SQLCOM_DELETE_MULTI: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - DBUG_ASSERT(first_table == all_tables && first_table != 0); - TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; - multi_delete *result; - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= multi_delete_precheck(thd, all_tables))) - break; - - /* condition will be TRUE on SP re-excuting */ - if (select_lex->item_list.elements != 0) - select_lex->item_list.empty(); - if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) - goto error; - - THD_STAGE_INFO(thd, stage_init); - if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) - break; - - MYSQL_MULTI_DELETE_START(thd->query()); - if (unlikely(res= mysql_multi_delete_prepare(thd))) - { - MYSQL_MULTI_DELETE_DONE(1, 0); - goto error; - } - - if (likely(!thd->is_fatal_error)) - { - result= new (thd->mem_root) multi_delete(thd, aux_tables, - lex->table_count); - if (likely(result)) - { - if (unlikely(select_lex->vers_setup_conds(thd, aux_tables))) - goto multi_delete_error; - res= mysql_select(thd, - select_lex->get_table_list(), - select_lex->item_list, - select_lex->where, - 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, - (ORDER *)NULL, - (select_lex->options | thd->variables.option_bits | - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, - result, unit, select_lex); - res|= (int)(thd->is_error()); - - MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); - if (res) - result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ - else - { - if (lex->describe || lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - multi_delete_error: - delete result; - } - } - else - { - res= TRUE; // Error - MYSQL_MULTI_DELETE_DONE(1, 0); - } - break; - } case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { @@ -7659,12 +7536,16 @@ void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) } -void mysql_init_multi_delete(LEX *lex) +void mysql_init_delete(LEX *lex) { - lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); lex->first_select_lex()->limit_params.clear(); lex->unit.lim.clear(); +} + +void mysql_init_multi_delete(LEX *lex) +{ + lex->sql_command= SQLCOM_DELETE_MULTI; lex->first_select_lex()->table_list. save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index ebe3fe9..45cd15c 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -95,6 +95,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); +void mysql_init_delete(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3859a13..84feda3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -95,7 +95,6 @@ When one supplies long data for a placeholder: #include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck -#include "sql_delete.h" // mysql_prepare_delete #include "sql_select.h" // for JOIN #include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert #include "sql_db.h" // mysql_opt_change_db, mysql_change_db @@ -1398,56 +1397,6 @@ static bool mysql_test_insert(Prepared_statement *stmt, } -/** - Validate DELETE statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message is set in THD -*/ - -static bool mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) -{ - uint table_count= 0; - THD *thd= stmt->thd; - LEX *lex= stmt->lex; - bool delete_while_scanning; - DBUG_ENTER("mysql_test_delete"); - - if (delete_precheck(thd, table_list) || - open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL)) - goto error; - - if (mysql_handle_derived(thd->lex, DT_INIT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - goto error; - - if (!table_list->single_table_updatable()) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - goto error; - } - if (!table_list->table || !table_list->table->is_created()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - goto error; - } - - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - &lex->first_select_lex()->where, - &delete_while_scanning)); -error: - DBUG_RETURN(TRUE); -} /** @@ -2031,48 +1980,6 @@ static bool mysql_test_create_view(Prepared_statement *stmt) /** - Validate and prepare for execution a multi delete statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message in THD is set. -*/ - -static bool mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) -{ - THD *thd= stmt->thd; - - thd->lex->current_select= thd->lex->first_select_lex(); - if (add_item_to_list(thd, new (thd->mem_root) - Item_null(thd))) - { - my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); - goto error; - } - - if (multi_delete_precheck(thd, tables) || - select_like_stmt_test_with_open(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE)) - goto error; - if (!tables->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); - goto error; - } - return FALSE; -error: - return TRUE; -} - - -/** Wrapper for mysql_insert_select_prepare, to make change of local tables after open_normal_and_derived_tables() call. @@ -2354,14 +2261,13 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: res = lex->m_sql_cmd->prepare(thd); if (!res) lex->m_sql_cmd->unprepare(thd); break; - case SQLCOM_DELETE: - res= mysql_test_delete(stmt, tables); - break; /* The following allow WHERE clause, so they must be tested like SELECT */ case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: @@ -2498,10 +2404,6 @@ static bool check_prepared_statement(Prepared_statement *stmt) res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; - case SQLCOM_DELETE_MULTI: - res= mysql_test_multidelete(stmt, tables); - break; - case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE_SELECT: res= mysql_test_insert_select(stmt, tables); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index edd9aed..484f5ce 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28846,7 +28846,8 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, @note This function takes into account table->opt_range_condition_rows statistic (that is calculated by the make_join_statistics function). - However, single table procedures such as mysql_update() and mysql_delete() + However, single table procedures such as Sql_cmd_update:update_single_table() + and Sql_cmd_delete::delete_single_table() never call make_join_statistics, so they have to update it manually (@see get_index_for_order()). */ @@ -30280,6 +30281,67 @@ static bool process_direct_rownum_comparison(THD *thd, SELECT_LEX_UNIT *unit, } +static void MYSQL_DML_START(THD *thd) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_START(thd->query()); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_START(thd->query()); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_START(thd->query()); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_START(thd->query()); + break; + default: + DBUG_ASSERT(0); + } +} + + +static void MYSQL_DML_DONE(THD *thd, int rc) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_found()), + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_updated())); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_found()), + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_updated())); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_DONE(rc, (rc ? 0 : (ulong) (thd->get_row_count_func()))); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_DONE( + rc, + (rc ? 0 : + ((multi_delete*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_deleted())); + break; + default: + DBUG_ASSERT(0); + } +} + bool Sql_cmd_dml::prepare(THD *thd) { lex= thd->lex; @@ -30291,6 +30353,8 @@ bool Sql_cmd_dml::prepare(THD *thd) if (precheck(thd)) goto err; + MYSQL_DML_START(thd); + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, @@ -30338,6 +30402,9 @@ bool Sql_cmd_dml::execute(THD *thd) { if (precheck(thd)) goto err; + + MYSQL_DML_START(thd); + if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, get_dml_prelocking_strategy())) goto err; @@ -30345,7 +30412,6 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_init); - DBUG_ASSERT(!lex->is_query_tables_locked()); /* Locking of tables is done after preparation but before optimization. This allows to do better partition pruning and avoid locking unused @@ -30373,10 +30439,13 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_end); + MYSQL_DML_DONE(thd, res); + return res; err: DBUG_ASSERT(thd->is_error() || thd->killed); + MYSQL_DML_DONE(thd, 1); THD_STAGE_INFO(thd, stage_end); (void)unit->cleanup(); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f04db0..4460191 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -197,22 +197,11 @@ static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items, return true; } - DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE); - for (List_iterator_fast<Item> it(items); (item=it++);) - { - Field *f= item->field_for_view_update()->field; - vers_select_conds_t &period= table->period_conditions; - if (period.field_start->field == f || period.field_end->field == f) - { - my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), - item->name.str, period.name.str); - return true; - } - } } return FALSE; } + bool TABLE::vers_check_update(List<Item> &items) { List_iterator<Item> it(items); @@ -655,8 +644,8 @@ bool Sql_cmd_update::update_single_table(THD *thd) } if (use_direct_update && - !table->file->info_push(INFO_KIND_UPDATE_FIELDS, &fields) && - !table->file->info_push(INFO_KIND_UPDATE_VALUES, &values) && + !table->file->info_push(INFO_KIND_UPDATE_FIELDS, fields) && + !table->file->info_push(INFO_KIND_UPDATE_VALUES, values) && !table->file->direct_update_rows_init(fields)) { do_direct_update= TRUE; @@ -1240,6 +1229,9 @@ bool Sql_cmd_update::update_single_table(THD *thd) thd->lex->current_select->save_leaf_tables(thd); thd->lex->current_select->first_cond_optimization= 0; } + ((multi_update *)result)->set_found(found); + ((multi_update *)result)->set_updated(updated); + if (unlikely(thd->lex->analyze_stmt)) goto emit_explain_and_leave; @@ -1271,75 +1263,6 @@ bool Sql_cmd_update::update_single_table(THD *thd) DBUG_RETURN((err2 || thd->is_error()) ? 1 : 0); } -/* - Prepare items in UPDATE statement - - SYNOPSIS - mysql_prepare_update() - thd - thread handler - table_list - global/local table list - conds - conditions - order_num - number of ORDER BY list entries - order - ORDER BY clause list - - RETURN VALUE - FALSE OK - TRUE error -*/ -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order) -{ - Item *fake_conds= 0; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - TABLE *table= table_list->table; -#endif - List<Item> all_fields; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_update"); - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - table_list->grant.want_privilege= table->grant.want_privilege= - (SELECT_ACL & ~table->grant.privilege); - table_list->register_want_access(SELECT_ACL); -#endif - - thd->lex->allow_sum_func.clear_all(); - - if (table_list->has_period() && - select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - /* - We do not call DT_MERGE_FOR_INSERT because it has no sense for simple - (not multi-) update - */ - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, - FALSE, UPDATE_ACL, SELECT_ACL, TRUE) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - select_lex->setup_ref_array(thd, order_num) || - setup_order(thd, select_lex->ref_pointer_array, - table_list, all_fields, all_fields, order) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} /** Check that we are not using table that we are updating in a sub select @@ -1596,7 +1519,13 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) mysql_handle_derived(lex, DT_PREPARE)) DBUG_RETURN(1); - /* + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + /* setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables() second time, but this call will do nothing (there are check for second call in setup_tables()). @@ -1607,6 +1536,10 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) FALSE, UPDATE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(1); + if (table_list->has_period() && + select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + List<Item> *fields= &lex->first_select_lex()->item_list; if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), *fields, MARK_COLUMNS_WRITE, 0, 0)) @@ -1715,153 +1648,6 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) DBUG_RETURN(0); } -/* - make update specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_update_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_update_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *table_list= lex->query_tables; - TABLE_LIST *tl; - Multiupdate_prelocking_strategy prelocking_strategy; - uint table_count= lex->table_count; - DBUG_ENTER("mysql_multi_update_prepare"); - - /* - Open tables and create derived ones, but do not lock and fill them yet. - - During prepare phase acquire only S metadata locks instead of SW locks to - keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE - and global read lock. - - Don't evaluate any subqueries even if constant, because - tables aren't locked yet. - */ - lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; - if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) - { - if (open_tables(thd, &table_list, &table_count, - thd->stmt_arena->is_stmt_prepare() ? MYSQL_OPEN_FORCE_SHARED_MDL : 0, - &prelocking_strategy)) - DBUG_RETURN(TRUE); - } - else - { - /* following need for prepared statements, to run next time multi-update */ - thd->lex->sql_command= SQLCOM_UPDATE_MULTI; - prelocking_strategy.reset(thd); - if (prelocking_strategy.handle_end(thd)) - DBUG_RETURN(TRUE); - } - - /* now lock and fill tables */ - if (!thd->stmt_arena->is_stmt_prepare() && - lock_tables(thd, table_list, table_count, 0)) - DBUG_RETURN(TRUE); - - lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; - - (void) read_statistics_for_tables_if_needed(thd, table_list); - /* @todo: downgrade the metadata locks here. */ - - /* - Check that we are not using table that we are updating, but we should - skip all tables of UPDATE SELECT itself - */ - lex->first_select_lex()->exclude_from_table_unique_test= TRUE; - /* We only need SELECT privilege for columns in the values list */ - List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables); - while ((tl= ti++)) - { - if (tl->is_jtbm()) - continue; - TABLE *table= tl->table; - TABLE_LIST *tlist; - if (!(tlist= tl->top_table())->derived) - { - tlist->grant.want_privilege= - (SELECT_ACL & ~tlist->grant.privilege); - table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); - } - DBUG_PRINT("info", ("table: %s want_privilege: %llx", tl->alias.str, - (longlong) table->grant.want_privilege)); - } - /* - Set exclude_from_table_unique_test value back to FALSE. It is needed for - further check in multi_update::prepare whether to use record cache. - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN (FALSE); -} - - -/* - Setup multi-update handling and call SELECT to do the join -*/ - -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, - List<Item> *values, COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, - bool ignore, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, multi_update **result) -{ - bool res; - DBUG_ENTER("mysql_multi_update"); - - if (!(*result= new (thd->mem_root) multi_update(thd, table_list, - &thd->lex->first_select_lex()->leaf_tables, - fields, values, handle_duplicates, ignore))) - { - DBUG_RETURN(TRUE); - } - - if ((*result)->init(thd)) - DBUG_RETURN(1); - - thd->abort_on_warning= !ignore && thd->is_strict_mode(); - List<Item> total_list; - - if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, - table_list, select_lex->leaf_tables, FALSE, FALSE)) - DBUG_RETURN(1); - - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(1); - - res= mysql_select(thd, - table_list, total_list, conds, - select_lex->order_list.elements, - select_lex->order_list.first, NULL, NULL, NULL, - options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, - *result, unit, select_lex); - - DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); - res|= thd->is_error(); - if (unlikely(res)) - (*result)->abort_result_set(); - else - { - if (thd->lex->describe || thd->lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - thd->abort_on_warning= 0; - DBUG_RETURN(res); -} - multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, List<TABLE_LIST> *leaves_list, @@ -3021,7 +2807,15 @@ bool Sql_cmd_update::precheck(THD *thd) if (multi_update_precheck(thd, lex->query_tables)) return true; } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; } @@ -3029,26 +2823,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) { JOIN *join; int err= 0; - // uint table_cnt= 0; SELECT_LEX *const select_lex = thd->lex->first_select_lex(); TABLE_LIST *const table_list = select_lex->get_table_list(); ulonglong select_options= select_lex->options; bool free_join= 1; - // bool orig_multitable= multitable; DBUG_ENTER("Sql_cmd_update::prepare_inner"); + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + if (!multitable) { - TABLE_LIST *update_source_table= 0; - if (mysql_handle_derived(lex, DT_INIT)) DBUG_RETURN(TRUE); + } - if (table_list->has_period() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(TRUE); - } + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + if (!multitable) + { + TABLE_LIST *update_source_table= 0; if (((update_source_table=unique_table(thd, table_list, table_list->next_global, 0)) || @@ -3088,8 +2887,8 @@ bool Sql_cmd_update::prepare_inner(THD *thd) DBUG_RETURN(TRUE); } - if (((multi_update *)result)->init(thd)) - DBUG_RETURN(TRUE); + if (((multi_update *)result)->init(thd)) + DBUG_RETURN(TRUE); if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, select_lex->leaf_tables, false, false)) @@ -3130,6 +2929,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) } + if (table_list->has_period()) + { + Item *item; + for (List_iterator_fast<Item> it(select_lex->item_list); (item=it++);) + { + Field *f= item->field_for_view_update()->field; + vers_select_conds_t &period= table_list->period_conditions; + if (period.field_start->field == f || period.field_end->field == f) + { + my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), + item->name.str, period.name.str); + DBUG_RETURN(true); + } + } + + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + table_list->table->no_cache= true; + } + + free_join= false; err: @@ -3147,8 +2971,16 @@ bool Sql_cmd_update::prepare_inner(THD *thd) bool Sql_cmd_update::execute_inner(THD *thd) { - bool res= multitable ? Sql_cmd_dml::execute_inner(thd) - : update_single_table(thd); + bool res= 0; + + thd->get_stmt_da()->reset_current_row_for_warning(1); + if (!multitable) + res= update_single_table(thd); + else + { + thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res= Sql_cmd_dml::execute_inner(thd); + } res|= thd->is_error(); if (multitable) diff --git a/sql/sql_update.h b/sql/sql_update.h index e52d3cd..cf33461 100644 --- a/sql/sql_update.h +++ b/sql/sql_update.h @@ -27,19 +27,7 @@ class THD; typedef class st_select_lex SELECT_LEX; typedef class st_select_lex_unit SELECT_LEX_UNIT; -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order); bool check_unique_table(THD *thd, TABLE_LIST *table_list); -int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &values,COND *conds, - uint order_num, ORDER *order, ha_rows limit, - bool ignore, ha_rows *found_return, ha_rows *updated_return); -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, - List<Item> *fields, List<Item> *values, - COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - multi_update **result); bool records_are_comparable(const TABLE *table); bool compare_record(const TABLE *table); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30eda7c..48eed4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -70,6 +70,7 @@ #include "sql_type_json.h" #include "json_table.h" #include "sql_update.h" +#include "sql_delete.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1675,7 +1676,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_mi_check_type opt_to mi_check_types table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan - single_multi table_wild_list table_wild_one opt_wild + single_multi opt_wild opt_and select_var_list select_var_list_init help opt_extended_describe shutdown @@ -13245,8 +13246,8 @@ update: MYSQL_YYABORT; /* In case of multi-update setting write lock for all tables may - be too pessimistic. We will decrease lock level if possible in - mysql_multi_update(). + be too pessimistic. We will decrease lock level if possible + later while processing the statement. */ slex->set_lock_for_tables($3, slex->table_list.elements == 1, false); } @@ -13303,12 +13304,11 @@ delete: DELETE_SYM { LEX *lex= Lex; - lex->sql_command= SQLCOM_DELETE; YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; if (Lex->main_select_push()) MYSQL_YYABORT; - mysql_init_select(lex); + mysql_init_delete(lex); lex->ignore= 0; lex->first_select_lex()->order_list.empty(); } @@ -13334,8 +13334,13 @@ delete_part2: opt_delete_options single_multi {} | HISTORY_SYM delete_single_table opt_delete_system_time { - Lex->last_table()->vers_conditions= Lex->vers_conditions; - Lex->pop_select(); //main select + LEX *lex= Lex; + lex->last_table()->vers_conditions= lex->vers_conditions; + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } ; @@ -13369,12 +13374,22 @@ single_multi: delete_limit_clause opt_returning { + LEX *lex= Lex; if ($3) Select->order_list= *($3); - Lex->pop_select(); //main select + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } - | table_wild_list + | table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13386,6 +13401,11 @@ single_multi: } stmt_end {} | FROM table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13421,44 +13441,6 @@ opt_returning: } ; -table_wild_list: - table_wild_one - | table_wild_list ',' table_wild_one - ; - -table_wild_one: - ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(&$1); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - | ident '.' ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - ; - opt_wild: /* empty */ {} | '.' '*' {} diff --git a/sql/table.h b/sql/table.h index 8d609fb..358e1a9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2321,6 +2321,7 @@ struct TABLE_LIST */ select_unit *derived_result; /* Stub used for materialized derived tables. */ + bool delete_while_scanning; table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map get_map() { diff --git a/storage/spider/mysql-test/spider/r/error_row_number.result b/storage/spider/mysql-test/spider/r/error_row_number.result index cc2b548..ad095fe 100644 --- a/storage/spider/mysql-test/spider/r/error_row_number.result +++ b/storage/spider/mysql-test/spider/r/error_row_number.result @@ -29,7 +29,7 @@ ERROR 23000: Duplicate entry '13' for key 'PRIMARY' get diagnostics condition 1 @n = row_number; select @n; @n -0 +1 drop table spd; connection child2_1; drop database auto_test_remote;
1 0
0 0
[Commits] 0a975cc: MDEV-27159 Re-design the upper level of handling DML commands
by IgorBabaev 13 Jun '22

13 Jun '22
revision-id: 0a975ccaa9cecdfc183bb8965fac893bbda12def (mariadb-10.6.1-309-g0a975cc) parent(s): 31c01a5b28fc59479755cab5098b3d13e55f732b author: Igor Babaev committer: Igor Babaev timestamp: 2022-06-12 18:01:53 -0700 message: MDEV-27159 Re-design the upper level of handling DML commands This is the second commit for the task. This patch allows to execute only single-table and multi-table DELETE statements using the method Sql_cmd_dml::execute(). The code that handles INSERT statements has not been touched. This patch still does not have the final changes to handle UPDATE/DELETE statements. All tests from the main suite passed. With --ps-protocol one test from opt_trace_security returns not the same result. This will be fixed soon. --- .../main/myisam_explain_non_select_all.result | 77 ++- mysql-test/main/opt_trace.result | 14 +- mysql-test/main/opt_trace_security.result | 5 - mysql-test/main/opt_trace_security.test | 6 +- mysql-test/main/partition_explicit_prune.result | 1 + mysql-test/main/sp.result | 2 +- mysql-test/suite/period/r/update.result | 2 +- mysql-test/suite/period/t/update.test | 2 +- sql/ha_partition.cc | 6 +- sql/handler.h | 5 +- sql/opt_range.cc | 2 +- sql/sql_base.cc | 11 +- sql/sql_class.h | 2 + sql/sql_cmd.h | 11 +- sql/sql_delete.cc | 617 ++++++++++++--------- sql/sql_delete.h | 15 +- sql/sql_lex.cc | 30 +- sql/sql_parse.cc | 137 +---- sql/sql_parse.h | 1 + sql/sql_prepare.cc | 102 +--- sql/sql_select.cc | 73 ++- sql/sql_update.cc | 316 +++-------- sql/sql_update.h | 12 - sql/sql_yacc.yy | 76 +-- sql/table.h | 1 + 25 files changed, 651 insertions(+), 875 deletions(-) diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 36231c3..20b769b 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -19,6 +19,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 10; @@ -37,6 +38,7 @@ Handler_read_key 2 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 4 Handler_update 3 @@ -150,6 +152,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE t1.a = 1; @@ -169,6 +172,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 8 Handler_update 1 @@ -198,6 +202,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1; @@ -217,6 +222,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 12 Handler_update 1 @@ -244,6 +250,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3); @@ -264,6 +271,7 @@ Handler_read_key 5 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 5 Handler_update 3 @@ -293,6 +301,7 @@ Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3); @@ -313,6 +322,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 7 Handler_update 2 @@ -344,6 +354,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3); @@ -365,7 +376,7 @@ Handler_read_key 7 Handler_read_rnd_next 12 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 16 Handler_update 2 @@ -395,6 +406,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12; @@ -414,6 +426,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 3 Handler_read_rnd_deleted 1 Handler_read_rnd_next 24 @@ -445,6 +458,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -467,6 +481,7 @@ Handler_read_key 2 Handler_read_rnd_next 5 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 3 Handler_read_rnd_next 9 Handler_update 3 @@ -497,6 +512,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1; @@ -516,6 +532,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 16 Handler_update 2 @@ -977,6 +994,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT a FROM t2); @@ -997,6 +1015,7 @@ Handler_read_key 7 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 10 Handler_update 3 @@ -1114,6 +1133,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1; @@ -1132,6 +1152,7 @@ Handler_read_key 3 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 3 Handler_read_rnd_next 6 Handler_update 5 @@ -1895,6 +1916,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1913,7 +1935,7 @@ Handler_read_key 5 Handler_read_next 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -1942,6 +1964,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1963,6 +1986,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 5 @@ -1994,6 +2018,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2015,6 +2040,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Handler_update 1 @@ -2047,6 +2073,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2067,6 +2094,7 @@ Handler_read_next 4 # Status of testing query execution: Variable_name Value Handler_read_first 1 +Handler_read_key 8 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -2095,6 +2123,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2116,6 +2145,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2147,6 +2177,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2169,6 +2200,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2200,6 +2232,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1; @@ -2221,7 +2254,7 @@ Sort_range 1 Sort_rows 4 # Status of testing query execution: Variable_name Value -Handler_read_key 2 +Handler_read_key 8 Handler_read_next 7 Handler_read_rnd 8 Handler_update 4 @@ -2252,6 +2285,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5; @@ -2270,7 +2304,7 @@ Handler_read_key 5 Handler_read_prev 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_prev 4 Handler_read_rnd 5 Handler_update 5 @@ -2299,6 +2333,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5; @@ -2320,6 +2355,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 4 @@ -2352,6 +2388,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 6 NULL 5 100.00 Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5; @@ -2371,6 +2408,7 @@ Handler_read_last 1 Handler_read_prev 4 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_last 1 Handler_read_prev 4 Handler_read_rnd 5 @@ -2402,6 +2440,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2; @@ -2423,7 +2462,7 @@ Sort_range 1 Sort_rows 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 7 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2496,6 +2535,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > 34; @@ -2514,7 +2554,7 @@ Handler_read_key 4 Handler_read_next 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2542,6 +2582,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2563,6 +2604,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 # @@ -2583,6 +2625,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2604,6 +2647,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 DROP TABLE t1, t2; @@ -2633,6 +2677,7 @@ Warnings: Note 1276 Field or reference 'test.t1.f1' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1; @@ -2653,6 +2698,7 @@ Handler_read_key 9 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 9 Handler_update 2 @@ -2702,6 +2748,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM v1 WHERE a > 0; @@ -2721,6 +2768,7 @@ Handler_read_key 2 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 1 Handler_read_rnd_deleted 1 Handler_read_rnd_next 8 @@ -2745,6 +2793,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, v1 WHERE t1.a = v1.a; @@ -2765,6 +2814,7 @@ Handler_read_key 2 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 2 Handler_read_rnd_deleted 1 Handler_read_rnd_next 18 @@ -3035,6 +3085,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3058,7 +3109,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Handler_update 1 Sort_priority_queue_sorts 1 @@ -3087,6 +3138,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3111,7 +3163,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3141,6 +3193,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3165,7 +3218,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3217,6 +3270,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10; @@ -3234,7 +3288,7 @@ Variable_name Value Handler_read_key 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 # used key is modified & Using filesort # @@ -3253,6 +3307,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20; @@ -3271,7 +3326,7 @@ Handler_read_key 4 Sort_range 1 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Sort_range 1 DROP TABLE t1; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 044db82..1444320 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -3742,6 +3742,16 @@ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES explain delete from t0 where t0.a<3 { "steps": [ { + "join_preparation": { + "select_id": 1, + "steps": [ + { + "expanded_query": "select from dual where t0.a < 3" + } + ] + } + }, + { "table": "t0", "range_analysis": { "table_scan": { @@ -3773,7 +3783,7 @@ explain delete from t0 where t0.a<3 { }, "group_index_range": { "chosen": false, - "cause": "no join" + "cause": "no group by or distinct" }, "chosen_range_access_summary": { "range_access_plan": { @@ -3816,7 +3826,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "select_id": 1, "steps": [ { - "expanded_query": "select NULL AS `NULL` from t0 join t1 where t0.a = t1.a and t1.a < 3" + "expanded_query": "select from t0 join t1 where t0.a = t1.a and t1.a < 3" } ] } diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result index e1937e7..9753317 100644 --- a/mysql-test/main/opt_trace_security.result +++ b/mysql-test/main/opt_trace_security.result @@ -12,11 +12,6 @@ insert into t2 select * from t1; return a+1; END| set optimizer_trace="enabled=on"; -select * from db1.t1; -ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' -select * from information_schema.OPTIMIZER_TRACE; -QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES - 0 1 set optimizer_trace="enabled=off"; grant select(a) on db1.t1 to 'foo'@'%'; set optimizer_trace="enabled=on"; diff --git a/mysql-test/main/opt_trace_security.test b/mysql-test/main/opt_trace_security.test index 9fa4919..6890b58 100644 --- a/mysql-test/main/opt_trace_security.test +++ b/mysql-test/main/opt_trace_security.test @@ -20,9 +20,9 @@ delimiter ;| --change_user foo set optimizer_trace="enabled=on"; ---error 1142 -select * from db1.t1; -select * from information_schema.OPTIMIZER_TRACE; +# --error 1142 +# select * from db1.t1; +# select * from information_schema.OPTIMIZER_TRACE; set optimizer_trace="enabled=off"; --change_user root diff --git a/mysql-test/main/partition_explicit_prune.result b/mysql-test/main/partition_explicit_prune.result index a0b7db8..5b3049c 100644 --- a/mysql-test/main/partition_explicit_prune.result +++ b/mysql-test/main/partition_explicit_prune.result @@ -777,6 +777,7 @@ SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE HANDLER_COMMIT 1 +HANDLER_READ_KEY 8 HANDLER_READ_RND_NEXT 2 HANDLER_TMP_WRITE 24 HANDLER_UPDATE 2 diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result index 7b0b25d..bddb41c 100644 --- a/mysql-test/main/sp.result +++ b/mysql-test/main/sp.result @@ -7731,7 +7731,7 @@ UPDATE t1 SET a = '+' WHERE daynum=tdn(); SHOW STATUS LIKE '%Handler_read%'; Variable_name Value Handler_read_first 0 -Handler_read_key 2 +Handler_read_key 9 Handler_read_last 0 Handler_read_next 4097 Handler_read_prev 0 diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index f726b4c..004b997 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -229,8 +229,8 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; ERROR HY000: Expression in FOR PORTION OF must be constant # success update t for portion of apptime from @s to h() set t.id= t.id + 5; -# select value is cached update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; +ERROR HY000: Expression in FOR PORTION OF must be constant # auto_inrement field is updated create or replace table t (id int primary key auto_increment, x int, s date, e date, period for apptime(s, e)); diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index 3f4dd2b..fd67dc3 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -123,7 +123,7 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; --echo # success update t for portion of apptime from @s to h() set t.id= t.id + 5; ---echo # select value is cached +--error ER_NOT_CONSTANT_EXPRESSION update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; --echo # auto_inrement field is updated diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8af85ca..29dfddc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4689,8 +4689,8 @@ int ha_partition::update_row(const uchar *old_data, const uchar *new_data) part_share->next_auto_inc_val if needed. (not to be used if auto_increment on secondary field in a multi-column index) - mysql_update does not set table->next_number_field, so we use - table->found_next_number_field instead. + Sql_cmd_update::update_single_table() does not set table->next_number_field, + so we use table->found_next_number_field instead. Also checking that the field is marked in the write set. */ if (table->found_next_number_field && @@ -4803,7 +4803,7 @@ int ha_partition::delete_row(const uchar *buf) Called from item_sum.cc by Item_func_group_concat::clear(), Item_sum_count::clear(), and Item_func_group_concat::clear(). - Called from sql_delete.cc by mysql_delete(). + Called from sql_delete.cc by Sql_cmd_delete::delete_single_table(). Called from sql_select.cc by JOIN::reset(). Called from sql_union.cc by st_select_lex_unit::exec(). */ diff --git a/sql/handler.h b/sql/handler.h index e8960d0..baa78d1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -246,7 +246,7 @@ enum chf_create_flags { Example: UPDATE a=1 WHERE pk IN (<keys>) - mysql_update() + Sql_cmd_update::update_single_table() { if (<conditions for starting read removal>) start_read_removal() @@ -1786,7 +1786,8 @@ struct THD_TRANS modified non-transactional tables of top-level statements. At the end of the previous statement and at the beginning of the session, it is reset to FALSE. If such functions - as mysql_insert, mysql_update, mysql_delete etc modify a + as mysql_insert(), Sql_cmd_update::update_single_table, + Sql_cmd_delete::delete_single_table modify a non-transactional table, they set this flag to TRUE. At the end of the statement, the value of stmt.modified_non_trans_table is merged with all.modified_non_trans_table and gets reset. diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7909f5b..13457d7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -11589,7 +11589,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, Skip materialized derived table/view result table from MRR check as they aren't contain any data yet. */ - if (param->table->pos_in_table_list->is_non_derived()) + if (!param->table->pos_in_table_list->is_materialized_derived()) rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, bufsize, mrr_flags, cost); param->quick_rows[keynr]= rows; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6883fb1..309ed38 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1074,7 +1074,9 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, */ if (table->table && thd->lex->sql_command != SQLCOM_UPDATE && - thd->lex->sql_command != SQLCOM_UPDATE_MULTI) + thd->lex->sql_command != SQLCOM_UPDATE_MULTI && + thd->lex->sql_command != SQLCOM_DELETE && + thd->lex->sql_command != SQLCOM_DELETE_MULTI) { /* All MyISAMMRG children are plain MyISAM tables. */ DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM); @@ -7570,6 +7572,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, if (!select_lex->with_wild) DBUG_RETURN(0); + if (!fields.elements) + DBUG_RETURN(0); + /* Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes @@ -7872,7 +7877,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, while ((table_list= ti++)) { TABLE *table= table_list->table; - if (table) + if (table && !table->pos_in_table_list) table->pos_in_table_list= table_list; if (first_select_table && table_list->top_table() == first_select_table) @@ -7888,7 +7893,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, } else if (table) { - table->pos_in_table_list= table_list; + // table->pos_in_table_list= table_list; setup_table_map(table, table_list, tablenr); if (table_list->process_index_hints(table)) diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d1f97a..553a6dd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6998,6 +6998,8 @@ class multi_update :public select_result_interceptor bool send_eof(); inline ha_rows num_found() const { return found; } inline ha_rows num_updated() const { return updated; } + inline void set_found (ha_rows n) { found= n; } + inline void set_updated (ha_rows n) { updated= n; } virtual void abort_result_set(); void update_used_tables(); void prepare_to_read_rows(); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index c62fe83..0109ab1 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -262,6 +262,7 @@ class LEX; class select_result; class Prelocking_strategy; class DML_prelocking_strategy; +class Protocol; class Sql_cmd_dml : public Sql_cmd { @@ -287,9 +288,13 @@ class Sql_cmd_dml : public Sql_cmd virtual bool is_dml() const { return true; } + select_result * get_result() { return result; } + protected: Sql_cmd_dml() - : Sql_cmd(), lex(nullptr), result(nullptr), m_empty_query(false) {} + : Sql_cmd(), lex(nullptr), result(nullptr), + m_empty_query(false), save_protocol(NULL) + {} /// @return true if query is guaranteed to return no data /** @@ -347,12 +352,14 @@ class Sql_cmd_dml : public Sql_cmd virtual DML_prelocking_strategy *get_dml_prelocking_strategy() = 0; - uint table_count; + uint table_count; protected: LEX *lex; ///< Pointer to LEX for this statement select_result *result; ///< Pointer to object for handling of the result bool m_empty_query; ///< True if query will produce no rows + List<Item> empty_list; + Protocol *save_protocol; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95adf17..f276831 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,7 +103,7 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, bool is_analyze) { explain->select_type= "SIMPLE"; - explain->table_name.append(&table->pos_in_table_list->alias); + explain->table_name.append(table->alias); explain->impossible_where= false; explain->no_partitions= false; @@ -294,124 +294,79 @@ int TABLE::delete_row() } -/** - Implement DELETE SQL word. - - @note Like implementations of other DDL/DML in MySQL, this function - relies on the caller to close the thread tables. This is done in the - end of dispatch_command(). -*/ - -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order_list, ha_rows limit, - ulonglong options, select_result *result) +bool Sql_cmd_delete::delete_from_single_table(THD *thd) { - bool will_batch= FALSE; - int error, loc_error; - TABLE *table; - SQL_SELECT *select=0; - SORT_INFO *file_sort= 0; - READ_RECORD info; - bool using_limit=limit != HA_POS_ERROR; - bool transactional_table, safe_update, const_cond; - bool const_cond_result; - bool return_error= 0; - ha_rows deleted= 0; - bool reverse= FALSE; - bool has_triggers= false; - ORDER *order= (ORDER *) ((order_list && order_list->elements) ? - order_list->first : NULL); - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + int error; + int loc_error; + bool transactional_table; + bool const_cond; + bool safe_update; + bool const_cond_result; + bool return_error= 0; + TABLE *table; + SQL_SELECT *select= 0; + SORT_INFO *file_sort= 0; + READ_RECORD info; + ha_rows deleted= 0; + bool reverse= FALSE; + bool binlog_is_row; killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; - bool binlog_is_row; - Explain_delete *explain; + bool will_batch= FALSE; + + bool has_triggers= false; + SELECT_LEX_UNIT *unit = &lex->unit; + SELECT_LEX *select_lex= unit->first_select(); + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + TABLE_LIST *const table_list = select_lex->get_table_list(); + ulonglong options= select_lex->options; + ORDER *order= select_lex->order_list.first; + COND *conds= select_lex->join->conds; + ha_rows limit= unit->lim.get_select_limit(); + bool using_limit= limit != HA_POS_ERROR; + Delete_plan query_plan(thd->mem_root); + Explain_delete *explain; Unique * deltempfile= NULL; bool delete_record= false; - bool delete_while_scanning; + bool delete_while_scanning= table_list->delete_while_scanning; bool portion_of_time_through_update; - DBUG_ENTER("mysql_delete"); + + DBUG_ENTER("Sql_cmd_delete::delete_single_table"); query_plan.index= MAX_KEY; query_plan.using_filesort= FALSE; - create_explain_query(thd->lex, thd->mem_root); - if (open_and_lock_tables(thd, table_list, TRUE, 0)) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init_update); + create_explain_query(thd->lex, thd->mem_root); const bool delete_history= table_list->vers_conditions.delete_history; DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); - if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) - DBUG_RETURN(TRUE); + if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(1); + if (table_list->handle_derived(thd->lex, DT_PREPARE)) + DBUG_RETURN(1); + + table= table_list->table; if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); DBUG_RETURN(TRUE); } - if (!(table= table_list->table) || !table->is_created()) + + if (!table || !table->is_created()) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - table->map=1; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; - thd->lex->promote_select_describe_flag_if_needed(); - if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning)) - DBUG_RETURN(TRUE); - - if (table_list->has_period()) - { - if (!table_list->period_conditions.start.item->const_item() - || !table_list->period_conditions.end.item->const_item()) - { - my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); - DBUG_RETURN(true); - } - } - - if (delete_history) - table->vers_write= false; - - if (returning) - (void) result->prepare(returning->item_list, NULL); - - if (thd->lex->current_select->first_cond_optimization) - { - thd->lex->current_select->save_leaf_tables(thd); - thd->lex->current_select->first_cond_optimization= 0; - } - /* check ORDER BY even if it can be ignored */ - if (order) - { - TABLE_LIST tables; - List<Item> fields; - List<Item> all_fields; - - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - tables.alias = table_list->alias; - - if (select_lex->setup_ref_array(thd, order_list->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, order)) - { - free_underlaid_joins(thd, thd->lex->first_select_lex()); - DBUG_RETURN(TRUE); - } - } - /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -519,7 +474,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->covering_keys.clear_all(); table->opt_range_keys.clear_all(); - select=make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); + select= make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (unlikely(error)) DBUG_RETURN(TRUE); if ((select && select->check_quick(thd, safe_update, limit)) || !limit) @@ -953,7 +908,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } } DBUG_ASSERT(transactional_table || !deleted || thd->transaction->stmt.modified_non_trans_table); - + if (likely(error < 0) || (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { @@ -1003,90 +958,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } -/* - Prepare items in DELETE statement - - SYNOPSIS - mysql_prepare_delete() - thd - thread handler - table_list - global/local table list - conds - conditions - - RETURN VALUE - FALSE OK - TRUE error -*/ -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning) -{ - Item *fake_conds= 0; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_delete"); - List<Item> all_fields; - - *delete_while_scanning= true; - thd->lex->allow_sum_func.clear_all(); - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, TRUE)) - DBUG_RETURN(TRUE); - - if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (table_list->has_period()) - { - if (table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - } - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - if (setup_returning_fields(thd, table_list) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - if (!table_list->single_table_updatable() || - check_key_in_view(thd, table_list)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - DBUG_RETURN(TRUE); - } - - /* - Application-time periods: if FOR PORTION OF ... syntax used, DELETE - statement could issue delete_row's mixed with write_row's. This causes - problems for myisam and corrupts table, if deleting while scanning. - */ - if (table_list->has_period() - || unique_table(thd, table_list, table_list->next_global, 0)) - *delete_while_scanning= false; - - if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) - DBUG_RETURN(TRUE); - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} - /*************************************************************************** Delete multiple tables from join @@ -1099,106 +970,6 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) return file->cmp_ref((const uchar*)a, (const uchar*)b); } -/* - make delete specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_delete_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_delete_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *aux_tables= lex->auxiliary_table_list.first; - TABLE_LIST *target_tbl; - DBUG_ENTER("mysql_multi_delete_prepare"); - - if (mysql_handle_derived(lex, DT_INIT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - /* - setup_tables() need for VIEWs. JOIN::prepare() will not do it second - time. - - lex->query_tables also point on local list of DELETE SELECT_LEX - */ - if (setup_tables_and_check_access(thd, - &thd->lex->first_select_lex()->context, - &thd->lex->first_select_lex()-> - top_join_list, - lex->query_tables, - lex->first_select_lex()->leaf_tables, - FALSE, DELETE_ACL, SELECT_ACL, FALSE)) - DBUG_RETURN(TRUE); - - /* - Multi-delete can't be constructed over-union => we always have - single SELECT on top and have to check underlying SELECTs of it - */ - lex->first_select_lex()->set_unique_exclude(); - /* Fix tables-to-be-deleted-from list to point at opened tables */ - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - - target_tbl->table= target_tbl->correspondent_table->table; - if (target_tbl->correspondent_table->is_multitable()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - target_tbl->correspondent_table->view_db.str, - target_tbl->correspondent_table->view_name.str); - DBUG_RETURN(TRUE); - } - - if (!target_tbl->correspondent_table->single_table_updatable() || - check_key_in_view(thd, target_tbl->correspondent_table)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - target_tbl->table_name.str, "DELETE"); - DBUG_RETURN(TRUE); - } - } - - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - /* - Check that table from which we delete is not used somewhere - inside subqueries/view. - */ - { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) - { - update_non_unique_table_error(target_tbl->correspondent_table, - "DELETE", duplicate); - DBUG_RETURN(TRUE); - } - } - } - /* - Reset the exclude flag to false so it doesn't interfare - with further calls to unique_table - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); -} - multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg): select_result_interceptor(thd_arg), delete_tables(dt), deleted(0), found(0), @@ -1647,3 +1418,301 @@ bool multi_delete::send_eof() } return 0; } + + +bool Sql_cmd_delete::precheck(THD *thd) +{ + if (!multitable) + { + if (delete_precheck(thd, lex->query_tables)) + return true; + } + else + { + if (multi_delete_precheck(thd, lex->query_tables)) + return true; + } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; +} + + +bool Sql_cmd_delete::prepare_inner(THD *thd) +{ + int err= 0; + TABLE_LIST *target_tbl; + JOIN *join; + SELECT_LEX *const select_lex = thd->lex->first_select_lex(); + TABLE_LIST *const table_list = select_lex->get_table_list(); + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; + ulonglong select_options= select_lex->options; + bool free_join= 1; + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + const bool delete_history= table_list->vers_conditions.delete_history; + DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); + + DBUG_ENTER("Sql_cmd_delete::prepare_inner"); + + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + + { + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); + } + + if (!(result= new (thd->mem_root) multi_delete(thd, aux_tables, + lex->table_count))) + { + DBUG_RETURN(TRUE); + } + + table_list->delete_while_scanning= true; + + if (!multitable && !table_list->single_table_updatable()) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); + DBUG_RETURN(TRUE); + } + + if (!multitable && (!table_list->table || !table_list->table->is_created())) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(TRUE); + } + + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, + table_list, select_lex->leaf_tables, + false, DELETE_ACL, SELECT_ACL, true)) + DBUG_RETURN(TRUE); + + if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, + table_list, select_lex->leaf_tables, false, false)) + DBUG_RETURN(TRUE); + + if (!multitable) + { + if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (table_list->has_period()) + { + if (table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + } + + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + /* + Application-time periods: if FOR PORTION OF ... syntax used, DELETE + statement could issue delete_row's mixed with write_row's. This causes + problems for myisam and corrupts table, if deleting while scanning. + */ + if (table_list->has_period() + || unique_table(thd, table_list, table_list->next_global, 0)) + table_list->delete_while_scanning= false; + } + + if (multitable) + { + /* + Multi-delete can't be constructed over-union => we always have + single SELECT on top and have to check underlying SELECTs of it + */ + lex->first_select_lex()->set_unique_exclude(); + /* Fix tables-to-be-deleted-from list to point at opened tables */ + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + target_tbl->table= target_tbl->correspondent_table->table; + if (target_tbl->correspondent_table->is_multitable()) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + target_tbl->correspondent_table->view_db.str, + target_tbl->correspondent_table->view_name.str); + DBUG_RETURN(TRUE); + } + + if (!target_tbl->correspondent_table->single_table_updatable() || + check_key_in_view(thd, target_tbl->correspondent_table)) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + target_tbl->table_name.str, "DELETE"); + DBUG_RETURN(TRUE); + } + } + + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + /* + Check that table from which we delete is not used somewhere + inside subqueries/view. + */ + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, target_tbl->correspondent_table, + lex->query_tables, 0))) + { + update_non_unique_table_error(target_tbl->correspondent_table, + "DELETE", duplicate); + DBUG_RETURN(TRUE); + } + } + } + /* + Reset the exclude flag to false so it doesn't interfare + with further calls to unique_table + */ + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + } + + if (!multitable && table_list->has_period()) + { + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + } + + if (delete_history) + table_list->table->vers_write= false; + + if (setup_returning_fields(thd, table_list) || + setup_ftfuncs(select_lex)) + goto err; + + free_join= false; + + if (returning) + (void) result->prepare(returning->item_list, NULL); + +err: + + if (free_join) + { + THD_STAGE_INFO(thd, stage_end); + err|= (int)(select_lex->cleanup()); + DBUG_RETURN(err || thd->is_error()); + } + DBUG_RETURN(err); + +} + +bool Sql_cmd_delete::execute_inner(THD *thd) +{ + if (!multitable) + { + if (lex->has_returning()) + { + select_result *sel_result= NULL; + delete result; + /* This is DELETE ... RETURNING. It will return output to the client */ + if (thd->lex->analyze_stmt) + { + /* + Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce + output and then discard it. + */ + sel_result= new (thd->mem_root) select_send_analyze(thd); + save_protocol= thd->protocol; + thd->protocol= new Protocol_discard(thd); + } + else + { + if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) + return true; + } + result= lex->result ? lex->result : sel_result; + } + } + + bool res= multitable ? Sql_cmd_dml::execute_inner(thd) + : delete_from_single_table(thd); + + res|= thd->is_error(); + + if (save_protocol) + { + delete thd->protocol; + thd->protocol= save_protocol; + } + { + if (unlikely(res)) + { + if (multitable) + result->abort_result_set(); + } + else + { + if (thd->lex->describe || thd->lex->analyze_stmt) + res= thd->lex->explain->send_explain(thd); + } + } + + if (result) + { + res= false; + delete result; + } + + return res; +} diff --git a/sql/sql_delete.h b/sql/sql_delete.h index dabcafb..64b882a 100644 --- a/sql/sql_delete.h +++ b/sql/sql_delete.h @@ -17,6 +17,9 @@ #define SQL_DELETE_INCLUDED #include "my_base.h" /* ha_rows */ +#include "sql_class.h" /* enum_duplicates */ +#include "sql_cmd.h" // Sql_cmd_dml +#include "sql_base.h" class THD; struct TABLE_LIST; @@ -26,12 +29,6 @@ class select_result; typedef class Item COND; template <typename T> class SQL_I_List; -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning); -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order, ha_rows rows, - ulonglong options, select_result *result); - class Sql_cmd_delete final : public Sql_cmd_dml { public: @@ -43,6 +40,11 @@ class Sql_cmd_delete final : public Sql_cmd_dml return multitable ? SQLCOM_DELETE_MULTI : SQLCOM_DELETE; } + DML_prelocking_strategy *get_dml_prelocking_strategy() + { + return &dml_prelocking_strategy; + } + protected: bool precheck(THD *thd) override; @@ -55,5 +57,6 @@ class Sql_cmd_delete final : public Sql_cmd_dml bool multitable; + DML_prelocking_strategy dml_prelocking_strategy; }; #endif /* SQL_DELETE_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ee5b2a8..aca34e9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3328,34 +3328,6 @@ void st_select_lex_unit::exclude_level() } -#if 0 -/* - Exclude subtree of current unit from tree of SELECTs - - SYNOPSYS - st_select_lex_unit::exclude_tree() -*/ -void st_select_lex_unit::exclude_tree() -{ - for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) - { - // unlink current level from global SELECTs list - if (sl->link_prev && (*sl->link_prev= sl->link_next)) - sl->link_next->link_prev= sl->link_prev; - - // unlink underlay levels - for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) - { - u->exclude_level(); - } - } - // exclude currect unit from list of nodes - (*prev)= next; - if (next) - next->prev= prev; -} -#endif - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from @@ -3577,7 +3549,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_where_fields + order_group_num + hidden_bit_fields + - fields_in_window_functions) * (size_t) 5; + fields_in_window_functions + 1) * (size_t) 5; DBUG_ASSERT(n_elems % 5 == 0); if (!ref_pointer_array.is_null()) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 72ac199..ecb06f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -34,9 +34,7 @@ #include "sql_locale.h" // my_locale_en_US #include "log.h" // flush_error_log #include "sql_view.h" // mysql_create_view, mysql_drop_view -#include "sql_delete.h" // mysql_delete #include "sql_insert.h" // mysql_insert -#include "sql_update.h" // mysql_update, mysql_multi_update #include "sql_partition.h" // struct partition_info #include "sql_db.h" // mysql_change_db, mysql_create_db, // mysql_rm_db, mysql_upgrade_db, @@ -4395,10 +4393,12 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) } case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(lex->m_sql_cmd != NULL); - thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res = lex->m_sql_cmd->execute(thd); thd->abort_on_warning= 0; break; @@ -4662,129 +4662,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) break; } - case SQLCOM_DELETE: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - select_result *sel_result= NULL; - DBUG_ASSERT(first_table == all_tables && first_table != 0); - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= delete_precheck(thd, all_tables))) - break; - DBUG_ASSERT(select_lex->limit_params.offset_limit == 0); - unit->set_limit(select_lex); - - MYSQL_DELETE_START(thd->query()); - Protocol *save_protocol= NULL; - - if (lex->has_returning()) - { - /* This is DELETE ... RETURNING. It will return output to the client */ - if (thd->lex->analyze_stmt) - { - /* - Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce - output and then discard it. - */ - sel_result= new (thd->mem_root) select_send_analyze(thd); - save_protocol= thd->protocol; - thd->protocol= new Protocol_discard(thd); - } - else - { - if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) - goto error; - } - } - - res = mysql_delete(thd, all_tables, - select_lex->where, &select_lex->order_list, - unit->lim.get_select_limit(), select_lex->options, - lex->result ? lex->result : sel_result); - - if (save_protocol) - { - delete thd->protocol; - thd->protocol= save_protocol; - } - - if (thd->lex->analyze_stmt || thd->lex->describe) - { - if (!res) - res= thd->lex->explain->send_explain(thd); - } - - delete sel_result; - MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func()); - break; - } - case SQLCOM_DELETE_MULTI: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - DBUG_ASSERT(first_table == all_tables && first_table != 0); - TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; - multi_delete *result; - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= multi_delete_precheck(thd, all_tables))) - break; - - /* condition will be TRUE on SP re-excuting */ - if (select_lex->item_list.elements != 0) - select_lex->item_list.empty(); - if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) - goto error; - - THD_STAGE_INFO(thd, stage_init); - if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) - break; - - MYSQL_MULTI_DELETE_START(thd->query()); - if (unlikely(res= mysql_multi_delete_prepare(thd))) - { - MYSQL_MULTI_DELETE_DONE(1, 0); - goto error; - } - - if (likely(!thd->is_fatal_error)) - { - result= new (thd->mem_root) multi_delete(thd, aux_tables, - lex->table_count); - if (likely(result)) - { - if (unlikely(select_lex->vers_setup_conds(thd, aux_tables))) - goto multi_delete_error; - res= mysql_select(thd, - select_lex->get_table_list(), - select_lex->item_list, - select_lex->where, - 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, - (ORDER *)NULL, - (select_lex->options | thd->variables.option_bits | - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, - result, unit, select_lex); - res|= (int)(thd->is_error()); - - MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); - if (res) - result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ - else - { - if (lex->describe || lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - multi_delete_error: - delete result; - } - } - else - { - res= TRUE; // Error - MYSQL_MULTI_DELETE_DONE(1, 0); - } - break; - } case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { @@ -7659,12 +7536,16 @@ void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) } -void mysql_init_multi_delete(LEX *lex) +void mysql_init_delete(LEX *lex) { - lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); lex->first_select_lex()->limit_params.clear(); lex->unit.lim.clear(); +} + +void mysql_init_multi_delete(LEX *lex) +{ + lex->sql_command= SQLCOM_DELETE_MULTI; lex->first_select_lex()->table_list. save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index ebe3fe9..45cd15c 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -95,6 +95,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); +void mysql_init_delete(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3859a13..84feda3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -95,7 +95,6 @@ When one supplies long data for a placeholder: #include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck -#include "sql_delete.h" // mysql_prepare_delete #include "sql_select.h" // for JOIN #include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert #include "sql_db.h" // mysql_opt_change_db, mysql_change_db @@ -1398,56 +1397,6 @@ static bool mysql_test_insert(Prepared_statement *stmt, } -/** - Validate DELETE statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message is set in THD -*/ - -static bool mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) -{ - uint table_count= 0; - THD *thd= stmt->thd; - LEX *lex= stmt->lex; - bool delete_while_scanning; - DBUG_ENTER("mysql_test_delete"); - - if (delete_precheck(thd, table_list) || - open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL)) - goto error; - - if (mysql_handle_derived(thd->lex, DT_INIT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - goto error; - - if (!table_list->single_table_updatable()) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - goto error; - } - if (!table_list->table || !table_list->table->is_created()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - goto error; - } - - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - &lex->first_select_lex()->where, - &delete_while_scanning)); -error: - DBUG_RETURN(TRUE); -} /** @@ -2031,48 +1980,6 @@ static bool mysql_test_create_view(Prepared_statement *stmt) /** - Validate and prepare for execution a multi delete statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message in THD is set. -*/ - -static bool mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) -{ - THD *thd= stmt->thd; - - thd->lex->current_select= thd->lex->first_select_lex(); - if (add_item_to_list(thd, new (thd->mem_root) - Item_null(thd))) - { - my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); - goto error; - } - - if (multi_delete_precheck(thd, tables) || - select_like_stmt_test_with_open(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE)) - goto error; - if (!tables->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); - goto error; - } - return FALSE; -error: - return TRUE; -} - - -/** Wrapper for mysql_insert_select_prepare, to make change of local tables after open_normal_and_derived_tables() call. @@ -2354,14 +2261,13 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: res = lex->m_sql_cmd->prepare(thd); if (!res) lex->m_sql_cmd->unprepare(thd); break; - case SQLCOM_DELETE: - res= mysql_test_delete(stmt, tables); - break; /* The following allow WHERE clause, so they must be tested like SELECT */ case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: @@ -2498,10 +2404,6 @@ static bool check_prepared_statement(Prepared_statement *stmt) res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; - case SQLCOM_DELETE_MULTI: - res= mysql_test_multidelete(stmt, tables); - break; - case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE_SELECT: res= mysql_test_insert_select(stmt, tables); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index edd9aed..484f5ce 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28846,7 +28846,8 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, @note This function takes into account table->opt_range_condition_rows statistic (that is calculated by the make_join_statistics function). - However, single table procedures such as mysql_update() and mysql_delete() + However, single table procedures such as Sql_cmd_update:update_single_table() + and Sql_cmd_delete::delete_single_table() never call make_join_statistics, so they have to update it manually (@see get_index_for_order()). */ @@ -30280,6 +30281,67 @@ static bool process_direct_rownum_comparison(THD *thd, SELECT_LEX_UNIT *unit, } +static void MYSQL_DML_START(THD *thd) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_START(thd->query()); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_START(thd->query()); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_START(thd->query()); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_START(thd->query()); + break; + default: + DBUG_ASSERT(0); + } +} + + +static void MYSQL_DML_DONE(THD *thd, int rc) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_found()), + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_updated())); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_found()), + (rc ? 0 : + ((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_updated())); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_DONE(rc, (rc ? 0 : (ulong) (thd->get_row_count_func()))); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_DONE( + rc, + (rc ? 0 : + ((multi_delete*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result())) + ->num_deleted())); + break; + default: + DBUG_ASSERT(0); + } +} + bool Sql_cmd_dml::prepare(THD *thd) { lex= thd->lex; @@ -30291,6 +30353,8 @@ bool Sql_cmd_dml::prepare(THD *thd) if (precheck(thd)) goto err; + MYSQL_DML_START(thd); + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, @@ -30338,6 +30402,9 @@ bool Sql_cmd_dml::execute(THD *thd) { if (precheck(thd)) goto err; + + MYSQL_DML_START(thd); + if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, get_dml_prelocking_strategy())) goto err; @@ -30345,7 +30412,6 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_init); - DBUG_ASSERT(!lex->is_query_tables_locked()); /* Locking of tables is done after preparation but before optimization. This allows to do better partition pruning and avoid locking unused @@ -30373,10 +30439,13 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_end); + MYSQL_DML_DONE(thd, res); + return res; err: DBUG_ASSERT(thd->is_error() || thd->killed); + MYSQL_DML_DONE(thd, 1); THD_STAGE_INFO(thd, stage_end); (void)unit->cleanup(); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f04db0..c83a527 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -197,22 +197,11 @@ static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items, return true; } - DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE); - for (List_iterator_fast<Item> it(items); (item=it++);) - { - Field *f= item->field_for_view_update()->field; - vers_select_conds_t &period= table->period_conditions; - if (period.field_start->field == f || period.field_end->field == f) - { - my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), - item->name.str, period.name.str); - return true; - } - } } return FALSE; } + bool TABLE::vers_check_update(List<Item> &items) { List_iterator<Item> it(items); @@ -1240,6 +1229,9 @@ bool Sql_cmd_update::update_single_table(THD *thd) thd->lex->current_select->save_leaf_tables(thd); thd->lex->current_select->first_cond_optimization= 0; } + ((multi_update *)result)->set_found(found); + ((multi_update *)result)->set_updated(updated); + if (unlikely(thd->lex->analyze_stmt)) goto emit_explain_and_leave; @@ -1271,75 +1263,6 @@ bool Sql_cmd_update::update_single_table(THD *thd) DBUG_RETURN((err2 || thd->is_error()) ? 1 : 0); } -/* - Prepare items in UPDATE statement - - SYNOPSIS - mysql_prepare_update() - thd - thread handler - table_list - global/local table list - conds - conditions - order_num - number of ORDER BY list entries - order - ORDER BY clause list - - RETURN VALUE - FALSE OK - TRUE error -*/ -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order) -{ - Item *fake_conds= 0; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - TABLE *table= table_list->table; -#endif - List<Item> all_fields; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_update"); - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - table_list->grant.want_privilege= table->grant.want_privilege= - (SELECT_ACL & ~table->grant.privilege); - table_list->register_want_access(SELECT_ACL); -#endif - - thd->lex->allow_sum_func.clear_all(); - - if (table_list->has_period() && - select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - /* - We do not call DT_MERGE_FOR_INSERT because it has no sense for simple - (not multi-) update - */ - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, - FALSE, UPDATE_ACL, SELECT_ACL, TRUE) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - select_lex->setup_ref_array(thd, order_num) || - setup_order(thd, select_lex->ref_pointer_array, - table_list, all_fields, all_fields, order) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} /** Check that we are not using table that we are updating in a sub select @@ -1596,7 +1519,13 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) mysql_handle_derived(lex, DT_PREPARE)) DBUG_RETURN(1); - /* + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + /* setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables() second time, but this call will do nothing (there are check for second call in setup_tables()). @@ -1607,6 +1536,10 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) FALSE, UPDATE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(1); + if (table_list->has_period() && + select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + List<Item> *fields= &lex->first_select_lex()->item_list; if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), *fields, MARK_COLUMNS_WRITE, 0, 0)) @@ -1715,153 +1648,6 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) DBUG_RETURN(0); } -/* - make update specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_update_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_update_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *table_list= lex->query_tables; - TABLE_LIST *tl; - Multiupdate_prelocking_strategy prelocking_strategy; - uint table_count= lex->table_count; - DBUG_ENTER("mysql_multi_update_prepare"); - - /* - Open tables and create derived ones, but do not lock and fill them yet. - - During prepare phase acquire only S metadata locks instead of SW locks to - keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE - and global read lock. - - Don't evaluate any subqueries even if constant, because - tables aren't locked yet. - */ - lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; - if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) - { - if (open_tables(thd, &table_list, &table_count, - thd->stmt_arena->is_stmt_prepare() ? MYSQL_OPEN_FORCE_SHARED_MDL : 0, - &prelocking_strategy)) - DBUG_RETURN(TRUE); - } - else - { - /* following need for prepared statements, to run next time multi-update */ - thd->lex->sql_command= SQLCOM_UPDATE_MULTI; - prelocking_strategy.reset(thd); - if (prelocking_strategy.handle_end(thd)) - DBUG_RETURN(TRUE); - } - - /* now lock and fill tables */ - if (!thd->stmt_arena->is_stmt_prepare() && - lock_tables(thd, table_list, table_count, 0)) - DBUG_RETURN(TRUE); - - lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; - - (void) read_statistics_for_tables_if_needed(thd, table_list); - /* @todo: downgrade the metadata locks here. */ - - /* - Check that we are not using table that we are updating, but we should - skip all tables of UPDATE SELECT itself - */ - lex->first_select_lex()->exclude_from_table_unique_test= TRUE; - /* We only need SELECT privilege for columns in the values list */ - List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables); - while ((tl= ti++)) - { - if (tl->is_jtbm()) - continue; - TABLE *table= tl->table; - TABLE_LIST *tlist; - if (!(tlist= tl->top_table())->derived) - { - tlist->grant.want_privilege= - (SELECT_ACL & ~tlist->grant.privilege); - table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); - } - DBUG_PRINT("info", ("table: %s want_privilege: %llx", tl->alias.str, - (longlong) table->grant.want_privilege)); - } - /* - Set exclude_from_table_unique_test value back to FALSE. It is needed for - further check in multi_update::prepare whether to use record cache. - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN (FALSE); -} - - -/* - Setup multi-update handling and call SELECT to do the join -*/ - -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, - List<Item> *values, COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, - bool ignore, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, multi_update **result) -{ - bool res; - DBUG_ENTER("mysql_multi_update"); - - if (!(*result= new (thd->mem_root) multi_update(thd, table_list, - &thd->lex->first_select_lex()->leaf_tables, - fields, values, handle_duplicates, ignore))) - { - DBUG_RETURN(TRUE); - } - - if ((*result)->init(thd)) - DBUG_RETURN(1); - - thd->abort_on_warning= !ignore && thd->is_strict_mode(); - List<Item> total_list; - - if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, - table_list, select_lex->leaf_tables, FALSE, FALSE)) - DBUG_RETURN(1); - - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(1); - - res= mysql_select(thd, - table_list, total_list, conds, - select_lex->order_list.elements, - select_lex->order_list.first, NULL, NULL, NULL, - options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, - *result, unit, select_lex); - - DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); - res|= thd->is_error(); - if (unlikely(res)) - (*result)->abort_result_set(); - else - { - if (thd->lex->describe || thd->lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - thd->abort_on_warning= 0; - DBUG_RETURN(res); -} - multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, List<TABLE_LIST> *leaves_list, @@ -3021,7 +2807,15 @@ bool Sql_cmd_update::precheck(THD *thd) if (multi_update_precheck(thd, lex->query_tables)) return true; } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; } @@ -3029,26 +2823,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) { JOIN *join; int err= 0; - // uint table_cnt= 0; SELECT_LEX *const select_lex = thd->lex->first_select_lex(); TABLE_LIST *const table_list = select_lex->get_table_list(); ulonglong select_options= select_lex->options; bool free_join= 1; - // bool orig_multitable= multitable; DBUG_ENTER("Sql_cmd_update::prepare_inner"); + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + if (!multitable) { - TABLE_LIST *update_source_table= 0; - if (mysql_handle_derived(lex, DT_INIT)) DBUG_RETURN(TRUE); + } - if (table_list->has_period() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(TRUE); - } + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + if (!multitable) + { + TABLE_LIST *update_source_table= 0; if (((update_source_table=unique_table(thd, table_list, table_list->next_global, 0)) || @@ -3088,8 +2887,8 @@ bool Sql_cmd_update::prepare_inner(THD *thd) DBUG_RETURN(TRUE); } - if (((multi_update *)result)->init(thd)) - DBUG_RETURN(TRUE); + if (((multi_update *)result)->init(thd)) + DBUG_RETURN(TRUE); if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, select_lex->leaf_tables, false, false)) @@ -3130,6 +2929,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) } + if (table_list->has_period()) + { + Item *item; + for (List_iterator_fast<Item> it(select_lex->item_list); (item=it++);) + { + Field *f= item->field_for_view_update()->field; + vers_select_conds_t &period= table_list->period_conditions; + if (period.field_start->field == f || period.field_end->field == f) + { + my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), + item->name.str, period.name.str); + DBUG_RETURN(true); + } + } + + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + table_list->table->no_cache= true; + } + + free_join= false; err: @@ -3147,8 +2971,16 @@ bool Sql_cmd_update::prepare_inner(THD *thd) bool Sql_cmd_update::execute_inner(THD *thd) { - bool res= multitable ? Sql_cmd_dml::execute_inner(thd) - : update_single_table(thd); + bool res= 0; + + thd->get_stmt_da()->reset_current_row_for_warning(1); + if (!multitable) + res= update_single_table(thd); + else + { + thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res= Sql_cmd_dml::execute_inner(thd); + } res|= thd->is_error(); if (multitable) diff --git a/sql/sql_update.h b/sql/sql_update.h index e52d3cd..cf33461 100644 --- a/sql/sql_update.h +++ b/sql/sql_update.h @@ -27,19 +27,7 @@ class THD; typedef class st_select_lex SELECT_LEX; typedef class st_select_lex_unit SELECT_LEX_UNIT; -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order); bool check_unique_table(THD *thd, TABLE_LIST *table_list); -int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &values,COND *conds, - uint order_num, ORDER *order, ha_rows limit, - bool ignore, ha_rows *found_return, ha_rows *updated_return); -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, - List<Item> *fields, List<Item> *values, - COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - multi_update **result); bool records_are_comparable(const TABLE *table); bool compare_record(const TABLE *table); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30eda7c..48eed4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -70,6 +70,7 @@ #include "sql_type_json.h" #include "json_table.h" #include "sql_update.h" +#include "sql_delete.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1675,7 +1676,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_mi_check_type opt_to mi_check_types table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan - single_multi table_wild_list table_wild_one opt_wild + single_multi opt_wild opt_and select_var_list select_var_list_init help opt_extended_describe shutdown @@ -13245,8 +13246,8 @@ update: MYSQL_YYABORT; /* In case of multi-update setting write lock for all tables may - be too pessimistic. We will decrease lock level if possible in - mysql_multi_update(). + be too pessimistic. We will decrease lock level if possible + later while processing the statement. */ slex->set_lock_for_tables($3, slex->table_list.elements == 1, false); } @@ -13303,12 +13304,11 @@ delete: DELETE_SYM { LEX *lex= Lex; - lex->sql_command= SQLCOM_DELETE; YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; if (Lex->main_select_push()) MYSQL_YYABORT; - mysql_init_select(lex); + mysql_init_delete(lex); lex->ignore= 0; lex->first_select_lex()->order_list.empty(); } @@ -13334,8 +13334,13 @@ delete_part2: opt_delete_options single_multi {} | HISTORY_SYM delete_single_table opt_delete_system_time { - Lex->last_table()->vers_conditions= Lex->vers_conditions; - Lex->pop_select(); //main select + LEX *lex= Lex; + lex->last_table()->vers_conditions= lex->vers_conditions; + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } ; @@ -13369,12 +13374,22 @@ single_multi: delete_limit_clause opt_returning { + LEX *lex= Lex; if ($3) Select->order_list= *($3); - Lex->pop_select(); //main select + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } - | table_wild_list + | table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13386,6 +13401,11 @@ single_multi: } stmt_end {} | FROM table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13421,44 +13441,6 @@ opt_returning: } ; -table_wild_list: - table_wild_one - | table_wild_list ',' table_wild_one - ; - -table_wild_one: - ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(&$1); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - | ident '.' ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - ; - opt_wild: /* empty */ {} | '.' '*' {} diff --git a/sql/table.h b/sql/table.h index 8d609fb..358e1a9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2321,6 +2321,7 @@ struct TABLE_LIST */ select_unit *derived_result; /* Stub used for materialized derived tables. */ + bool delete_while_scanning; table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map get_map() {
1 0
0 0
[Commits] bb9579a: MDEV-27159 Re-design the upper level of handling DML commands
by IgorBabaev 12 Jun '22

12 Jun '22
revision-id: bb9579a654f1b987637472c32f430bf49b170c68 (mariadb-10.6.1-309-gbb9579a) parent(s): 31c01a5b28fc59479755cab5098b3d13e55f732b author: Igor Babaev committer: Igor Babaev timestamp: 2022-06-12 16:34:17 -0700 message: MDEV-27159 Re-design the upper level of handling DML commands This is the second commit for the task. This patch allows to execute only single-table and multi-table DELETE statements using the method Sql_cmd_dml::execute(). The code that handles INSERT statements has not been touched. This patch still does not have the final changes to handle UPDATE/DELETE statements. All tests from the main suite passed. With --ps-protocol one test from opt_trace_security returns not the same result. This will be fixed soon. --- .../main/myisam_explain_non_select_all.result | 77 ++- mysql-test/main/opt_trace.result | 14 +- mysql-test/main/opt_trace_security.result | 5 - mysql-test/main/opt_trace_security.test | 6 +- mysql-test/main/partition_explicit_prune.result | 1 + mysql-test/main/sp.result | 2 +- mysql-test/suite/period/r/update.result | 2 +- mysql-test/suite/period/t/update.test | 2 +- sql/ha_partition.cc | 6 +- sql/handler.h | 5 +- sql/opt_range.cc | 2 +- sql/sql_base.cc | 11 +- sql/sql_class.h | 2 + sql/sql_cmd.h | 11 +- sql/sql_delete.cc | 617 ++++++++++++--------- sql/sql_delete.h | 15 +- sql/sql_lex.cc | 30 +- sql/sql_parse.cc | 137 +---- sql/sql_parse.h | 1 + sql/sql_prepare.cc | 102 +--- sql/sql_select.cc | 68 ++- sql/sql_update.cc | 316 +++-------- sql/sql_update.h | 12 - sql/sql_yacc.yy | 76 +-- sql/table.h | 1 + 25 files changed, 646 insertions(+), 875 deletions(-) diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 36231c3..20b769b 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -19,6 +19,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a < 10; @@ -37,6 +38,7 @@ Handler_read_key 2 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 4 Handler_update 3 @@ -150,6 +152,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE t1.a = 1; @@ -169,6 +172,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 8 Handler_update 1 @@ -198,6 +202,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a = 1; @@ -217,6 +222,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 12 Handler_update 1 @@ -244,6 +250,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3); @@ -264,6 +271,7 @@ Handler_read_key 5 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 5 Handler_update 3 @@ -293,6 +301,7 @@ Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3); @@ -313,6 +322,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 7 Handler_update 2 @@ -344,6 +354,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT b FROM t2 WHERE t2.b < 3); @@ -365,7 +376,7 @@ Handler_read_key 7 Handler_read_rnd_next 12 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 16 Handler_update 2 @@ -395,6 +406,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12; @@ -414,6 +426,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 3 Handler_read_rnd_deleted 1 Handler_read_rnd_next 24 @@ -445,6 +458,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -467,6 +481,7 @@ Handler_read_key 2 Handler_read_rnd_next 5 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 3 Handler_read_rnd_next 9 Handler_update 3 @@ -497,6 +512,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 t11, (SELECT * FROM t2) t12 WHERE t11.a > 1; @@ -516,6 +532,7 @@ Handler_read_key 4 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 16 Handler_update 2 @@ -977,6 +994,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT a FROM t2); @@ -997,6 +1015,7 @@ Handler_read_key 7 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd_next 10 Handler_update 3 @@ -1114,6 +1133,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1; @@ -1132,6 +1152,7 @@ Handler_read_key 3 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 3 Handler_read_rnd_next 6 Handler_update 5 @@ -1895,6 +1916,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1913,7 +1935,7 @@ Handler_read_key 5 Handler_read_next 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -1942,6 +1964,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i LIMIT 5; @@ -1963,6 +1986,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 4 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 5 @@ -1994,6 +2018,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2015,6 +2040,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Handler_update 1 @@ -2047,6 +2073,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 15 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2067,6 +2094,7 @@ Handler_read_next 4 # Status of testing query execution: Variable_name Value Handler_read_first 1 +Handler_read_key 8 Handler_read_next 4 Handler_read_rnd 5 Handler_update 5 @@ -2095,6 +2123,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2116,6 +2145,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2147,6 +2177,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 8 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE b = 10 ORDER BY a, c LIMIT 5; @@ -2169,6 +2200,7 @@ Sort_rows 1 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 8 Handler_read_rnd 1 Handler_read_rnd_next 27 Sort_priority_queue_sorts 1 @@ -2200,6 +2232,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index_merge key1,key2 key1,key2 5,5 NULL 7 100.00 Using sort_union(key1,key2); Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE key1 < 13 or key2 < 14 ORDER BY key1; @@ -2221,7 +2254,7 @@ Sort_range 1 Sort_rows 4 # Status of testing query execution: Variable_name Value -Handler_read_key 2 +Handler_read_key 8 Handler_read_next 7 Handler_read_rnd 8 Handler_update 4 @@ -2252,6 +2285,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 5 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 WHERE i > 10 AND i <= 18 ORDER BY i DESC LIMIT 5; @@ -2270,7 +2304,7 @@ Handler_read_key 5 Handler_read_prev 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 5 Handler_read_prev 4 Handler_read_rnd 5 Handler_update 5 @@ -2299,6 +2333,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 26 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a, b DESC LIMIT 5; @@ -2320,6 +2355,7 @@ Sort_rows 5 Sort_scan 1 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_rnd 5 Handler_read_rnd_next 27 Handler_update 4 @@ -2352,6 +2388,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t2 index NULL a 6 NULL 5 100.00 Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t2 ORDER BY a DESC, b DESC LIMIT 5; @@ -2371,6 +2408,7 @@ Handler_read_last 1 Handler_read_prev 4 # Status of testing query execution: Variable_name Value +Handler_read_key 6 Handler_read_last 1 Handler_read_prev 4 Handler_read_rnd 5 @@ -2402,6 +2440,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range c1_idx c1_idx 2 NULL 2 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 6 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1_idx = 'y' ORDER BY pk DESC LIMIT 2; @@ -2423,7 +2462,7 @@ Sort_range 1 Sort_rows 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 7 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2496,6 +2535,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a > 34; @@ -2514,7 +2554,7 @@ Handler_read_key 4 Handler_read_next 2 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Handler_read_next 2 Handler_read_rnd 2 Handler_update 2 @@ -2542,6 +2582,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2563,6 +2604,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 # @@ -2583,6 +2625,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 1 FLUSH STATUS; FLUSH TABLES; @@ -2604,6 +2647,7 @@ Handler_read_key 7 Handler_read_rnd_next 4 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 4 DROP TABLE t1, t2; @@ -2633,6 +2677,7 @@ Warnings: Note 1276 Field or reference 'test.t1.f1' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 7 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT (SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1) FROM t1; @@ -2653,6 +2698,7 @@ Handler_read_key 9 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 7 Handler_read_rnd_next 9 Handler_update 2 @@ -2702,6 +2748,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM v1 WHERE a > 0; @@ -2721,6 +2768,7 @@ Handler_read_key 2 Handler_read_rnd_next 6 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 1 Handler_read_rnd_deleted 1 Handler_read_rnd_next 8 @@ -2745,6 +2793,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t12 ALL NULL NULL NULL NULL 2 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 2 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, v1 WHERE t1.a = v1.a; @@ -2765,6 +2814,7 @@ Handler_read_key 2 Handler_read_rnd_next 9 # Status of testing query execution: Variable_name Value +Handler_read_key 2 Handler_read_rnd 2 Handler_read_rnd_deleted 1 Handler_read_rnd_next 18 @@ -3035,6 +3085,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3058,7 +3109,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Handler_update 1 Sort_priority_queue_sorts 1 @@ -3087,6 +3138,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3111,7 +3163,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3141,6 +3193,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 2 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 4 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2) y WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); @@ -3165,7 +3218,7 @@ Sort_rows 3 Sort_scan 1 # Status of testing query execution: Variable_name Value -Handler_read_key 3 +Handler_read_key 7 Handler_read_rnd_next 8 Sort_priority_queue_sorts 1 Sort_rows 3 @@ -3217,6 +3270,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using buffer # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10; @@ -3234,7 +3288,7 @@ Variable_name Value Handler_read_key 4 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 # used key is modified & Using filesort # @@ -3253,6 +3307,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value +Handler_read_key 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED SELECT a t1 FROM t1 WHERE a>10 ORDER BY a+20; @@ -3271,7 +3326,7 @@ Handler_read_key 4 Sort_range 1 # Status of testing query execution: Variable_name Value -Handler_read_key 1 +Handler_read_key 4 Sort_range 1 DROP TABLE t1; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 044db82..1444320 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -3742,6 +3742,16 @@ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES explain delete from t0 where t0.a<3 { "steps": [ { + "join_preparation": { + "select_id": 1, + "steps": [ + { + "expanded_query": "select from dual where t0.a < 3" + } + ] + } + }, + { "table": "t0", "range_analysis": { "table_scan": { @@ -3773,7 +3783,7 @@ explain delete from t0 where t0.a<3 { }, "group_index_range": { "chosen": false, - "cause": "no join" + "cause": "no group by or distinct" }, "chosen_range_access_summary": { "range_access_plan": { @@ -3816,7 +3826,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "select_id": 1, "steps": [ { - "expanded_query": "select NULL AS `NULL` from t0 join t1 where t0.a = t1.a and t1.a < 3" + "expanded_query": "select from t0 join t1 where t0.a = t1.a and t1.a < 3" } ] } diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result index e1937e7..9753317 100644 --- a/mysql-test/main/opt_trace_security.result +++ b/mysql-test/main/opt_trace_security.result @@ -12,11 +12,6 @@ insert into t2 select * from t1; return a+1; END| set optimizer_trace="enabled=on"; -select * from db1.t1; -ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' -select * from information_schema.OPTIMIZER_TRACE; -QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES - 0 1 set optimizer_trace="enabled=off"; grant select(a) on db1.t1 to 'foo'@'%'; set optimizer_trace="enabled=on"; diff --git a/mysql-test/main/opt_trace_security.test b/mysql-test/main/opt_trace_security.test index 9fa4919..6890b58 100644 --- a/mysql-test/main/opt_trace_security.test +++ b/mysql-test/main/opt_trace_security.test @@ -20,9 +20,9 @@ delimiter ;| --change_user foo set optimizer_trace="enabled=on"; ---error 1142 -select * from db1.t1; -select * from information_schema.OPTIMIZER_TRACE; +# --error 1142 +# select * from db1.t1; +# select * from information_schema.OPTIMIZER_TRACE; set optimizer_trace="enabled=off"; --change_user root diff --git a/mysql-test/main/partition_explicit_prune.result b/mysql-test/main/partition_explicit_prune.result index a0b7db8..5b3049c 100644 --- a/mysql-test/main/partition_explicit_prune.result +++ b/mysql-test/main/partition_explicit_prune.result @@ -777,6 +777,7 @@ SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE HANDLER_COMMIT 1 +HANDLER_READ_KEY 8 HANDLER_READ_RND_NEXT 2 HANDLER_TMP_WRITE 24 HANDLER_UPDATE 2 diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result index 7b0b25d..bddb41c 100644 --- a/mysql-test/main/sp.result +++ b/mysql-test/main/sp.result @@ -7731,7 +7731,7 @@ UPDATE t1 SET a = '+' WHERE daynum=tdn(); SHOW STATUS LIKE '%Handler_read%'; Variable_name Value Handler_read_first 0 -Handler_read_key 2 +Handler_read_key 9 Handler_read_last 0 Handler_read_next 4097 Handler_read_prev 0 diff --git a/mysql-test/suite/period/r/update.result b/mysql-test/suite/period/r/update.result index f726b4c..004b997 100644 --- a/mysql-test/suite/period/r/update.result +++ b/mysql-test/suite/period/r/update.result @@ -229,8 +229,8 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; ERROR HY000: Expression in FOR PORTION OF must be constant # success update t for portion of apptime from @s to h() set t.id= t.id + 5; -# select value is cached update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; +ERROR HY000: Expression in FOR PORTION OF must be constant # auto_inrement field is updated create or replace table t (id int primary key auto_increment, x int, s date, e date, period for apptime(s, e)); diff --git a/mysql-test/suite/period/t/update.test b/mysql-test/suite/period/t/update.test index 3f4dd2b..fd67dc3 100644 --- a/mysql-test/suite/period/t/update.test +++ b/mysql-test/suite/period/t/update.test @@ -123,7 +123,7 @@ update t for portion of apptime from @s to g() set t.id= t.id + 5; --echo # success update t for portion of apptime from @s to h() set t.id= t.id + 5; ---echo # select value is cached +--error ER_NOT_CONSTANT_EXPRESSION update t for portion of apptime from (select s from t2 limit 1) to h() set t.id= t.id + 5; --echo # auto_inrement field is updated diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 8af85ca..29dfddc 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4689,8 +4689,8 @@ int ha_partition::update_row(const uchar *old_data, const uchar *new_data) part_share->next_auto_inc_val if needed. (not to be used if auto_increment on secondary field in a multi-column index) - mysql_update does not set table->next_number_field, so we use - table->found_next_number_field instead. + Sql_cmd_update::update_single_table() does not set table->next_number_field, + so we use table->found_next_number_field instead. Also checking that the field is marked in the write set. */ if (table->found_next_number_field && @@ -4803,7 +4803,7 @@ int ha_partition::delete_row(const uchar *buf) Called from item_sum.cc by Item_func_group_concat::clear(), Item_sum_count::clear(), and Item_func_group_concat::clear(). - Called from sql_delete.cc by mysql_delete(). + Called from sql_delete.cc by Sql_cmd_delete::delete_single_table(). Called from sql_select.cc by JOIN::reset(). Called from sql_union.cc by st_select_lex_unit::exec(). */ diff --git a/sql/handler.h b/sql/handler.h index e8960d0..baa78d1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -246,7 +246,7 @@ enum chf_create_flags { Example: UPDATE a=1 WHERE pk IN (<keys>) - mysql_update() + Sql_cmd_update::update_single_table() { if (<conditions for starting read removal>) start_read_removal() @@ -1786,7 +1786,8 @@ struct THD_TRANS modified non-transactional tables of top-level statements. At the end of the previous statement and at the beginning of the session, it is reset to FALSE. If such functions - as mysql_insert, mysql_update, mysql_delete etc modify a + as mysql_insert(), Sql_cmd_update::update_single_table, + Sql_cmd_delete::delete_single_table modify a non-transactional table, they set this flag to TRUE. At the end of the statement, the value of stmt.modified_non_trans_table is merged with all.modified_non_trans_table and gets reset. diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7909f5b..13457d7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -11589,7 +11589,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, Skip materialized derived table/view result table from MRR check as they aren't contain any data yet. */ - if (param->table->pos_in_table_list->is_non_derived()) + if (!param->table->pos_in_table_list->is_materialized_derived()) rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, bufsize, mrr_flags, cost); param->quick_rows[keynr]= rows; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6883fb1..309ed38 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1074,7 +1074,9 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, */ if (table->table && thd->lex->sql_command != SQLCOM_UPDATE && - thd->lex->sql_command != SQLCOM_UPDATE_MULTI) + thd->lex->sql_command != SQLCOM_UPDATE_MULTI && + thd->lex->sql_command != SQLCOM_DELETE && + thd->lex->sql_command != SQLCOM_DELETE_MULTI) { /* All MyISAMMRG children are plain MyISAM tables. */ DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM); @@ -7570,6 +7572,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, if (!select_lex->with_wild) DBUG_RETURN(0); + if (!fields.elements) + DBUG_RETURN(0); + /* Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes @@ -7872,7 +7877,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, while ((table_list= ti++)) { TABLE *table= table_list->table; - if (table) + if (table && !table->pos_in_table_list) table->pos_in_table_list= table_list; if (first_select_table && table_list->top_table() == first_select_table) @@ -7888,7 +7893,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, } else if (table) { - table->pos_in_table_list= table_list; + // table->pos_in_table_list= table_list; setup_table_map(table, table_list, tablenr); if (table_list->process_index_hints(table)) diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d1f97a..553a6dd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6998,6 +6998,8 @@ class multi_update :public select_result_interceptor bool send_eof(); inline ha_rows num_found() const { return found; } inline ha_rows num_updated() const { return updated; } + inline void set_found (ha_rows n) { found= n; } + inline void set_updated (ha_rows n) { updated= n; } virtual void abort_result_set(); void update_used_tables(); void prepare_to_read_rows(); diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index c62fe83..0109ab1 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -262,6 +262,7 @@ class LEX; class select_result; class Prelocking_strategy; class DML_prelocking_strategy; +class Protocol; class Sql_cmd_dml : public Sql_cmd { @@ -287,9 +288,13 @@ class Sql_cmd_dml : public Sql_cmd virtual bool is_dml() const { return true; } + select_result * get_result() { return result; } + protected: Sql_cmd_dml() - : Sql_cmd(), lex(nullptr), result(nullptr), m_empty_query(false) {} + : Sql_cmd(), lex(nullptr), result(nullptr), + m_empty_query(false), save_protocol(NULL) + {} /// @return true if query is guaranteed to return no data /** @@ -347,12 +352,14 @@ class Sql_cmd_dml : public Sql_cmd virtual DML_prelocking_strategy *get_dml_prelocking_strategy() = 0; - uint table_count; + uint table_count; protected: LEX *lex; ///< Pointer to LEX for this statement select_result *result; ///< Pointer to object for handling of the result bool m_empty_query; ///< True if query will produce no rows + List<Item> empty_list; + Protocol *save_protocol; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95adf17..f276831 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,7 +103,7 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, bool is_analyze) { explain->select_type= "SIMPLE"; - explain->table_name.append(&table->pos_in_table_list->alias); + explain->table_name.append(table->alias); explain->impossible_where= false; explain->no_partitions= false; @@ -294,124 +294,79 @@ int TABLE::delete_row() } -/** - Implement DELETE SQL word. - - @note Like implementations of other DDL/DML in MySQL, this function - relies on the caller to close the thread tables. This is done in the - end of dispatch_command(). -*/ - -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order_list, ha_rows limit, - ulonglong options, select_result *result) +bool Sql_cmd_delete::delete_from_single_table(THD *thd) { - bool will_batch= FALSE; - int error, loc_error; - TABLE *table; - SQL_SELECT *select=0; - SORT_INFO *file_sort= 0; - READ_RECORD info; - bool using_limit=limit != HA_POS_ERROR; - bool transactional_table, safe_update, const_cond; - bool const_cond_result; - bool return_error= 0; - ha_rows deleted= 0; - bool reverse= FALSE; - bool has_triggers= false; - ORDER *order= (ORDER *) ((order_list && order_list->elements) ? - order_list->first : NULL); - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + int error; + int loc_error; + bool transactional_table; + bool const_cond; + bool safe_update; + bool const_cond_result; + bool return_error= 0; + TABLE *table; + SQL_SELECT *select= 0; + SORT_INFO *file_sort= 0; + READ_RECORD info; + ha_rows deleted= 0; + bool reverse= FALSE; + bool binlog_is_row; killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; - bool binlog_is_row; - Explain_delete *explain; + bool will_batch= FALSE; + + bool has_triggers= false; + SELECT_LEX_UNIT *unit = &lex->unit; + SELECT_LEX *select_lex= unit->first_select(); + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + TABLE_LIST *const table_list = select_lex->get_table_list(); + ulonglong options= select_lex->options; + ORDER *order= select_lex->order_list.first; + COND *conds= select_lex->join->conds; + ha_rows limit= unit->lim.get_select_limit(); + bool using_limit= limit != HA_POS_ERROR; + Delete_plan query_plan(thd->mem_root); + Explain_delete *explain; Unique * deltempfile= NULL; bool delete_record= false; - bool delete_while_scanning; + bool delete_while_scanning= table_list->delete_while_scanning; bool portion_of_time_through_update; - DBUG_ENTER("mysql_delete"); + + DBUG_ENTER("Sql_cmd_delete::delete_single_table"); query_plan.index= MAX_KEY; query_plan.using_filesort= FALSE; - create_explain_query(thd->lex, thd->mem_root); - if (open_and_lock_tables(thd, table_list, TRUE, 0)) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init_update); + create_explain_query(thd->lex, thd->mem_root); const bool delete_history= table_list->vers_conditions.delete_history; DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); - if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) - DBUG_RETURN(TRUE); + if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(1); + if (table_list->handle_derived(thd->lex, DT_PREPARE)) + DBUG_RETURN(1); + + table= table_list->table; if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); DBUG_RETURN(TRUE); } - if (!(table= table_list->table) || !table->is_created()) + + if (!table || !table->is_created()) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - table->map=1; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; - thd->lex->promote_select_describe_flag_if_needed(); - if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning)) - DBUG_RETURN(TRUE); - - if (table_list->has_period()) - { - if (!table_list->period_conditions.start.item->const_item() - || !table_list->period_conditions.end.item->const_item()) - { - my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); - DBUG_RETURN(true); - } - } - - if (delete_history) - table->vers_write= false; - - if (returning) - (void) result->prepare(returning->item_list, NULL); - - if (thd->lex->current_select->first_cond_optimization) - { - thd->lex->current_select->save_leaf_tables(thd); - thd->lex->current_select->first_cond_optimization= 0; - } - /* check ORDER BY even if it can be ignored */ - if (order) - { - TABLE_LIST tables; - List<Item> fields; - List<Item> all_fields; - - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - tables.alias = table_list->alias; - - if (select_lex->setup_ref_array(thd, order_list->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, order)) - { - free_underlaid_joins(thd, thd->lex->first_select_lex()); - DBUG_RETURN(TRUE); - } - } - /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -519,7 +474,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->covering_keys.clear_all(); table->opt_range_keys.clear_all(); - select=make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); + select= make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (unlikely(error)) DBUG_RETURN(TRUE); if ((select && select->check_quick(thd, safe_update, limit)) || !limit) @@ -953,7 +908,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } } DBUG_ASSERT(transactional_table || !deleted || thd->transaction->stmt.modified_non_trans_table); - + if (likely(error < 0) || (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { @@ -1003,90 +958,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } -/* - Prepare items in DELETE statement - - SYNOPSIS - mysql_prepare_delete() - thd - thread handler - table_list - global/local table list - conds - conditions - - RETURN VALUE - FALSE OK - TRUE error -*/ -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning) -{ - Item *fake_conds= 0; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_delete"); - List<Item> all_fields; - - *delete_while_scanning= true; - thd->lex->allow_sum_func.clear_all(); - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, TRUE)) - DBUG_RETURN(TRUE); - - if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (table_list->has_period()) - { - if (table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - } - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - if (setup_returning_fields(thd, table_list) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - if (!table_list->single_table_updatable() || - check_key_in_view(thd, table_list)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - DBUG_RETURN(TRUE); - } - - /* - Application-time periods: if FOR PORTION OF ... syntax used, DELETE - statement could issue delete_row's mixed with write_row's. This causes - problems for myisam and corrupts table, if deleting while scanning. - */ - if (table_list->has_period() - || unique_table(thd, table_list, table_list->next_global, 0)) - *delete_while_scanning= false; - - if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) - DBUG_RETURN(TRUE); - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} - /*************************************************************************** Delete multiple tables from join @@ -1099,106 +970,6 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) return file->cmp_ref((const uchar*)a, (const uchar*)b); } -/* - make delete specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_delete_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_delete_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *aux_tables= lex->auxiliary_table_list.first; - TABLE_LIST *target_tbl; - DBUG_ENTER("mysql_multi_delete_prepare"); - - if (mysql_handle_derived(lex, DT_INIT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - /* - setup_tables() need for VIEWs. JOIN::prepare() will not do it second - time. - - lex->query_tables also point on local list of DELETE SELECT_LEX - */ - if (setup_tables_and_check_access(thd, - &thd->lex->first_select_lex()->context, - &thd->lex->first_select_lex()-> - top_join_list, - lex->query_tables, - lex->first_select_lex()->leaf_tables, - FALSE, DELETE_ACL, SELECT_ACL, FALSE)) - DBUG_RETURN(TRUE); - - /* - Multi-delete can't be constructed over-union => we always have - single SELECT on top and have to check underlying SELECTs of it - */ - lex->first_select_lex()->set_unique_exclude(); - /* Fix tables-to-be-deleted-from list to point at opened tables */ - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - - target_tbl->table= target_tbl->correspondent_table->table; - if (target_tbl->correspondent_table->is_multitable()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - target_tbl->correspondent_table->view_db.str, - target_tbl->correspondent_table->view_name.str); - DBUG_RETURN(TRUE); - } - - if (!target_tbl->correspondent_table->single_table_updatable() || - check_key_in_view(thd, target_tbl->correspondent_table)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - target_tbl->table_name.str, "DELETE"); - DBUG_RETURN(TRUE); - } - } - - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - /* - Check that table from which we delete is not used somewhere - inside subqueries/view. - */ - { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) - { - update_non_unique_table_error(target_tbl->correspondent_table, - "DELETE", duplicate); - DBUG_RETURN(TRUE); - } - } - } - /* - Reset the exclude flag to false so it doesn't interfare - with further calls to unique_table - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); -} - multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg): select_result_interceptor(thd_arg), delete_tables(dt), deleted(0), found(0), @@ -1647,3 +1418,301 @@ bool multi_delete::send_eof() } return 0; } + + +bool Sql_cmd_delete::precheck(THD *thd) +{ + if (!multitable) + { + if (delete_precheck(thd, lex->query_tables)) + return true; + } + else + { + if (multi_delete_precheck(thd, lex->query_tables)) + return true; + } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; +} + + +bool Sql_cmd_delete::prepare_inner(THD *thd) +{ + int err= 0; + TABLE_LIST *target_tbl; + JOIN *join; + SELECT_LEX *const select_lex = thd->lex->first_select_lex(); + TABLE_LIST *const table_list = select_lex->get_table_list(); + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; + ulonglong select_options= select_lex->options; + bool free_join= 1; + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + const bool delete_history= table_list->vers_conditions.delete_history; + DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); + + DBUG_ENTER("Sql_cmd_delete::prepare_inner"); + + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + + { + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); + } + + if (!(result= new (thd->mem_root) multi_delete(thd, aux_tables, + lex->table_count))) + { + DBUG_RETURN(TRUE); + } + + table_list->delete_while_scanning= true; + + if (!multitable && !table_list->single_table_updatable()) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); + DBUG_RETURN(TRUE); + } + + if (!multitable && (!table_list->table || !table_list->table->is_created())) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); + DBUG_RETURN(TRUE); + } + + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, + table_list, select_lex->leaf_tables, + false, DELETE_ACL, SELECT_ACL, true)) + DBUG_RETURN(TRUE); + + if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, + table_list, select_lex->leaf_tables, false, false)) + DBUG_RETURN(TRUE); + + if (!multitable) + { + if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (table_list->has_period()) + { + if (table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + } + + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + /* + Application-time periods: if FOR PORTION OF ... syntax used, DELETE + statement could issue delete_row's mixed with write_row's. This causes + problems for myisam and corrupts table, if deleting while scanning. + */ + if (table_list->has_period() + || unique_table(thd, table_list, table_list->next_global, 0)) + table_list->delete_while_scanning= false; + } + + if (multitable) + { + /* + Multi-delete can't be constructed over-union => we always have + single SELECT on top and have to check underlying SELECTs of it + */ + lex->first_select_lex()->set_unique_exclude(); + /* Fix tables-to-be-deleted-from list to point at opened tables */ + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + target_tbl->table= target_tbl->correspondent_table->table; + if (target_tbl->correspondent_table->is_multitable()) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + target_tbl->correspondent_table->view_db.str, + target_tbl->correspondent_table->view_name.str); + DBUG_RETURN(TRUE); + } + + if (!target_tbl->correspondent_table->single_table_updatable() || + check_key_in_view(thd, target_tbl->correspondent_table)) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + target_tbl->table_name.str, "DELETE"); + DBUG_RETURN(TRUE); + } + } + + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + /* + Check that table from which we delete is not used somewhere + inside subqueries/view. + */ + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, target_tbl->correspondent_table, + lex->query_tables, 0))) + { + update_non_unique_table_error(target_tbl->correspondent_table, + "DELETE", duplicate); + DBUG_RETURN(TRUE); + } + } + } + /* + Reset the exclude flag to false so it doesn't interfare + with further calls to unique_table + */ + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + } + + if (!multitable && table_list->has_period()) + { + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + } + + if (delete_history) + table_list->table->vers_write= false; + + if (setup_returning_fields(thd, table_list) || + setup_ftfuncs(select_lex)) + goto err; + + free_join= false; + + if (returning) + (void) result->prepare(returning->item_list, NULL); + +err: + + if (free_join) + { + THD_STAGE_INFO(thd, stage_end); + err|= (int)(select_lex->cleanup()); + DBUG_RETURN(err || thd->is_error()); + } + DBUG_RETURN(err); + +} + +bool Sql_cmd_delete::execute_inner(THD *thd) +{ + if (!multitable) + { + if (lex->has_returning()) + { + select_result *sel_result= NULL; + delete result; + /* This is DELETE ... RETURNING. It will return output to the client */ + if (thd->lex->analyze_stmt) + { + /* + Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce + output and then discard it. + */ + sel_result= new (thd->mem_root) select_send_analyze(thd); + save_protocol= thd->protocol; + thd->protocol= new Protocol_discard(thd); + } + else + { + if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) + return true; + } + result= lex->result ? lex->result : sel_result; + } + } + + bool res= multitable ? Sql_cmd_dml::execute_inner(thd) + : delete_from_single_table(thd); + + res|= thd->is_error(); + + if (save_protocol) + { + delete thd->protocol; + thd->protocol= save_protocol; + } + { + if (unlikely(res)) + { + if (multitable) + result->abort_result_set(); + } + else + { + if (thd->lex->describe || thd->lex->analyze_stmt) + res= thd->lex->explain->send_explain(thd); + } + } + + if (result) + { + res= false; + delete result; + } + + return res; +} diff --git a/sql/sql_delete.h b/sql/sql_delete.h index dabcafb..64b882a 100644 --- a/sql/sql_delete.h +++ b/sql/sql_delete.h @@ -17,6 +17,9 @@ #define SQL_DELETE_INCLUDED #include "my_base.h" /* ha_rows */ +#include "sql_class.h" /* enum_duplicates */ +#include "sql_cmd.h" // Sql_cmd_dml +#include "sql_base.h" class THD; struct TABLE_LIST; @@ -26,12 +29,6 @@ class select_result; typedef class Item COND; template <typename T> class SQL_I_List; -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning); -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order, ha_rows rows, - ulonglong options, select_result *result); - class Sql_cmd_delete final : public Sql_cmd_dml { public: @@ -43,6 +40,11 @@ class Sql_cmd_delete final : public Sql_cmd_dml return multitable ? SQLCOM_DELETE_MULTI : SQLCOM_DELETE; } + DML_prelocking_strategy *get_dml_prelocking_strategy() + { + return &dml_prelocking_strategy; + } + protected: bool precheck(THD *thd) override; @@ -55,5 +57,6 @@ class Sql_cmd_delete final : public Sql_cmd_dml bool multitable; + DML_prelocking_strategy dml_prelocking_strategy; }; #endif /* SQL_DELETE_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ee5b2a8..aca34e9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3328,34 +3328,6 @@ void st_select_lex_unit::exclude_level() } -#if 0 -/* - Exclude subtree of current unit from tree of SELECTs - - SYNOPSYS - st_select_lex_unit::exclude_tree() -*/ -void st_select_lex_unit::exclude_tree() -{ - for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) - { - // unlink current level from global SELECTs list - if (sl->link_prev && (*sl->link_prev= sl->link_next)) - sl->link_next->link_prev= sl->link_prev; - - // unlink underlay levels - for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) - { - u->exclude_level(); - } - } - // exclude currect unit from list of nodes - (*prev)= next; - if (next) - next->prev= prev; -} -#endif - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from @@ -3577,7 +3549,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_where_fields + order_group_num + hidden_bit_fields + - fields_in_window_functions) * (size_t) 5; + fields_in_window_functions + 1) * (size_t) 5; DBUG_ASSERT(n_elems % 5 == 0); if (!ref_pointer_array.is_null()) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 72ac199..ecb06f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -34,9 +34,7 @@ #include "sql_locale.h" // my_locale_en_US #include "log.h" // flush_error_log #include "sql_view.h" // mysql_create_view, mysql_drop_view -#include "sql_delete.h" // mysql_delete #include "sql_insert.h" // mysql_insert -#include "sql_update.h" // mysql_update, mysql_multi_update #include "sql_partition.h" // struct partition_info #include "sql_db.h" // mysql_change_db, mysql_create_db, // mysql_rm_db, mysql_upgrade_db, @@ -4395,10 +4393,12 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) } case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(lex->m_sql_cmd != NULL); - thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res = lex->m_sql_cmd->execute(thd); thd->abort_on_warning= 0; break; @@ -4662,129 +4662,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) break; } - case SQLCOM_DELETE: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - select_result *sel_result= NULL; - DBUG_ASSERT(first_table == all_tables && first_table != 0); - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= delete_precheck(thd, all_tables))) - break; - DBUG_ASSERT(select_lex->limit_params.offset_limit == 0); - unit->set_limit(select_lex); - - MYSQL_DELETE_START(thd->query()); - Protocol *save_protocol= NULL; - - if (lex->has_returning()) - { - /* This is DELETE ... RETURNING. It will return output to the client */ - if (thd->lex->analyze_stmt) - { - /* - Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce - output and then discard it. - */ - sel_result= new (thd->mem_root) select_send_analyze(thd); - save_protocol= thd->protocol; - thd->protocol= new Protocol_discard(thd); - } - else - { - if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) - goto error; - } - } - - res = mysql_delete(thd, all_tables, - select_lex->where, &select_lex->order_list, - unit->lim.get_select_limit(), select_lex->options, - lex->result ? lex->result : sel_result); - - if (save_protocol) - { - delete thd->protocol; - thd->protocol= save_protocol; - } - - if (thd->lex->analyze_stmt || thd->lex->describe) - { - if (!res) - res= thd->lex->explain->send_explain(thd); - } - - delete sel_result; - MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func()); - break; - } - case SQLCOM_DELETE_MULTI: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - DBUG_ASSERT(first_table == all_tables && first_table != 0); - TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; - multi_delete *result; - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= multi_delete_precheck(thd, all_tables))) - break; - - /* condition will be TRUE on SP re-excuting */ - if (select_lex->item_list.elements != 0) - select_lex->item_list.empty(); - if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) - goto error; - - THD_STAGE_INFO(thd, stage_init); - if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) - break; - - MYSQL_MULTI_DELETE_START(thd->query()); - if (unlikely(res= mysql_multi_delete_prepare(thd))) - { - MYSQL_MULTI_DELETE_DONE(1, 0); - goto error; - } - - if (likely(!thd->is_fatal_error)) - { - result= new (thd->mem_root) multi_delete(thd, aux_tables, - lex->table_count); - if (likely(result)) - { - if (unlikely(select_lex->vers_setup_conds(thd, aux_tables))) - goto multi_delete_error; - res= mysql_select(thd, - select_lex->get_table_list(), - select_lex->item_list, - select_lex->where, - 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, - (ORDER *)NULL, - (select_lex->options | thd->variables.option_bits | - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, - result, unit, select_lex); - res|= (int)(thd->is_error()); - - MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); - if (res) - result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ - else - { - if (lex->describe || lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - multi_delete_error: - delete result; - } - } - else - { - res= TRUE; // Error - MYSQL_MULTI_DELETE_DONE(1, 0); - } - break; - } case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { @@ -7659,12 +7536,16 @@ void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) } -void mysql_init_multi_delete(LEX *lex) +void mysql_init_delete(LEX *lex) { - lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); lex->first_select_lex()->limit_params.clear(); lex->unit.lim.clear(); +} + +void mysql_init_multi_delete(LEX *lex) +{ + lex->sql_command= SQLCOM_DELETE_MULTI; lex->first_select_lex()->table_list. save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index ebe3fe9..45cd15c 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -95,6 +95,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); +void mysql_init_delete(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3859a13..84feda3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -95,7 +95,6 @@ When one supplies long data for a placeholder: #include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck -#include "sql_delete.h" // mysql_prepare_delete #include "sql_select.h" // for JOIN #include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert #include "sql_db.h" // mysql_opt_change_db, mysql_change_db @@ -1398,56 +1397,6 @@ static bool mysql_test_insert(Prepared_statement *stmt, } -/** - Validate DELETE statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message is set in THD -*/ - -static bool mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) -{ - uint table_count= 0; - THD *thd= stmt->thd; - LEX *lex= stmt->lex; - bool delete_while_scanning; - DBUG_ENTER("mysql_test_delete"); - - if (delete_precheck(thd, table_list) || - open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL)) - goto error; - - if (mysql_handle_derived(thd->lex, DT_INIT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - goto error; - - if (!table_list->single_table_updatable()) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - goto error; - } - if (!table_list->table || !table_list->table->is_created()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - goto error; - } - - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - &lex->first_select_lex()->where, - &delete_while_scanning)); -error: - DBUG_RETURN(TRUE); -} /** @@ -2031,48 +1980,6 @@ static bool mysql_test_create_view(Prepared_statement *stmt) /** - Validate and prepare for execution a multi delete statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message in THD is set. -*/ - -static bool mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) -{ - THD *thd= stmt->thd; - - thd->lex->current_select= thd->lex->first_select_lex(); - if (add_item_to_list(thd, new (thd->mem_root) - Item_null(thd))) - { - my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); - goto error; - } - - if (multi_delete_precheck(thd, tables) || - select_like_stmt_test_with_open(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE)) - goto error; - if (!tables->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); - goto error; - } - return FALSE; -error: - return TRUE; -} - - -/** Wrapper for mysql_insert_select_prepare, to make change of local tables after open_normal_and_derived_tables() call. @@ -2354,14 +2261,13 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: res = lex->m_sql_cmd->prepare(thd); if (!res) lex->m_sql_cmd->unprepare(thd); break; - case SQLCOM_DELETE: - res= mysql_test_delete(stmt, tables); - break; /* The following allow WHERE clause, so they must be tested like SELECT */ case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: @@ -2498,10 +2404,6 @@ static bool check_prepared_statement(Prepared_statement *stmt) res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; - case SQLCOM_DELETE_MULTI: - res= mysql_test_multidelete(stmt, tables); - break; - case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE_SELECT: res= mysql_test_insert_select(stmt, tables); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index edd9aed..31c12fa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28846,7 +28846,8 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab, @note This function takes into account table->opt_range_condition_rows statistic (that is calculated by the make_join_statistics function). - However, single table procedures such as mysql_update() and mysql_delete() + However, single table procedures such as Sql_cmd_update:update_single_table() + and Sql_cmd_delete::delete_single_table() never call make_join_statistics, so they have to update it manually (@see get_index_for_order()). */ @@ -30280,6 +30281,62 @@ static bool process_direct_rownum_comparison(THD *thd, SELECT_LEX_UNIT *unit, } +static void MYSQL_DML_START(THD *thd) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_START(thd->query()); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_START(thd->query()); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_START(thd->query()); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_START(thd->query()); + break; + default: + DBUG_ASSERT(0); + } +} + + +static void MYSQL_DML_DONE(THD *thd, int rc) +{ + switch (thd->lex->sql_command) { + + case SQLCOM_UPDATE: + MYSQL_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update *)(thd->lex->m_sql_cmd->get_result))->num_found()), + (rc ? 0 : + ((multi_update *)(thd->lex->m_sql_cmd->get_resul))->num_updated())); + break; + case SQLCOM_UPDATE_MULTI: + MYSQL_MULTI_UPDATE_DONE( + rc, + (rc ? 0 : + ((multi_update *)(thd->lex->m_sql_cmd->get_result))->num_found()), + (rc ? 0 : + ((multi_update *)(thd->lex->m_sql_cmd->get_resul))->num_updated())); + break; + case SQLCOM_DELETE: + MYSQL_DELETE_DONE(rc, (rc ? 0 : (ulong) (thd->get_row_count_func()))); + break; + case SQLCOM_DELETE_MULTI: + MYSQL_MULTI_DELETE_DONE( + rc, + (rc ? 0 : + ((multi_delete *)(thd->lex->m_sql_cmd->get_resul))->num_deleted())); + break; + default: + DBUG_ASSERT(0); + } +} + bool Sql_cmd_dml::prepare(THD *thd) { lex= thd->lex; @@ -30291,6 +30348,8 @@ bool Sql_cmd_dml::prepare(THD *thd) if (precheck(thd)) goto err; + MYSQL_DML_START(thd); + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, @@ -30338,6 +30397,9 @@ bool Sql_cmd_dml::execute(THD *thd) { if (precheck(thd)) goto err; + + MYSQL_DML_START(thd); + if (open_tables_for_query(thd, lex->query_tables, &table_count, 0, get_dml_prelocking_strategy())) goto err; @@ -30345,7 +30407,6 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_init); - DBUG_ASSERT(!lex->is_query_tables_locked()); /* Locking of tables is done after preparation but before optimization. This allows to do better partition pruning and avoid locking unused @@ -30373,10 +30434,13 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_end); + MYSQL_DML_DONE(thd, res); + return res; err: DBUG_ASSERT(thd->is_error() || thd->killed); + MYSQL_DML_DONE(thd, 1); THD_STAGE_INFO(thd, stage_end); (void)unit->cleanup(); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f04db0..c83a527 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -197,22 +197,11 @@ static bool check_fields(THD *thd, TABLE_LIST *table, List<Item> &items, return true; } - DBUG_ASSERT(thd->lex->sql_command == SQLCOM_UPDATE); - for (List_iterator_fast<Item> it(items); (item=it++);) - { - Field *f= item->field_for_view_update()->field; - vers_select_conds_t &period= table->period_conditions; - if (period.field_start->field == f || period.field_end->field == f) - { - my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), - item->name.str, period.name.str); - return true; - } - } } return FALSE; } + bool TABLE::vers_check_update(List<Item> &items) { List_iterator<Item> it(items); @@ -1240,6 +1229,9 @@ bool Sql_cmd_update::update_single_table(THD *thd) thd->lex->current_select->save_leaf_tables(thd); thd->lex->current_select->first_cond_optimization= 0; } + ((multi_update *)result)->set_found(found); + ((multi_update *)result)->set_updated(updated); + if (unlikely(thd->lex->analyze_stmt)) goto emit_explain_and_leave; @@ -1271,75 +1263,6 @@ bool Sql_cmd_update::update_single_table(THD *thd) DBUG_RETURN((err2 || thd->is_error()) ? 1 : 0); } -/* - Prepare items in UPDATE statement - - SYNOPSIS - mysql_prepare_update() - thd - thread handler - table_list - global/local table list - conds - conditions - order_num - number of ORDER BY list entries - order - ORDER BY clause list - - RETURN VALUE - FALSE OK - TRUE error -*/ -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order) -{ - Item *fake_conds= 0; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - TABLE *table= table_list->table; -#endif - List<Item> all_fields; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_update"); - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - table_list->grant.want_privilege= table->grant.want_privilege= - (SELECT_ACL & ~table->grant.privilege); - table_list->register_want_access(SELECT_ACL); -#endif - - thd->lex->allow_sum_func.clear_all(); - - if (table_list->has_period() && - select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - /* - We do not call DT_MERGE_FOR_INSERT because it has no sense for simple - (not multi-) update - */ - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, - FALSE, UPDATE_ACL, SELECT_ACL, TRUE) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - select_lex->setup_ref_array(thd, order_num) || - setup_order(thd, select_lex->ref_pointer_array, - table_list, all_fields, all_fields, order) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} /** Check that we are not using table that we are updating in a sub select @@ -1596,7 +1519,13 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) mysql_handle_derived(lex, DT_PREPARE)) DBUG_RETURN(1); - /* + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + /* setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables() second time, but this call will do nothing (there are check for second call in setup_tables()). @@ -1607,6 +1536,10 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) FALSE, UPDATE_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(1); + if (table_list->has_period() && + select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + List<Item> *fields= &lex->first_select_lex()->item_list; if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), *fields, MARK_COLUMNS_WRITE, 0, 0)) @@ -1715,153 +1648,6 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) DBUG_RETURN(0); } -/* - make update specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_update_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_update_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *table_list= lex->query_tables; - TABLE_LIST *tl; - Multiupdate_prelocking_strategy prelocking_strategy; - uint table_count= lex->table_count; - DBUG_ENTER("mysql_multi_update_prepare"); - - /* - Open tables and create derived ones, but do not lock and fill them yet. - - During prepare phase acquire only S metadata locks instead of SW locks to - keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE - and global read lock. - - Don't evaluate any subqueries even if constant, because - tables aren't locked yet. - */ - lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; - if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) - { - if (open_tables(thd, &table_list, &table_count, - thd->stmt_arena->is_stmt_prepare() ? MYSQL_OPEN_FORCE_SHARED_MDL : 0, - &prelocking_strategy)) - DBUG_RETURN(TRUE); - } - else - { - /* following need for prepared statements, to run next time multi-update */ - thd->lex->sql_command= SQLCOM_UPDATE_MULTI; - prelocking_strategy.reset(thd); - if (prelocking_strategy.handle_end(thd)) - DBUG_RETURN(TRUE); - } - - /* now lock and fill tables */ - if (!thd->stmt_arena->is_stmt_prepare() && - lock_tables(thd, table_list, table_count, 0)) - DBUG_RETURN(TRUE); - - lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; - - (void) read_statistics_for_tables_if_needed(thd, table_list); - /* @todo: downgrade the metadata locks here. */ - - /* - Check that we are not using table that we are updating, but we should - skip all tables of UPDATE SELECT itself - */ - lex->first_select_lex()->exclude_from_table_unique_test= TRUE; - /* We only need SELECT privilege for columns in the values list */ - List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables); - while ((tl= ti++)) - { - if (tl->is_jtbm()) - continue; - TABLE *table= tl->table; - TABLE_LIST *tlist; - if (!(tlist= tl->top_table())->derived) - { - tlist->grant.want_privilege= - (SELECT_ACL & ~tlist->grant.privilege); - table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); - } - DBUG_PRINT("info", ("table: %s want_privilege: %llx", tl->alias.str, - (longlong) table->grant.want_privilege)); - } - /* - Set exclude_from_table_unique_test value back to FALSE. It is needed for - further check in multi_update::prepare whether to use record cache. - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN (FALSE); -} - - -/* - Setup multi-update handling and call SELECT to do the join -*/ - -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, - List<Item> *values, COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, - bool ignore, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, multi_update **result) -{ - bool res; - DBUG_ENTER("mysql_multi_update"); - - if (!(*result= new (thd->mem_root) multi_update(thd, table_list, - &thd->lex->first_select_lex()->leaf_tables, - fields, values, handle_duplicates, ignore))) - { - DBUG_RETURN(TRUE); - } - - if ((*result)->init(thd)) - DBUG_RETURN(1); - - thd->abort_on_warning= !ignore && thd->is_strict_mode(); - List<Item> total_list; - - if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, - table_list, select_lex->leaf_tables, FALSE, FALSE)) - DBUG_RETURN(1); - - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(1); - - res= mysql_select(thd, - table_list, total_list, conds, - select_lex->order_list.elements, - select_lex->order_list.first, NULL, NULL, NULL, - options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, - *result, unit, select_lex); - - DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); - res|= thd->is_error(); - if (unlikely(res)) - (*result)->abort_result_set(); - else - { - if (thd->lex->describe || thd->lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - thd->abort_on_warning= 0; - DBUG_RETURN(res); -} - multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, List<TABLE_LIST> *leaves_list, @@ -3021,7 +2807,15 @@ bool Sql_cmd_update::precheck(THD *thd) if (multi_update_precheck(thd, lex->query_tables)) return true; } + + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); + return false; + +#ifdef WITH_WSREP +wsrep_error_label: +#endif + return true; } @@ -3029,26 +2823,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) { JOIN *join; int err= 0; - // uint table_cnt= 0; SELECT_LEX *const select_lex = thd->lex->first_select_lex(); TABLE_LIST *const table_list = select_lex->get_table_list(); ulonglong select_options= select_lex->options; bool free_join= 1; - // bool orig_multitable= multitable; DBUG_ENTER("Sql_cmd_update::prepare_inner"); + (void) read_statistics_for_tables_if_needed(thd, table_list); + + THD_STAGE_INFO(thd, stage_init_update); + if (!multitable) { - TABLE_LIST *update_source_table= 0; - if (mysql_handle_derived(lex, DT_INIT)) DBUG_RETURN(TRUE); + } - if (table_list->has_period() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(TRUE); - } + if (table_list->has_period() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(TRUE); + } + + if (!multitable) + { + TABLE_LIST *update_source_table= 0; if (((update_source_table=unique_table(thd, table_list, table_list->next_global, 0)) || @@ -3088,8 +2887,8 @@ bool Sql_cmd_update::prepare_inner(THD *thd) DBUG_RETURN(TRUE); } - if (((multi_update *)result)->init(thd)) - DBUG_RETURN(TRUE); + if (((multi_update *)result)->init(thd)) + DBUG_RETURN(TRUE); if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, select_lex->leaf_tables, false, false)) @@ -3130,6 +2929,31 @@ bool Sql_cmd_update::prepare_inner(THD *thd) } + if (table_list->has_period()) + { + Item *item; + for (List_iterator_fast<Item> it(select_lex->item_list); (item=it++);) + { + Field *f= item->field_for_view_update()->field; + vers_select_conds_t &period= table_list->period_conditions; + if (period.field_start->field == f || period.field_end->field == f) + { + my_error(ER_PERIOD_COLUMNS_UPDATED, MYF(0), + item->name.str, period.name.str); + DBUG_RETURN(true); + } + } + + if (!table_list->period_conditions.start.item->const_item() + || !table_list->period_conditions.end.item->const_item()) + { + my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); + DBUG_RETURN(true); + } + table_list->table->no_cache= true; + } + + free_join= false; err: @@ -3147,8 +2971,16 @@ bool Sql_cmd_update::prepare_inner(THD *thd) bool Sql_cmd_update::execute_inner(THD *thd) { - bool res= multitable ? Sql_cmd_dml::execute_inner(thd) - : update_single_table(thd); + bool res= 0; + + thd->get_stmt_da()->reset_current_row_for_warning(1); + if (!multitable) + res= update_single_table(thd); + else + { + thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + res= Sql_cmd_dml::execute_inner(thd); + } res|= thd->is_error(); if (multitable) diff --git a/sql/sql_update.h b/sql/sql_update.h index e52d3cd..cf33461 100644 --- a/sql/sql_update.h +++ b/sql/sql_update.h @@ -27,19 +27,7 @@ class THD; typedef class st_select_lex SELECT_LEX; typedef class st_select_lex_unit SELECT_LEX_UNIT; -bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, - Item **conds, uint order_num, ORDER *order); bool check_unique_table(THD *thd, TABLE_LIST *table_list); -int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &values,COND *conds, - uint order_num, ORDER *order, ha_rows limit, - bool ignore, ha_rows *found_return, ha_rows *updated_return); -bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, - List<Item> *fields, List<Item> *values, - COND *conds, ulonglong options, - enum enum_duplicates handle_duplicates, bool ignore, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - multi_update **result); bool records_are_comparable(const TABLE *table); bool compare_record(const TABLE *table); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30eda7c..48eed4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -70,6 +70,7 @@ #include "sql_type_json.h" #include "json_table.h" #include "sql_update.h" +#include "sql_delete.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1675,7 +1676,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_mi_check_type opt_to mi_check_types table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan - single_multi table_wild_list table_wild_one opt_wild + single_multi opt_wild opt_and select_var_list select_var_list_init help opt_extended_describe shutdown @@ -13245,8 +13246,8 @@ update: MYSQL_YYABORT; /* In case of multi-update setting write lock for all tables may - be too pessimistic. We will decrease lock level if possible in - mysql_multi_update(). + be too pessimistic. We will decrease lock level if possible + later while processing the statement. */ slex->set_lock_for_tables($3, slex->table_list.elements == 1, false); } @@ -13303,12 +13304,11 @@ delete: DELETE_SYM { LEX *lex= Lex; - lex->sql_command= SQLCOM_DELETE; YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; if (Lex->main_select_push()) MYSQL_YYABORT; - mysql_init_select(lex); + mysql_init_delete(lex); lex->ignore= 0; lex->first_select_lex()->order_list.empty(); } @@ -13334,8 +13334,13 @@ delete_part2: opt_delete_options single_multi {} | HISTORY_SYM delete_single_table opt_delete_system_time { - Lex->last_table()->vers_conditions= Lex->vers_conditions; - Lex->pop_select(); //main select + LEX *lex= Lex; + lex->last_table()->vers_conditions= lex->vers_conditions; + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } ; @@ -13369,12 +13374,22 @@ single_multi: delete_limit_clause opt_returning { + LEX *lex= Lex; if ($3) Select->order_list= *($3); - Lex->pop_select(); //main select + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } - | table_wild_list + | table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13386,6 +13401,11 @@ single_multi: } stmt_end {} | FROM table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13421,44 +13441,6 @@ opt_returning: } ; -table_wild_list: - table_wild_one - | table_wild_list ',' table_wild_one - ; - -table_wild_one: - ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(&$1); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - | ident '.' ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - ; - opt_wild: /* empty */ {} | '.' '*' {} diff --git a/sql/table.h b/sql/table.h index 8d609fb..358e1a9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2321,6 +2321,7 @@ struct TABLE_LIST */ select_unit *derived_result; /* Stub used for materialized derived tables. */ + bool delete_while_scanning; table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map get_map() {
1 0
0 0
[Commits] d5d8695: MDEV-7487 Semi-join optimization for single-table UPDATE/DELETEs
by IgorBabaev 04 Jun '22

04 Jun '22
revision-id: d5d8695423ff9ed8fb245fe1dd1cf38d1c57856e (mariadb-10.6.1-310-gd5d8695) parent(s): 1f0333db90fb942b2a8435733184460ca3c56288 author: Igor Babaev committer: Igor Babaev timestamp: 2022-06-03 20:05:31 -0700 message: MDEV-7487 Semi-join optimization for single-table UPDATE/DELETEs This is a preliminary patch. --- mysql-test/main/delete_single_to_multi.result | 2144 ++++++++++++++++++++ mysql-test/main/delete_single_to_multi.test | 723 +++++++ mysql-test/main/log_state.result | 2 +- .../main/myisam_explain_non_select_all.result | 43 +- mysql-test/main/opt_trace.result | 20 + mysql-test/main/update_single_to_multi.result | 2137 +++++++++++++++++++ mysql-test/main/update_single_to_multi.test | 511 +++++ sql/opt_subselect.cc | 31 +- sql/sql_class.h | 1 + sql/sql_delete.cc | 76 +- sql/sql_lex.h | 1 + sql/sql_select.cc | 3 +- sql/sql_update.cc | 12 +- sql/sql_yacc.yy | 13 + 14 files changed, 5656 insertions(+), 61 deletions(-) diff --git a/mysql-test/main/delete_single_to_multi.result b/mysql-test/main/delete_single_to_multi.result new file mode 100644 index 0000000..4cf93ce --- /dev/null +++ b/mysql-test/main/delete_single_to_multi.result @@ -0,0 +1,2144 @@ +DROP DATABASE IF EXISTS dbt3_s001; +CREATE DATABASE dbt3_s001; +use dbt3_s001; +create index i_n_name on nation(n_name); +analyze table nation; +Table Op Msg_type Msg_text +dbt3_s001.nation analyze status Engine-independent statistics collected +dbt3_s001.nation analyze status OK +# Pullout +# ======= +explain +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (7%) Using where; Using rowid filter +explain format=json +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "nation", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_n_name"], + "key": "i_n_name", + "key_length": "26", + "used_key_parts": ["n_name"], + "ref": ["const"], + "rows": 1, + "filtered": 100, + "index_condition": "nation.n_name = 'PERU'" + }, + "table": { + "table_name": "customer", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "key": "i_c_nationkey", + "key_length": "5", + "used_key_parts": ["c_nationkey"], + "ref": ["dbt3_s001.nation.n_nationkey"], + "rows": 11, + "filtered": 100 + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 108, + "selectivity_pct": 7.2 + }, + "rows": 11, + "filtered": 7.199999809, + "attached_condition": "orders.o_orderDATE between '1992-01-01' and '1992-06-30'" + } + } +} +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +5382 138423.03 +644 201268.06 +737 12984.85 +create table t as +select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +explain +delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (7%) Using where; Using rowid filter +explain format=json +delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "nation", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_n_name"], + "key": "i_n_name", + "key_length": "26", + "used_key_parts": ["n_name"], + "ref": ["const"], + "rows": 1, + "filtered": 100, + "index_condition": "nation.n_name = 'PERU'" + }, + "table": { + "table_name": "customer", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "key": "i_c_nationkey", + "key_length": "5", + "used_key_parts": ["c_nationkey"], + "ref": ["dbt3_s001.nation.n_nationkey"], + "rows": 11, + "filtered": 100 + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 108, + "selectivity_pct": 7.2 + }, + "rows": 11, + "filtered": 7.199999809, + "attached_condition": "orders.o_orderDATE between '1992-01-01' and '1992-06-30'" + } + } +} +delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +insert into orders select * from t; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +5382 138423.03 +644 201268.06 +737 12984.85 +drop table t; +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +1 8 357.84 +3 8 645.4 +4 1 444.37 +5 8 50.52 +6 1 642.13 +7 8 763.98 +8 1 957.34 +create table t as +select * from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +explain +delete from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +delete from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +insert into partsupp select * from t; +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +1 8 357.84 +3 8 645.4 +4 1 444.37 +5 8 50.52 +6 1 642.13 +7 8 763.98 +8 1 957.34 +drop table t; +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +1 8 357.84 +3 8 645.4 +4 1 444.37 +5 8 50.52 +6 1 642.13 +7 8 763.98 +8 1 957.34 +create table t as +select * from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +explain +delete from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +delete from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +insert into partsupp select * from t; +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +1 8 357.84 +3 8 645.4 +4 1 444.37 +5 8 50.52 +6 1 642.13 +7 8 763.98 +8 1 957.34 +drop table t; +explain +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_suppkey 5 dbt3_s001.supplier.s_suppkey 100 Using where +1 PRIMARY orders eq_ref|filter PRIMARY,i_o_orderdate,i_o_custkey PRIMARY|i_o_orderdate 4|4 dbt3_s001.lineitem.l_orderkey 1 (7%) Using where; Using rowid filter +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.lineitem.l_partkey 1 Using where +1 PRIMARY customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +2500 2 0.02 +2500 4 0.02 +4996 1 0.01 +933 1 0.04 +create table t as +select * from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +explain +delete from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_suppkey 5 dbt3_s001.supplier.s_suppkey 100 Using where +1 PRIMARY orders eq_ref|filter PRIMARY,i_o_orderdate,i_o_custkey PRIMARY|i_o_orderdate 4|4 dbt3_s001.lineitem.l_orderkey 1 (7%) Using where; Using rowid filter +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.lineitem.l_partkey 1 Using where +1 PRIMARY customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where +delete from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +insert into lineitem select * from t; +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +2500 2 0.02 +2500 4 0.02 +4996 1 0.01 +933 1 0.04 +drop table t; +# FirstMatch +# ========== +explain +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY,i_c_nationkey NULL NULL NULL 150 Using where +1 PRIMARY nation eq_ref|filter PRIMARY,i_n_regionkey PRIMARY|i_n_regionkey 4|5 dbt3_s001.customer.c_nationkey 1 (40%) Using where; Using rowid filter +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (6%) Using where; FirstMatch(nation); Using rowid filter +explain format=json +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "customer", + "access_type": "ALL", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "rows": 150, + "filtered": 100, + "attached_condition": "customer.c_nationkey is not null" + }, + "table": { + "table_name": "nation", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY", "i_n_regionkey"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["n_nationkey"], + "ref": ["dbt3_s001.customer.c_nationkey"], + "rowid_filter": { + "range": { + "key": "i_n_regionkey", + "used_key_parts": ["n_regionkey"] + }, + "rows": 10, + "selectivity_pct": 40 + }, + "rows": 1, + "filtered": 40, + "attached_condition": "nation.n_regionkey in (1,2)" + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 89, + "selectivity_pct": 5.933333333 + }, + "rows": 11, + "filtered": 5.933333397, + "attached_condition": "orders.o_orderDATE between '1992-10-09' and '1993-03-08'", + "first_match": "nation" + } + } +} +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +create table t as +select * from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +explain +delete from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY,i_c_nationkey NULL NULL NULL 150 Using where +1 PRIMARY nation eq_ref|filter PRIMARY,i_n_regionkey PRIMARY|i_n_regionkey 4|5 dbt3_s001.customer.c_nationkey 1 (40%) Using where; Using rowid filter +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (6%) Using where; FirstMatch(nation); Using rowid filter +explain format=json +delete from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "customer", + "access_type": "ALL", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "rows": 150, + "filtered": 100, + "attached_condition": "customer.c_nationkey is not null" + }, + "table": { + "table_name": "nation", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY", "i_n_regionkey"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["n_nationkey"], + "ref": ["dbt3_s001.customer.c_nationkey"], + "rowid_filter": { + "range": { + "key": "i_n_regionkey", + "used_key_parts": ["n_regionkey"] + }, + "rows": 10, + "selectivity_pct": 40 + }, + "rows": 1, + "filtered": 40, + "attached_condition": "nation.n_regionkey in (1,2)" + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 89, + "selectivity_pct": 5.933333333 + }, + "rows": 11, + "filtered": 5.933333397, + "attached_condition": "orders.o_orderDATE between '1992-10-09' and '1993-03-08'", + "first_match": "nation" + } + } +} +delete from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +drop table t; +explain +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (14%) Using where; FirstMatch(customer); Using rowid filter +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +Customer#000000008 6819.74 +Customer#000000035 1228.24 +Customer#000000061 1536.24 +Customer#000000097 2164.48 +Customer#000000121 6428.32 +Customer#000000133 2314.67 +create table t as +select * from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +explain +delete from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (14%) Using where; FirstMatch(customer); Using rowid filter +delete from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +Customer#000000008 6819.74 +Customer#000000035 1228.24 +Customer#000000061 1536.24 +Customer#000000097 2164.48 +Customer#000000121 6428.32 +Customer#000000133 2314.67 +drop table t; +# Materialization +# =============== +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 28 Using index condition; Using where +explain format=json +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'", + "attached_condition": "orders.o_custkey is not null" + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["dbt3_s001.orders.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 28 Using index condition; Using where +explain format=json +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'", + "attached_condition": "orders.o_custkey is not null" + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["dbt3_s001.orders.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +drop table t; +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 114 Using index condition; Using where +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +Customer#000000001 711.56 +Customer#000000002 121.65 +Customer#000000007 9561.95 +Customer#000000008 6819.74 +Customer#000000010 2753.54 +Customer#000000011 -272.6 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000029 7618.27 +Customer#000000031 5236.89 +Customer#000000034 8589.7 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000043 9904.28 +Customer#000000044 7315.94 +Customer#000000046 5744.59 +Customer#000000047 274.58 +Customer#000000049 4573.94 +Customer#000000053 4113.64 +Customer#000000055 4572.11 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000070 4867.52 +Customer#000000071 -611.19 +Customer#000000073 4288.5 +Customer#000000074 2764.43 +Customer#000000076 5745.33 +Customer#000000079 5121.28 +Customer#000000080 7383.53 +Customer#000000082 9468.34 +Customer#000000083 6463.51 +Customer#000000085 3386.64 +Customer#000000086 3306.32 +Customer#000000088 8031.44 +Customer#000000091 4643.14 +Customer#000000092 1182.91 +Customer#000000095 5327.38 +Customer#000000097 2164.48 +Customer#000000100 9889.89 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000104 -588.38 +Customer#000000106 3288.42 +Customer#000000109 -716.1 +Customer#000000110 7462.99 +Customer#000000112 2953.35 +Customer#000000118 3582.37 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000131 8595.53 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +Customer#000000136 -842.39 +Customer#000000137 7838.3 +Customer#000000139 7897.78 +Customer#000000142 2209.81 +Customer#000000143 2186.5 +Customer#000000148 2135.6 +Customer#000000149 8959.65 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 114 Using index condition; Using where +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +Customer#000000001 711.56 +Customer#000000002 121.65 +Customer#000000007 9561.95 +Customer#000000008 6819.74 +Customer#000000010 2753.54 +Customer#000000011 -272.6 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000029 7618.27 +Customer#000000031 5236.89 +Customer#000000034 8589.7 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000043 9904.28 +Customer#000000044 7315.94 +Customer#000000046 5744.59 +Customer#000000047 274.58 +Customer#000000049 4573.94 +Customer#000000053 4113.64 +Customer#000000055 4572.11 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000070 4867.52 +Customer#000000071 -611.19 +Customer#000000073 4288.5 +Customer#000000074 2764.43 +Customer#000000076 5745.33 +Customer#000000079 5121.28 +Customer#000000080 7383.53 +Customer#000000082 9468.34 +Customer#000000083 6463.51 +Customer#000000085 3386.64 +Customer#000000086 3306.32 +Customer#000000088 8031.44 +Customer#000000091 4643.14 +Customer#000000092 1182.91 +Customer#000000095 5327.38 +Customer#000000097 2164.48 +Customer#000000100 9889.89 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000104 -588.38 +Customer#000000106 3288.42 +Customer#000000109 -716.1 +Customer#000000110 7462.99 +Customer#000000112 2953.35 +Customer#000000118 3582.37 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000131 8595.53 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +Customer#000000136 -842.39 +Customer#000000137 7838.3 +Customer#000000139 7897.78 +Customer#000000142 2209.81 +Customer#000000143 2186.5 +Customer#000000148 2135.6 +Customer#000000149 8959.65 +drop table t; +# Materialization SJM +# =================== +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 <subquery2>.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 28 Using index condition; Using temporary +explain format=json +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "count(orders.o_custkey) > 1", + "temporary_table": { + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'" + } + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["<subquery2>.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 <subquery2>.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 28 Using index condition; Using temporary +explain format=json +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "count(orders.o_custkey) > 1", + "temporary_table": { + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'" + } + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["<subquery2>.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +drop table t; +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.customer.c_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 242 Using index condition; Using temporary +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000016 4681.03 +Customer#000000037 -917.75 +Customer#000000046 5744.59 +Customer#000000091 4643.14 +Customer#000000103 2757.45 +Customer#000000118 3582.37 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.customer.c_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 242 Using index condition; Using temporary +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000016 4681.03 +Customer#000000037 -917.75 +Customer#000000046 5744.59 +Customer#000000091 4643.14 +Customer#000000103 2757.45 +Customer#000000118 3582.37 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +drop table t; +# Pullout PS +# ========== +prepare stmt from " +delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +"; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +5382 138423.03 +644 201268.06 +737 12984.85 +create table t as +select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +execute stmt; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +insert into orders select * from t; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +5382 138423.03 +644 201268.06 +737 12984.85 +create table r as +select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +execute stmt; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +insert into orders select * from r; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +5382 138423.03 +644 201268.06 +737 12984.85 +drop table t,r; +deallocate prepare stmt; +# FirstMatch PS +# ============= +prepare stmt from " +delete from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +"; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +create table t as +select * from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +execute stmt; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +create table r as +select * from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +execute stmt; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +insert into customer select * from r; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +drop table t,r; +deallocate prepare stmt; +# Materialization PS +# ================== +prepare stmt from " +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') and c_name like ?; +"; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +set @a1='Customer#%1_'; +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') and c_name like @a1; +execute stmt using @a1; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +set @a2='Customer#%3_'; +create table r as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') and c_name like @a2; +execute stmt using @a2; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000140 9963.15 +insert into customer select * from r; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000005 794.47 +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000035 1228.24 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000040 1335.3 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000098 -551.37 +Customer#000000109 -716.1 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000136 -842.39 +Customer#000000140 9963.15 +drop table t,r; +deallocate prepare stmt; +# Materialization SJM PS +# ====================== +prepare stmt from " +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') and c_acctbal between ? and ?; +"; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +set @a1=3500; +set @a2=4000; +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1) and c_acctbal between @a1 and @a2; +execute stmt using @a1, @a2; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +set @a3=-1000; +set @a4=3500; +create table r as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1) and c_acctbal between @a3 and @a4; +execute stmt using @a3, @a4; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +insert into customer select * from r; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +drop table t,r; +deallocate prepare stmt; +# Pullout SP +# ========== +create procedure p(a1 int, a2 int) +delete from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')) and o_totalprice between a1 and a2; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +644 201268.06 +737 12984.85 +create table t as +select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')) and o_totalprice between 150000 and 200000; +call p(150000, 200000); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +644 201268.06 +737 12984.85 +insert into orders select * from t; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +644 201268.06 +737 12984.85 +create table r as +select * from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')) and o_totalprice between 180000 and 210000; +call p(180000, 210000); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5121 150334.57 +737 12984.85 +insert into orders select * from r; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +1729 12137.76 +2880 145761.99 +3142 16030.15 +5095 184583.99 +5121 150334.57 +644 201268.06 +737 12984.85 +drop table t,r; +drop procedure p; +# FirstMatch SP +# ============= +create procedure p(a int) +delete from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08') and c_acctbal > a; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +create table t as +select * from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08') and c_acctbal > 4000; +call p(4000); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000097 2164.48 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000133 2314.67 +insert into customer select * from t; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +create table r as +select * from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08') and c_acctbal > 2000; +call p(2000); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000047 274.58 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +insert into customer select * from r; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +drop table t,r; +drop procedure p; +# Materialization SP +# ================== +create procedure p() +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000140 9963.15 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +call p(); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000140 9963.15 +create table r as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +call p(); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +insert into customer select * from r; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000016 4681.03 +Customer#000000025 7133.7 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000038 6345.11 +Customer#000000052 5630.28 +Customer#000000056 6530.86 +Customer#000000065 8795.16 +Customer#000000076 5745.33 +Customer#000000091 4643.14 +Customer#000000115 7508.92 +Customer#000000116 8403.99 +Customer#000000118 3582.37 +Customer#000000140 9963.15 +drop table t,r; +drop procedure p; +# Materialization SJM SP +# ====================== +create procedure p() +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +call p(); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +insert into customer select * from t; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +create table r as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +call p(); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +insert into customer select * from r; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000056 6530.86 +Customer#000000118 3582.37 +drop table t,r; +drop procedure p; +# Check for DELETE ... RETURNING with SJ subquery in WHERE +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name +Customer#000000013 +Customer#000000016 +Customer#000000025 +Customer#000000032 +Customer#000000037 +Customer#000000038 +Customer#000000052 +Customer#000000056 +Customer#000000065 +Customer#000000076 +Customer#000000091 +Customer#000000115 +Customer#000000116 +Customer#000000118 +Customer#000000140 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') returning c_name; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL NULL NULL NULL NULL 141 Using where +2 DEPENDENT SUBQUERY orders index_subquery|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 func 175 (2%) Using where; Using rowid filter +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08') returning c_name; +c_name +Customer#000000013 +Customer#000000016 +Customer#000000025 +Customer#000000032 +Customer#000000037 +Customer#000000038 +Customer#000000052 +Customer#000000056 +Customer#000000065 +Customer#000000076 +Customer#000000091 +Customer#000000115 +Customer#000000116 +Customer#000000118 +Customer#000000140 +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name +insert into customer select * from t; +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name +Customer#000000013 +Customer#000000016 +Customer#000000025 +Customer#000000032 +Customer#000000037 +Customer#000000038 +Customer#000000052 +Customer#000000056 +Customer#000000065 +Customer#000000076 +Customer#000000091 +Customer#000000115 +Customer#000000116 +Customer#000000118 +Customer#000000140 +drop table t; +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name +Customer#000000013 +Customer#000000032 +Customer#000000037 +Customer#000000056 +Customer#000000118 +create table t as +select * from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +explain +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1) returning c_name; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL NULL NULL NULL NULL 141 Using where +2 DEPENDENT SUBQUERY orders range i_o_orderdate i_o_orderdate 4 NULL 28 Using index condition; Using temporary +delete from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1) returning c_name; +c_name +Customer#000000013 +Customer#000000032 +Customer#000000037 +Customer#000000056 +Customer#000000118 +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name +insert into customer select * from t; +select c_name from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name +Customer#000000013 +Customer#000000032 +Customer#000000037 +Customer#000000056 +Customer#000000118 +drop table t; +DROP DATABASE dbt3_s001; diff --git a/mysql-test/main/delete_single_to_multi.test b/mysql-test/main/delete_single_to_multi.test new file mode 100644 index 0000000..825da74 --- /dev/null +++ b/mysql-test/main/delete_single_to_multi.test @@ -0,0 +1,723 @@ +--disable_warnings +DROP DATABASE IF EXISTS dbt3_s001; +--enable_warnings + +CREATE DATABASE dbt3_s001; + +use dbt3_s001; + +--disable_query_log +--disable_result_log +--disable_warnings +--source include/dbt3_s001.inc +--enable_warnings +--enable_result_log +--enable_query_log + +create index i_n_name on nation(n_name); +analyze table nation; + + +--echo # Pullout +--echo # ======= + +let $c1= + o_orderDATE between '1992-01-01' and '1992-06-30' and + o_custkey in (select c_custkey from customer + where c_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select o_orderkey, o_totalprice from orders where $c1; +eval +explain format=json +select o_orderkey, o_totalprice from orders where $c1; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +eval +create table t as +select * from orders where $c1; + +eval +explain +delete from orders where $c1; +eval +explain format=json +delete from orders where $c1; +eval +delete from orders where $c1; +eval +select o_orderkey, o_totalprice from orders where $c1; + + +insert into orders select * from t; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +drop table t; + + +let $c2= + (ps_partkey, ps_suppkey) in + (select p_partkey, s_suppkey from part, supplier + where p_retailprice between 901 and 910 and + s_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; +--sorted_result +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; +eval +create table t as +select * from partsupp where $c2; + +eval +explain +delete from partsupp where $c2; +eval +delete from partsupp where $c2; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; + +insert into partsupp select * from t; +--sorted_result +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; +drop table t; + + +let $c3= + ps_partkey in (select p_partkey from part + where p_retailprice between 901 and 910) and + ps_suppkey in (select s_suppkey from supplier + where s_nationkey in (select n_nationkey from nation + where n_name='PERU')); +eval +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; +--sorted_result +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; +eval +create table t as +select * from partsupp where $c3; + +eval +explain +delete from partsupp where $c3; +eval +delete from partsupp where $c3; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; + +insert into partsupp select * from t; +--sorted_result +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; +drop table t; + + +let $c4= + l_orderkey in (select o_orderkey from orders + where o_custkey in + (select c_custkey from customer + where c_nationkey in + (select n_nationkey from nation + where n_name='PERU')) + and + o_orderDATE between '1992-06-30' and '1992-12-31') + and + (l_partkey, l_suppkey) in + (select p_partkey, s_suppkey from part, supplier + where p_retailprice between 901 and 1000 and + s_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; +--sorted_result +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; +eval +create table t as +select * from lineitem where $c4; + +eval +explain +delete from lineitem where $c4; +eval +delete from lineitem where $c4; +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; + +insert into lineitem select * from t; +--sorted_result +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; +drop table t; + + +--echo # FirstMatch +--echo # ========== + +let $c5= + c_nationkey in (select n_nationkey from nation + where n_regionkey in (1,2)) + and + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-10-09' and '1993-03-08'); + +eval +explain +select c_name, c_acctbal from customer where $c5; +eval +explain format=json +select c_name, c_acctbal from customer where $c5; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +eval +create table t as +select * from customer where $c5; + +eval +explain +delete from customer where $c5; +eval +explain format=json +delete from customer where $c5; +eval +delete from customer where $c5; +eval +select c_name, c_acctbal from customer where $c5; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +drop table t; + + +let $c6= + c_nationkey in (select n_nationkey from nation where n_name='PERU') + and + c_custkey in (select o_custkey from orders + where o_orderDATE between "1992-01-09" and "1993-01-08"); + +eval +explain +select c_name, c_acctbal from customer where $c6; +--sorted_result +eval +select c_name, c_acctbal from customer where $c6; +eval +create table t as +select * from customer where $c6; + +eval +explain +delete from customer where $c6; +eval +delete from customer where $c6; +eval +select c_name, c_acctbal from customer where $c6; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c6; +drop table t; + + +--echo # Materialization +--echo # =============== + +let $c7= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1992-03-08'); + +eval +explain +select c_name, c_acctbal from customer where $c7; +eval +explain format=json +select c_name, c_acctbal from customer where $c7; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +eval +create table t as +select * from customer where $c7; + +eval +explain +delete from customer where $c7; +eval +explain format=json +delete from customer where $c7; +eval +delete from customer where $c7; +eval +select c_name, c_acctbal from customer where $c7; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +drop table t; + + +let $c8= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-06-09' and '1993-01-08'); + +eval +explain +select c_name, c_acctbal from customer where $c8; +--sorted_result +eval +select c_name, c_acctbal from customer where $c8; +eval +create table t as +select * from customer where $c8; + +eval +explain +delete from customer where $c8; +eval +delete from customer where $c8; +eval +select c_name, c_acctbal from customer where $c8; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c8; +drop table t; + + +--echo # Materialization SJM +--echo # =================== + +let $c9= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); + +eval +explain +select c_name, c_acctbal from customer where $c9; +eval +explain format=json +select c_name, c_acctbal from customer where $c9; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +eval +create table t as +select * from customer where $c9; + +eval +explain +delete from customer where $c9; +eval +explain format=json +delete from customer where $c9; +eval +delete from customer where $c9; +eval +select c_name, c_acctbal from customer where $c9; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +drop table t; + + +let $c10= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); + +eval +explain +select c_name, c_acctbal from customer where $c10; +--sorted_result +eval +select c_name, c_acctbal from customer where $c10; +eval +create table t as +select * from customer where $c10; + +eval +explain +delete from customer where $c10; +eval +delete from customer where $c10; +eval +select c_name, c_acctbal from customer where $c10; + +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c10; +drop table t; + + +--echo # Pullout PS +--echo # ========== + +eval +prepare stmt from " +delete from orders where $c1; +"; + +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +eval +create table t as +select * from orders where $c1; +execute stmt; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +insert into orders select * from t; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +eval +create table r as +select * from orders where $c1; +execute stmt; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +insert into orders select * from r; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +drop table t,r; + +deallocate prepare stmt; + + +--echo # FirstMatch PS +--echo # ============= + +eval +prepare stmt from " +delete from customer where $c5; +"; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +eval +create table t as +select * from customer where $c5; +execute stmt; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +eval +create table r as +select * from customer where $c5; +execute stmt; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +drop table t,r; + +deallocate prepare stmt; + + +--echo # Materialization PS +--echo # ================== + +eval +prepare stmt from " +delete from customer where $c7 and c_name like ?; +"; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +set @a1='Customer#%1_'; +eval +create table t as +select * from customer where $c7 and c_name like @a1; +execute stmt using @a1; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +set @a2='Customer#%3_'; +eval +create table r as +select * from customer where $c7 and c_name like @a2; +execute stmt using @a2; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +drop table t,r; + +deallocate prepare stmt; + + +--echo # Materialization SJM PS +--echo # ====================== + +eval +prepare stmt from " +delete from customer where $c7 and c_acctbal between ? and ?; +"; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +set @a1=3500; +set @a2=4000; +eval +create table t as +select * from customer where $c9 and c_acctbal between @a1 and @a2; +execute stmt using @a1, @a2; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +set @a3=-1000; +set @a4=3500; +eval +create table r as +select * from customer where $c9 and c_acctbal between @a3 and @a4; +execute stmt using @a3, @a4; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +drop table t,r; + +deallocate prepare stmt; + + +--echo # Pullout SP +--echo # ========== + +eval +create procedure p(a1 int, a2 int) +delete from orders where $c1 and o_totalprice between a1 and a2; + +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +eval +create table t as +select * from orders where $c1 and o_totalprice between 150000 and 200000; +call p(150000, 200000); +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +insert into orders select * from t; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +eval +create table r as +select * from orders where $c1 and o_totalprice between 180000 and 210000; +call p(180000, 210000); +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +insert into orders select * from r; +--sorted_result +eval +select o_orderkey, o_totalprice from orders where $c1; +drop table t,r; + +drop procedure p; + + +--echo # FirstMatch SP +--echo # ============= + +eval +create procedure p(a int) +delete from customer where $c5 and c_acctbal > a; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +eval +create table t as +select * from customer where $c5 and c_acctbal > 4000; +call p(4000); +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +eval +create table r as +select * from customer where $c5 and c_acctbal > 2000; +call p(2000); +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c5; +drop table t,r; + +drop procedure p; + + +--echo # Materialization SP +--echo # ================== + +eval +create procedure p() +delete from customer where $c7; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +eval +create table t as +select * from customer where $c7; +call p(); +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +eval +create table r as +select * from customer where $c7; +call p(); +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c7; +drop table t,r; + +drop procedure p; + + +--echo # Materialization SJM SP +--echo # ====================== + +eval +create procedure p() +delete from customer where $c9; + +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +eval +create table t as +select * from customer where $c9; +call p(); +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +insert into customer select * from t; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +eval +create table r as +select * from customer where $c9; +call p(); +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +insert into customer select * from r; +--sorted_result +eval +select c_name, c_acctbal from customer where $c9; +drop table t,r; + +drop procedure p; + +--echo # Check for DELETE ... RETURNING with SJ subquery in WHERE + +--sorted_result +eval +select c_name from customer where $c7; +eval +create table t as +select * from customer where $c7; +eval +explain +delete from customer where $c7 returning c_name; +--sorted_result +eval +delete from customer where $c7 returning c_name; +--sorted_result +eval +select c_name from customer where $c7; +insert into customer select * from t; +--sorted_result +eval +select c_name from customer where $c7; +drop table t; + +--sorted_result +eval +select c_name from customer where $c9; +eval +create table t as +select * from customer where $c9; +eval +explain +delete from customer where $c9 returning c_name; +--sorted_result +eval +delete from customer where $c9 returning c_name; +--sorted_result +eval +select c_name from customer where $c9; +insert into customer select * from t; +--sorted_result +eval +select c_name from customer where $c9; +drop table t; + +DROP DATABASE dbt3_s001; diff --git a/mysql-test/main/log_state.result b/mysql-test/main/log_state.result index 5e7aac8..1b1c737 100644 --- a/mysql-test/main/log_state.result +++ b/mysql-test/main/log_state.result @@ -243,7 +243,7 @@ rows_examined sql_text 4 UPDATE t1 SET a=a+sleep(.02) WHERE a>2 8 UPDATE t1 SET a=a+sleep(.02) ORDER BY a DESC 1 UPDATE t2 set b=b+sleep(.02) limit 1 -4 UPDATE t1 SET a=a+sleep(.02) WHERE a in (SELECT b from t2) +10 UPDATE t1 SET a=a+sleep(.02) WHERE a in (SELECT b from t2) 6 DELETE FROM t1 WHERE a=a+sleep(.02) ORDER BY a LIMIT 2 disconnect con2; connection default; diff --git a/mysql-test/main/myisam_explain_non_select_all.result b/mysql-test/main/myisam_explain_non_select_all.result index 36231c3..945c5ff 100644 --- a/mysql-test/main/myisam_explain_non_select_all.result +++ b/mysql-test/main/myisam_explain_non_select_all.result @@ -234,14 +234,16 @@ Warnings: Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead EXPLAIN UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 Using where FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE 1 IN (SELECT 1 FROM t2 WHERE t2.b < 3); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Using where # Status of EXPLAIN EXTENDED query Variable_name Value FLUSH STATUS; @@ -264,7 +266,9 @@ Handler_read_key 5 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value -Handler_read_rnd_next 5 +Handler_read_key 1 +Handler_read_rnd 3 +Handler_read_rnd_next 12 Handler_update 3 DROP TABLE t1, t2; @@ -282,13 +286,13 @@ Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 Using where; FirstMatch(t1) FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT b FROM t2 WHERE t1.a < 3); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t2 ALL NULL NULL NULL NULL 3 100.00 Using where; FirstMatch(t1) Warnings: Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 # Status of EXPLAIN EXTENDED query @@ -967,14 +971,16 @@ Warnings: Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT a FROM t2); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 # Status of EXPLAIN EXTENDED query Variable_name Value FLUSH STATUS; @@ -997,7 +1003,8 @@ Handler_read_key 7 Handler_read_rnd_next 8 # Status of testing query execution: Variable_name Value -Handler_read_rnd_next 10 +Handler_read_key 3 +Handler_read_rnd_next 8 Handler_update 3 DROP TABLE t1, t2; @@ -1060,14 +1067,14 @@ Warnings: Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be removed in a future release. Please use 'SELECT <select list> INTO <destination> FROM...' instead EXPLAIN DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 Using where; FirstMatch(t1) FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED DELETE FROM t1 WHERE a1 IN (SELECT a2 FROM t2 WHERE a2 > 2); id select_type table type possible_keys key key_len ref rows filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00 Using where -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 5 100.00 Using where +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00 +1 PRIMARY t2 ALL NULL NULL NULL NULL 5 100.00 Using where; FirstMatch(t1) # Status of EXPLAIN EXTENDED query Variable_name Value Handler_read_key 4 @@ -3024,14 +3031,14 @@ Warning 1287 '<select expression> INTO <destination>;' is deprecated and will be EXPLAIN UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where -2 DEPENDENT SUBQUERY <derived3> index_subquery key0 key0 5 func 2 +1 PRIMARY <derived3> ref key0 key0 5 test.t1.a 2 FirstMatch(t1) 3 DERIVED t2 ALL NULL NULL NULL NULL 3 Using filesort FLUSH STATUS; FLUSH TABLES; EXPLAIN EXTENDED UPDATE t1 SET a = 10 WHERE a IN (SELECT * FROM (SELECT b FROM t2 ORDER BY b LIMIT 2,2) x); id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where -2 DEPENDENT SUBQUERY <derived3> index_subquery key0 key0 5 func 2 100.00 +1 PRIMARY <derived3> ref key0 key0 5 test.t1.a 2 100.00 FirstMatch(t1) 3 DERIVED t2 ALL NULL NULL NULL NULL 3 100.00 Using filesort # Status of EXPLAIN EXTENDED query Variable_name Value diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 1444320..8885860 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -3945,6 +3945,16 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { } }, { + "table": "t0", + "rowid_filters": [ + { + "key": "a", + "build_cost": 0.174715752, + "rows": 3 + } + ] + }, + { "selectivity_for_indexes": [ { "index_name": "a", @@ -4010,6 +4020,16 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { } }, { + "table": "t1", + "rowid_filters": [ + { + "key": "a", + "build_cost": 0.174715752, + "rows": 3 + } + ] + }, + { "selectivity_for_indexes": [ { "index_name": "a", diff --git a/mysql-test/main/update_single_to_multi.result b/mysql-test/main/update_single_to_multi.result new file mode 100644 index 0000000..66fdf3f --- /dev/null +++ b/mysql-test/main/update_single_to_multi.result @@ -0,0 +1,2137 @@ +DROP DATABASE IF EXISTS dbt3_s001; +CREATE DATABASE dbt3_s001; +use dbt3_s001; +create index i_n_name on nation(n_name); +analyze table nation; +Table Op Msg_type Msg_text +dbt3_s001.nation analyze status Engine-independent statistics collected +dbt3_s001.nation analyze status OK +# Pullout +# ======= +explain +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (7%) Using where; Using rowid filter +explain format=json +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "nation", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_n_name"], + "key": "i_n_name", + "key_length": "26", + "used_key_parts": ["n_name"], + "ref": ["const"], + "rows": 1, + "filtered": 100, + "index_condition": "nation.n_name = 'PERU'" + }, + "table": { + "table_name": "customer", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "key": "i_c_nationkey", + "key_length": "5", + "used_key_parts": ["c_nationkey"], + "ref": ["dbt3_s001.nation.n_nationkey"], + "rows": 11, + "filtered": 100 + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 108, + "selectivity_pct": 7.2 + }, + "rows": 11, + "filtered": 7.199999809, + "attached_condition": "orders.o_orderDATE between '1992-01-01' and '1992-06-30'" + } + } +} +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +explain +update orders set o_totalprice = o_totalprice-50 where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (7%) Using where; Using rowid filter +explain format=json +update orders set o_totalprice = o_totalprice-50 where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "nation", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_n_name"], + "key": "i_n_name", + "key_length": "26", + "used_key_parts": ["n_name"], + "ref": ["const"], + "rows": 1, + "filtered": 100, + "index_condition": "nation.n_name = 'PERU'" + }, + "table": { + "table_name": "customer", + "access_type": "ref", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "key": "i_c_nationkey", + "key_length": "5", + "used_key_parts": ["c_nationkey"], + "ref": ["dbt3_s001.nation.n_nationkey"], + "rows": 11, + "filtered": 100 + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 108, + "selectivity_pct": 7.2 + }, + "rows": 11, + "filtered": 7.199999809, + "attached_condition": "orders.o_orderDATE between '1992-01-01' and '1992-06-30'" + } + } +} +update orders set o_totalprice = o_totalprice-50 where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201218.06 +2880 145711.99 +3142 15980.15 +5382 138373.03 +5095 184533.99 +737 12934.85 +1729 12087.76 +5121 150284.57 +update orders set o_totalprice= o_totalprice+50 where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 444.37 +6 1 642.13 +8 1 957.34 +1 8 357.84 +3 8 645.4 +5 8 50.52 +7 8 763.98 +explain +update partsupp set ps_supplycost = ps_supplycost+2 where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +update partsupp set ps_supplycost = ps_supplycost+2 where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 446.37 +6 1 644.13 +8 1 959.34 +1 8 359.84 +3 8 647.4 +5 8 52.52 +7 8 765.98 +update partsupp set ps_supplycost = ps_supplycost-2 where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where (ps_partkey, ps_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 910 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 444.37 +6 1 642.13 +8 1 957.34 +1 8 357.84 +3 8 645.4 +5 8 50.52 +7 8 763.98 +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 444.37 +6 1 642.13 +8 1 957.34 +1 8 357.84 +3 8 645.4 +5 8 50.52 +7 8 763.98 +explain +update partsupp set ps_supplycost = ps_supplycost+10 where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY partsupp ref PRIMARY,i_ps_partkey,i_ps_suppkey i_ps_suppkey 4 dbt3_s001.supplier.s_suppkey 16 +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.partsupp.ps_partkey 1 Using where +update partsupp set ps_supplycost = ps_supplycost+10 where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 454.37 +6 1 652.13 +8 1 967.34 +1 8 367.84 +3 8 655.4 +5 8 60.52 +7 8 773.98 +update partsupp set ps_supplycost = ps_supplycost-10 where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where ps_partkey in (select p_partkey from part +where p_retailprice between 901 and 910) and +ps_suppkey in (select s_suppkey from supplier +where s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +ps_partkey ps_suppkey ps_supplycost +4 1 444.37 +6 1 642.13 +8 1 957.34 +1 8 357.84 +3 8 645.4 +5 8 50.52 +7 8 763.98 +explain +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_suppkey 5 dbt3_s001.supplier.s_suppkey 100 Using where +1 PRIMARY orders eq_ref|filter PRIMARY,i_o_orderdate,i_o_custkey PRIMARY|i_o_orderdate 4|4 dbt3_s001.lineitem.l_orderkey 1 (7%) Using where; Using rowid filter +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.lineitem.l_partkey 1 Using where +1 PRIMARY customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +4996 1 0.01 +933 1 0.04 +2500 2 0.02 +2500 4 0.02 +explain +update lineitem set l_tax = (l_tax*100+1)/100 where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY supplier ref PRIMARY,i_s_nationkey i_s_nationkey 5 dbt3_s001.nation.n_nationkey 2 +1 PRIMARY lineitem ref PRIMARY,i_l_suppkey_partkey,i_l_partkey,i_l_suppkey,i_l_orderkey,i_l_orderkey_quantity i_l_suppkey 5 dbt3_s001.supplier.s_suppkey 100 Using where +1 PRIMARY orders eq_ref|filter PRIMARY,i_o_orderdate,i_o_custkey PRIMARY|i_o_orderdate 4|4 dbt3_s001.lineitem.l_orderkey 1 (7%) Using where; Using rowid filter +1 PRIMARY part eq_ref PRIMARY PRIMARY 4 dbt3_s001.lineitem.l_partkey 1 Using where +1 PRIMARY customer eq_ref PRIMARY,i_c_nationkey PRIMARY 4 dbt3_s001.orders.o_custkey 1 Using where +update lineitem set l_tax = (l_tax*100+1)/100 where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +4996 1 0.02 +933 1 0.05 +2500 2 0.03 +2500 4 0.03 +update lineitem set l_tax = (l_tax*100-1)/100 where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select l_orderkey, l_linenumber, l_tax from lineitem where l_orderkey in (select o_orderkey from orders +where o_custkey in +(select c_custkey from customer +where c_nationkey in +(select n_nationkey from nation +where n_name='PERU')) +and +o_orderDATE between '1992-06-30' and '1992-12-31') +and +(l_partkey, l_suppkey) in +(select p_partkey, s_suppkey from part, supplier +where p_retailprice between 901 and 1000 and +s_nationkey in (select n_nationkey from nation +where n_name='PERU')); +l_orderkey l_linenumber l_tax +4996 1 0.01 +933 1 0.04 +2500 2 0.02 +2500 4 0.02 +# FirstMatch +# ========== +explain +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY,i_c_nationkey NULL NULL NULL 150 Using where +1 PRIMARY nation eq_ref|filter PRIMARY,i_n_regionkey PRIMARY|i_n_regionkey 4|5 dbt3_s001.customer.c_nationkey 1 (40%) Using where; Using rowid filter +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (6%) Using where; FirstMatch(nation); Using rowid filter +explain format=json +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "customer", + "access_type": "ALL", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "rows": 150, + "filtered": 100, + "attached_condition": "customer.c_nationkey is not null" + }, + "table": { + "table_name": "nation", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY", "i_n_regionkey"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["n_nationkey"], + "ref": ["dbt3_s001.customer.c_nationkey"], + "rowid_filter": { + "range": { + "key": "i_n_regionkey", + "used_key_parts": ["n_regionkey"] + }, + "rows": 10, + "selectivity_pct": 40 + }, + "rows": 1, + "filtered": 40, + "attached_condition": "nation.n_regionkey in (1,2)" + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 89, + "selectivity_pct": 5.933333333 + }, + "rows": 11, + "filtered": 5.933333397, + "attached_condition": "orders.o_orderDATE between '1992-10-09' and '1993-03-08'", + "first_match": "nation" + } + } +} +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +explain +update customer set c_acctbal = c_acctbal+10 where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY,i_c_nationkey NULL NULL NULL 150 Using where +1 PRIMARY nation eq_ref|filter PRIMARY,i_n_regionkey PRIMARY|i_n_regionkey 4|5 dbt3_s001.customer.c_nationkey 1 (40%) Using where; Using rowid filter +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (6%) Using where; FirstMatch(nation); Using rowid filter +explain format=json +update customer set c_acctbal = c_acctbal+10 where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "customer", + "access_type": "ALL", + "possible_keys": ["PRIMARY", "i_c_nationkey"], + "rows": 150, + "filtered": 100, + "attached_condition": "customer.c_nationkey is not null" + }, + "table": { + "table_name": "nation", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY", "i_n_regionkey"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["n_nationkey"], + "ref": ["dbt3_s001.customer.c_nationkey"], + "rowid_filter": { + "range": { + "key": "i_n_regionkey", + "used_key_parts": ["n_regionkey"] + }, + "rows": 10, + "selectivity_pct": 40 + }, + "rows": 1, + "filtered": 40, + "attached_condition": "nation.n_regionkey in (1,2)" + }, + "table": { + "table_name": "orders", + "access_type": "ref", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_custkey", + "key_length": "5", + "used_key_parts": ["o_custkey"], + "ref": ["dbt3_s001.customer.c_custkey"], + "rowid_filter": { + "range": { + "key": "i_o_orderdate", + "used_key_parts": ["o_orderDATE"] + }, + "rows": 89, + "selectivity_pct": 5.933333333 + }, + "rows": 11, + "filtered": 5.933333397, + "attached_condition": "orders.o_orderDATE between '1992-10-09' and '1993-03-08'", + "first_match": "nation" + } + } +} +update customer set c_acctbal = c_acctbal+10 where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9571.95 +Customer#000000019 8924.71 +Customer#000000022 601.98 +Customer#000000025 7143.7 +Customer#000000028 1017.18 +Customer#000000037 -907.75 +Customer#000000040 1345.3 +Customer#000000047 284.58 +Customer#000000059 3468.6 +Customer#000000061 1546.24 +Customer#000000064 -636.64 +Customer#000000067 8176.59 +Customer#000000082 9478.34 +Customer#000000091 4653.14 +Customer#000000094 5510.11 +Customer#000000097 2174.48 +Customer#000000101 7480.96 +Customer#000000103 2767.45 +Customer#000000106 3298.42 +Customer#000000115 7518.92 +Customer#000000121 6438.32 +Customer#000000122 7875.46 +Customer#000000127 9290.71 +Customer#000000130 5083.58 +Customer#000000133 2324.67 +Customer#000000139 7907.78 +update customer set c_acctbal = c_acctbal-10 where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +explain +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (14%) Using where; FirstMatch(customer); Using rowid filter +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +Customer#000000008 6819.74 +Customer#000000035 1228.24 +Customer#000000061 1536.24 +Customer#000000097 2164.48 +Customer#000000121 6428.32 +Customer#000000133 2314.67 +explain +update customer set c_acctbal = c_acctbal+20 where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY nation ref PRIMARY,i_n_name i_n_name 26 const 1 Using index condition +1 PRIMARY customer ref PRIMARY,i_c_nationkey i_c_nationkey 5 dbt3_s001.nation.n_nationkey 11 +1 PRIMARY orders ref|filter i_o_orderdate,i_o_custkey i_o_custkey|i_o_orderdate 5|4 dbt3_s001.customer.c_custkey 11 (14%) Using where; FirstMatch(customer); Using rowid filter +update customer set c_acctbal = c_acctbal+20 where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +Customer#000000008 6839.74 +Customer#000000035 1248.24 +Customer#000000061 1556.24 +Customer#000000097 2184.48 +Customer#000000121 6448.32 +Customer#000000133 2334.67 +update customer set c_acctbal = c_acctbal-20 where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation where n_name='PERU') +and +c_custkey in (select o_custkey from orders +where o_orderDATE between "1992-01-09" and "1993-01-08"); +c_name c_acctbal +Customer#000000008 6819.74 +Customer#000000035 1228.24 +Customer#000000061 1536.24 +Customer#000000097 2164.48 +Customer#000000121 6428.32 +Customer#000000133 2314.67 +# Materialization +# =============== +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 28 Using index condition; Using where +explain format=json +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'", + "attached_condition": "orders.o_custkey is not null" + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["dbt3_s001.orders.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +explain +update customer set c_acctbal = c_acctbal+5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 dbt3_s001.orders.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 28 Using index condition; Using where +explain format=json +update customer set c_acctbal = c_acctbal+5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate", "i_o_custkey"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'", + "attached_condition": "orders.o_custkey is not null" + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["dbt3_s001.orders.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +update customer set c_acctbal = c_acctbal+5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7138.7 +Customer#000000013 3862.34 +Customer#000000065 8800.16 +Customer#000000032 3476.53 +Customer#000000023 3337.02 +Customer#000000035 1233.24 +Customer#000000091 4648.14 +Customer#000000016 4686.03 +Customer#000000098 -546.37 +Customer#000000037 -912.75 +Customer#000000136 -837.39 +Customer#000000118 3587.37 +Customer#000000022 596.98 +Customer#000000005 799.47 +Customer#000000109 -711.1 +Customer#000000038 6350.11 +Customer#000000076 5750.33 +Customer#000000056 6535.86 +Customer#000000040 1340.3 +Customer#000000116 8408.99 +Customer#000000115 7513.92 +Customer#000000140 9968.15 +Customer#000000017 11.34 +Customer#000000052 5635.28 +update customer set c_acctbal = c_acctbal-5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 114 Using index condition; Using where +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +Customer#000000001 711.56 +Customer#000000002 121.65 +Customer#000000007 9561.95 +Customer#000000008 6819.74 +Customer#000000010 2753.54 +Customer#000000011 -272.6 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000029 7618.27 +Customer#000000031 5236.89 +Customer#000000034 8589.7 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000043 9904.28 +Customer#000000044 7315.94 +Customer#000000046 5744.59 +Customer#000000047 274.58 +Customer#000000049 4573.94 +Customer#000000053 4113.64 +Customer#000000055 4572.11 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000070 4867.52 +Customer#000000071 -611.19 +Customer#000000073 4288.5 +Customer#000000074 2764.43 +Customer#000000076 5745.33 +Customer#000000079 5121.28 +Customer#000000080 7383.53 +Customer#000000082 9468.34 +Customer#000000083 6463.51 +Customer#000000085 3386.64 +Customer#000000086 3306.32 +Customer#000000088 8031.44 +Customer#000000091 4643.14 +Customer#000000092 1182.91 +Customer#000000095 5327.38 +Customer#000000097 2164.48 +Customer#000000100 9889.89 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000104 -588.38 +Customer#000000106 3288.42 +Customer#000000109 -716.1 +Customer#000000110 7462.99 +Customer#000000112 2953.35 +Customer#000000118 3582.37 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000131 8595.53 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +Customer#000000136 -842.39 +Customer#000000137 7838.3 +Customer#000000139 7897.78 +Customer#000000142 2209.81 +Customer#000000143 2186.5 +Customer#000000148 2135.6 +Customer#000000149 8959.65 +explain +update customer set c_acctbal = c_acctbal+1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 +2 MATERIALIZED orders range i_o_orderdate,i_o_custkey i_o_orderdate 4 NULL 114 Using index condition; Using where +update customer set c_acctbal = c_acctbal+1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +Customer#000000001 712.56 +Customer#000000002 122.65 +Customer#000000007 9562.95 +Customer#000000008 6820.74 +Customer#000000010 2754.54 +Customer#000000011 -271.6 +Customer#000000016 4682.03 +Customer#000000017 7.34 +Customer#000000019 8915.71 +Customer#000000022 592.98 +Customer#000000023 3333.02 +Customer#000000025 7134.7 +Customer#000000028 1008.18 +Customer#000000029 7619.27 +Customer#000000031 5237.89 +Customer#000000034 8590.7 +Customer#000000037 -916.75 +Customer#000000040 1336.3 +Customer#000000043 9905.28 +Customer#000000044 7316.94 +Customer#000000046 5745.59 +Customer#000000047 275.58 +Customer#000000049 4574.94 +Customer#000000053 4114.64 +Customer#000000055 4573.11 +Customer#000000061 1537.24 +Customer#000000064 -645.64 +Customer#000000067 8167.59 +Customer#000000070 4868.52 +Customer#000000071 -610.19 +Customer#000000073 4289.5 +Customer#000000074 2765.43 +Customer#000000076 5746.33 +Customer#000000079 5122.28 +Customer#000000080 7384.53 +Customer#000000082 9469.34 +Customer#000000083 6464.51 +Customer#000000085 3387.64 +Customer#000000086 3307.32 +Customer#000000088 8032.44 +Customer#000000091 4644.14 +Customer#000000092 1183.91 +Customer#000000095 5328.38 +Customer#000000097 2165.48 +Customer#000000100 9890.89 +Customer#000000101 7471.96 +Customer#000000103 2758.45 +Customer#000000104 -587.38 +Customer#000000106 3289.42 +Customer#000000109 -715.1 +Customer#000000110 7463.99 +Customer#000000112 2954.35 +Customer#000000118 3583.37 +Customer#000000121 6429.32 +Customer#000000122 7866.46 +Customer#000000127 9281.71 +Customer#000000130 5074.58 +Customer#000000131 8596.53 +Customer#000000133 2315.67 +Customer#000000134 4609.9 +Customer#000000136 -841.39 +Customer#000000137 7839.3 +Customer#000000139 7898.78 +Customer#000000142 2210.81 +Customer#000000143 2187.5 +Customer#000000148 2136.6 +Customer#000000149 8960.65 +update customer set c_acctbal = c_acctbal-1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-06-09' and '1993-01-08'); +c_name c_acctbal +Customer#000000001 711.56 +Customer#000000002 121.65 +Customer#000000007 9561.95 +Customer#000000008 6819.74 +Customer#000000010 2753.54 +Customer#000000011 -272.6 +Customer#000000016 4681.03 +Customer#000000017 6.34 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000023 3332.02 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000029 7618.27 +Customer#000000031 5236.89 +Customer#000000034 8589.7 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000043 9904.28 +Customer#000000044 7315.94 +Customer#000000046 5744.59 +Customer#000000047 274.58 +Customer#000000049 4573.94 +Customer#000000053 4113.64 +Customer#000000055 4572.11 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000070 4867.52 +Customer#000000071 -611.19 +Customer#000000073 4288.5 +Customer#000000074 2764.43 +Customer#000000076 5745.33 +Customer#000000079 5121.28 +Customer#000000080 7383.53 +Customer#000000082 9468.34 +Customer#000000083 6463.51 +Customer#000000085 3386.64 +Customer#000000086 3306.32 +Customer#000000088 8031.44 +Customer#000000091 4643.14 +Customer#000000092 1182.91 +Customer#000000095 5327.38 +Customer#000000097 2164.48 +Customer#000000100 9889.89 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000104 -588.38 +Customer#000000106 3288.42 +Customer#000000109 -716.1 +Customer#000000110 7462.99 +Customer#000000112 2953.35 +Customer#000000118 3582.37 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000131 8595.53 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +Customer#000000136 -842.39 +Customer#000000137 7838.3 +Customer#000000139 7897.78 +Customer#000000142 2209.81 +Customer#000000143 2186.5 +Customer#000000148 2135.6 +Customer#000000149 8959.65 +# Materialization SJM +# =================== +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 <subquery2>.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 28 Using index condition; Using temporary +explain format=json +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "count(orders.o_custkey) > 1", + "temporary_table": { + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'" + } + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["<subquery2>.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +explain +update customer set c_acctbal = c_acctbal-5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 28 +1 PRIMARY customer eq_ref PRIMARY PRIMARY 4 <subquery2>.o_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 28 Using index condition; Using temporary +explain format=json +update customer set c_acctbal = c_acctbal-5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<subquery2>", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "rows": 28, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "having_condition": "count(orders.o_custkey) > 1", + "temporary_table": { + "table": { + "table_name": "orders", + "access_type": "range", + "possible_keys": ["i_o_orderdate"], + "key": "i_o_orderdate", + "key_length": "4", + "used_key_parts": ["o_orderDATE"], + "rows": 28, + "filtered": 100, + "index_condition": "orders.o_orderDATE between '1992-01-09' and '1992-03-08'" + } + } + } + } + }, + "table": { + "table_name": "customer", + "access_type": "eq_ref", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["c_custkey"], + "ref": ["<subquery2>.o_custkey"], + "rows": 1, + "filtered": 100 + } + } +} +update customer set c_acctbal = c_acctbal-5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3852.34 +Customer#000000032 3466.53 +Customer#000000037 -922.75 +Customer#000000118 3577.37 +Customer#000000056 6525.86 +update customer set c_acctbal = c_acctbal+5 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +explain +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.customer.c_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 242 Using index condition; Using temporary +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000016 4681.03 +Customer#000000037 -917.75 +Customer#000000046 5744.59 +Customer#000000091 4643.14 +Customer#000000103 2757.45 +Customer#000000118 3582.37 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +explain +update customer set c_acctbal = c_acctbal-1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY customer ALL PRIMARY NULL NULL NULL 150 +1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 dbt3_s001.customer.c_custkey 1 +2 MATERIALIZED orders range i_o_orderdate i_o_orderdate 4 NULL 242 Using index condition; Using temporary +update customer set c_acctbal = c_acctbal-1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +Customer#000000007 9560.95 +Customer#000000016 4680.03 +Customer#000000037 -918.75 +Customer#000000046 5743.59 +Customer#000000091 4642.14 +Customer#000000103 2756.45 +Customer#000000118 3581.37 +Customer#000000133 2313.67 +Customer#000000134 4607.9 +update customer set c_acctbal = c_acctbal+1 where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000016 4681.03 +Customer#000000037 -917.75 +Customer#000000046 5744.59 +Customer#000000091 4643.14 +Customer#000000103 2757.45 +Customer#000000118 3582.37 +Customer#000000133 2314.67 +Customer#000000134 4608.9 +# Pullout PS +# ========== +prepare stmt from " +update orders set o_totalprice = o_totalprice+? where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +"; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +set @a1=-20; +execute stmt using @a1; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201248.06 +2880 145741.99 +3142 16010.15 +5382 138403.03 +5095 184563.99 +737 12964.85 +1729 12117.76 +5121 150314.57 +set @a2=-10; +execute stmt using @a2; +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201238.06 +2880 145731.99 +3142 16000.15 +5382 138393.03 +5095 184553.99 +737 12954.85 +1729 12107.76 +5121 150304.57 +execute stmt using -(@a1+@a2); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +deallocate prepare stmt; +# FirstMatch PS +# ============= +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +"; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.18 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +set @a1=15; +execute stmt using @a1; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9576.95 +Customer#000000019 8929.71 +Customer#000000022 606.98 +Customer#000000025 7148.7 +Customer#000000028 1022.18 +Customer#000000037 -902.75 +Customer#000000040 1350.3 +Customer#000000047 289.58 +Customer#000000059 3473.6 +Customer#000000061 1551.24 +Customer#000000064 -631.64 +Customer#000000067 8181.59 +Customer#000000082 9483.34 +Customer#000000091 4658.14 +Customer#000000094 5515.11 +Customer#000000097 2179.48 +Customer#000000101 7485.96 +Customer#000000103 2772.45 +Customer#000000106 3303.42 +Customer#000000115 7523.92 +Customer#000000121 6443.32 +Customer#000000122 7880.46 +Customer#000000127 9295.71 +Customer#000000130 5088.58 +Customer#000000133 2329.67 +Customer#000000139 7912.78 +set @a2=5; +execute stmt using @a2; +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9581.95 +Customer#000000019 8934.71 +Customer#000000022 611.98 +Customer#000000025 7153.7 +Customer#000000028 1027.1799999999998 +Customer#000000037 -897.75 +Customer#000000040 1355.3 +Customer#000000047 294.58 +Customer#000000059 3478.6 +Customer#000000061 1556.24 +Customer#000000064 -626.64 +Customer#000000067 8186.59 +Customer#000000082 9488.34 +Customer#000000091 4663.14 +Customer#000000094 5520.11 +Customer#000000097 2184.48 +Customer#000000101 7490.96 +Customer#000000103 2777.45 +Customer#000000106 3308.42 +Customer#000000115 7528.92 +Customer#000000121 6448.32 +Customer#000000122 7885.46 +Customer#000000127 9300.71 +Customer#000000130 5093.58 +Customer#000000133 2334.67 +Customer#000000139 7917.78 +execute stmt using -(@a1+@a2); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.1799999999998 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +deallocate prepare stmt; +# Materialization PS +# ================== +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +"; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +set @a1=7; +execute stmt using @a1; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7140.7 +Customer#000000013 3864.34 +Customer#000000065 8802.16 +Customer#000000032 3478.53 +Customer#000000023 3339.02 +Customer#000000035 1235.24 +Customer#000000091 4650.14 +Customer#000000016 4688.03 +Customer#000000098 -544.37 +Customer#000000037 -910.75 +Customer#000000136 -835.39 +Customer#000000118 3589.37 +Customer#000000022 598.98 +Customer#000000005 801.47 +Customer#000000109 -709.1 +Customer#000000038 6352.11 +Customer#000000076 5752.33 +Customer#000000056 6537.86 +Customer#000000040 1342.3 +Customer#000000116 8410.99 +Customer#000000115 7515.92 +Customer#000000140 9970.15 +Customer#000000017 13.34 +Customer#000000052 5637.28 +set @a2=3; +execute stmt using @a2; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7143.7 +Customer#000000013 3867.34 +Customer#000000065 8805.16 +Customer#000000032 3481.53 +Customer#000000023 3342.02 +Customer#000000035 1238.24 +Customer#000000091 4653.14 +Customer#000000016 4691.03 +Customer#000000098 -541.37 +Customer#000000037 -907.75 +Customer#000000136 -832.39 +Customer#000000118 3592.37 +Customer#000000022 601.98 +Customer#000000005 804.47 +Customer#000000109 -706.1 +Customer#000000038 6355.11 +Customer#000000076 5755.33 +Customer#000000056 6540.86 +Customer#000000040 1345.3 +Customer#000000116 8413.99 +Customer#000000115 7518.92 +Customer#000000140 9973.15 +Customer#000000017 16.34 +Customer#000000052 5640.28 +execute stmt using -(@a1+@a2); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +deallocate prepare stmt; +# Materialization SJM PS +# ====================== +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +"; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +set @a1=-2; +execute stmt using @a1; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3855.34 +Customer#000000032 3469.53 +Customer#000000037 -919.75 +Customer#000000118 3580.37 +Customer#000000056 6528.86 +set @a2=-1; +execute stmt using @a2; +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3854.34 +Customer#000000032 3468.53 +Customer#000000037 -920.75 +Customer#000000118 3579.37 +Customer#000000056 6527.86 +execute stmt using -(@a1+@a2); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +deallocate prepare stmt; +# Pullout SP +# ========== +create procedure p(d int) +update orders set o_totalprice = o_totalprice+d where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +call p(-10); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201258.06 +2880 145751.99 +3142 16020.15 +5382 138413.03 +5095 184573.99 +737 12974.85 +1729 12127.76 +5121 150324.57 +call p(-20); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201238.06 +2880 145731.99 +3142 16000.15 +5382 138393.03 +5095 184553.99 +737 12954.85 +1729 12107.76 +5121 150304.57 +call p(10+20); +select o_orderkey, o_totalprice from orders where o_orderDATE between '1992-01-01' and '1992-06-30' and +o_custkey in (select c_custkey from customer +where c_nationkey in (select n_nationkey from nation +where n_name='PERU')); +o_orderkey o_totalprice +644 201268.06 +2880 145761.99 +3142 16030.15 +5382 138423.03 +5095 184583.99 +737 12984.85 +1729 12137.76 +5121 150334.57 +drop procedure p; +# FirstMatch SP +# ============= +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.1799999999998 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +call p(5); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9566.95 +Customer#000000019 8919.71 +Customer#000000022 596.98 +Customer#000000025 7138.7 +Customer#000000028 1012.1799999999998 +Customer#000000037 -912.75 +Customer#000000040 1340.3 +Customer#000000047 279.58 +Customer#000000059 3463.6 +Customer#000000061 1541.24 +Customer#000000064 -641.64 +Customer#000000067 8171.59 +Customer#000000082 9473.34 +Customer#000000091 4648.14 +Customer#000000094 5505.11 +Customer#000000097 2169.48 +Customer#000000101 7475.96 +Customer#000000103 2762.45 +Customer#000000106 3293.42 +Customer#000000115 7513.92 +Customer#000000121 6433.32 +Customer#000000122 7870.46 +Customer#000000127 9285.71 +Customer#000000130 5078.58 +Customer#000000133 2319.67 +Customer#000000139 7902.78 +call p(15); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9581.95 +Customer#000000019 8934.71 +Customer#000000022 611.98 +Customer#000000025 7153.7 +Customer#000000028 1027.1799999999998 +Customer#000000037 -897.75 +Customer#000000040 1355.3 +Customer#000000047 294.58 +Customer#000000059 3478.6 +Customer#000000061 1556.24 +Customer#000000064 -626.64 +Customer#000000067 8186.59 +Customer#000000082 9488.34 +Customer#000000091 4663.14 +Customer#000000094 5520.11 +Customer#000000097 2184.48 +Customer#000000101 7490.96 +Customer#000000103 2777.45 +Customer#000000106 3308.42 +Customer#000000115 7528.92 +Customer#000000121 6448.32 +Customer#000000122 7885.46 +Customer#000000127 9300.71 +Customer#000000130 5093.58 +Customer#000000133 2334.67 +Customer#000000139 7917.78 +call p(-(5+15)); +select c_name, c_acctbal from customer where c_nationkey in (select n_nationkey from nation +where n_regionkey in (1,2)) +and +c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-10-09' and '1993-03-08'); +c_name c_acctbal +Customer#000000007 9561.95 +Customer#000000019 8914.71 +Customer#000000022 591.98 +Customer#000000025 7133.7 +Customer#000000028 1007.1799999999998 +Customer#000000037 -917.75 +Customer#000000040 1335.3 +Customer#000000047 274.58 +Customer#000000059 3458.6 +Customer#000000061 1536.24 +Customer#000000064 -646.64 +Customer#000000067 8166.59 +Customer#000000082 9468.34 +Customer#000000091 4643.14 +Customer#000000094 5500.11 +Customer#000000097 2164.48 +Customer#000000101 7470.96 +Customer#000000103 2757.45 +Customer#000000106 3288.42 +Customer#000000115 7508.92 +Customer#000000121 6428.32 +Customer#000000122 7865.46 +Customer#000000127 9280.71 +Customer#000000130 5073.58 +Customer#000000133 2314.67 +Customer#000000139 7897.78 +drop procedure p; +# Materialization SP +# ================== +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +call p(3); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7136.7 +Customer#000000013 3860.34 +Customer#000000065 8798.16 +Customer#000000032 3474.53 +Customer#000000023 3335.02 +Customer#000000035 1231.24 +Customer#000000091 4646.14 +Customer#000000016 4684.03 +Customer#000000098 -548.37 +Customer#000000037 -914.75 +Customer#000000136 -839.39 +Customer#000000118 3585.37 +Customer#000000022 594.98 +Customer#000000005 797.47 +Customer#000000109 -713.1 +Customer#000000038 6348.11 +Customer#000000076 5748.33 +Customer#000000056 6533.86 +Customer#000000040 1338.3 +Customer#000000116 8406.99 +Customer#000000115 7511.92 +Customer#000000140 9966.15 +Customer#000000017 9.34 +Customer#000000052 5633.28 +call p(7); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7143.7 +Customer#000000013 3867.34 +Customer#000000065 8805.16 +Customer#000000032 3481.53 +Customer#000000023 3342.02 +Customer#000000035 1238.24 +Customer#000000091 4653.14 +Customer#000000016 4691.03 +Customer#000000098 -541.37 +Customer#000000037 -907.75 +Customer#000000136 -832.39 +Customer#000000118 3592.37 +Customer#000000022 601.98 +Customer#000000005 804.47 +Customer#000000109 -706.1 +Customer#000000038 6355.11 +Customer#000000076 5755.33 +Customer#000000056 6540.86 +Customer#000000040 1345.3 +Customer#000000116 8413.99 +Customer#000000115 7518.92 +Customer#000000140 9973.15 +Customer#000000017 16.34 +Customer#000000052 5640.28 +call p(-(3+7)); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08'); +c_name c_acctbal +Customer#000000025 7133.7 +Customer#000000013 3857.34 +Customer#000000065 8795.16 +Customer#000000032 3471.53 +Customer#000000023 3332.02 +Customer#000000035 1228.24 +Customer#000000091 4643.14 +Customer#000000016 4681.03 +Customer#000000098 -551.37 +Customer#000000037 -917.75 +Customer#000000136 -842.39 +Customer#000000118 3582.37 +Customer#000000022 591.98 +Customer#000000005 794.47 +Customer#000000109 -716.1 +Customer#000000038 6345.11 +Customer#000000076 5745.33 +Customer#000000056 6530.86 +Customer#000000040 1335.3 +Customer#000000116 8403.99 +Customer#000000115 7508.92 +Customer#000000140 9963.15 +Customer#000000017 6.34 +Customer#000000052 5630.28 +drop procedure p; +# Materialization SJM SP +# ====================== +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +call p(-1); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3856.34 +Customer#000000032 3470.53 +Customer#000000037 -918.75 +Customer#000000118 3581.37 +Customer#000000056 6529.86 +call p(-2); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3854.34 +Customer#000000032 3468.53 +Customer#000000037 -920.75 +Customer#000000118 3579.37 +Customer#000000056 6527.86 +call p(1+2); +select c_name, c_acctbal from customer where c_custkey in (select o_custkey from orders +where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); +c_name c_acctbal +Customer#000000013 3857.34 +Customer#000000032 3471.53 +Customer#000000037 -917.75 +Customer#000000118 3582.37 +Customer#000000056 6530.86 +drop procedure p; +DROP DATABASE dbt3_s001; diff --git a/mysql-test/main/update_single_to_multi.test b/mysql-test/main/update_single_to_multi.test new file mode 100644 index 0000000..f018365 --- /dev/null +++ b/mysql-test/main/update_single_to_multi.test @@ -0,0 +1,511 @@ +--disable_warnings +DROP DATABASE IF EXISTS dbt3_s001; +--enable_warnings + +CREATE DATABASE dbt3_s001; + +use dbt3_s001; + +--disable_query_log +--disable_result_log +--disable_warnings +--source include/dbt3_s001.inc +--enable_warnings +--enable_result_log +--enable_query_log + +create index i_n_name on nation(n_name); +analyze table nation; + + +--echo # Pullout +--echo # ======= + +let $c1= + o_orderDATE between '1992-01-01' and '1992-06-30' and + o_custkey in (select c_custkey from customer + where c_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select o_orderkey, o_totalprice from orders where $c1; +eval +explain format=json +select o_orderkey, o_totalprice from orders where $c1; +eval +select o_orderkey, o_totalprice from orders where $c1; + +eval +explain +update orders set o_totalprice = o_totalprice-50 where $c1; +eval +explain format=json +update orders set o_totalprice = o_totalprice-50 where $c1; +eval +update orders set o_totalprice = o_totalprice-50 where $c1; +eval +select o_orderkey, o_totalprice from orders where $c1; + +eval +update orders set o_totalprice= o_totalprice+50 where $c1; +eval +select o_orderkey, o_totalprice from orders where $c1; + + +let $c2= + (ps_partkey, ps_suppkey) in + (select p_partkey, s_suppkey from part, supplier + where p_retailprice between 901 and 910 and + s_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; + +eval +explain +update partsupp set ps_supplycost = ps_supplycost+2 where $c2; +eval +update partsupp set ps_supplycost = ps_supplycost+2 where $c2; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; + +eval +update partsupp set ps_supplycost = ps_supplycost-2 where $c2; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c2; + + +let $c3= + ps_partkey in (select p_partkey from part + where p_retailprice between 901 and 910) and + ps_suppkey in (select s_suppkey from supplier + where s_nationkey in (select n_nationkey from nation + where n_name='PERU')); +eval +explain +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; + +eval +explain +update partsupp set ps_supplycost = ps_supplycost+10 where $c3; +eval +update partsupp set ps_supplycost = ps_supplycost+10 where $c3; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; + +eval +update partsupp set ps_supplycost = ps_supplycost-10 where $c3; +eval +select ps_partkey, ps_suppkey, ps_supplycost from partsupp where $c3; + + +let $c4= + l_orderkey in (select o_orderkey from orders + where o_custkey in + (select c_custkey from customer + where c_nationkey in + (select n_nationkey from nation + where n_name='PERU')) + and + o_orderDATE between '1992-06-30' and '1992-12-31') + and + (l_partkey, l_suppkey) in + (select p_partkey, s_suppkey from part, supplier + where p_retailprice between 901 and 1000 and + s_nationkey in (select n_nationkey from nation + where n_name='PERU')); + +eval +explain +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; + +eval +explain +update lineitem set l_tax = (l_tax*100+1)/100 where $c4; +eval +update lineitem set l_tax = (l_tax*100+1)/100 where $c4; +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; + +eval +update lineitem set l_tax = (l_tax*100-1)/100 where $c4; +eval +select l_orderkey, l_linenumber, l_tax from lineitem where $c4; + + +--echo # FirstMatch +--echo # ========== + +let $c5= + c_nationkey in (select n_nationkey from nation + where n_regionkey in (1,2)) + and + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-10-09' and '1993-03-08'); + +eval +explain +select c_name, c_acctbal from customer where $c5; +eval +explain format=json +select c_name, c_acctbal from customer where $c5; +eval +select c_name, c_acctbal from customer where $c5; + +eval +explain +update customer set c_acctbal = c_acctbal+10 where $c5; +eval +explain format=json +update customer set c_acctbal = c_acctbal+10 where $c5; +eval +update customer set c_acctbal = c_acctbal+10 where $c5; +eval +select c_name, c_acctbal from customer where $c5; + +eval +update customer set c_acctbal = c_acctbal-10 where $c5; +eval +select c_name, c_acctbal from customer where $c5; + + +let $c6= + c_nationkey in (select n_nationkey from nation where n_name='PERU') + and + c_custkey in (select o_custkey from orders + where o_orderDATE between "1992-01-09" and "1993-01-08"); + +eval +explain +select c_name, c_acctbal from customer where $c6; +eval +select c_name, c_acctbal from customer where $c6; + +eval +explain +update customer set c_acctbal = c_acctbal+20 where $c6; +eval +update customer set c_acctbal = c_acctbal+20 where $c6; +eval +select c_name, c_acctbal from customer where $c6; + +eval +update customer set c_acctbal = c_acctbal-20 where $c6; +eval +select c_name, c_acctbal from customer where $c6; + + +--echo # Materialization +--echo # =============== + +let $c7= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1992-03-08'); + +eval +explain +select c_name, c_acctbal from customer where $c7; +eval +explain format=json +select c_name, c_acctbal from customer where $c7; +eval +select c_name, c_acctbal from customer where $c7; + +eval +explain +update customer set c_acctbal = c_acctbal+5 where $c7; +eval +explain format=json +update customer set c_acctbal = c_acctbal+5 where $c7; +eval +update customer set c_acctbal = c_acctbal+5 where $c7; +eval +select c_name, c_acctbal from customer where $c7; + +eval +update customer set c_acctbal = c_acctbal-5 where $c7; +eval +select c_name, c_acctbal from customer where $c7; + + +let $c8= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-06-09' and '1993-01-08'); + +eval +explain +select c_name, c_acctbal from customer where $c8; +eval +select c_name, c_acctbal from customer where $c8; + +eval +explain +update customer set c_acctbal = c_acctbal+1 where $c8; +eval +update customer set c_acctbal = c_acctbal+1 where $c8; +eval +select c_name, c_acctbal from customer where $c8; + +eval +update customer set c_acctbal = c_acctbal-1 where $c8; +eval +select c_name, c_acctbal from customer where $c8; + + +--echo # Materialization SJM +--echo # =================== + +let $c9= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1992-03-08' + group by o_custkey having count(o_custkey) > 1); + +eval +explain +select c_name, c_acctbal from customer where $c9; +eval +explain format=json +select c_name, c_acctbal from customer where $c9; +eval +select c_name, c_acctbal from customer where $c9; + +eval +explain +update customer set c_acctbal = c_acctbal-5 where $c9; +eval +explain format=json +update customer set c_acctbal = c_acctbal-5 where $c9; +eval +update customer set c_acctbal = c_acctbal-5 where $c9; +eval +select c_name, c_acctbal from customer where $c9; + +eval +update customer set c_acctbal = c_acctbal+5 where $c9; +eval +select c_name, c_acctbal from customer where $c9; + + +let $c10= + c_custkey in (select o_custkey from orders + where o_orderDATE between '1992-01-09' and '1993-03-08' + group by o_custkey having count(o_custkey) > 5); + +eval +explain +select c_name, c_acctbal from customer where $c10; +eval +select c_name, c_acctbal from customer where $c10; + +eval +explain +update customer set c_acctbal = c_acctbal-1 where $c10; +eval +update customer set c_acctbal = c_acctbal-1 where $c10; +eval +select c_name, c_acctbal from customer where $c10; + +eval +update customer set c_acctbal = c_acctbal+1 where $c10; +eval +select c_name, c_acctbal from customer where $c10; + + +--echo # Pullout PS +--echo # ========== + +eval +prepare stmt from " +update orders set o_totalprice = o_totalprice+? where $c1; +"; + +eval +select o_orderkey, o_totalprice from orders where $c1; +set @a1=-20; +execute stmt using @a1; +eval +select o_orderkey, o_totalprice from orders where $c1; +set @a2=-10; +execute stmt using @a2; +eval +select o_orderkey, o_totalprice from orders where $c1; +execute stmt using -(@a1+@a2); +eval +select o_orderkey, o_totalprice from orders where $c1; + +deallocate prepare stmt; + + +--echo # FirstMatch PS +--echo # ============= + +eval +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where $c5; +"; + +eval +select c_name, c_acctbal from customer where $c5; +set @a1=15; +execute stmt using @a1; +eval +select c_name, c_acctbal from customer where $c5; +set @a2=5; +execute stmt using @a2; +eval +select c_name, c_acctbal from customer where $c5; +execute stmt using -(@a1+@a2); +eval +select c_name, c_acctbal from customer where $c5; + +deallocate prepare stmt; + + +--echo # Materialization PS +--echo # ================== + +eval +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where $c7; +"; + +eval +select c_name, c_acctbal from customer where $c7; +set @a1=7; +execute stmt using @a1; +eval +select c_name, c_acctbal from customer where $c7; +set @a2=3; +execute stmt using @a2; +eval +select c_name, c_acctbal from customer where $c7; +execute stmt using -(@a1+@a2); +eval +select c_name, c_acctbal from customer where $c7; + +deallocate prepare stmt; + + +--echo # Materialization SJM PS +--echo # ====================== + +eval +prepare stmt from " +update customer set c_acctbal = c_acctbal+? where $c9; +"; + +eval +select c_name, c_acctbal from customer where $c9; +set @a1=-2; +execute stmt using @a1; +eval +select c_name, c_acctbal from customer where $c9; +set @a2=-1; +execute stmt using @a2; +eval +select c_name, c_acctbal from customer where $c9; +execute stmt using -(@a1+@a2); +eval +select c_name, c_acctbal from customer where $c9; + +deallocate prepare stmt; + + +--echo # Pullout SP +--echo # ========== + +eval +create procedure p(d int) +update orders set o_totalprice = o_totalprice+d where $c1; + +eval +select o_orderkey, o_totalprice from orders where $c1; +call p(-10); +eval +select o_orderkey, o_totalprice from orders where $c1; +call p(-20); +eval +select o_orderkey, o_totalprice from orders where $c1; +call p(10+20); +eval +select o_orderkey, o_totalprice from orders where $c1; + +drop procedure p; + + +--echo # FirstMatch SP +--echo # ============= + +eval +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where $c5; + +eval +select c_name, c_acctbal from customer where $c5; +call p(5); +eval +select c_name, c_acctbal from customer where $c5; +call p(15); +eval +select c_name, c_acctbal from customer where $c5; +call p(-(5+15)); +eval +select c_name, c_acctbal from customer where $c5; + +drop procedure p; + + +--echo # Materialization SP +--echo # ================== + +eval +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where $c7; + +eval +select c_name, c_acctbal from customer where $c7; +call p(3); +eval +select c_name, c_acctbal from customer where $c7; +call p(7); +eval +select c_name, c_acctbal from customer where $c7; +call p(-(3+7)); +eval +select c_name, c_acctbal from customer where $c7; + +drop procedure p; + + +--echo # Materialization SJM SP +--echo # ====================== + +eval +create procedure p(d int) +update customer set c_acctbal = c_acctbal+d where $c9; + +eval +select c_name, c_acctbal from customer where $c9; +call p(-1); +eval +select c_name, c_acctbal from customer where $c9; +call p(-2); +eval +select c_name, c_acctbal from customer where $c9; +call p(1+2); +eval +select c_name, c_acctbal from customer where $c9; + +drop procedure p; + + +DROP DATABASE dbt3_s001; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 58d8687..df8f808 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -675,9 +675,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) 3. Subquery does not have GROUP BY or ORDER BY 4. Subquery does not use aggregate functions or HAVING 5. Subquery predicate is at the AND-top-level of ON/WHERE clause - 6. We are not in a subquery of a single table UPDATE/DELETE that - doesn't have a JOIN (TODO: We should handle this at some - point by switching to multi-table UPDATE/DELETE) + 6. We are not in a top level subquery of a single table DELETE + with RETURNING 7. We're not in a table-less subquery like "SELECT 1" 8. No execution method was already chosen (by a prepared statement) 9. Parent select is not a table-less select @@ -692,9 +691,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) !select_lex->group_list.elements && !join->order && // 3 !join->having && !select_lex->with_sum_func && // 4 in_subs->emb_on_expr_nest && // 5 - select_lex->outer_select()->join && // 6 - (!thd->lex->m_sql_cmd || - thd->lex->m_sql_cmd->sql_command_code() == SQLCOM_UPDATE_MULTI) && + !(thd->lex->sql_command == SQLCOM_DELETE && // 6 + thd->lex->has_returning() && // 6 + !select_lex->outer_select()->outer_select()) && // 6 parent_unit->first_select()->leaf_tables.elements && // 7 !in_subs->has_strategy() && // 8 select_lex->outer_select()->table_list.first && // 9 @@ -7192,3 +7191,23 @@ bool TABLE_LIST::is_sjm_scan_table() { return is_active_sjm() && sj_mat_info->is_sj_scan; } + + +bool SELECT_LEX::is_sj_subselect_lifted_to_top() +{ + st_select_lex *sl= this; + st_select_lex *outer_sl= outer_select(); + for ( ; outer_sl; sl= outer_sl, outer_sl= outer_sl->outer_select()) + { + List_iterator_fast<Item_in_subselect> it(outer_sl->sj_subselects); + Item_in_subselect *in_subs; + while ((in_subs= it++)) + { + if (in_subs->unit->first_select() == sl) + break; + } + if (!in_subs) + return false; + } + return true; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d1f97a..f0160eb 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6931,6 +6931,7 @@ class multi_delete :public select_result_interceptor // Methods used by ColumnStore uint get_num_of_tables() const { return num_of_tables; } TABLE_LIST* get_tables() const { return delete_tables; } + void set_delete_tables (TABLE_LIST *tbl) { delete_tables= tbl; } public: multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7ac4797..611ce48 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1511,6 +1511,47 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) table_list->delete_while_scanning= false; } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + if (!multitable && + select_lex->sj_subselects.elements && + !select_lex->order_list.elements && + select_lex->master_unit()->lim.get_select_limit() == HA_POS_ERROR && + !thd->lex->has_returning()) + multitable= true; + + if (!multitable) + ((multi_delete *)result)->set_delete_tables(0); + } + if (multitable) { /* @@ -1552,7 +1593,8 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) { TABLE_LIST *duplicate; if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) + lex->query_tables, 0)) && + !duplicate->select_lex->is_sj_subselect_lifted_to_top()) { update_non_unique_table_error(target_tbl->correspondent_table, "DELETE", duplicate); @@ -1567,38 +1609,6 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) lex->first_select_lex()->exclude_from_table_unique_test= FALSE; } - { - if (thd->lex->describe) - select_options|= SELECT_DESCRIBE; - - /* - When in EXPLAIN, delay deleting the joins so that they are still - available when we're producing EXPLAIN EXTENDED warning text. - */ - if (select_options & SELECT_DESCRIBE) - free_join= 0; - select_options|= - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; - - if (!(join= new (thd->mem_root) JOIN(thd, empty_list, - select_options, result))) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init); - select_lex->join= join; - thd->lex->used_tables=0; - if ((err= join->prepare(table_list, select_lex->where, - select_lex->order_list.elements, - select_lex->order_list.first, - false, NULL, NULL, NULL, - select_lex, &lex->unit))) - - { - goto err; - } - - } - - if (setup_returning_fields(thd, table_list) || setup_ftfuncs(select_lex)) goto err; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5436bfd..f760ea1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1642,6 +1642,7 @@ class st_select_lex: public st_select_lex_node void lex_start(LEX *plex); bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); } void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; } + bool is_sj_subselect_lifted_to_top(); }; typedef class st_select_lex SELECT_LEX; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ffd2efe..8360e36 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5800,8 +5800,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, s->needed_reg=select->needed_reg; select->quick=0; impossible_range= records == 0 && s->table->reginfo.impossible_range; - if (join->thd->lex->sql_command == SQLCOM_SELECT && - optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER)) + if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER)) s->table->init_cost_info_for_usable_range_rowid_filters(join->thd); } if (!impossible_range) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0ed25c3..7c48f8e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -2671,6 +2671,8 @@ int multi_update::do_updates() table = cur_table->table; if (table == table_to_update) continue; // Already updated + if (table->file->pushed_rowid_filter) + table->file->disable_pushed_rowid_filter(); org_updated= updated; tmp_table= tmp_tables[cur_table->shared]; tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache @@ -2865,7 +2867,8 @@ int multi_update::do_updates() check_opt_it.rewind(); while (TABLE *tbl= check_opt_it++) tbl->file->ha_rnd_end(); - + if (table->file->save_pushed_rowid_filter) + table->file->enable_pushed_rowid_filter(); } DBUG_RETURN(0); @@ -2876,6 +2879,8 @@ int multi_update::do_updates() } err2: + if (table->file->save_pushed_rowid_filter) + table->file->enable_pushed_rowid_filter(); if (table->file->inited) (void) table->file->ha_rnd_end(); if (tmp_table->file->inited) @@ -3126,6 +3131,11 @@ bool Sql_cmd_update::prepare_inner(THD *thd) goto err; } + if (!multitable && + select_lex->sj_subselects.elements && + !select_lex->order_list.elements && + select_lex->master_unit()->lim.get_select_limit() == HA_POS_ERROR) + multitable= true; } free_join= false; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4dfbfb4..3953136 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13347,8 +13347,21 @@ delete_single_table: YYPS->m_lock_type, YYPS->m_mdl_type, NULL, + 0))) + MYSQL_YYABORT; + Select->table_list.save_and_clear(&Lex->auxiliary_table_list); + Lex->table_count= 1; + Lex->query_tables= 0; + Lex->query_tables_last= &Lex->query_tables; + if (unlikely(!Select-> + add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, $3))) MYSQL_YYABORT; + Lex->auxiliary_table_list.first->correspondent_table= + Lex->query_tables; YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; }
1 0
0 0
[Commits] 6e7c6fc: MDEV-28448 Assertion failure for SELECT with subquery using ON expression
by IgorBabaev 30 Apr '22

30 Apr '22
revision-id: 6e7c6fcfd1f1ac131c423c1ba084d61abad10e8b (mariadb-10.4.23-82-g6e7c6fc) parent(s): c8228369f6dad5cfd17c5a9d9ea1c5c3ecd30fe7 author: Igor Babaev committer: Igor Babaev timestamp: 2022-04-30 13:25:34 -0700 message: MDEV-28448 Assertion failure for SELECT with subquery using ON expression This patch corrects the fix for MDEV-26412. Note that when parsing an ON expression the pointer to the current select is always in select_stack[select_stack_top - 1]. So the pointer to the outer select (if any) is in select_stack[select_stack_top - 2]. The query manifesting this bug is added to the test case of MDEV-26412. --- mysql-test/main/insert.result | 4 ++++ mysql-test/main/insert.test | 5 +++++ sql/sql_lex.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/insert.result b/mysql-test/main/insert.result index 1062ddd..af7dcbe 100644 --- a/mysql-test/main/insert.result +++ b/mysql-test/main/insert.result @@ -766,4 +766,8 @@ replace t4 select * from t1 left join t2 on (select t1.i from t3); ERROR 42S22: Unknown column 't1.i' in 'field list' drop table t1,t2,t3,t4; +create table t (a int); +select 1 in (select count(*) from t t1 join (t t2 join t t3 on (t1.a != 0))); +ERROR 42S22: Unknown column 't1.a' in 'on clause' +drop table t; # End of 10.4 tests diff --git a/mysql-test/main/insert.test b/mysql-test/main/insert.test index 9fd0933..27d4491 100644 --- a/mysql-test/main/insert.test +++ b/mysql-test/main/insert.test @@ -633,4 +633,9 @@ replace t4 drop table t1,t2,t3,t4; +create table t (a int); +--error ER_BAD_FIELD_ERROR +select 1 in (select count(*) from t t1 join (t t2 join t t3 on (t1.a != 0))); +drop table t; + --echo # End of 10.4 tests diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 3e35d16..6a3a01f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3700,7 +3700,7 @@ struct LEX: public Query_tables_list SELECT_LEX *parser_current_outer_select() { return select_stack_top - 1 == select_stack_outer_barrier ? - 0 : select_stack[select_stack_top - 1]; + 0 : select_stack[select_stack_top - 2]; } Name_resolution_context *current_context()
1 0
0 0
[Commits] c985c93: MDEV-28080 Crash when using HAVING with NOT EXIST predicate in an equality
by IgorBabaev 29 Apr '22

29 Apr '22
revision-id: c985c93b6e10c247865b4710c1b9e6623bd6cceb (mariadb-10.4.23-75-gc985c93) parent(s): 39feab3cd31b5414aa9b428eaba915c251ac34a2 author: Igor Babaev committer: Igor Babaev timestamp: 2022-04-29 10:37:01 -0700 message: MDEV-28080 Crash when using HAVING with NOT EXIST predicate in an equality MDEV-28082 Crash when using HAVING with IS NULL predicate in an equality These bugs have been fixed by the patch for MDEV-26402. Only test cases are added. --- mysql-test/main/having_cond_pushdown.result | 31 +++++++++++++++++++++++++++ mysql-test/main/having_cond_pushdown.test | 33 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result index 9a9ed2b..ad8befb 100644 --- a/mysql-test/main/having_cond_pushdown.result +++ b/mysql-test/main/having_cond_pushdown.result @@ -4939,3 +4939,34 @@ i Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'x' DROP TABLE t1; +# +# MDEV-28080: HAVING with NOT EXIST predicate in an equality +# (fixed by the patch for MDEV-26402) +# +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (0), (1), (1), (0); +INSERT INTO t2 VALUES (3), (7); +SELECT a FROM t1 +GROUP BY a HAVING a= (NOT EXISTS (SELECT b FROM t2 WHERE b = 1)); +a +1 +SELECT a FROM t1 +GROUP BY a HAVING a= (NOT EXISTS (SELECT b FROM t2 WHERE b = 7)); +a +0 +DROP TABLE t1, t2; +# +# MDEV-28082: HAVING with IS NULL predicate in an equality +# (fixed by the patch for MDEV-26402) +# +CREATE TABLE t1 (a int, b int NOT NULL) ; +INSERT INTO t1 VALUES (1,10), (0,11), (0,11), (1,10); +SELECT a,b FROM t1 GROUP BY a HAVING a = (b IS NULL); +a b +0 11 +SELECT a,b FROM t1 GROUP BY a,b HAVING a = (b IS NULL); +a b +0 11 +DROP TABLE t1; +End of 10.4 tests diff --git a/mysql-test/main/having_cond_pushdown.test b/mysql-test/main/having_cond_pushdown.test index 270eac2..aee5a77 100644 --- a/mysql-test/main/having_cond_pushdown.test +++ b/mysql-test/main/having_cond_pushdown.test @@ -1450,3 +1450,36 @@ SELECT * FROM t1 GROUP BY i HAVING i IN ( i IS NULL); SELECT * FROM t1 GROUP BY i HAVING i IN ( i IS NULL AND 'x' = 0); SELECT * FROM t1 GROUP BY i HAVING i='1' IN ( i IS NULL AND 'x' = 0); DROP TABLE t1; + +--echo # +--echo # MDEV-28080: HAVING with NOT EXIST predicate in an equality +--echo # (fixed by the patch for MDEV-26402) +--echo # + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (0), (1), (1), (0); +INSERT INTO t2 VALUES (3), (7); + +SELECT a FROM t1 + GROUP BY a HAVING a= (NOT EXISTS (SELECT b FROM t2 WHERE b = 1)); +SELECT a FROM t1 + GROUP BY a HAVING a= (NOT EXISTS (SELECT b FROM t2 WHERE b = 7)); + +DROP TABLE t1, t2; + +--echo # +--echo # MDEV-28082: HAVING with IS NULL predicate in an equality +--echo # (fixed by the patch for MDEV-26402) +--echo # + +CREATE TABLE t1 (a int, b int NOT NULL) ; +INSERT INTO t1 VALUES (1,10), (0,11), (0,11), (1,10); + +SELECT a,b FROM t1 GROUP BY a HAVING a = (b IS NULL); + +SELECT a,b FROM t1 GROUP BY a,b HAVING a = (b IS NULL); + +DROP TABLE t1; + +--echo End of 10.4 tests
1 0
0 0
[Commits] 1f0333d: MDEV-27159 Re-design the upper level of handling DML commands
by IgorBabaev 29 Apr '22

29 Apr '22
revision-id: 1f0333db90fb942b2a8435733184460ca3c56288 (mariadb-10.6.1-309-g1f0333d) parent(s): 31c01a5b28fc59479755cab5098b3d13e55f732b author: Igor Babaev committer: Igor Babaev timestamp: 2022-04-28 17:15:26 -0700 message: MDEV-27159 Re-design the upper level of handling DML commands This is the second commit for the task. This patch allows to execute only single-table and multi-table DELETE statements using the method Sql_cmd_dml::execute(). The code that handles INSERT statements has not been touched. This patch still does not have the final changes to handle UPDATE/DELETE statements. All tests from the main suite passed. With --ps-protocol one test from opt_trace_security returns not the same result. This will be fixed soon. --- extra/wolfssl/wolfssl | 2 +- mysql-test/main/opt_trace.result | 14 +- mysql-test/main/opt_trace_security.result | 1 - sql/opt_range.cc | 2 +- sql/sql_base.cc | 7 +- sql/sql_cmd.h | 9 +- sql/sql_delete.cc | 577 ++++++++++++++++-------------- sql/sql_delete.h | 9 + sql/sql_lex.cc | 30 +- sql/sql_parse.cc | 138 +------ sql/sql_parse.h | 1 + sql/sql_prepare.cc | 102 +----- sql/sql_select.cc | 1 - sql/sql_update.cc | 7 +- sql/sql_yacc.yy | 63 ++-- sql/table.h | 1 + 16 files changed, 379 insertions(+), 585 deletions(-) diff --git a/extra/wolfssl/wolfssl b/extra/wolfssl/wolfssl index c3513bf..9c87f97 160000 --- a/extra/wolfssl/wolfssl +++ b/extra/wolfssl/wolfssl @@ -1 +1 @@ -Subproject commit c3513bf2573c30f6d2df815de216120e92142020 +Subproject commit 9c87f979a7f1d3a6d786b260653d566c1d31a1c4 diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index 044db82..1444320 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -3742,6 +3742,16 @@ QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES explain delete from t0 where t0.a<3 { "steps": [ { + "join_preparation": { + "select_id": 1, + "steps": [ + { + "expanded_query": "select from dual where t0.a < 3" + } + ] + } + }, + { "table": "t0", "range_analysis": { "table_scan": { @@ -3773,7 +3783,7 @@ explain delete from t0 where t0.a<3 { }, "group_index_range": { "chosen": false, - "cause": "no join" + "cause": "no group by or distinct" }, "chosen_range_access_summary": { "range_access_plan": { @@ -3816,7 +3826,7 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 { "select_id": 1, "steps": [ { - "expanded_query": "select NULL AS `NULL` from t0 join t1 where t0.a = t1.a and t1.a < 3" + "expanded_query": "select from t0 join t1 where t0.a = t1.a and t1.a < 3" } ] } diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result index e1937e7..d960dd2 100644 --- a/mysql-test/main/opt_trace_security.result +++ b/mysql-test/main/opt_trace_security.result @@ -16,7 +16,6 @@ select * from db1.t1; ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1' select * from information_schema.OPTIMIZER_TRACE; QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES - 0 1 set optimizer_trace="enabled=off"; grant select(a) on db1.t1 to 'foo'@'%'; set optimizer_trace="enabled=on"; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7909f5b..13457d7 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -11589,7 +11589,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, Skip materialized derived table/view result table from MRR check as they aren't contain any data yet. */ - if (param->table->pos_in_table_list->is_non_derived()) + if (!param->table->pos_in_table_list->is_materialized_derived()) rows= file->multi_range_read_info_const(keynr, &seq_if, (void*)&seq, 0, bufsize, mrr_flags, cost); param->quick_rows[keynr]= rows; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6883fb1..51b619d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1074,7 +1074,9 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, */ if (table->table && thd->lex->sql_command != SQLCOM_UPDATE && - thd->lex->sql_command != SQLCOM_UPDATE_MULTI) + thd->lex->sql_command != SQLCOM_UPDATE_MULTI && + thd->lex->sql_command != SQLCOM_DELETE && + thd->lex->sql_command != SQLCOM_DELETE_MULTI) { /* All MyISAMMRG children are plain MyISAM tables. */ DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM); @@ -7570,6 +7572,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, if (!select_lex->with_wild) DBUG_RETURN(0); + if (!fields.elements) + DBUG_RETURN(0); + /* Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index c62fe83..2c069cf 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -262,6 +262,7 @@ class LEX; class select_result; class Prelocking_strategy; class DML_prelocking_strategy; +class Protocol; class Sql_cmd_dml : public Sql_cmd { @@ -289,7 +290,9 @@ class Sql_cmd_dml : public Sql_cmd protected: Sql_cmd_dml() - : Sql_cmd(), lex(nullptr), result(nullptr), m_empty_query(false) {} + : Sql_cmd(), lex(nullptr), result(nullptr), + m_empty_query(false), save_protocol(NULL) + {} /// @return true if query is guaranteed to return no data /** @@ -347,12 +350,14 @@ class Sql_cmd_dml : public Sql_cmd virtual DML_prelocking_strategy *get_dml_prelocking_strategy() = 0; - uint table_count; + uint table_count; protected: LEX *lex; ///< Pointer to LEX for this statement select_result *result; ///< Pointer to object for handling of the result bool m_empty_query; ///< True if query will produce no rows + List<Item> empty_list; + Protocol *save_protocol; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95adf17..7ac4797 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,7 +103,7 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, bool is_analyze) { explain->select_type= "SIMPLE"; - explain->table_name.append(&table->pos_in_table_list->alias); + explain->table_name.append(table->alias); explain->impossible_where= false; explain->no_partitions= false; @@ -294,124 +294,79 @@ int TABLE::delete_row() } -/** - Implement DELETE SQL word. - - @note Like implementations of other DDL/DML in MySQL, this function - relies on the caller to close the thread tables. This is done in the - end of dispatch_command(). -*/ - -bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_I_List<ORDER> *order_list, ha_rows limit, - ulonglong options, select_result *result) +bool Sql_cmd_delete::delete_from_single_table(THD *thd) { - bool will_batch= FALSE; - int error, loc_error; - TABLE *table; - SQL_SELECT *select=0; - SORT_INFO *file_sort= 0; - READ_RECORD info; - bool using_limit=limit != HA_POS_ERROR; - bool transactional_table, safe_update, const_cond; - bool const_cond_result; - bool return_error= 0; - ha_rows deleted= 0; - bool reverse= FALSE; - bool has_triggers= false; - ORDER *order= (ORDER *) ((order_list && order_list->elements) ? - order_list->first : NULL); - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + int error; + int loc_error; + bool transactional_table; + bool const_cond; + bool safe_update; + bool const_cond_result; + bool return_error= 0; + TABLE *table; + SQL_SELECT *select= 0; + SORT_INFO *file_sort= 0; + READ_RECORD info; + ha_rows deleted= 0; + bool reverse= FALSE; + bool binlog_is_row; killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; - bool binlog_is_row; - Explain_delete *explain; + bool will_batch= FALSE; + + bool has_triggers= false; + SELECT_LEX_UNIT *unit = &lex->unit; + SELECT_LEX *select_lex= unit->first_select(); + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + TABLE_LIST *const table_list = select_lex->get_table_list(); + ulonglong options= select_lex->options; + ORDER *order= select_lex->order_list.first; + COND *conds= select_lex->join->conds; + ha_rows limit= unit->lim.get_select_limit(); + bool using_limit= limit != HA_POS_ERROR; + Delete_plan query_plan(thd->mem_root); + Explain_delete *explain; Unique * deltempfile= NULL; bool delete_record= false; - bool delete_while_scanning; + bool delete_while_scanning= table_list->delete_while_scanning; bool portion_of_time_through_update; - DBUG_ENTER("mysql_delete"); + + DBUG_ENTER("Sql_cmd_delete::delete_single_table"); query_plan.index= MAX_KEY; query_plan.using_filesort= FALSE; - create_explain_query(thd->lex, thd->mem_root); - if (open_and_lock_tables(thd, table_list, TRUE, 0)) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init_update); + create_explain_query(thd->lex, thd->mem_root); const bool delete_history= table_list->vers_conditions.delete_history; DBUG_ASSERT(!(delete_history && table_list->period_conditions.is_set())); - if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) - DBUG_RETURN(TRUE); + if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(1); + if (table_list->handle_derived(thd->lex, DT_PREPARE)) + DBUG_RETURN(1); + + table= table_list->table; if (!table_list->single_table_updatable()) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); DBUG_RETURN(TRUE); } - if (!(table= table_list->table) || !table->is_created()) + + if (!table || !table->is_created()) { my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - table->map=1; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; - thd->lex->promote_select_describe_flag_if_needed(); - if (mysql_prepare_delete(thd, table_list, &conds, &delete_while_scanning)) - DBUG_RETURN(TRUE); - - if (table_list->has_period()) - { - if (!table_list->period_conditions.start.item->const_item() - || !table_list->period_conditions.end.item->const_item()) - { - my_error(ER_NOT_CONSTANT_EXPRESSION, MYF(0), "FOR PORTION OF"); - DBUG_RETURN(true); - } - } - - if (delete_history) - table->vers_write= false; - - if (returning) - (void) result->prepare(returning->item_list, NULL); - - if (thd->lex->current_select->first_cond_optimization) - { - thd->lex->current_select->save_leaf_tables(thd); - thd->lex->current_select->first_cond_optimization= 0; - } - /* check ORDER BY even if it can be ignored */ - if (order) - { - TABLE_LIST tables; - List<Item> fields; - List<Item> all_fields; - - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - tables.alias = table_list->alias; - - if (select_lex->setup_ref_array(thd, order_list->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, order)) - { - free_underlaid_joins(thd, thd->lex->first_select_lex()); - DBUG_RETURN(TRUE); - } - } - /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -519,7 +474,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->covering_keys.clear_all(); table->opt_range_keys.clear_all(); - select=make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); + select= make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (unlikely(error)) DBUG_RETURN(TRUE); if ((select && select->check_quick(thd, safe_update, limit)) || !limit) @@ -953,7 +908,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } } DBUG_ASSERT(transactional_table || !deleted || thd->transaction->stmt.modified_non_trans_table); - + if (likely(error < 0) || (thd->lex->ignore && !thd->is_error() && !thd->is_fatal_error)) { @@ -1003,90 +958,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } -/* - Prepare items in DELETE statement - - SYNOPSIS - mysql_prepare_delete() - thd - thread handler - table_list - global/local table list - conds - conditions - - RETURN VALUE - FALSE OK - TRUE error -*/ -int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds, - bool *delete_while_scanning) -{ - Item *fake_conds= 0; - SELECT_LEX *select_lex= thd->lex->first_select_lex(); - DBUG_ENTER("mysql_prepare_delete"); - List<Item> all_fields; - - *delete_while_scanning= true; - thd->lex->allow_sum_func.clear_all(); - if (setup_tables_and_check_access(thd, &select_lex->context, - &select_lex->top_join_list, table_list, - select_lex->leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, TRUE)) - DBUG_RETURN(TRUE); - - if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (table_list->has_period()) - { - if (table_list->is_view_or_derived()) - { - my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); - DBUG_RETURN(true); - } - - if (select_lex->period_setup_conds(thd, table_list)) - DBUG_RETURN(true); - } - - DBUG_ASSERT(table_list->table); - // conds could be cached from previous SP call - DBUG_ASSERT(!table_list->vers_conditions.need_setup() || - !*conds || thd->stmt_arena->is_stmt_execute()); - if (select_lex->vers_setup_conds(thd, table_list)) - DBUG_RETURN(TRUE); - - *conds= select_lex->where; - - if (setup_returning_fields(thd, table_list) || - setup_conds(thd, table_list, select_lex->leaf_tables, conds) || - setup_ftfuncs(select_lex)) - DBUG_RETURN(TRUE); - if (!table_list->single_table_updatable() || - check_key_in_view(thd, table_list)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - DBUG_RETURN(TRUE); - } - - /* - Application-time periods: if FOR PORTION OF ... syntax used, DELETE - statement could issue delete_row's mixed with write_row's. This causes - problems for myisam and corrupts table, if deleting while scanning. - */ - if (table_list->has_period() - || unique_table(thd, table_list, table_list->next_global, 0)) - *delete_while_scanning= false; - - if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) - DBUG_RETURN(TRUE); - - select_lex->fix_prepare_information(thd, conds, &fake_conds); - DBUG_RETURN(FALSE); -} - /*************************************************************************** Delete multiple tables from join @@ -1099,106 +970,6 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) return file->cmp_ref((const uchar*)a, (const uchar*)b); } -/* - make delete specific preparation and checks after opening tables - - SYNOPSIS - mysql_multi_delete_prepare() - thd thread handler - - RETURN - FALSE OK - TRUE Error -*/ - -int mysql_multi_delete_prepare(THD *thd) -{ - LEX *lex= thd->lex; - TABLE_LIST *aux_tables= lex->auxiliary_table_list.first; - TABLE_LIST *target_tbl; - DBUG_ENTER("mysql_multi_delete_prepare"); - - if (mysql_handle_derived(lex, DT_INIT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) - DBUG_RETURN(TRUE); - if (mysql_handle_derived(lex, DT_PREPARE)) - DBUG_RETURN(TRUE); - /* - setup_tables() need for VIEWs. JOIN::prepare() will not do it second - time. - - lex->query_tables also point on local list of DELETE SELECT_LEX - */ - if (setup_tables_and_check_access(thd, - &thd->lex->first_select_lex()->context, - &thd->lex->first_select_lex()-> - top_join_list, - lex->query_tables, - lex->first_select_lex()->leaf_tables, - FALSE, DELETE_ACL, SELECT_ACL, FALSE)) - DBUG_RETURN(TRUE); - - /* - Multi-delete can't be constructed over-union => we always have - single SELECT on top and have to check underlying SELECTs of it - */ - lex->first_select_lex()->set_unique_exclude(); - /* Fix tables-to-be-deleted-from list to point at opened tables */ - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - - target_tbl->table= target_tbl->correspondent_table->table; - if (target_tbl->correspondent_table->is_multitable()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - target_tbl->correspondent_table->view_db.str, - target_tbl->correspondent_table->view_name.str); - DBUG_RETURN(TRUE); - } - - if (!target_tbl->correspondent_table->single_table_updatable() || - check_key_in_view(thd, target_tbl->correspondent_table)) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - target_tbl->table_name.str, "DELETE"); - DBUG_RETURN(TRUE); - } - } - - for (target_tbl= (TABLE_LIST*) aux_tables; - target_tbl; - target_tbl= target_tbl->next_local) - { - /* - Check that table from which we delete is not used somewhere - inside subqueries/view. - */ - { - TABLE_LIST *duplicate; - if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) - { - update_non_unique_table_error(target_tbl->correspondent_table, - "DELETE", duplicate); - DBUG_RETURN(TRUE); - } - } - } - /* - Reset the exclude flag to false so it doesn't interfare - with further calls to unique_table - */ - lex->first_select_lex()->exclude_from_table_unique_test= FALSE; - - if (lex->save_prep_leaf_tables()) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); -} - multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables_arg): select_result_interceptor(thd_arg), delete_tables(dt), deleted(0), found(0), @@ -1647,3 +1418,261 @@ bool multi_delete::send_eof() } return 0; } + + +bool Sql_cmd_delete::precheck(THD *thd) +{ + if (!multitable) + { + if (delete_precheck(thd, lex->query_tables)) + return true; + } + else + { + if (multi_delete_precheck(thd, lex->query_tables)) + return true; + } + return false; +} + + +bool Sql_cmd_delete::prepare_inner(THD *thd) +{ + int err= 0; + TABLE_LIST *target_tbl; + JOIN *join; + SELECT_LEX *const select_lex = thd->lex->first_select_lex(); + TABLE_LIST *const table_list = select_lex->get_table_list(); + TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; + ulonglong select_options= select_lex->options; + bool free_join= 1; + SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0; + + DBUG_ENTER("Sql_cmd_delete::prepare_inner"); + + (void) read_statistics_for_tables_if_needed(thd, table_list); + + { + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); + } + + if (!(result= new (thd->mem_root) multi_delete(thd, aux_tables, + lex->table_count))) + { + DBUG_RETURN(TRUE); + } + + table_list->delete_while_scanning= true; + + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, + table_list, select_lex->leaf_tables, + false, DELETE_ACL, SELECT_ACL, true)) + DBUG_RETURN(TRUE); + + if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, + table_list, select_lex->leaf_tables, false, false)) + DBUG_RETURN(TRUE); + + if (!multitable) + { + if (table_list->vers_conditions.is_set() && table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (table_list->has_period()) + { + if (table_list->is_view_or_derived()) + { + my_error(ER_IT_IS_A_VIEW, MYF(0), table_list->table_name.str); + DBUG_RETURN(true); + } + + if (select_lex->period_setup_conds(thd, table_list)) + DBUG_RETURN(true); + } + + if (select_lex->vers_setup_conds(thd, table_list)) + DBUG_RETURN(TRUE); + /* + Application-time periods: if FOR PORTION OF ... syntax used, DELETE + statement could issue delete_row's mixed with write_row's. This causes + problems for myisam and corrupts table, if deleting while scanning. + */ + if (table_list->has_period() + || unique_table(thd, table_list, table_list->next_global, 0)) + table_list->delete_while_scanning= false; + } + + if (multitable) + { + /* + Multi-delete can't be constructed over-union => we always have + single SELECT on top and have to check underlying SELECTs of it + */ + lex->first_select_lex()->set_unique_exclude(); + /* Fix tables-to-be-deleted-from list to point at opened tables */ + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + target_tbl->table= target_tbl->correspondent_table->table; + if (target_tbl->correspondent_table->is_multitable()) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + target_tbl->correspondent_table->view_db.str, + target_tbl->correspondent_table->view_name.str); + DBUG_RETURN(TRUE); + } + + if (!target_tbl->correspondent_table->single_table_updatable() || + check_key_in_view(thd, target_tbl->correspondent_table)) + { + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + target_tbl->table_name.str, "DELETE"); + DBUG_RETURN(TRUE); + } + } + + for (target_tbl= (TABLE_LIST*) aux_tables; + target_tbl; + target_tbl= target_tbl->next_local) + { + /* + Check that table from which we delete is not used somewhere + inside subqueries/view. + */ + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, target_tbl->correspondent_table, + lex->query_tables, 0))) + { + update_non_unique_table_error(target_tbl->correspondent_table, + "DELETE", duplicate); + DBUG_RETURN(TRUE); + } + } + } + /* + Reset the exclude flag to false so it doesn't interfare + with further calls to unique_table + */ + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + } + + + if (setup_returning_fields(thd, table_list) || + setup_ftfuncs(select_lex)) + goto err; + + free_join= false; + + if (returning) + (void) result->prepare(returning->item_list, NULL); + +err: + + if (free_join) + { + THD_STAGE_INFO(thd, stage_end); + err|= (int)(select_lex->cleanup()); + DBUG_RETURN(err || thd->is_error()); + } + DBUG_RETURN(err); + +} + +bool Sql_cmd_delete::execute_inner(THD *thd) +{ + if (!multitable) + { + if (lex->has_returning()) + { + select_result *sel_result= NULL; + delete result; + /* This is DELETE ... RETURNING. It will return output to the client */ + if (thd->lex->analyze_stmt) + { + /* + Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce + output and then discard it. + */ + sel_result= new (thd->mem_root) select_send_analyze(thd); + save_protocol= thd->protocol; + thd->protocol= new Protocol_discard(thd); + } + else + { + if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) + return true; + } + result= lex->result ? lex->result : sel_result; + } + } + + bool res= multitable ? Sql_cmd_dml::execute_inner(thd) + : delete_from_single_table(thd); + + res|= thd->is_error(); + + if (save_protocol) + { + delete thd->protocol; + thd->protocol= save_protocol; + } + { + if (unlikely(res)) + result->abort_result_set(); + else + { + if (thd->lex->describe || thd->lex->analyze_stmt) + res= thd->lex->explain->send_explain(thd); + } + } + + if (result) + { + res= false; + delete result; + } + + return res; +} diff --git a/sql/sql_delete.h b/sql/sql_delete.h index dabcafb..4aee510 100644 --- a/sql/sql_delete.h +++ b/sql/sql_delete.h @@ -17,6 +17,9 @@ #define SQL_DELETE_INCLUDED #include "my_base.h" /* ha_rows */ +#include "sql_class.h" /* enum_duplicates */ +#include "sql_cmd.h" // Sql_cmd_dml +#include "sql_base.h" class THD; struct TABLE_LIST; @@ -43,6 +46,11 @@ class Sql_cmd_delete final : public Sql_cmd_dml return multitable ? SQLCOM_DELETE_MULTI : SQLCOM_DELETE; } + DML_prelocking_strategy *get_dml_prelocking_strategy() + { + return &dml_prelocking_strategy; + } + protected: bool precheck(THD *thd) override; @@ -55,5 +63,6 @@ class Sql_cmd_delete final : public Sql_cmd_dml bool multitable; + DML_prelocking_strategy dml_prelocking_strategy; }; #endif /* SQL_DELETE_INCLUDED */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index ee5b2a8..aca34e9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3328,34 +3328,6 @@ void st_select_lex_unit::exclude_level() } -#if 0 -/* - Exclude subtree of current unit from tree of SELECTs - - SYNOPSYS - st_select_lex_unit::exclude_tree() -*/ -void st_select_lex_unit::exclude_tree() -{ - for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) - { - // unlink current level from global SELECTs list - if (sl->link_prev && (*sl->link_prev= sl->link_next)) - sl->link_next->link_prev= sl->link_prev; - - // unlink underlay levels - for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) - { - u->exclude_level(); - } - } - // exclude currect unit from list of nodes - (*prev)= next; - if (next) - next->prev= prev; -} -#endif - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from @@ -3577,7 +3549,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) select_n_where_fields + order_group_num + hidden_bit_fields + - fields_in_window_functions) * (size_t) 5; + fields_in_window_functions + 1) * (size_t) 5; DBUG_ASSERT(n_elems % 5 == 0); if (!ref_pointer_array.is_null()) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 72ac199..4a32736 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4395,10 +4395,15 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) } case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: { DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(lex->m_sql_cmd != NULL); - thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); + + if (lex->sql_command == SQLCOM_UPDATE || + lex->sql_command == SQLCOM_UPDATE_MULTI) + thd->abort_on_warning= !thd->lex->ignore && thd->is_strict_mode(); res = lex->m_sql_cmd->execute(thd); thd->abort_on_warning= 0; break; @@ -4662,129 +4667,6 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) break; } - case SQLCOM_DELETE: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - select_result *sel_result= NULL; - DBUG_ASSERT(first_table == all_tables && first_table != 0); - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= delete_precheck(thd, all_tables))) - break; - DBUG_ASSERT(select_lex->limit_params.offset_limit == 0); - unit->set_limit(select_lex); - - MYSQL_DELETE_START(thd->query()); - Protocol *save_protocol= NULL; - - if (lex->has_returning()) - { - /* This is DELETE ... RETURNING. It will return output to the client */ - if (thd->lex->analyze_stmt) - { - /* - Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce - output and then discard it. - */ - sel_result= new (thd->mem_root) select_send_analyze(thd); - save_protocol= thd->protocol; - thd->protocol= new Protocol_discard(thd); - } - else - { - if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) - goto error; - } - } - - res = mysql_delete(thd, all_tables, - select_lex->where, &select_lex->order_list, - unit->lim.get_select_limit(), select_lex->options, - lex->result ? lex->result : sel_result); - - if (save_protocol) - { - delete thd->protocol; - thd->protocol= save_protocol; - } - - if (thd->lex->analyze_stmt || thd->lex->describe) - { - if (!res) - res= thd->lex->explain->send_explain(thd); - } - - delete sel_result; - MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func()); - break; - } - case SQLCOM_DELETE_MULTI: - { - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - DBUG_ASSERT(first_table == all_tables && first_table != 0); - TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; - multi_delete *result; - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - - if ((res= multi_delete_precheck(thd, all_tables))) - break; - - /* condition will be TRUE on SP re-excuting */ - if (select_lex->item_list.elements != 0) - select_lex->item_list.empty(); - if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) - goto error; - - THD_STAGE_INFO(thd, stage_init); - if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) - break; - - MYSQL_MULTI_DELETE_START(thd->query()); - if (unlikely(res= mysql_multi_delete_prepare(thd))) - { - MYSQL_MULTI_DELETE_DONE(1, 0); - goto error; - } - - if (likely(!thd->is_fatal_error)) - { - result= new (thd->mem_root) multi_delete(thd, aux_tables, - lex->table_count); - if (likely(result)) - { - if (unlikely(select_lex->vers_setup_conds(thd, aux_tables))) - goto multi_delete_error; - res= mysql_select(thd, - select_lex->get_table_list(), - select_lex->item_list, - select_lex->where, - 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, - (ORDER *)NULL, - (select_lex->options | thd->variables.option_bits | - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, - result, unit, select_lex); - res|= (int)(thd->is_error()); - - MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); - if (res) - result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ - else - { - if (lex->describe || lex->analyze_stmt) - res= thd->lex->explain->send_explain(thd); - } - multi_delete_error: - delete result; - } - } - else - { - res= TRUE; // Error - MYSQL_MULTI_DELETE_DONE(1, 0); - } - break; - } case SQLCOM_DROP_SEQUENCE: case SQLCOM_DROP_TABLE: { @@ -7659,12 +7541,16 @@ void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) } -void mysql_init_multi_delete(LEX *lex) +void mysql_init_delete(LEX *lex) { - lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); lex->first_select_lex()->limit_params.clear(); lex->unit.lim.clear(); +} + +void mysql_init_multi_delete(LEX *lex) +{ + lex->sql_command= SQLCOM_DELETE_MULTI; lex->first_select_lex()->table_list. save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index ebe3fe9..45cd15c 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -95,6 +95,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); void create_select_for_variable(THD *thd, LEX_CSTRING *var_name); void create_table_set_open_action_and_adjust_tables(LEX *lex); +void mysql_init_delete(LEX *lex); void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3859a13..84feda3 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -95,7 +95,6 @@ When one supplies long data for a placeholder: #include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck -#include "sql_delete.h" // mysql_prepare_delete #include "sql_select.h" // for JOIN #include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert #include "sql_db.h" // mysql_opt_change_db, mysql_change_db @@ -1398,56 +1397,6 @@ static bool mysql_test_insert(Prepared_statement *stmt, } -/** - Validate DELETE statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message is set in THD -*/ - -static bool mysql_test_delete(Prepared_statement *stmt, - TABLE_LIST *table_list) -{ - uint table_count= 0; - THD *thd= stmt->thd; - LEX *lex= stmt->lex; - bool delete_while_scanning; - DBUG_ENTER("mysql_test_delete"); - - if (delete_precheck(thd, table_list) || - open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL)) - goto error; - - if (mysql_handle_derived(thd->lex, DT_INIT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) - goto error; - if (mysql_handle_derived(thd->lex, DT_PREPARE)) - goto error; - - if (!table_list->single_table_updatable()) - { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "DELETE"); - goto error; - } - if (!table_list->table || !table_list->table->is_created()) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); - goto error; - } - - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - &lex->first_select_lex()->where, - &delete_while_scanning)); -error: - DBUG_RETURN(TRUE); -} /** @@ -2031,48 +1980,6 @@ static bool mysql_test_create_view(Prepared_statement *stmt) /** - Validate and prepare for execution a multi delete statement. - - @param stmt prepared statement - @param tables list of tables used in this query - - @retval - FALSE success - @retval - TRUE error, error message in THD is set. -*/ - -static bool mysql_test_multidelete(Prepared_statement *stmt, - TABLE_LIST *tables) -{ - THD *thd= stmt->thd; - - thd->lex->current_select= thd->lex->first_select_lex(); - if (add_item_to_list(thd, new (thd->mem_root) - Item_null(thd))) - { - my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0); - goto error; - } - - if (multi_delete_precheck(thd, tables) || - select_like_stmt_test_with_open(stmt, tables, - &mysql_multi_delete_prepare, - OPTION_SETUP_TABLES_DONE)) - goto error; - if (!tables->table) - { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - tables->view_db.str, tables->view_name.str); - goto error; - } - return FALSE; -error: - return TRUE; -} - - -/** Wrapper for mysql_insert_select_prepare, to make change of local tables after open_normal_and_derived_tables() call. @@ -2354,14 +2261,13 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_UPDATE: case SQLCOM_UPDATE_MULTI: + case SQLCOM_DELETE: + case SQLCOM_DELETE_MULTI: res = lex->m_sql_cmd->prepare(thd); if (!res) lex->m_sql_cmd->unprepare(thd); break; - case SQLCOM_DELETE: - res= mysql_test_delete(stmt, tables); - break; /* The following allow WHERE clause, so they must be tested like SELECT */ case SQLCOM_SHOW_DATABASES: case SQLCOM_SHOW_TABLES: @@ -2498,10 +2404,6 @@ static bool check_prepared_statement(Prepared_statement *stmt) res= mysql_test_set_fields(stmt, tables, &lex->var_list); break; - case SQLCOM_DELETE_MULTI: - res= mysql_test_multidelete(stmt, tables); - break; - case SQLCOM_INSERT_SELECT: case SQLCOM_REPLACE_SELECT: res= mysql_test_insert_select(stmt, tables); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index edd9aed..ffd2efe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -30345,7 +30345,6 @@ bool Sql_cmd_dml::execute(THD *thd) THD_STAGE_INFO(thd, stage_init); - DBUG_ASSERT(!lex->is_query_tables_locked()); /* Locking of tables is done after preparation but before optimization. This allows to do better partition pruning and avoid locking unused diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f04db0..0ed25c3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -3029,12 +3029,10 @@ bool Sql_cmd_update::prepare_inner(THD *thd) { JOIN *join; int err= 0; - // uint table_cnt= 0; SELECT_LEX *const select_lex = thd->lex->first_select_lex(); TABLE_LIST *const table_list = select_lex->get_table_list(); ulonglong select_options= select_lex->options; bool free_join= 1; - // bool orig_multitable= multitable; DBUG_ENTER("Sql_cmd_update::prepare_inner"); if (!multitable) @@ -3088,8 +3086,8 @@ bool Sql_cmd_update::prepare_inner(THD *thd) DBUG_RETURN(TRUE); } - if (((multi_update *)result)->init(thd)) - DBUG_RETURN(TRUE); + if (((multi_update *)result)->init(thd)) + DBUG_RETURN(TRUE); if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, table_list, select_lex->leaf_tables, false, false)) @@ -3147,6 +3145,7 @@ bool Sql_cmd_update::prepare_inner(THD *thd) bool Sql_cmd_update::execute_inner(THD *thd) { + thd->get_stmt_da()->reset_current_row_for_warning(1); bool res= multitable ? Sql_cmd_dml::execute_inner(thd) : update_single_table(thd); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30eda7c..4dfbfb4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -70,6 +70,7 @@ #include "sql_type_json.h" #include "json_table.h" #include "sql_update.h" +#include "sql_delete.h" /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER @@ -1675,7 +1676,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); opt_mi_check_type opt_to mi_check_types table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan - single_multi table_wild_list table_wild_one opt_wild + single_multi opt_wild opt_and select_var_list select_var_list_init help opt_extended_describe shutdown @@ -13303,12 +13304,11 @@ delete: DELETE_SYM { LEX *lex= Lex; - lex->sql_command= SQLCOM_DELETE; YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; if (Lex->main_select_push()) MYSQL_YYABORT; - mysql_init_select(lex); + mysql_init_delete(lex); lex->ignore= 0; lex->first_select_lex()->order_list.empty(); } @@ -13369,12 +13369,22 @@ single_multi: delete_limit_clause opt_returning { + LEX *lex= Lex; if ($3) Select->order_list= *($3); - Lex->pop_select(); //main select + lex->pop_select(); //main select + lex->sql_command= SQLCOM_DELETE; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(false))) + MYSQL_YYABORT; } - | table_wild_list + | table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13386,6 +13396,11 @@ single_multi: } stmt_end {} | FROM table_alias_ref_list { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE_MULTI; + if (!(lex->m_sql_cmd= + new (thd->mem_root) Sql_cmd_delete(true))) + MYSQL_YYABORT; mysql_init_multi_delete(Lex); YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; @@ -13421,44 +13436,6 @@ opt_returning: } ; -table_wild_list: - table_wild_one - | table_wild_list ',' table_wild_one - ; - -table_wild_one: - ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(&$1); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - | ident '.' ident opt_wild - { - Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); - if (unlikely(ti == NULL)) - MYSQL_YYABORT; - if (unlikely(!Select-> - add_table_to_list(thd, - ti, - NULL, - (TL_OPTION_UPDATING | - TL_OPTION_ALIAS), - YYPS->m_lock_type, - YYPS->m_mdl_type))) - MYSQL_YYABORT; - } - ; - opt_wild: /* empty */ {} | '.' '*' {} diff --git a/sql/table.h b/sql/table.h index 8d609fb..358e1a9 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2321,6 +2321,7 @@ struct TABLE_LIST */ select_unit *derived_result; /* Stub used for materialized derived tables. */ + bool delete_while_scanning; table_map map; /* ID bit of table (1,2,4,8,16...) */ table_map get_map() {
1 0
0 0
[Commits] f04bf35: MDEV-26412 Server crash in Item_field::fix_outer_field for INSERT SELECT
by IgorBabaev 26 Apr '22

26 Apr '22
revision-id: f04bf3529cbe472c6d73158e9bc73b1a5e8c1841 (mariadb-10.4.23-34-gf04bf35) parent(s): c519aa3d7aea1afb7754ccf70aa5b276ff5fbf87 author: Igor Babaev committer: Igor Babaev timestamp: 2022-04-25 18:08:57 -0700 message: MDEV-26412 Server crash in Item_field::fix_outer_field for INSERT SELECT IF an INSERT/REPLACE SELECT statement contained an ON expression in the top level select and this expression used a subquery with a column reference that could not be resolved then an attempt to resolve this reference as an outer reference caused a crash of the server. This happened because the outer context field in the Name_resolution_context structure was not set to NULL for such references. Rather it pointed to the first element in the select_stack. Note that starting from 10.4 we cannot use the SELECT_LEX::outer_select() method when parsing a SELECT construct. Approved by Oleksandr Byelkin <sanja(a)mariadb.com> --- mysql-test/main/insert.result | 16 ++++++++++++++++ mysql-test/main/insert.test | 22 ++++++++++++++++++++++ sql/sql_lex.cc | 1 + sql/sql_lex.h | 17 +++++++++++++++++ sql/sql_parse.cc | 4 +--- sql/sql_yacc.yy | 2 ++ 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/insert.result b/mysql-test/main/insert.result index 4aea812..1062ddd 100644 --- a/mysql-test/main/insert.result +++ b/mysql-test/main/insert.result @@ -751,3 +751,19 @@ REPLACE INTO v1 SET f = NULL; ERROR 22007: Truncated incorrect DOUBLE value: 'foo' DROP VIEW v1; DROP TABLE t1; +# End of 10.0 tests +# +# MDEV-26412: INSERT CREATE with subquery in ON expression +# +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +create table t4 (d1 int, d2 int); +insert into t4 +select * from t1 left join t2 on (select t1.i from t3); +ERROR 42S22: Unknown column 't1.i' in 'field list' +replace t4 +select * from t1 left join t2 on (select t1.i from t3); +ERROR 42S22: Unknown column 't1.i' in 'field list' +drop table t1,t2,t3,t4; +# End of 10.4 tests diff --git a/mysql-test/main/insert.test b/mysql-test/main/insert.test index e00c9cd..9fd0933 100644 --- a/mysql-test/main/insert.test +++ b/mysql-test/main/insert.test @@ -612,3 +612,25 @@ CREATE VIEW v1 AS SELECT * FROM t1 WHERE f <=> 'foo' WITH CHECK OPTION; REPLACE INTO v1 SET f = NULL; DROP VIEW v1; DROP TABLE t1; + +--echo # End of 10.0 tests + +--echo # +--echo # MDEV-26412: INSERT CREATE with subquery in ON expression +--echo # + +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +create table t4 (d1 int, d2 int); + +--error ER_BAD_FIELD_ERROR +insert into t4 + select * from t1 left join t2 on (select t1.i from t3); +--error ER_BAD_FIELD_ERROR +replace t4 + select * from t1 left join t2 on (select t1.i from t3); + +drop table t1,t2,t3,t4; + +--echo # End of 10.4 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a93652c..b8f009f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -701,6 +701,7 @@ void LEX::start(THD *thd_arg) context_stack.empty(); //empty select_stack select_stack_top= 0; + select_stack_outer_barrier= 0; unit.init_query(); current_select_number= 0; curr_with_clause= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 19d4eb0..f274695 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3246,6 +3246,12 @@ struct LEX: public Query_tables_list List<Name_resolution_context> context_stack; SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1]; uint select_stack_top; + /* + Usually this is set to 0, but for INSERT/REPLACE SELECT it is set to 1. + When parsing such statements the pointer to the most outer select is placed + into the second element of select_stack rather than into the first. + */ + uint select_stack_outer_barrier; SQL_I_List<ORDER> proc_list; SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list; @@ -3686,6 +3692,17 @@ struct LEX: public Query_tables_list bool copy_db_to(LEX_CSTRING *to); + void inc_select_stack_outer_barrier() + { + select_stack_outer_barrier++; + } + + SELECT_LEX *parser_current_outer_select() + { + return select_stack_top - 1 == select_stack_outer_barrier ? + 0 : select_stack[select_stack_top - 1]; + } + Name_resolution_context *current_context() { return context_stack.head(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 35310d2..723f072 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9015,9 +9015,7 @@ push_new_name_resolution_context(THD *thd, right_op->last_leaf_for_name_resolution(); LEX *lex= thd->lex; on_context->select_lex = lex->current_select; - st_select_lex *curr_select= lex->pop_select(); - st_select_lex *outer_sel= lex->select_stack_head(); - lex->push_select(curr_select); + st_select_lex *outer_sel= lex->parser_current_outer_select(); on_context->outer_context = outer_sel ? &outer_sel->context : 0; return lex->push_context(on_context); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fed704e..ddb3604 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13579,6 +13579,7 @@ insert: if (Lex->main_select_push()) MYSQL_YYABORT; mysql_init_select(lex); + lex->inc_select_stack_outer_barrier(); lex->current_select->parsing_place= BEFORE_OPT_LIST; } insert_lock_option @@ -13605,6 +13606,7 @@ replace: if (Lex->main_select_push()) MYSQL_YYABORT; mysql_init_select(lex); + lex->inc_select_stack_outer_barrier(); lex->current_select->parsing_place= BEFORE_OPT_LIST; } replace_lock_option insert2
1 0
0 0
[Commits] c01ee954bf3: MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker
by psergey 22 Apr '22

22 Apr '22
revision-id: c01ee954bf3b10fef85af7b8c77d319ff7bd6b61 (mariadb-10.2.43-72-gc01ee954bf3) parent(s): 3c209bfc040ddfc41ece8357d772547432353fd2 author: Sergei Petrunia committer: Sergei Petrunia timestamp: 2022-04-22 20:26:14 +0300 message: MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker The cause of crash: remove_redundant_subquery_clauses() removes redundant item expressions. The primary goal of this is to remove the subquery items. The removal process unlinks the subquery from SELECT_LEX tree, but does not remove it from SELECT_LEX:::ref_pointer_array or from JOIN::all_fields. Then, setup_subquery_caches() tries to wrap the subquery item in an expression cache, which fails, the first reason for failure being that the item doesn't have a query plan. Solution: do not wrap eliminated items with expression cache. (also added an assert to check that we do not attempt to execute them). This may look like an incomplete fix: why don't we remove any mention of eliminated item everywhere? The difficulties here are: * items can be "un-removed" (see set_fake_select_as_master_processor) * it's difficult to remove an element from ref_pointer_array: Item_ref objects refer to elements of that array, so one can't shift elements in it. Replacing eliminated subselect with a dummy Item doesn't look like a good idea, either. --- mysql-test/r/subselect_innodb.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/subselect_innodb.test | 28 ++++++++++++++++++++++++++++ sql/item_subselect.cc | 11 +++++++++++ 3 files changed, 71 insertions(+) diff --git a/mysql-test/r/subselect_innodb.result b/mysql-test/r/subselect_innodb.result index 4eaea099451..4796245f8e3 100644 --- a/mysql-test/r/subselect_innodb.result +++ b/mysql-test/r/subselect_innodb.result @@ -629,3 +629,35 @@ a b 2019-03-10 02:55:05 2019-03-10 02:55:05 DROP TABLE t1,t2; set character_set_connection=@save_character_set_connection; +# +# MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker +# +CREATE TABLE t1 (a int) engine=innodb; +SELECT 1 IN ( +SELECT NULL +FROM t1 +WHERE +a IS NOT NULL +GROUP BY +(SELECT NULL from dual WHERE a = 1) +); +1 IN ( +SELECT NULL +FROM t1 +WHERE +a IS NOT NULL +GROUP BY +(SELECT NULL from dual WHERE a = 1) +) +0 +drop table t1; +# Testcase from MDEV-26164 +create table t1(a int); +# Disable the warning as it includes current time and changes for every test run. +select 1 from t1 where not exists +( +select 1 from t1 where binary current_time() +group by (select a),(select 1) +); +1 +drop table t1; diff --git a/mysql-test/t/subselect_innodb.test b/mysql-test/t/subselect_innodb.test index 2c117fe00d6..f42ac514d53 100644 --- a/mysql-test/t/subselect_innodb.test +++ b/mysql-test/t/subselect_innodb.test @@ -627,3 +627,31 @@ SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t DROP TABLE t1,t2; set character_set_connection=@save_character_set_connection; + +--echo # +--echo # MDEV-26047: MariaDB server crash at Item_subselect::init_expr_cache_tracker +--echo # +CREATE TABLE t1 (a int) engine=innodb; + +SELECT 1 IN ( + SELECT NULL + FROM t1 + WHERE + a IS NOT NULL + GROUP BY + (SELECT NULL from dual WHERE a = 1) +); +drop table t1; + +--echo # Testcase from MDEV-26164 +create table t1(a int); +--echo # Disable the warning as it includes current time and changes for every test run. +--disable_warnings +select 1 from t1 where not exists +( + select 1 from t1 where binary current_time() + group by (select a),(select 1) +); +--enable_warnings +drop table t1; + diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7033d38c07b..de9b5dc8438 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -752,6 +752,7 @@ bool Item_subselect::exec() DBUG_ENTER("Item_subselect::exec"); DBUG_ASSERT(fixed); + DBUG_ASSERT(!eliminated); /* Do not execute subselect in case of a fatal error @@ -1313,6 +1314,16 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(THD *tmp_thd, DBUG_ASSERT(thd == tmp_thd); + /* + Do not create subquery cache if the subquery was eliminated. + The optimizer may eliminate subquery items (see + eliminate_subselect_processor). However it does not update + all query's data structures, so the eliminated item may be + still reachable. + */ + if (eliminated) + DBUG_RETURN(this); + if (expr_cache) DBUG_RETURN(expr_cache);
1 0
0 0
[Commits] 173e232: MDEV-27212 Crash in Item_equal::sort on second execution of stored procedure
by IgorBabaev 22 Apr '22

22 Apr '22
revision-id: 173e232a67a8f9f6bd4321a8069319a78698ed58 (mariadb-10.2.31-1420-g173e232) parent(s): 33ff18627ea009709bb0ba55b68f873e6c6c784c author: Igor Babaev committer: Igor Babaev timestamp: 2022-04-22 07:53:16 -0700 message: MDEV-27212 Crash in Item_equal::sort on second execution of stored procedure This bug could cause a crash of the server at the second call of a stored procedure when it executed a query containing a mergeable derived table / view whose specification used another mergeable derived_table or view and a subquery with outer reference in the select list of the specification. Such queries could cause the same problem when they were executed for the second time in a prepared mode. The problem appeared due to a typo mistake in the legacy code of the function create_view_field() that prevented building Item_direct_view_ref wrapper for the mentioned outer reference at the second execution of the query and setting the depended_from field for the outer reference. Approved by Oleksandr Byelkin <sanja(a)mariadb.com> --- mysql-test/r/derived_view.result | 60 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/derived_view.test | 52 ++++++++++++++++++++++++++++++++++ sql/table.cc | 2 +- 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index 0c045e3..31a9220 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -3586,4 +3586,64 @@ f2 f3 DROP PROCEDURE p1; DROP VIEW v1,v2,v3; DROP TABLE t1; +# +# MDEV-27212: 2-nd execution of PS for select with embedded derived tables +# and correlated subquery in select list of outer derived +# +create table t1 ( id int, id2 int ) engine=myisam; +create table t2 ( x3 int , x1 int , x2 int, a1 int) engine=myisam; +insert into t1 values (3, 2), (4, 2), (3, 4); +insert into t2 values (1, 2, 2, 1), (1, 3, 3, 2), (2, 3, 3, 1); +prepare stmt from "select id from t1 +join +( select dt2.x1, +( select sum(a1) from t2 where t2.x1 = dt2.x1 ) m +from ( select x1 from t2 u where x3 = 1 ) dt2 +) dt +on t1.id = dt.x1 +where t1.id2 < dt.m"; +execute stmt; +id +3 +execute stmt; +id +3 +deallocate prepare stmt; +create procedure sp1() select id from t1 +join +( select dt2.x1, +( select sum(a1) from t2 where t2.x1 = dt2.x1 ) m +from ( select x1 from t2 u where x3 = 1 ) dt2 +) dt +on t1.id = dt.x1 +where t1.id2 < dt.m; +call sp1(); +id +3 +call sp1(); +id +3 +create view v2 as select x1 from t2 u where x3 = 1; +create view v as +select v2.x1, +( select sum(a1) from t2 where t2.x1 = v2.x1 ) m from v2; +prepare stmt from "select id from t1 join v on t1.id = v.x1 where t1.id2 < v.m"; +execute stmt; +id +3 +execute stmt; +id +3 +deallocate prepare stmt; +create procedure sp2() select id from t1 join v on t1.id = v.x1 where t1.id2 < v.m; +call sp2(); +id +3 +call sp2(); +id +3 +drop procedure sp1; +drop procedure sp2; +drop view v, v2; +drop table t1,t2; # End of 10.2 tests diff --git a/mysql-test/t/derived_view.test b/mysql-test/t/derived_view.test index 0f3d9b2..f364012 100644 --- a/mysql-test/t/derived_view.test +++ b/mysql-test/t/derived_view.test @@ -2376,4 +2376,56 @@ DROP PROCEDURE p1; DROP VIEW v1,v2,v3; DROP TABLE t1; +--echo # +--echo # MDEV-27212: 2-nd execution of PS for select with embedded derived tables +--echo # and correlated subquery in select list of outer derived +--echo # +create table t1 ( id int, id2 int ) engine=myisam; +create table t2 ( x3 int , x1 int , x2 int, a1 int) engine=myisam; +insert into t1 values (3, 2), (4, 2), (3, 4); +insert into t2 values (1, 2, 2, 1), (1, 3, 3, 2), (2, 3, 3, 1); + +let $q= +select id from t1 + join + ( select dt2.x1, + ( select sum(a1) from t2 where t2.x1 = dt2.x1 ) m + from ( select x1 from t2 u where x3 = 1 ) dt2 + ) dt + on t1.id = dt.x1 +where t1.id2 < dt.m; + +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +eval create procedure sp1() $q; +call sp1(); +call sp1(); + +create view v2 as select x1 from t2 u where x3 = 1; +create view v as +select v2.x1, + ( select sum(a1) from t2 where t2.x1 = v2.x1 ) m from v2; + +let $q= +select id from t1 join v on t1.id = v.x1 where t1.id2 < v.m; + +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +eval create procedure sp2() $q; +call sp2(); +call sp2(); + +drop procedure sp1; +drop procedure sp2; + +drop view v, v2; + +drop table t1,t2; + --echo # End of 10.2 tests diff --git a/sql/table.cc b/sql/table.cc index 1f7b645..1060ee2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5994,7 +5994,7 @@ Item *Field_iterator_view::create_item(THD *thd) Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, const char *name) { - bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + bool save_wrapper= thd->lex->current_select->no_wrap_view_item; Item *field= *field_ref; DBUG_ENTER("create_view_field");
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • ...
  • 1461
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.