MDEV-29640 FederatedX does not properly handle pushdown in case of difference in local and remote table names
FederatedX table may refer to a table with a different name on the remote server: test> CREATE TABLE t2 (...) ENGINE="FEDERATEDX" CONNECTION="mysql://user:pass@192.168.1.111:9308/federatedx/t1"; test> select * from t2 where ...; This could cause an issue with federated_pushdown=1, because FederatedX pushes the query (or derived table's) text to the remote server. The remote server will try to read from table t2 (while it should read from t1). Solution: do not allow pushing down queries with tables that have different db_name.table name on the local and remote server. This patch also fixes: MDEV-29863 Server crashes in federatedx_txn::acquire after select from the FederatedX table with partitions Solution: disallow pushdown when partitioned FederatedX tables are used.
This commit is contained in:
parent
58cd0bd59e
commit
5f296f3a18
@ -420,6 +420,55 @@ 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 federated.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 federated.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 federated.t1_local;
|
||||
COUNT(DISTINCT a)
|
||||
70000
|
||||
#
|
||||
# MDEV-29863 Server crashes in federatedx_txn::acquire after select from
|
||||
# the Federated table with partitions and federated_pushdown=1
|
||||
# in case of difference in local and remote table names
|
||||
#
|
||||
connection slave;
|
||||
CREATE TABLE federated.t3 (a INT);
|
||||
INSERT INTO federated.t3 VALUES (1),(2),(3);
|
||||
CREATE TABLE federated.t4 (a INT);
|
||||
connection master;
|
||||
CREATE SERVER fedlink FOREIGN DATA WRAPPER mysql
|
||||
OPTIONS (USER 'root', HOST '127.0.0.1', DATABASE 'federated',
|
||||
PORT SLAVE_PORT);
|
||||
CREATE TABLE federated.t3 (a INT)
|
||||
ENGINE=FEDERATED
|
||||
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3'
|
||||
PARTITION BY list (a)
|
||||
(PARTITION p1 VALUES IN (1) CONNECTION='fedlink/t3',
|
||||
PARTITION p2 VALUES IN (2) CONNECTION='fedlink/t4');
|
||||
EXPLAIN SELECT * FROM federated.t3;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t3 ALL NULL NULL NULL NULL 3
|
||||
SELECT * FROM federated.t3;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
set global federated_pushdown=0;
|
||||
connection master;
|
||||
DROP TABLE IF EXISTS federated.t1;
|
||||
|
@ -1,6 +1,7 @@
|
||||
--source have_federatedx.inc
|
||||
--source include/federated.inc
|
||||
--source include/no_valgrind_without_big.inc
|
||||
--source include/have_partition.inc
|
||||
|
||||
connection default;
|
||||
|
||||
@ -266,6 +267,53 @@ 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 federated.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 federated.t1_local;
|
||||
SELECT COUNT(DISTINCT a) FROM federated.t1_local;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-29863 Server crashes in federatedx_txn::acquire after select from
|
||||
--echo # the Federated table with partitions and federated_pushdown=1
|
||||
--echo # in case of difference in local and remote table names
|
||||
--echo #
|
||||
connection slave;
|
||||
CREATE TABLE federated.t3 (a INT);
|
||||
INSERT INTO federated.t3 VALUES (1),(2),(3);
|
||||
CREATE TABLE federated.t4 (a INT);
|
||||
|
||||
connection master;
|
||||
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||
eval CREATE SERVER fedlink FOREIGN DATA WRAPPER mysql
|
||||
OPTIONS (USER 'root', HOST '127.0.0.1', DATABASE 'federated',
|
||||
PORT $SLAVE_MYPORT);
|
||||
|
||||
CREATE TABLE federated.t3 (a INT)
|
||||
ENGINE=FEDERATED
|
||||
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t3'
|
||||
PARTITION BY list (a)
|
||||
(PARTITION p1 VALUES IN (1) CONNECTION='fedlink/t3',
|
||||
PARTITION p2 VALUES IN (2) CONNECTION='fedlink/t4');
|
||||
|
||||
EXPLAIN SELECT * FROM federated.t3;
|
||||
SELECT * FROM federated.t3;
|
||||
|
||||
set global federated_pushdown=0;
|
||||
|
||||
source include/federated_cleanup.inc;
|
||||
|
@ -35,6 +35,64 @@
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Check if table and database names are equal on local and remote servers
|
||||
|
||||
SYNOPSIS
|
||||
local_and_remote_names_match()
|
||||
tbl_share Pointer to current table TABLE_SHARE structure
|
||||
fshare Pointer to current table FEDERATEDX_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(const TABLE_SHARE *tbl_share,
|
||||
const FEDERATEDX_SHARE *fshare)
|
||||
{
|
||||
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
if (strcasecmp(fshare->database, tbl_share->db.str) != 0)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(fshare->database, tbl_share->db.str, tbl_share->db.length) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return my_strnncoll(system_charset_info, (uchar *) fshare->table_name,
|
||||
strlen(fshare->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)
|
||||
{
|
||||
@ -42,7 +100,6 @@ create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
||||
return 0;
|
||||
|
||||
ha_federatedx_derived_handler* handler = NULL;
|
||||
handlerton *ht= 0;
|
||||
|
||||
SELECT_LEX_UNIT *unit= derived->derived;
|
||||
|
||||
@ -54,9 +111,16 @@ create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
||||
{
|
||||
if (!tbl->table)
|
||||
return 0;
|
||||
if (!ht)
|
||||
ht= tbl->table->file->partition_ht();
|
||||
else if (ht != tbl->table->file->partition_ht())
|
||||
/*
|
||||
We intentionally don't support partitioned federatedx tables here, so
|
||||
use file->ht and not file->partition_ht().
|
||||
*/
|
||||
if (tbl->table->file->ht != federatedx_hton)
|
||||
return 0;
|
||||
|
||||
const FEDERATEDX_SHARE *fshare=
|
||||
((ha_federatedx*)tbl->table->file)->get_federatedx_share();
|
||||
if (local_and_remote_names_mismatch(tbl->table->s, fshare))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -170,15 +234,22 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel)
|
||||
return 0;
|
||||
|
||||
ha_federatedx_select_handler* handler = NULL;
|
||||
handlerton *ht= 0;
|
||||
|
||||
for (TABLE_LIST *tbl= thd->lex->query_tables; tbl; tbl= tbl->next_global)
|
||||
{
|
||||
if (!tbl->table)
|
||||
return 0;
|
||||
if (!ht)
|
||||
ht= tbl->table->file->partition_ht();
|
||||
else if (ht != tbl->table->file->partition_ht())
|
||||
/*
|
||||
We intentionally don't support partitioned federatedx tables here, so
|
||||
use file->ht and not file->partition_ht().
|
||||
*/
|
||||
if (tbl->table->file->ht != federatedx_hton)
|
||||
return 0;
|
||||
|
||||
const FEDERATEDX_SHARE *fshare=
|
||||
((ha_federatedx*)tbl->table->file)->get_federatedx_share();
|
||||
|
||||
if (local_and_remote_names_mismatch(tbl->table->s, fshare))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -463,6 +463,7 @@ public:
|
||||
int reset(void);
|
||||
int free_result(void);
|
||||
|
||||
const FEDERATEDX_SHARE *get_federatedx_share() const { return share; }
|
||||
friend class ha_federatedx_derived_handler;
|
||||
friend class ha_federatedx_select_handler;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user