summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2016-09-29 01:15:00 -0700
committerIgor Babaev <igor@askmonty.org>2016-09-30 17:40:40 -0700
commit903f34c7a99d15ca1b861a7dd4848ebed9891c44 (patch)
tree80e25801f2ae4bc53bf1705c6360d8062a14c702
parent6aeaebd8cfa3ce3cf7037a282a77ca4c6cdb7e16 (diff)
downloadmariadb-git-903f34c7a99d15ca1b861a7dd4848ebed9891c44.tar.gz
Fixed bug mdev-10868.
There was no implementation of the virtual method print() for the Item_window_func class. As a result for a view containing window function an invalid view definition could be written in the frm file. When a query that refers to this view was executed a syntax error was reported.
-rw-r--r--mysql-test/r/win.result116
-rw-r--r--mysql-test/t/win.test43
-rw-r--r--sql/item_windowfunc.cc7
-rw-r--r--sql/item_windowfunc.h4
-rw-r--r--sql/sql_window.cc78
-rw-r--r--sql/sql_window.h7
6 files changed, 253 insertions, 2 deletions
diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result
index 78293c96244..7cbf644bd54 100644
--- a/mysql-test/r/win.result
+++ b/mysql-test/r/win.result
@@ -1779,7 +1779,7 @@ EXPLAIN
"query_block": {
"select_id": 1,
"filesort": {
- "sort_key": "X",
+ "sort_key": "row_number() over ( order by t1.s1,t1.s2)",
"window_functions_computation": {
"sorts": {
"filesort": {
@@ -2236,3 +2236,117 @@ sum(t.a) over (partition by t.b order by a) sqrt(ifnull((sum(t.a) over (partitio
3.0000000000 1.7320508075688772
0.0000000000 0
drop table t;
+#
+# MDEV-10868: view definitions with window functions
+#
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table t1 (pk int, c int);
+insert into t1 select a+1,1 from t0;
+update t1 set c=2 where pk not in (1,2,3,4);
+select * from t1;
+pk c
+1 1
+2 1
+3 1
+4 1
+5 2
+6 2
+7 2
+8 2
+9 2
+10 2
+select pk, c, c/count(*) over (partition by c order by pk
+rows between 1 preceding and 2 following) as CNT
+from t1;
+pk c CNT
+1 1 0.3333
+2 1 0.2500
+3 1 0.3333
+4 1 0.5000
+5 2 0.6667
+6 2 0.5000
+7 2 0.5000
+8 2 0.5000
+9 2 0.6667
+10 2 1.0000
+create view v1 as select pk, c, c/count(*) over (partition by c order by pk
+rows between 1 preceding and 2 following) as CNT
+from t1;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,(`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between 1 preceding and 2 following )) AS `CNT` from `t1` latin1 latin1_swedish_ci
+select * from v1;
+pk c CNT
+1 1 0.3333
+2 1 0.2500
+3 1 0.3333
+4 1 0.5000
+5 2 0.6667
+6 2 0.5000
+7 2 0.5000
+8 2 0.5000
+9 2 0.6667
+10 2 1.0000
+select pk, c, c/count(*) over w1 as CNT from t1
+window w1 as (partition by c order by pk rows between 1 preceding and 2 following);
+pk c CNT
+1 1 0.3333
+2 1 0.2500
+3 1 0.3333
+4 1 0.5000
+5 2 0.6667
+6 2 0.5000
+7 2 0.5000
+8 2 0.5000
+9 2 0.6667
+10 2 1.0000
+create view v2 as select pk, c, c/count(*) over w1 as CNT from t1
+window w1 as (partition by c order by pk rows between 1 preceding and 2 following);
+show create view v2;
+View Create View character_set_client collation_connection
+v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,(`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between 1 preceding and 2 following )) AS `CNT` from `t1` latin1 latin1_swedish_ci
+select * from v2;
+pk c CNT
+1 1 0.3333
+2 1 0.2500
+3 1 0.3333
+4 1 0.5000
+5 2 0.6667
+6 2 0.5000
+7 2 0.5000
+8 2 0.5000
+9 2 0.6667
+10 2 1.0000
+select pk, c, c/count(*) over w1 as CNT from t1
+window w1 as (partition by c order by pk rows unbounded preceding);
+pk c CNT
+1 1 1.0000
+2 1 0.5000
+3 1 0.3333
+4 1 0.2500
+5 2 2.0000
+6 2 1.0000
+7 2 0.6667
+8 2 0.5000
+9 2 0.4000
+10 2 0.3333
+create view v3 as select pk, c, c/count(*) over w1 as CNT from t1
+window w1 as (partition by c order by pk rows unbounded preceding);
+show create view v3;
+View Create View character_set_client collation_connection
+v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`pk` AS `pk`,`t1`.`c` AS `c`,(`t1`.`c` / count(0) over ( partition by `t1`.`c` order by `t1`.`pk` rows between unbounded preceding and current row )) AS `CNT` from `t1` latin1 latin1_swedish_ci
+select * from v3;
+pk c CNT
+1 1 1.0000
+2 1 0.5000
+3 1 0.3333
+4 1 0.2500
+5 2 2.0000
+6 2 1.0000
+7 2 0.6667
+8 2 0.5000
+9 2 0.4000
+10 2 0.3333
+drop view v1,v2,v3;
+drop table t0,t1;
diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test
index 4b0e4a86f14..971e91a26cb 100644
--- a/mysql-test/t/win.test
+++ b/mysql-test/t/win.test
@@ -1373,3 +1373,46 @@ SELECT sum(t.a) over (partition by t.b order by a),
sqrt(ifnull((sum(t.a) over (partition by t.b order by a)), 0))
from t;
drop table t;
+
+--echo #
+--echo # MDEV-10868: view definitions with window functions
+--echo #
+
+create table t0 (a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+create table t1 (pk int, c int);
+insert into t1 select a+1,1 from t0;
+update t1 set c=2 where pk not in (1,2,3,4);
+select * from t1;
+
+let $q=
+select pk, c, c/count(*) over (partition by c order by pk
+ rows between 1 preceding and 2 following) as CNT
+from t1;
+
+eval $q;
+eval create view v1 as $q;
+show create view v1;
+select * from v1;
+
+let $q=
+select pk, c, c/count(*) over w1 as CNT from t1
+ window w1 as (partition by c order by pk rows between 1 preceding and 2 following);
+
+eval $q;
+eval create view v2 as $q;
+show create view v2;
+select * from v2;
+
+let $q=
+select pk, c, c/count(*) over w1 as CNT from t1
+ window w1 as (partition by c order by pk rows unbounded preceding);
+
+eval $q;
+eval create view v3 as $q;
+show create view v3;
+select * from v3;
+
+drop view v1,v2,v3;
+drop table t0,t1;
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index ccdbdd3294f..a13967eaaad 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -446,3 +446,10 @@ void Item_sum_hybrid_simple::update_field()
{
DBUG_ASSERT(0);
}
+
+void Item_window_func::print(String *str, enum_query_type query_type)
+{
+ window_func()->print(str, query_type);
+ str->append(" over ");
+ window_spec->print(str, query_type);
+}
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h
index 5b368e2cdbc..15e5c9a7c5b 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -963,7 +963,9 @@ public:
bool resolve_window_name(THD *thd);
- Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
+ void print(String *str, enum_query_type query_type);
+
+ Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
};
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 8fed2418b82..28be70c2890 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -61,6 +61,25 @@ Window_spec::check_window_names(List_iterator_fast<Window_spec> &it)
return false;
}
+void
+Window_spec::print(String *str, enum_query_type query_type)
+{
+ str->append('(');
+ if (partition_list->first)
+ {
+ str->append(STRING_WITH_LEN(" partition by "));
+ st_select_lex::print_order(str, partition_list->first, query_type);
+ }
+ if (order_list->first)
+ {
+ str->append(STRING_WITH_LEN(" order by "));
+ st_select_lex::print_order(str, order_list->first, query_type);
+ }
+ if (window_frame)
+ window_frame->print(str, query_type);
+ str->append(')');
+}
+
bool
Window_frame::check_frame_bounds()
{
@@ -81,6 +100,65 @@ Window_frame::check_frame_bounds()
}
+void
+Window_frame::print(String *str, enum_query_type query_type)
+{
+ switch (units) {
+ case UNITS_ROWS:
+ str->append(STRING_WITH_LEN(" rows "));
+ break;
+ case UNITS_RANGE: str->append(STRING_WITH_LEN(" range "));
+ }
+
+ str->append(STRING_WITH_LEN("between "));
+ top_bound->print(str, query_type);
+ str->append(STRING_WITH_LEN(" and "));
+ bottom_bound->print(str, query_type);
+
+ if (exclusion != EXCL_NONE)
+ {
+ str->append(STRING_WITH_LEN(" exclude "));
+ switch (exclusion) {
+ case EXCL_CURRENT_ROW:
+ str->append(STRING_WITH_LEN(" current row "));
+ break;
+ case EXCL_GROUP:
+ str->append(STRING_WITH_LEN(" group "));
+ break;
+ case EXCL_TIES:
+ str->append(STRING_WITH_LEN(" ties "));
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+
+void
+Window_frame_bound::print(String *str, enum_query_type query_type)
+{
+ if (precedence_type == CURRENT)
+ {
+ str->append(STRING_WITH_LEN(" current row "));
+ return;
+ }
+ if (is_unbounded())
+ str->append(STRING_WITH_LEN(" unbounded "));
+ else
+ offset->print(str ,query_type);
+ switch (precedence_type) {
+ case PRECEDING:
+ str->append(STRING_WITH_LEN(" preceding "));
+ break;
+ case FOLLOWING:
+ str->append(STRING_WITH_LEN(" following "));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+}
+
/*
Setup window functions in a select
*/
diff --git a/sql/sql_window.h b/sql/sql_window.h
index b94a1fc6dc4..6a56fc84392 100644
--- a/sql/sql_window.h
+++ b/sql/sql_window.h
@@ -45,6 +45,8 @@ public:
bool is_unbounded() { return offset == NULL; }
+ void print(String *str, enum_query_type query_type);
+
};
@@ -84,6 +86,8 @@ public:
bool check_frame_bounds();
+ void print(String *str, enum_query_type query_type);
+
};
class Window_spec : public Sql_alloc
@@ -125,6 +129,9 @@ class Window_spec : public Sql_alloc
{
*(partition_list->next)= NULL;
}
+
+ void print(String *str, enum_query_type query_type);
+
};
class Window_def : public Window_spec