summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleg Smirnov <olernov@gmail.com>2022-10-23 20:48:43 +0700
committerOleg Smirnov <olernov@gmail.com>2022-10-24 12:14:33 +0700
commite78a948b9b27d9e6a8d1967cc12ff1be8396bfb8 (patch)
tree47b34657cf290f5e35f07b2c8d5beb4ed2f268fe
parent291872ec82fc2a19aedf8dcf13838ecd34101caa (diff)
downloadmariadb-git-bb-10.4-MDEV-29640.tar.gz
MDEV-29640 FederatedX does not properly handle pushdown in case of difference in local and remote table namesbb-10.4-MDEV-29640
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"). Solution: do not allow pushing down queries with tables having different names on local and remote names.
-rw-r--r--mysql-test/suite/federated/federatedx_create_handlers.result23
-rw-r--r--mysql-test/suite/federated/federatedx_create_handlers.test22
-rw-r--r--storage/federatedx/federatedx_pushdown.cc68
-rw-r--r--storage/federatedx/ha_federatedx.cc6
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 :