diff options
-rw-r--r-- | mysql-test/suite/federated/federatedx_create_handlers.result | 23 | ||||
-rw-r--r-- | mysql-test/suite/federated/federatedx_create_handlers.test | 22 | ||||
-rw-r--r-- | storage/federatedx/federatedx_pushdown.cc | 68 | ||||
-rw-r--r-- | storage/federatedx/ha_federatedx.cc | 6 |
4 files changed, 116 insertions, 3 deletions
diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index b115cc73b87..de1f42f0c9c 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -420,6 +420,29 @@ SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt; SELECT COUNT(DISTINCT a) FROM federated.t2; COUNT(DISTINCT a) 70000 +# +# MDEV-29640 FederatedX does not properly handle pushdown +# in case of difference in local and remote table names +# +connection master; +# Use tables from the previous test. Make sure pushdown works: +EXPLAIN SELECT COUNT(DISTINCT a) FROM federated.t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +SELECT COUNT(DISTINCT a) FROM federated.t2; +COUNT(DISTINCT a) +70000 +# Link remote table `federated.t1` with the local table named `t1_local` +CREATE TABLE t1_local ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +# No pushdown here due to table names mismatch, retrieve data as usual: +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1_local; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1_local ALL NULL NULL NULL NULL 70000 +SELECT COUNT(DISTINCT a) FROM t1_local; +COUNT(DISTINCT a) +70000 +DROP TABLE t1_local; set global federated_pushdown=0; connection master; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index 8863a057b47..ea2bc2f74f2 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -266,6 +266,28 @@ INSERT INTO federated.t2 SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt; SELECT COUNT(DISTINCT a) FROM federated.t2; + +--echo # +--echo # MDEV-29640 FederatedX does not properly handle pushdown +--echo # in case of difference in local and remote table names +--echo # +connection master; +--echo # Use tables from the previous test. Make sure pushdown works: +EXPLAIN SELECT COUNT(DISTINCT a) FROM federated.t2; +SELECT COUNT(DISTINCT a) FROM federated.t2; + +--echo # Link remote table `federated.t1` with the local table named `t1_local` +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE t1_local ENGINE="FEDERATED" +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +--echo # No pushdown here due to table names mismatch, retrieve data as usual: +EXPLAIN SELECT COUNT(DISTINCT a) FROM t1_local; +SELECT COUNT(DISTINCT a) FROM t1_local; + +DROP TABLE t1_local; + set global federated_pushdown=0; source include/federated_cleanup.inc; diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc index 15b0b0d3d4e..c26fbffa4c1 100644 --- a/storage/federatedx/federatedx_pushdown.cc +++ b/storage/federatedx/federatedx_pushdown.cc @@ -35,6 +35,68 @@ */ +/* + Check if table and database names are equal on local and remote servers + + SYNOPSIS + local_and_remote_names_match() + thd Thread descriptor + tbl_share Pointer to current table TABLE_SHARE structure + + DESCRIPTION + FederatedX table on the local server may refer to a table having another + name on the remote server. The remote table may even reside in a different + database. For example: + + -- Remote server + CREATE TABLE t1 (id int(32)); + + -- Local server + CREATE TABLE t2 ENGINE="FEDERATEDX" + CONNECTION="mysql://joe:joespass@192.168.1.111:9308/federatedx/t1"; + + It's not a problem while the federated_pushdown is disabled 'cause + the CONNECTION strings are being parsed for every table during + the execution, so the table names are translated from local to remote. + But in case of the federated_pushdown the whole query is pushed down + to the engine without any translation, so the remote server may try + to select data from a nonexistent table (for example, query + "SELECT * FROM t2" will try to retrieve data from nonexistent "t2"). + + This function checks whether there is a mismatch between local and remote + table/database names + + RETURN VALUE + false names are equal + true names are not equal + +*/ +bool local_and_remote_names_mismatch(THD *thd, const TABLE_SHARE *tbl_share) +{ + FEDERATEDX_SHARE tmp_share; + bzero(&tmp_share, sizeof(tmp_share)); + if (parse_url(thd->mem_root, &tmp_share, tbl_share, 0)) + return true; + + if (lower_case_table_names) + { + if (strcasecmp(tmp_share.database, tbl_share->db.str) != 0) + return true; + } + else + { + if (strncmp(tmp_share.database, tbl_share->db.str, tbl_share->db.length) != + 0) + return true; + } + + return my_strnncoll(system_charset_info, (uchar *) tmp_share.table_name, + strlen(tmp_share.table_name), + (uchar *) tbl_share->table_name.str, + tbl_share->table_name.length) != 0; +} + + static derived_handler* create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived) { @@ -58,6 +120,9 @@ create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived) ht= tbl->table->file->partition_ht(); else if (ht != tbl->table->file->partition_ht()) return 0; + if (ht == federatedx_hton && + local_and_remote_names_mismatch(thd, tbl->table->s)) + return 0; } } @@ -180,6 +245,9 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel) ht= tbl->table->file->partition_ht(); else if (ht != tbl->table->file->partition_ht()) return 0; + if (ht == federatedx_hton && + local_and_remote_names_mismatch(thd, tbl->table->s)) + return 0; } /* diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index 085422e6016..2eda3786d9d 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -528,7 +528,7 @@ err: } -static int parse_url_error(FEDERATEDX_SHARE *share, TABLE_SHARE *table_s, +static int parse_url_error(FEDERATEDX_SHARE *share, const TABLE_SHARE *table_s, int error_num) { char buf[FEDERATEDX_QUERY_BUFFER_SIZE]; @@ -609,7 +609,7 @@ error: parse_url() mem_root MEM_ROOT pointer for memory allocation share pointer to FEDERATEDX share - table pointer to current TABLE class + table_s pointer to current TABLE_SHARE class table_create_flag determines what error to throw DESCRIPTION @@ -658,7 +658,7 @@ error: */ static int parse_url(MEM_ROOT *mem_root, FEDERATEDX_SHARE *share, - TABLE_SHARE *table_s, uint table_create_flag) + const TABLE_SHARE *table_s, uint table_create_flag) { uint error_num= (table_create_flag ? ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE : |