diff options
author | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2017-06-28 18:42:56 +0300 |
---|---|---|
committer | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2017-06-28 19:21:31 +0300 |
commit | 31ba0fa48d27715e82258b1e74401093e0ee17a2 (patch) | |
tree | f4f4f6faa740c127d69cab064ad27fe58cdeacc8 | |
parent | 23edc7c88f29d7bee01f39f1a58f4ada05f724c3 (diff) | |
download | mariadb-git-31ba0fa48d27715e82258b1e74401093e0ee17a2.tar.gz |
MDEV-12851: Case with window functions query crashes server
The "is null" function performs one operation which no other Item_func
does, which is to update used tables during fix_length_and_dec().
This however can not be performed before window functions have had a
chance to resolve their order by and partition by definitions, which
happens after the initial setup_fields call. Consequently, do not call
Item_func_isnull update_used_tables during fix_length_and_dec().
There was another issue detected once the crash was resolved.
Because window functions did not implement is_null() method, we would
end up returning bad results for "is null" and "is not null" functions.
Implemented is_null() method for Item_windowfunc.
-rw-r--r-- | mysql-test/r/win.result | 30 | ||||
-rw-r--r-- | mysql-test/t/win.test | 27 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 5 | ||||
-rw-r--r-- | sql/item_func.cc | 5 | ||||
-rw-r--r-- | sql/item_windowfunc.h | 11 |
5 files changed, 71 insertions, 7 deletions
diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index a67c336e5b4..952bd82ac7f 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -3097,3 +3097,33 @@ a 300 300 drop table t; +# +# MDEV-12851 case with window functions query crashes server +# +create table t1(dt datetime); +insert into t1 values ('2017-05-17'), ('2017-05-18'); +select dt, +case when (max(dt) over (order by dt rows between 1 following and 1 following) is null) +then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) +end x, +case when (max(dt) over (order by dt rows between 1 following and 1 following) is not null) +then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) +end x +from t1; +dt x x +2017-05-17 00:00:00 2017-05-18 00:00:00 9999-12-31 12:00:00 +2017-05-18 00:00:00 9999-12-31 12:00:00 NULL +drop table t1; +create table t1(i int); +insert into t1 values (null),(1),(2); +select max(i) over (order by i), +max(i) over (order by i) is null, +max(i) over (order by i) is not null +from t1; +max(i) over (order by i) max(i) over (order by i) is null max(i) over (order by i) is not null +NULL 1 0 +1 0 1 +2 0 1 +drop table t1; diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index 0ecb2b35074..45653b18682 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -1887,3 +1887,30 @@ insert into t values (1, 10), (2, 20), (3, 30); prepare stmt from "SELECT (CASE WHEN sum(t.a) over (partition by t.b)=1 THEN 1000 ELSE 300 END) AS a FROM t"; execute stmt; drop table t; + +--echo # +--echo # MDEV-12851 case with window functions query crashes server +--echo # + +create table t1(dt datetime); +insert into t1 values ('2017-05-17'), ('2017-05-18'); +select dt, + case when (max(dt) over (order by dt rows between 1 following and 1 following) is null) + then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) + end x, + case when (max(dt) over (order by dt rows between 1 following and 1 following) is not null) + then '9999-12-31 12:00:00' + else max(dt) over (order by dt rows between 1 following and 1 following) + end x +from t1; + +drop table t1; + +create table t1(i int); +insert into t1 values (null),(1),(2); +select max(i) over (order by i), + max(i) over (order by i) is null, + max(i) over (order by i) is not null +from t1; +drop table t1; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c81a1621f8a..2f98c68bb5f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1770,11 +1770,6 @@ public: Item_func_isnull(THD *thd, Item *a): Item_func_null_predicate(thd, a) {} longlong val_int(); enum Functype functype() const { return ISNULL_FUNC; } - void fix_length_and_dec() - { - Item_func_null_predicate::fix_length_and_dec(); - update_used_tables(); - } const char *func_name() const { return "isnull"; } void print(String *str, enum_query_type query_type); enum precedence precedence() const { return CMP_PRECEDENCE; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 8529a1d08ca..1b83f86d19c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -153,8 +153,9 @@ void Item_func::sync_with_sum_func_and_with_field(List<Item> &list) is to allow all Item_field() objects to setup pointers to the table fields. Sets as a side effect the following class variables: - maybe_null Set if any argument may return NULL - with_sum_func Set if any of the arguments contains a sum function + maybe_null Set if any argument may return NULL + with_sum_func Set if any of the arguments contains a sum function + with_window_func Set if any of the arguments contain a window function with_field Set if any of the arguments contains or is a field used_tables_cache Set to union of the tables used by arguments diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index b4953c8a6ac..0dee60915f8 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -848,6 +848,17 @@ public: read_value_from_result_field= true; } + bool is_null() + { + if (force_return_blank) + return false; + + if (read_value_from_result_field) + return result_field->is_null(); + + return window_func()->is_null(); + } + double val_real() { double res; |