From 6af4a253c4a9d81ffc821a5418419d60ebddb761 Mon Sep 17 00:00:00 2001 From: Arcadiy Ivanov Date: Wed, 12 Aug 2026 19:46:33 -0400 Subject: [PATCH] MDEV-40739 Server crashes in `spider_db_open_item_field` `spider_db_open_item_field()` looks a field's table up among the Spider tables of the query whenever the field does not belong to an internal temporary table: if (field->table->s->tmp_table != INTERNAL_TMP_TABLE) That is a hand-rolled copy of the server's own `TABLE_SHARE::is_optimizer_tmp_table()` predicate. Temporary tables created by `Create_tmp_table` are marked `RESULT_TMP_TABLE` rather than `INTERNAL_TMP_TABLE`, so a field of such a table passes the test, `spider_fields::find_table()` finds no holder for it, and the returned `NULL` is dereferenced. Only the second pass crashes. The first pass, which decides whether the group by handler can be created at all, does guard against a `NULL` holder. The two passes do not resolve to the same items, though: an `Item_direct_ref` is followed through `real_item()`, and between optimization and execution it is re-pointed at a field of the optimizer's result temporary table. Ask the server's accessor instead of restating it, so that the predicate keeps following the server's definition of an optimizer temporary table. --- .../bugfix/r/gbh_row_in_subquery.result | 27 ++++++++++++++++ .../spider/bugfix/t/gbh_row_in_subquery.test | 32 +++++++++++++++++++ storage/spider/spd_db_conn.cc | 9 +++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/gbh_row_in_subquery.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/gbh_row_in_subquery.test diff --git a/storage/spider/mysql-test/spider/bugfix/r/gbh_row_in_subquery.result b/storage/spider/mysql-test/spider/bugfix/r/gbh_row_in_subquery.result new file mode 100644 index 0000000000000..16dd2e2dfe411 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/gbh_row_in_subquery.result @@ -0,0 +1,27 @@ +# +# Row comparison IN subquery on a Spider table handled by the +# group by handler +# +for master_1 +for child2 +for child3 +set spider_same_server_link= 1; +CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test', USER 'root'); +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t1_s (a INT, b INT) ENGINE=SPIDER +WRAPPER=mariadb REMOTE_SERVER=srv REMOTE_TABLE=t1; +SELECT 1 WHERE (1,1) IN (SELECT a, b FROM t1_s); +1 +1 +SELECT 1 WHERE (2,2) IN (SELECT a, b FROM t1_s); +1 +1 +SELECT 1 WHERE (1,2) IN (SELECT a, b FROM t1_s); +1 +DROP TABLE t1_s, t1; +DROP SERVER srv; +for master_1 +for child2 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/t/gbh_row_in_subquery.test b/storage/spider/mysql-test/spider/bugfix/t/gbh_row_in_subquery.test new file mode 100644 index 0000000000000..d46f3dc7c394d --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/gbh_row_in_subquery.test @@ -0,0 +1,32 @@ +--echo # +--echo # Row comparison IN subquery on a Spider table handled by the +--echo # group by handler +--echo # + +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +set spider_same_server_link= 1; +evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test', USER 'root'); + +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t1_s (a INT, b INT) ENGINE=SPIDER + WRAPPER=mariadb REMOTE_SERVER=srv REMOTE_TABLE=t1; + +SELECT 1 WHERE (1,1) IN (SELECT a, b FROM t1_s); +SELECT 1 WHERE (2,2) IN (SELECT a, b FROM t1_s); +SELECT 1 WHERE (1,2) IN (SELECT a, b FROM t1_s); + +DROP TABLE t1_s, t1; +DROP SERVER srv; + +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index ea3d2978cf0ca..6d2dbdf22076a 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -7260,7 +7260,14 @@ int spider_db_open_item_field( DBUG_RETURN(0); } else { DBUG_PRINT("info",("spider tmp_table=%u", field->table->s->tmp_table)); - if (field->table->s->tmp_table != INTERNAL_TMP_TABLE) + /* + A field of a temporary table created by the optimizer, or of one + standing in for a normal table, belongs to no remote table, so it + is printed as a plain identifier below rather than looked up among + the spider tables. + */ + if (field->table->s->tmp_table != INTERNAL_TMP_TABLE && + !field->table->s->is_optimizer_tmp_table()) { if (!use_fields) {