summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2020-03-26 15:01:44 +0300
committerSergei Petrunia <psergey@askmonty.org>2020-03-26 15:01:44 +0300
commitaf4b2ae8588bd51cc17e66cfc8210c3225992fbe (patch)
tree3e05f500883c00f15f111bcfa7c96c4f2cf0d300
parent1c8de231a3ea7ef2e08b1a5cfe17c37d733ea6ce (diff)
downloadmariadb-git-af4b2ae8588bd51cc17e66cfc8210c3225992fbe.tar.gz
MDEV-21887: federatedx crashes on SELECT ... INTO query in select_handler code
Backport to 10.4: - Don't try to push down SELECTs that have a side effect - In case the storage engine did support pushdown of SELECT with an INTO clause, write the rows we've got from it into select->join->result, and not thd->protocol. This way, SELECT ... INTO ... FROM smart_engine_table will put the result into where instructed, and NOT send it to the client.
-rw-r--r--mysql-test/suite/federated/federatedx_create_handlers.result22
-rw-r--r--mysql-test/suite/federated/federatedx_create_handlers.test21
-rw-r--r--sql/select_handler.cc25
-rw-r--r--storage/federatedx/federatedx_pushdown.cc13
4 files changed, 57 insertions, 24 deletions
diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result
index 473972c2cd4..65a9d52803f 100644
--- a/mysql-test/suite/federated/federatedx_create_handlers.result
+++ b/mysql-test/suite/federated/federatedx_create_handlers.result
@@ -299,7 +299,27 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 7
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL
-DROP TABLE federated.t1, federated.t2, federated.t3;
+#
+# MDEV-21887: federatedx crashes on SELECT ... INTO query in select_handler code
+#
+CREATE TABLE federated.t4 (
+id int(20) NOT NULL,
+name varchar(16) NOT NULL default ''
+) engine=myisam;
+insert into federated.t4 select * from federated.t1;
+select * from federated.t4;
+id name
+1 zzz
+3 xxx
+4 xxx
+5 yyy
+7 yyy
+select name into @var from federated.t1 where id=3 limit 1 ;
+select @var;
+@var
+xxx
+select name into outfile 'tmp.txt' from federated.t1;
+DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4;
connection slave;
DROP TABLE federated.t1, federated.t2;
connection default;
diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test
index 373b2aaaa33..42a03e60d67 100644
--- a/mysql-test/suite/federated/federatedx_create_handlers.test
+++ b/mysql-test/suite/federated/federatedx_create_handlers.test
@@ -147,8 +147,27 @@ FROM federated.t3,
SELECT * FROM federated.t1 WHERE id >= 5) t
WHERE federated.t3.name=t.name;
+--echo #
+--echo # MDEV-21887: federatedx crashes on SELECT ... INTO query in select_handler code
+--echo #
-DROP TABLE federated.t1, federated.t2, federated.t3;
+CREATE TABLE federated.t4 (
+ id int(20) NOT NULL,
+ name varchar(16) NOT NULL default ''
+) engine=myisam;
+insert into federated.t4 select * from federated.t1;
+
+--sorted_result
+select * from federated.t4;
+
+select name into @var from federated.t1 where id=3 limit 1 ;
+select @var;
+select name into outfile 'tmp.txt' from federated.t1;
+
+let $path=`select concat(@@datadir, 'test/tmp.txt')`;
+remove_file $path;
+
+DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4;
connection slave;
DROP TABLE federated.t1, federated.t2;
diff --git a/sql/select_handler.cc b/sql/select_handler.cc
index b364cb12341..495b6d957b1 100644
--- a/sql/select_handler.cc
+++ b/sql/select_handler.cc
@@ -77,18 +77,17 @@ bool Pushdown_select::init()
bool Pushdown_select::send_result_set_metadata()
{
- THD *thd= handler->thd;
- Protocol *protocol= thd->protocol;
DBUG_ENTER("Pushdown_select::send_result_set_metadata");
#ifdef WITH_WSREP
+ THD *thd= handler->thd;
if (WSREP(thd) && thd->wsrep_retry_query)
{
WSREP_DEBUG("skipping select metadata");
DBUG_RETURN(false);
}
#endif /* WITH_WSREP */
- if (protocol->send_result_set_metadata(&result_columns,
+ if (select->join->result->send_result_set_metadata(result_columns,
Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
DBUG_RETURN(true);
@@ -100,23 +99,13 @@ bool Pushdown_select::send_result_set_metadata()
bool Pushdown_select::send_data()
{
THD *thd= handler->thd;
- Protocol *protocol= thd->protocol;
DBUG_ENTER("Pushdown_select::send_data");
if (thd->killed == ABORT_QUERY)
DBUG_RETURN(false);
- protocol->prepare_for_resend();
- if (protocol->send_result_set_row(&result_columns))
- {
- protocol->remove_last_row();
+ if (select->join->result->send_data(result_columns))
DBUG_RETURN(true);
- }
-
- thd->inc_sent_row_count(1);
-
- if (thd->vio_ok())
- DBUG_RETURN(protocol->write());
DBUG_RETURN(false);
}
@@ -124,16 +113,10 @@ bool Pushdown_select::send_data()
bool Pushdown_select::send_eof()
{
- THD *thd= handler->thd;
DBUG_ENTER("Pushdown_select::send_eof");
- /*
- Don't send EOF if we're in error condition (which implies we've already
- sent or are sending an error)
- */
- if (thd->is_error())
+ if (select->join->result->send_eof())
DBUG_RETURN(true);
- ::my_eof(thd);
DBUG_RETURN(false);
}
diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc
index 2bcee943308..15b0b0d3d4e 100644
--- a/storage/federatedx/federatedx_pushdown.cc
+++ b/storage/federatedx/federatedx_pushdown.cc
@@ -182,6 +182,16 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel)
return 0;
}
+ /*
+ Currently, ha_federatedx_select_handler::init_scan just takes the
+ thd->query and sends it to the backend.
+ This obviously won't work if the SELECT uses an "INTO @var" or
+ "INTO OUTFILE". It is also unlikely to work if the select has some
+ other kind of side effect.
+ */
+ if (sel->uncacheable & UNCACHEABLE_SIDEEFFECT)
+ return NULL;
+
handler= new ha_federatedx_select_handler(thd, sel);
return handler;
@@ -286,8 +296,9 @@ int ha_federatedx_select_handler::end_scan()
DBUG_RETURN(0);
}
-void ha_federatedx_select_handler::print_error(int, unsigned long)
+void ha_federatedx_select_handler::print_error(int error, myf error_flag)
{
+ select_handler::print_error(error, error_flag);
}