mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-32401 expression cache lead to crash if table of wrong type created and the cache switched off
1) take into account TMP_TABLE_ALL_COLUMNS when we are modifying agg_item->result_field 2) remove unused now "bool materialized_subquery;" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Oleksandr "Sanja" Byelkin
parent
e03abdfec3
commit
155a970264
@@ -3888,6 +3888,77 @@ pk b
|
||||
29 3
|
||||
drop view v1;
|
||||
drop table t1,t2,t3,t4;
|
||||
#
|
||||
# MDEV-32401 expression cache lead to crash if table of wrong type
|
||||
# created and the cache switched off
|
||||
#
|
||||
CREATE TABLE t0 (c TEXT);
|
||||
INSERT INTO t0 VALUES (71), (-79);
|
||||
SELECT t1.d FROM (SELECT c AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
d
|
||||
71
|
||||
-79
|
||||
71
|
||||
-79
|
||||
EXPLAIN EXTENDED SELECT t1.d FROM (SELECT c AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 100.00 Using where
|
||||
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
|
||||
3 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'd' of SELECT #4 was resolved in SELECT #1
|
||||
Note 1981 Aggregate function 'bit_or()' of SELECT #4 belongs to SELECT #3
|
||||
Note 1276 Field or reference 'd' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1003 /* select#1 */ select `test`.`t0`.`c` AS `d` from `test`.`t0` join `test`.`t0` where <expr_cache><`test`.`t0`.`c`>((/* select#3 */ select ord(<expr_cache><`test`.`t0`.`c`,bit_or(`test`.`t0`.`c`),bit_or(`test`.`t0`.`c`)>((/* select#4 */ select bit_or(`test`.`t0`.`c`)))) from `test`.`t0` group by `test`.`t0`.`c`))
|
||||
SELECT t1.d FROM (SELECT CAST(c as int) AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
d
|
||||
71
|
||||
-79
|
||||
71
|
||||
-79
|
||||
EXPLAIN EXTENDED SELECT t1.d FROM (SELECT CAST(c as int) AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 100.00 Using where
|
||||
1 PRIMARY t0 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
|
||||
3 DEPENDENT SUBQUERY t0 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'd' of SELECT #4 was resolved in SELECT #1
|
||||
Note 1981 Aggregate function 'bit_or()' of SELECT #4 belongs to SELECT #3
|
||||
Note 1276 Field or reference 'd' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1003 /* select#1 */ select cast(`test`.`t0`.`c` as signed) AS `d` from `test`.`t0` join `test`.`t0` where <expr_cache><cast(`test`.`t0`.`c` as signed)>((/* select#3 */ select ord(<expr_cache><cast(`test`.`t0`.`c` as signed),bit_or(cast(`test`.`t0`.`c` as signed)),bit_or(cast(`test`.`t0`.`c` as signed))>((/* select#4 */ select bit_or(cast(`test`.`t0`.`c` as signed))))) from `test`.`t0` group by cast(`test`.`t0`.`c` as signed)))
|
||||
CREATE TABLE t1 (c INT);
|
||||
INSERT INTO t1 VALUES (71), (-79);
|
||||
SELECT t2.d FROM (SELECT c AS d FROM t1) AS t2 JOIN t1 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t1 GROUP BY d
|
||||
);
|
||||
d
|
||||
71
|
||||
-79
|
||||
71
|
||||
-79
|
||||
EXPLAIN EXTENDED SELECT t2.d FROM (SELECT c AS d FROM t1) AS t2 JOIN t1 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t1 GROUP BY d
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
|
||||
3 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
4 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'd' of SELECT #4 was resolved in SELECT #1
|
||||
Note 1981 Aggregate function 'bit_or()' of SELECT #4 belongs to SELECT #3
|
||||
Note 1276 Field or reference 'd' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1003 /* select#1 */ select `test`.`t1`.`c` AS `d` from `test`.`t1` join `test`.`t1` where <expr_cache><`test`.`t1`.`c`>((/* select#3 */ select ord(<expr_cache><`test`.`t1`.`c`,bit_or(`test`.`t1`.`c`),bit_or(`test`.`t1`.`c`)>((/* select#4 */ select bit_or(`test`.`t1`.`c`)))) from `test`.`t1` group by `test`.`t1`.`c`))
|
||||
DROP TABLE t0, t1;
|
||||
# End of 11.4 tests
|
||||
SET optimizer_switch=@save_optimizer_switch;
|
||||
# restore default
|
||||
set @@optimizer_switch= default;
|
||||
|
||||
@@ -1739,7 +1739,36 @@ SELECT * FROM t4 WHERE b NOT IN ( SELECT * FROM v1 );
|
||||
drop view v1;
|
||||
drop table t1,t2,t3,t4;
|
||||
|
||||
SET optimizer_switch=@save_optimizer_switch;
|
||||
--echo #
|
||||
--echo # MDEV-32401 expression cache lead to crash if table of wrong type
|
||||
--echo # created and the cache switched off
|
||||
--echo #
|
||||
|
||||
--echo # restore default
|
||||
set @@optimizer_switch= default;
|
||||
CREATE TABLE t0 (c TEXT);
|
||||
INSERT INTO t0 VALUES (71), (-79);
|
||||
SELECT t1.d FROM (SELECT c AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
EXPLAIN EXTENDED SELECT t1.d FROM (SELECT c AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
SELECT t1.d FROM (SELECT CAST(c as int) AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
EXPLAIN EXTENDED SELECT t1.d FROM (SELECT CAST(c as int) AS d FROM t0) AS t1 JOIN t0 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t0 GROUP BY d
|
||||
);
|
||||
CREATE TABLE t1 (c INT);
|
||||
INSERT INTO t1 VALUES (71), (-79);
|
||||
SELECT t2.d FROM (SELECT c AS d FROM t1) AS t2 JOIN t1 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t1 GROUP BY d
|
||||
);
|
||||
EXPLAIN EXTENDED SELECT t2.d FROM (SELECT c AS d FROM t1) AS t2 JOIN t1 ON (
|
||||
SELECT ORD((SELECT BIT_OR(d))) FROM t1 GROUP BY d
|
||||
);
|
||||
|
||||
DROP TABLE t0, t1;
|
||||
|
||||
--echo # End of 11.4 tests
|
||||
|
||||
SET optimizer_switch=@save_optimizer_switch;
|
||||
|
||||
@@ -5329,8 +5329,6 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id)
|
||||
if (!(name.str= (char*) thd->memdup(buf, name.length + 1)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
result_sink->get_tmp_table_param()->materialized_subquery= true;
|
||||
|
||||
if (item->substype() == Item_subselect::IN_SUBS &&
|
||||
(item->get_IN_subquery()->is_jtbm_merged))
|
||||
{
|
||||
|
||||
@@ -4641,7 +4641,6 @@ void TMP_TABLE_PARAM::init()
|
||||
table_charset= 0;
|
||||
precomputed_group_by= 0;
|
||||
bit_fields_as_long= 0;
|
||||
materialized_subquery= 0;
|
||||
force_not_null_cols= 0;
|
||||
skip_create_table= 0;
|
||||
tmp_name= "temptable"; // Name of temp table on disk
|
||||
|
||||
@@ -6803,8 +6803,6 @@ public:
|
||||
bool using_outer_summary_function;
|
||||
CHARSET_INFO *table_charset;
|
||||
bool schema_table;
|
||||
/* TRUE if the temp table is created for subquery materialization. */
|
||||
bool materialized_subquery;
|
||||
/* TRUE if all columns of the table are guaranteed to be non-nullable */
|
||||
bool force_not_null_cols;
|
||||
/*
|
||||
@@ -6832,7 +6830,7 @@ public:
|
||||
:copy_field(0), group_parts(0),
|
||||
group_length(0), group_null_parts(0),
|
||||
using_outer_summary_function(0),
|
||||
schema_table(0), materialized_subquery(0), force_not_null_cols(0),
|
||||
schema_table(0), force_not_null_cols(0),
|
||||
precomputed_group_by(0), group_concat(0),
|
||||
force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0)
|
||||
{
|
||||
|
||||
@@ -58,6 +58,16 @@
|
||||
#define OPTION_BIG_SELECTS (1ULL << 9) // THD, user
|
||||
#define OPTION_LOG_OFF (1ULL << 10) // THD, user
|
||||
#define OPTION_QUOTE_SHOW_CREATE (1ULL << 11) // THD, user
|
||||
/*
|
||||
This flag has two effects:
|
||||
1. Include all select list columns in the temporary table. Do not skip
|
||||
constant expressions or expressions that include aggregate functions.
|
||||
2. For items in select list, do NOT set item->result_field to point to
|
||||
item's image field in the created temporary table.
|
||||
|
||||
Roughly speaking, TMP_TABLE_ALL_COLUMNS is NOT used for temporary tables
|
||||
that do GROUP BY operation, and used for most other tables.
|
||||
*/
|
||||
#define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern
|
||||
#define OPTION_WARNINGS (1ULL << 13) // THD, user
|
||||
#define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog
|
||||
|
||||
@@ -22326,6 +22326,8 @@ bool Create_tmp_table::add_fields(THD *thd,
|
||||
if (type == Item::SUM_FUNC_ITEM && !m_group && !m_save_sum_fields)
|
||||
{ /* Can't calc group yet */
|
||||
Item_sum *sum_item= (Item_sum *) item;
|
||||
/* There is actually no need to clear result_field */
|
||||
DBUG_ASSERT(!sum_item->result_field);
|
||||
sum_item->result_field=0;
|
||||
for (uint i= 0 ; i < sum_item->get_arg_count() ; i++)
|
||||
{
|
||||
@@ -22412,26 +22414,25 @@ bool Create_tmp_table::add_fields(THD *thd,
|
||||
{
|
||||
Item_sum *agg_item= (Item_sum *) item;
|
||||
/*
|
||||
Update the result field only if it has never been set, or if the
|
||||
created temporary table is not to be used for subquery
|
||||
materialization.
|
||||
Set agg_item->result_field to point to its image in the temporary
|
||||
table. Do this only when this temporary table is created without
|
||||
TMP_TABLE_ALL_COLUMNS flag (and so not_all_columns=true).
|
||||
|
||||
The reason is that for subqueries that require
|
||||
materialization as part of their plan, we create the
|
||||
'external' temporary table needed for IN execution, after
|
||||
the 'internal' temporary table needed for grouping. Since
|
||||
both the external and the internal temporary tables are
|
||||
created for the same list of SELECT fields of the subquery,
|
||||
setting 'result_field' for each invocation of
|
||||
create_tmp_table overrides the previous value of
|
||||
'result_field'.
|
||||
In this case, the temporary table will be read by going through the
|
||||
select list and its item->result_field pointers. The most common
|
||||
examples of this are GROUP BY operation and buffering for
|
||||
SQL_BUFFER_RESULT).
|
||||
|
||||
The condition below prevents the creation of the external
|
||||
temp table to override the 'result_field' that was set for
|
||||
the internal temp table.
|
||||
Note that SELECT has one "select list" but may be processed with
|
||||
multiple temporary tables. It is therefore important to only set
|
||||
result_field to point to the right temporary table.
|
||||
That's why we assert here that we don't set it twice.
|
||||
*/
|
||||
if (!agg_item->result_field || !param->materialized_subquery)
|
||||
if (not_all_columns)
|
||||
{
|
||||
DBUG_ASSERT(!agg_item->result_field);
|
||||
agg_item->result_field= new_field;
|
||||
}
|
||||
}
|
||||
tmp_from_field++;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user