From dcf59cc2480dbb1920874fa32bd967e8527f4315 Mon Sep 17 00:00:00 2001 From: Raghunandan Bhat Date: Mon, 13 Oct 2025 17:13:35 +0530 Subject: [PATCH] MDEV-37484: `Sql_cmd_dml::execute_inner`, `Sql_cmd_update::execute_inner` do not call Select handler for the engine involved Problem: After the re-design of `UPDATE` and `DELETE` in MDEV-28883, the call to find select handler is missing. This prevents the server from handring over multi-update/multi-delete queries to storage engines capable of executng such queries on their own (e.g., ColumnStore). MDEV-32382 introduced a check in `find_select_handler_inner` function, that blocked pushdown of queries involving CTEs, without checking if the storage engine is capable of handling such queries. Fix: Add a call to find the select handler for the engine involved in the multi-update/multi-delete query, allowing the storage engines to execute such queries. Fix the `find_select_handler_inner` function by allowing the storage engine's create_select functions to decide the pushdown of queries involving CTEs. --- .../federatedx_create_handlers.result | 224 ++++++++++++++++++ .../federated/federatedx_create_handlers.test | 126 +++++++++- sql/sql_delete.cc | 7 + sql/sql_select.cc | 13 +- storage/federatedx/federatedx_pushdown.cc | 3 + .../spider/bugfix/r/mdev_37484.result | 118 +++++++++ .../spider/bugfix/t/mdev_37484.test | 110 +++++++++ 7 files changed, 592 insertions(+), 9 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_37484.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_37484.test diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index d2e919cf840..1c3838a08be 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -1350,6 +1350,229 @@ federated.t12, federated.t13, federated.t14; connection slave; DROP TABLES federated.t1, federated.t2, federated.t11, federated.t12, federated.t13, federated.t14; +# +# MDEV-37484: `Sql_cmd_dml::execute_inner`, `Sql_cmd_update::execute_inner` do not call Select handler for the engine involved +# +connection default; +set global federated_pushdown=1; +connection slave; +create table federated.product_tag (product_id bigint); +CREATE TABLE federated.product ( +`product_id` bigint(20) DEFAULT NULL, +`price` bigint(20) DEFAULT NULL, +`short_description` varchar(7998) DEFAULT NULL, +`brand` varchar(254) DEFAULT NULL, +`modified_dtm` datetime DEFAULT NULL, +`created_dtm` datetime DEFAULT NULL, +`modified_by` int(11) DEFAULT NULL +) CHARSET=latin1; +connection master; +create table federated.product_tag (product_id bigint) +ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/product_tag'; +CREATE TABLE federated.product ( +`product_id` bigint(20) DEFAULT NULL, +`price` bigint(20) DEFAULT NULL, +`short_description` varchar(7998) DEFAULT NULL, +`brand` varchar(254) DEFAULT NULL, +`modified_dtm` datetime DEFAULT NULL, +`created_dtm` datetime DEFAULT NULL, +`modified_by` int(11) DEFAULT NULL +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/product'; +insert into federated.product_tag values (1),(2),(3),(4); +insert into federated.product values (1,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +insert into federated.product values (3,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +select * from federated.product order by product_id; +product_id price short_description brand modified_dtm created_dtm modified_by +1 22 fes rets 2011-12-12 12:12:12 2011-12-13 01:01:10 343 +3 22 fes rets 2011-12-12 12:12:12 2011-12-13 01:01:10 343 +explain format=json update +federated.product p join +(select product_id from federated.product_tag limit 1000) t using (product_id) +set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', +short_description=concat(short_description,modified_by); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost": 1000.010933, + "nested_loop": [ + { + "table": { + "table_name": "p", + "access_type": "ALL", + "loops": 1, + "rows": 2, + "cost": 1000.010388, + "filtered": 100, + "attached_condition": "p.product_id is not null" + } + }, + { + "table": { + "table_name": "", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "9", + "used_key_parts": ["product_id"], + "ref": ["federated.p.product_id"], + "loops": 2, + "rows": 1, + "cost": 0.000545388, + "filtered": 100, + "materialized": { + "query_block": { + "select_id": 2, + "table": { + "message": "Pushed derived" + } + } + } + } + } + ] + } +} +update +federated.product p join +(select product_id from federated.product_tag limit 1000) t using (product_id) +set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', +short_description=concat(short_description,modified_by); +select * from federated.product order by product_id; +product_id price short_description brand modified_dtm created_dtm modified_by +1 555 fes343 1 2011-12-15 15:15:30 2011-12-13 01:01:10 343 +3 555 fes343 3 2011-12-15 15:15:30 2011-12-13 01:01:10 343 +drop table federated.product_tag; +drop table federated.product; +connection slave; +drop table federated.product_tag; +drop table federated.product; +# Setup +create or replace table federated.t1 (id int); +create or replace table federated.t2 (id int, op varchar(10), op_count int DEFAULT 0) CHARSET=latin1; +connection master; +create or replace table federated.t1 (id int) +ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +create or replace table federated.t2 (id int, op varchar(10), op_count int DEFAULT 0) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2'; +insert into federated.t1 values (1),(2),(3),(4); +insert into federated.t2 (id, op) values (1, 'inserted'), (2, 'inserted'), (3, 'inserted'), (4, 'inserted'); +select * from federated.t2 order by id; +id op op_count +1 inserted 0 +2 inserted 0 +3 inserted 0 +4 inserted 0 +# Update tests +explain format=json update federated.t2 inner join federated.t1 on t2.id = t1.id +set t2.op = 'updated', t2.op_count = t2.op_count + 1 +where t2.id in (1, 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost": 2000.022975, + "nested_loop": [ + { + "table": { + "table_name": "t2", + "access_type": "ALL", + "loops": 1, + "rows": 4, + "cost": 1000.010655, + "filtered": 100, + "attached_condition": "t2.`id` in (1,2)" + } + }, + { + "table": { + "table_name": "t1", + "access_type": "ALL", + "loops": 4, + "rows": 4, + "cost": 1000.012319, + "filtered": 100, + "attached_condition": "t1.`id` = t2.`id`" + } + } + ] + } +} +update federated.t2 inner join federated.t1 on t2.id = t1.id +set t2.op = 'updated', t2.op_count = t2.op_count + 1 +where t2.id in (1, 2); +select * from federated.t2 order by id; +id op op_count +1 updated 1 +2 updated 1 +3 inserted 0 +4 inserted 0 +# Prepared update stmt +PREPARE stmt_update FROM +'update federated.t2 inner join federated.t1 on t2.id = t1.id set t2.op_count = t2.op_count + 1, t2.op="updated" where t2.id in (1, 2)'; +EXECUTE stmt_update; +DEALLOCATE PREPARE stmt_update; +select * from federated.t2 order by id; +id op op_count +1 updated 2 +2 updated 2 +3 inserted 0 +4 inserted 0 +# Delete tests +explain format=json +delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id and t2.op = 'updated'; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost": 2000.023025, + "nested_loop": [ + { + "table": { + "table_name": "t2", + "access_type": "ALL", + "loops": 1, + "rows": 4, + "cost": 1000.010705, + "filtered": 100, + "attached_condition": "t2.op = 'updated'" + } + }, + { + "table": { + "table_name": "t1", + "access_type": "ALL", + "loops": 4, + "rows": 4, + "cost": 1000.012319, + "filtered": 100, + "attached_condition": "t1.`id` = t2.`id`" + } + } + ] + } +} +delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id and t2.op = 'updated'; +select * from federated.t2 order by id; +id op op_count +3 inserted 0 +4 inserted 0 +# Prepared delete stmt +PREPARE stmt_delete FROM +'delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id where t2.id = 3'; +EXECUTE stmt_delete; +DEALLOCATE PREPARE stmt_delete; +select * from federated.t2 order by id; +id op op_count +4 inserted 0 +drop table federated.t1, federated.t2; +connection slave; +drop table federated.t1, federated.t2; connection default; set global federated_pushdown=0; connection master; @@ -1358,3 +1581,4 @@ DROP DATABASE IF EXISTS federated; connection slave; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; +# End of 11.4 tests diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index 5c60c27014e..3c18c3704a7 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -895,9 +895,133 @@ connection slave; DROP TABLES federated.t1, federated.t2, federated.t11, federated.t12, federated.t13, federated.t14; +--echo # +--echo # MDEV-37484: `Sql_cmd_dml::execute_inner`, `Sql_cmd_update::execute_inner` do not call Select handler for the engine involved +--echo # + connection default; +set global federated_pushdown=1; +connection slave; +create table federated.product_tag (product_id bigint); +CREATE TABLE federated.product ( + `product_id` bigint(20) DEFAULT NULL, + `price` bigint(20) DEFAULT NULL, + `short_description` varchar(7998) DEFAULT NULL, + `brand` varchar(254) DEFAULT NULL, + `modified_dtm` datetime DEFAULT NULL, + `created_dtm` datetime DEFAULT NULL, + `modified_by` int(11) DEFAULT NULL +) CHARSET=latin1; + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +create table federated.product_tag (product_id bigint) +ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/product_tag'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.product ( + `product_id` bigint(20) DEFAULT NULL, + `price` bigint(20) DEFAULT NULL, + `short_description` varchar(7998) DEFAULT NULL, + `brand` varchar(254) DEFAULT NULL, + `modified_dtm` datetime DEFAULT NULL, + `created_dtm` datetime DEFAULT NULL, + `modified_by` int(11) DEFAULT NULL +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/product'; + +insert into federated.product_tag values (1),(2),(3),(4); +insert into federated.product values (1,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +insert into federated.product values (3,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +select * from federated.product order by product_id; + +let $query= +update + federated.product p join + (select product_id from federated.product_tag limit 1000) t using (product_id) + set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', + short_description=concat(short_description,modified_by); + +eval explain format=json $query; +eval $query; + +select * from federated.product order by product_id; + +drop table federated.product_tag; +drop table federated.product; + +connection slave; +drop table federated.product_tag; +drop table federated.product; + +--echo # Setup +create or replace table federated.t1 (id int); +create or replace table federated.t2 (id int, op varchar(10), op_count int DEFAULT 0) CHARSET=latin1; + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +create or replace table federated.t1 (id int) +ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +create or replace table federated.t2 (id int, op varchar(10), op_count int DEFAULT 0) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2'; + +insert into federated.t1 values (1),(2),(3),(4); +insert into federated.t2 (id, op) values (1, 'inserted'), (2, 'inserted'), (3, 'inserted'), (4, 'inserted'); +select * from federated.t2 order by id; + +--echo # Update tests +let $query= + update federated.t2 inner join federated.t1 on t2.id = t1.id + set t2.op = 'updated', t2.op_count = t2.op_count + 1 + where t2.id in (1, 2); + +eval explain format=json $query; +eval $query; + +select * from federated.t2 order by id; + +--echo # Prepared update stmt +PREPARE stmt_update FROM +'update federated.t2 inner join federated.t1 on t2.id = t1.id set t2.op_count = t2.op_count + 1, t2.op="updated" where t2.id in (1, 2)'; +EXECUTE stmt_update; +DEALLOCATE PREPARE stmt_update; + +select * from federated.t2 order by id; + +--echo # Delete tests +explain format=json + delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id and t2.op = 'updated'; + +delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id and t2.op = 'updated'; +select * from federated.t2 order by id; + +--echo # Prepared delete stmt +PREPARE stmt_delete FROM +'delete federated.t2 from federated.t2 inner join federated.t1 on t2.id = t1.id where t2.id = 3'; +EXECUTE stmt_delete; +DEALLOCATE PREPARE stmt_delete; + +select * from federated.t2 order by id; + +drop table federated.t1, federated.t2; + +connection slave; +drop table federated.t1, federated.t2; + +# cleanup +connection default; set global federated_pushdown=0; - source include/federated_cleanup.inc; +--echo # End of 11.4 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e7c163d335e..c6d6916e0a0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1622,6 +1622,13 @@ bool Sql_cmd_delete::precheck(THD *thd) { if (multi_delete_precheck(thd, lex->query_tables)) return true; + + SELECT_LEX *select_lex= lex->first_select_lex(); + /* 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))) + return true; } #ifdef WITH_WSREP diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6c480401e7f..c97241d2b75 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5218,15 +5218,9 @@ select_handler *find_select_handler_inner(THD *thd, SELECT_LEX *select_lex, SELECT_LEX_UNIT *select_lex_unit) { - if (select_lex->master_unit()->outer_select() || - (select_lex_unit && select_lex->master_unit()->with_clause)) - { - /* - Pushdown is not supported neither for non-top-level SELECTs nor for parts - of SELECT_LEX_UNITs that have CTEs (SELECT_LEX_UNIT::with_clause) - */ + // Pushdown is not supported for non-top-level SELECTs + if (select_lex->master_unit()->outer_select()) return 0; - } TABLE_LIST *tbl= nullptr; // For SQLCOM_INSERT_SELECT the server takes TABLE_LIST @@ -34603,6 +34597,9 @@ bool Sql_cmd_dml::execute_inner(THD *thd) SELECT_LEX *select_lex= unit->first_select(); JOIN *join= select_lex->join; + // look for select_handler provided by engines + select_lex->pushdown_select= find_single_select_handler(thd, select_lex); + if (join->optimize()) goto err; diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc index 0b3c45d2b2c..fd445bebb25 100644 --- a/storage/federatedx/federatedx_pushdown.cc +++ b/storage/federatedx/federatedx_pushdown.cc @@ -239,6 +239,9 @@ create_federatedx_select_handler(THD *thd, SELECT_LEX *sel_lex, if (!use_pushdown || !is_supported_by_select_handler(thd->lex->sql_command)) return nullptr; + if (lex_unit && sel_lex->master_unit()->with_clause) + return nullptr; + auto tbl= get_fed_table_for_pushdown(sel_lex); if (!tbl) return nullptr; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_37484.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_37484.result new file mode 100644 index 00000000000..65f0f83c1de --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_37484.result @@ -0,0 +1,118 @@ +# +# MDEV-37484: `Sql_cmd_dml::execute_inner`, `Sql_cmd_update::execute_inner` do not call Select handler for the engine involved +# +for master_1 +for child2 +for child3 +set spider_same_server_link=1; +CREATE SERVER s FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test', user 'root'); +create table product_tag(product_id bigint); +create table product ( +`product_id` bigint(20) DEFAULT NULL, +`price` bigint(20) DEFAULT NULL, +`short_description` varchar(7998) DEFAULT NULL, +`brand` varchar(254) DEFAULT NULL, +`modified_dtm` datetime DEFAULT NULL, +`created_dtm` datetime DEFAULT NULL, +`modified_by` int(11) DEFAULT NULL +); +insert into product_tag values (1),(2),(3),(4); +insert into product values (1,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +insert into product values (3,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +create table product_tag_spider (product_id bigint) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=product_tag; +create table product_spider ( +`product_id` bigint(20) DEFAULT NULL, +`price` bigint(20) DEFAULT NULL, +`short_description` varchar(7998) DEFAULT NULL, +`brand` varchar(254) DEFAULT NULL, +`modified_dtm` datetime DEFAULT NULL, +`created_dtm` datetime DEFAULT NULL, +`modified_by` int(11) DEFAULT NULL +) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=product; +select * from product_spider order by product_id; +product_id price short_description brand modified_dtm created_dtm modified_by +1 22 fes rets 2011-12-12 12:12:12 2011-12-13 01:01:10 343 +3 22 fes rets 2011-12-12 12:12:12 2011-12-13 01:01:10 343 +explain update +product_spider p join +(select product_id from product_tag_spider limit 1000) t using (product_id) +set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', +short_description=concat(short_description,modified_by); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY p ALL NULL NULL NULL NULL 2 Using where with pushed condition +1 PRIMARY ref key0 key0 9 test.p.product_id 1 +2 DERIVED product_tag_spider ALL NULL NULL NULL NULL 4 +update +product_spider p join +(select product_id from product_tag_spider limit 1000) t using (product_id) +set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', +short_description=concat(short_description,modified_by); +select * from product_spider order by product_id; +product_id price short_description brand modified_dtm created_dtm modified_by +1 555 fes343 1 2011-12-15 15:15:30 2011-12-13 01:01:10 343 +3 555 fes343 3 2011-12-15 15:15:30 2011-12-13 01:01:10 343 +drop table product, product_tag, product_spider, product_tag_spider; +create table t1 (id int); +create table t2 (id int, op varchar(10), op_count int DEFAULT 0); +insert into t1 values (1),(2),(3),(4); +insert into t2 (id, op) values (1, 'inserted'), (2, 'inserted'), (3, 'inserted'), (4, 'inserted'); +CREATE TABLE t1_SPIDER (id int) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=t1; +CREATE TABLE t2_SPIDER (id int, op varchar(10), op_count int DEFAULT 0) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=t2; +select * from t2_SPIDER order by id; +id op op_count +1 inserted 0 +2 inserted 0 +3 inserted 0 +4 inserted 0 +# Update tests +explain update t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id +set t2_SPIDER.op = 'updated', t2_SPIDER.op_count = t2_SPIDER.op_count + 1 +where t2_SPIDER.id in (1, 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2_SPIDER ALL NULL NULL NULL NULL 4 Using where with pushed condition +1 SIMPLE t1_SPIDER ALL NULL NULL NULL NULL 4 Using where +update t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id +set t2_SPIDER.op = 'updated', t2_SPIDER.op_count = t2_SPIDER.op_count + 1 +where t2_SPIDER.id in (1, 2); +select * from t2_SPIDER order by id; +id op op_count +1 updated 1 +2 updated 1 +3 inserted 0 +4 inserted 0 +PREPARE stmt_update FROM +'update t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id set t2_SPIDER.op_count = t2_SPIDER.op_count + 1, t2_SPIDER.op="updated" where t2_SPIDER.id in (1, 2)'; +EXECUTE stmt_update; +DEALLOCATE PREPARE stmt_update; +select * from t2_SPIDER order by id; +id op op_count +1 updated 2 +2 updated 2 +3 inserted 0 +4 inserted 0 +# Delete tests +explain +delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id and t2_SPIDER.op = 'updated'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2_SPIDER ALL NULL NULL NULL NULL 4 Using where with pushed condition +1 SIMPLE t1_SPIDER ALL NULL NULL NULL NULL 4 Using where +delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id and t2_SPIDER.op = 'updated'; +select * from t2_SPIDER order by id; +id op op_count +3 inserted 0 +4 inserted 0 +PREPARE stmt_delete FROM +'delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id where t2_SPIDER.id = 3'; +EXECUTE stmt_delete; +DEALLOCATE PREPARE stmt_delete; +select * from t2_SPIDER order by id; +id op op_count +4 inserted 0 +drop table t1, t2, t1_SPIDER, t2_SPIDER; +drop server s; +for master_1 +for child2 +for child3 +# +# end of test MDEV-37484 +# diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_37484.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_37484.test new file mode 100644 index 00000000000..24ad142557b --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_37484.test @@ -0,0 +1,110 @@ +--echo # +--echo # MDEV-37484: `Sql_cmd_dml::execute_inner`, `Sql_cmd_update::execute_inner` do not call Select handler for the engine involved +--echo # + +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log +set spider_same_server_link=1; + +evalp CREATE SERVER s FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test', user 'root'); + +create table product_tag(product_id bigint); +create table product ( + `product_id` bigint(20) DEFAULT NULL, + `price` bigint(20) DEFAULT NULL, + `short_description` varchar(7998) DEFAULT NULL, + `brand` varchar(254) DEFAULT NULL, + `modified_dtm` datetime DEFAULT NULL, + `created_dtm` datetime DEFAULT NULL, + `modified_by` int(11) DEFAULT NULL +); + +insert into product_tag values (1),(2),(3),(4); +insert into product values (1,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); +insert into product values (3,22,'fes','rets','2011-12-12 12:12:12','2011-12-13 1:1:10',343); + +create table product_tag_spider (product_id bigint) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=product_tag; +create table product_spider ( + `product_id` bigint(20) DEFAULT NULL, + `price` bigint(20) DEFAULT NULL, + `short_description` varchar(7998) DEFAULT NULL, + `brand` varchar(254) DEFAULT NULL, + `modified_dtm` datetime DEFAULT NULL, + `created_dtm` datetime DEFAULT NULL, + `modified_by` int(11) DEFAULT NULL +) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=product; + +select * from product_spider order by product_id; + +let $query= +update + product_spider p join + (select product_id from product_tag_spider limit 1000) t using (product_id) + set brand=p.product_id, price=555, modified_dtm='2011-12-15 15:15:30', + short_description=concat(short_description,modified_by); + +eval explain $query; +eval $query; + +select * from product_spider order by product_id; + +drop table product, product_tag, product_spider, product_tag_spider; + +create table t1 (id int); +create table t2 (id int, op varchar(10), op_count int DEFAULT 0); + +insert into t1 values (1),(2),(3),(4); +insert into t2 (id, op) values (1, 'inserted'), (2, 'inserted'), (3, 'inserted'), (4, 'inserted'); + +CREATE TABLE t1_SPIDER (id int) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=t1; +CREATE TABLE t2_SPIDER (id int, op varchar(10), op_count int DEFAULT 0) ENGINE=SPIDER REMOTE_SERVER=s REMOTE_TABLE=t2; + +select * from t2_SPIDER order by id; + +--echo # Update tests +let $query= + update t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id + set t2_SPIDER.op = 'updated', t2_SPIDER.op_count = t2_SPIDER.op_count + 1 + where t2_SPIDER.id in (1, 2); + +eval explain $query; +eval $query; + +select * from t2_SPIDER order by id; + +PREPARE stmt_update FROM +'update t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id set t2_SPIDER.op_count = t2_SPIDER.op_count + 1, t2_SPIDER.op="updated" where t2_SPIDER.id in (1, 2)'; +EXECUTE stmt_update; +DEALLOCATE PREPARE stmt_update; + +select * from t2_SPIDER order by id; + +--echo # Delete tests +explain + delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id and t2_SPIDER.op = 'updated'; + +delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id and t2_SPIDER.op = 'updated'; +select * from t2_SPIDER order by id; + +PREPARE stmt_delete FROM +'delete t2_SPIDER from t2_SPIDER inner join t1_SPIDER on t2_SPIDER.id = t1_SPIDER.id where t2_SPIDER.id = 3'; +EXECUTE stmt_delete; +DEALLOCATE PREPARE stmt_delete; + +select * from t2_SPIDER order by id; + +drop table t1, t2, t1_SPIDER, t2_SPIDER; +drop server s; + +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log + +--echo # +--echo # end of test MDEV-37484 +--echo #