mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE...
The failure happened for group by queries when all tables where marked as 'const tables' (tables with 0-1 matching rows) and no row matched the where clause and there was in addition a direct reference to a field. In this case the field would not be properly reset and the query would return 'random data' that happended to be in table->record[0]. Fixed by marking all const tables as null tables in this particular case. Sergei also provided an extra test case for the code. @reviewer Sergei Petrunia <psergey@askmonty.org>
This commit is contained in:
@@ -2934,5 +2934,34 @@ f COUNT(*)
|
|||||||
NULL 1
|
NULL 1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
|
# MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT '');
|
||||||
|
INSERT INTO t1 (a) VALUES ('foo');
|
||||||
|
CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
|
||||||
|
SELECT * from t2;
|
||||||
|
f1 f2
|
||||||
|
NULL NULL
|
||||||
|
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
|
||||||
|
f1 f2
|
||||||
|
NULL NULL
|
||||||
|
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0;
|
||||||
|
f1 f2
|
||||||
|
NULL NULL
|
||||||
|
drop table t1,t2;
|
||||||
|
# Extra test by to check the fix for MDEV-24710
|
||||||
|
create table t20 (pk int primary key, a int);
|
||||||
|
insert into t20 values (1,1);
|
||||||
|
create table t21 (pk int primary key, b int not null);
|
||||||
|
insert into t21 values (1,1);
|
||||||
|
create table t22 (a int);
|
||||||
|
insert into t22 values (1),(2);
|
||||||
|
select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10
|
||||||
|
where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22;
|
||||||
|
a SUBQ
|
||||||
|
1 NULL
|
||||||
|
2 NULL
|
||||||
|
drop table t20, t21, t22;
|
||||||
|
#
|
||||||
# End of 10.3 tests
|
# End of 10.3 tests
|
||||||
#
|
#
|
||||||
|
@@ -2040,6 +2040,29 @@ INSERT INTO t1 VALUES ('2032-10-08');
|
|||||||
SELECT d != '2023-03-04' AS f, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP;
|
SELECT d != '2023-03-04' AS f, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT '');
|
||||||
|
INSERT INTO t1 (a) VALUES ('foo');
|
||||||
|
CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
|
||||||
|
SELECT * from t2;
|
||||||
|
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL;
|
||||||
|
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo # Extra test by to check the fix for MDEV-24710
|
||||||
|
|
||||||
|
create table t20 (pk int primary key, a int);
|
||||||
|
insert into t20 values (1,1);create table t21 (pk int primary key, b int not null);
|
||||||
|
insert into t21 values (1,1);
|
||||||
|
create table t22 (a int);
|
||||||
|
insert into t22 values (1),(2);
|
||||||
|
select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10
|
||||||
|
where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22;
|
||||||
|
drop table t20, t21, t22;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.3 tests
|
--echo # End of 10.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@@ -13668,21 +13668,70 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
used only in JOIN::clear
|
used only in JOIN::clear (always) and in do_select()
|
||||||
|
(if there where no matching rows)
|
||||||
|
|
||||||
|
@param join JOIN
|
||||||
|
@param cleared_tables If not null, clear also const tables and mark all
|
||||||
|
cleared tables in the map. cleared_tables is only
|
||||||
|
set when called from do_select() when there is a
|
||||||
|
group function and there where no matching rows.
|
||||||
*/
|
*/
|
||||||
static void clear_tables(JOIN *join)
|
|
||||||
|
static void clear_tables(JOIN *join, table_map *cleared_tables)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
must clear only the non-const tables, as const tables
|
must clear only the non-const tables as const tables are not re-calculated.
|
||||||
are not re-calculated.
|
|
||||||
*/
|
*/
|
||||||
for (uint i= 0 ; i < join->table_count ; i++)
|
for (uint i= 0 ; i < join->table_count ; i++)
|
||||||
{
|
{
|
||||||
if (!(join->table[i]->map & join->const_table_map))
|
TABLE *table= join->table[i];
|
||||||
mark_as_null_row(join->table[i]); // All fields are NULL
|
|
||||||
|
if (table->null_row)
|
||||||
|
continue; // Nothing more to do
|
||||||
|
if (!(table->map & join->const_table_map) || cleared_tables)
|
||||||
|
{
|
||||||
|
if (cleared_tables)
|
||||||
|
{
|
||||||
|
(*cleared_tables)|= (((table_map) 1) << i);
|
||||||
|
if (table->s->null_bytes)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Remember null bits for the record so that we can restore the
|
||||||
|
original const record in unclear_tables()
|
||||||
|
*/
|
||||||
|
memcpy(table->record[1], table->null_flags, table->s->null_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mark_as_null_row(table); // All fields are NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reverse null marking for tables and restore null bits.
|
||||||
|
|
||||||
|
We have to do this because the tables may be re-used in a sub query
|
||||||
|
and the subquery will assume that the const tables contains the original
|
||||||
|
data before clear_tables().
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void unclear_tables(JOIN *join, table_map *cleared_tables)
|
||||||
|
{
|
||||||
|
for (uint i= 0 ; i < join->table_count ; i++)
|
||||||
|
{
|
||||||
|
if ((*cleared_tables) & (((table_map) 1) << i))
|
||||||
|
{
|
||||||
|
TABLE *table= join->table[i];
|
||||||
|
if (table->s->null_bytes)
|
||||||
|
memcpy(table->null_flags, table->record[1], table->s->null_bytes);
|
||||||
|
unmark_as_null_row(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
Make som simple condition optimization:
|
Make som simple condition optimization:
|
||||||
@@ -19194,6 +19243,7 @@ do_select(JOIN *join, Procedure *procedure)
|
|||||||
if (join->only_const_tables() && !join->need_tmp)
|
if (join->only_const_tables() && !join->need_tmp)
|
||||||
{
|
{
|
||||||
Next_select_func end_select= setup_end_select_func(join, NULL);
|
Next_select_func end_select= setup_end_select_func(join, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
HAVING will be checked after processing aggregate functions,
|
HAVING will be checked after processing aggregate functions,
|
||||||
But WHERE should checked here (we alredy have read tables).
|
But WHERE should checked here (we alredy have read tables).
|
||||||
@@ -19220,12 +19270,29 @@ do_select(JOIN *join, Procedure *procedure)
|
|||||||
}
|
}
|
||||||
else if (join->send_row_on_empty_set())
|
else if (join->send_row_on_empty_set())
|
||||||
{
|
{
|
||||||
|
table_map cleared_tables= (table_map) 0;
|
||||||
|
if (end_select == end_send_group)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Was a grouping query but we did not find any rows. In this case
|
||||||
|
we clear all tables to get null in any referenced fields,
|
||||||
|
like in case of:
|
||||||
|
SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL
|
||||||
|
*/
|
||||||
|
clear_tables(join, &cleared_tables);
|
||||||
|
}
|
||||||
if (!join->having || join->having->val_int())
|
if (!join->having || join->having->val_int())
|
||||||
{
|
{
|
||||||
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
|
List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
|
||||||
join->fields);
|
join->fields);
|
||||||
rc= join->result->send_data(*columns_list) > 0;
|
rc= join->result->send_data(*columns_list) > 0;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
We have to remove the null markings from the tables as this table
|
||||||
|
may be part of a sub query that is re-evaluated
|
||||||
|
*/
|
||||||
|
if (cleared_tables)
|
||||||
|
unclear_tables(join, &cleared_tables);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
An error can happen when evaluating the conds
|
An error can happen when evaluating the conds
|
||||||
@@ -20197,7 +20264,7 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos)
|
|||||||
if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0)))
|
if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0)))
|
||||||
mark_as_null_row(table);
|
mark_as_null_row(table);
|
||||||
}
|
}
|
||||||
if (!table->null_row)
|
if (!table->null_row && ! tab->join->mixed_implicit_grouping)
|
||||||
table->maybe_null= 0;
|
table->maybe_null= 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -25331,7 +25398,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, TABL
|
|||||||
|
|
||||||
void JOIN::clear()
|
void JOIN::clear()
|
||||||
{
|
{
|
||||||
clear_tables(this);
|
clear_tables(this, 0);
|
||||||
copy_fields(&tmp_table_param);
|
copy_fields(&tmp_table_param);
|
||||||
|
|
||||||
if (sum_funcs)
|
if (sum_funcs)
|
||||||
|
@@ -3145,6 +3145,12 @@ inline void mark_as_null_row(TABLE *table)
|
|||||||
bfill(table->null_flags,table->s->null_bytes,255);
|
bfill(table->null_flags,table->s->null_bytes,255);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void unmark_as_null_row(TABLE *table)
|
||||||
|
{
|
||||||
|
table->null_row=0;
|
||||||
|
table->status= STATUS_NO_RECORD;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_simple_order(ORDER *order);
|
bool is_simple_order(ORDER *order);
|
||||||
|
|
||||||
class Open_tables_backup;
|
class Open_tables_backup;
|
||||||
|
Reference in New Issue
Block a user