summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <vicentiu@mariadb.org>2017-06-28 18:42:56 +0300
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2017-06-28 19:21:31 +0300
commit31ba0fa48d27715e82258b1e74401093e0ee17a2 (patch)
treef4f4f6faa740c127d69cab064ad27fe58cdeacc8
parent23edc7c88f29d7bee01f39f1a58f4ada05f724c3 (diff)
downloadmariadb-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.result30
-rw-r--r--mysql-test/t/win.test27
-rw-r--r--sql/item_cmpfunc.h5
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_windowfunc.h11
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;