Commit e74181e3 authored by Igor Babaev's avatar Igor Babaev

MDEV-15159 NULL is treated as 0 in CTE

Forced columns of recursive CTEs to be nullable. SQL standard
requires this only from recursive columns, but in our code
so far we do not differentiate between recursive and non-recursive
columns when aggregating types of the union that specifies a
recursive CTE.
parent 4a5e23e2
......@@ -3509,3 +3509,22 @@ Beijing
Bangkok
Paris
drop table flights, distances;
#
# MDEV-15159: Forced nullability of columns in recursive CTE
#
WITH RECURSIVE cte AS (
SELECT 1 AS a UNION ALL
SELECT NULL FROM cte WHERE a IS NOT NULL)
SELECT * FROM cte;
a
1
NULL
CREATE TABLE t1 (a int NOT NULL);
INSERT INTO t1 VALUES (0);
WITH RECURSIVE cte AS
(SELECT a FROM t1 where a=0 UNION SELECT NULL FROM cte)
SELECT * FROM cte;
a
0
NULL
DROP TABLE t1;
......@@ -2458,3 +2458,21 @@ with recursive destinations (city) as
select * from destinations;
drop table flights, distances;
--echo #
--echo # MDEV-15159: Forced nullability of columns in recursive CTE
--echo #
WITH RECURSIVE cte AS (
SELECT 1 AS a UNION ALL
SELECT NULL FROM cte WHERE a IS NOT NULL)
SELECT * FROM cte;
CREATE TABLE t1 (a int NOT NULL);
INSERT INTO t1 VALUES (0);
WITH RECURSIVE cte AS
(SELECT a FROM t1 where a=0 UNION SELECT NULL FROM cte)
SELECT * FROM cte;
DROP TABLE t1;
......@@ -788,18 +788,28 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
join_union_type_attributes(thd_arg, holders, count))
DBUG_RETURN(true);
bool is_recursive= with_element && with_element->is_recursive;
types.empty();
List_iterator_fast<Item> it(first_sl->item_list);
Item *item_tmp;
for (uint pos= 0; (item_tmp= it++); pos++)
{
/*
SQL standard requires forced nullability only for
recursive columns. However type aggregation in our
implementation so far does not differentiate between
recursive and non-recursive columns of a recursive CTE.
TODO: this should be fixed.
*/
bool pos_maybe_null= is_recursive ? true : holders[pos].get_maybe_null();
/* Error's in 'new' will be detected after loop */
types.push_back(new (thd_arg->mem_root)
Item_type_holder(thd_arg,
item_tmp,
holders[pos].type_handler(),
&holders[pos]/*Type_all_attributes*/,
holders[pos].get_maybe_null()));
pos_maybe_null));
}
if (unlikely(thd_arg->is_fatal_error))
DBUG_RETURN(true); // out of memory
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment