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;
|
SELECT COUNT(DISTINCT a) FROM federated.t2;
|
||||||
COUNT(DISTINCT a)
|
COUNT(DISTINCT a)
|
||||||
70000
|
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;
|
set global federated_pushdown=0;
|
||||||
connection master;
|
connection master;
|
||||||
DROP TABLE IF EXISTS federated.t1;
|
DROP TABLE IF EXISTS federated.t1;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
--source have_federatedx.inc
|
--source have_federatedx.inc
|
||||||
--source include/federated.inc
|
--source include/federated.inc
|
||||||
--source include/no_valgrind_without_big.inc
|
--source include/no_valgrind_without_big.inc
|
||||||
|
--source include/have_partition.inc
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
|
|
||||||
@ -266,6 +267,53 @@ INSERT INTO federated.t2
|
|||||||
SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt;
|
SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt;
|
||||||
SELECT COUNT(DISTINCT a) FROM federated.t2;
|
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;
|
set global federated_pushdown=0;
|
||||||
|
|
||||||
source include/federated_cleanup.inc;
|
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*
|
static derived_handler*
|
||||||
create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
||||||
{
|
{
|
||||||
@ -42,7 +100,6 @@ create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ha_federatedx_derived_handler* handler = NULL;
|
ha_federatedx_derived_handler* handler = NULL;
|
||||||
handlerton *ht= 0;
|
|
||||||
|
|
||||||
SELECT_LEX_UNIT *unit= derived->derived;
|
SELECT_LEX_UNIT *unit= derived->derived;
|
||||||
|
|
||||||
@ -54,9 +111,16 @@ create_federatedx_derived_handler(THD* thd, TABLE_LIST *derived)
|
|||||||
{
|
{
|
||||||
if (!tbl->table)
|
if (!tbl->table)
|
||||||
return 0;
|
return 0;
|
||||||
if (!ht)
|
/*
|
||||||
ht= tbl->table->file->partition_ht();
|
We intentionally don't support partitioned federatedx tables here, so
|
||||||
else if (ht != tbl->table->file->partition_ht())
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,15 +234,22 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ha_federatedx_select_handler* handler = NULL;
|
ha_federatedx_select_handler* handler = NULL;
|
||||||
handlerton *ht= 0;
|
|
||||||
|
|
||||||
for (TABLE_LIST *tbl= thd->lex->query_tables; tbl; tbl= tbl->next_global)
|
for (TABLE_LIST *tbl= thd->lex->query_tables; tbl; tbl= tbl->next_global)
|
||||||
{
|
{
|
||||||
if (!tbl->table)
|
if (!tbl->table)
|
||||||
return 0;
|
return 0;
|
||||||
if (!ht)
|
/*
|
||||||
ht= tbl->table->file->partition_ht();
|
We intentionally don't support partitioned federatedx tables here, so
|
||||||
else if (ht != tbl->table->file->partition_ht())
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,7 +609,7 @@ error:
|
|||||||
parse_url()
|
parse_url()
|
||||||
mem_root MEM_ROOT pointer for memory allocation
|
mem_root MEM_ROOT pointer for memory allocation
|
||||||
share pointer to FEDERATEDX share
|
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
|
table_create_flag determines what error to throw
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
|
@ -463,6 +463,7 @@ public:
|
|||||||
int reset(void);
|
int reset(void);
|
||||||
int free_result(void);
|
int free_result(void);
|
||||||
|
|
||||||
|
const FEDERATEDX_SHARE *get_federatedx_share() const { return share; }
|
||||||
friend class ha_federatedx_derived_handler;
|
friend class ha_federatedx_derived_handler;
|
||||||
friend class ha_federatedx_select_handler;
|
friend class ha_federatedx_select_handler;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user