summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalina Shalygina <galashalygina@gmail.com>2017-06-29 15:32:17 +0300
committerGalina Shalygina <galashalygina@gmail.com>2017-06-29 15:36:07 +0300
commit615da8f70bd61aa0918c08a256638d90d425fe0e (patch)
tree16d6d48e705db076d42f56e5c8ecd10f00dde60d
parent0fe7d8a2a221196d977e5efe3f3dedb22806bb53 (diff)
downloadmariadb-git-615da8f70bd61aa0918c08a256638d90d425fe0e.tar.gz
New structure Table Value Constructor added in grammar.
TVC can be used in UNION-statement, in view and in subquery. Files where TVC is defined and its methods are stored added. Methods exec and prepare for TVC added. Tests for TVC added.
-rw-r--r--mysql-test/t/table_value_const.test30
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/sql_class.h58
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_tvc.cc128
-rw-r--r--sql/sql_tvc.h27
-rw-r--r--sql/sql_union.cc78
-rw-r--r--sql/sql_yacc.yy40
8 files changed, 301 insertions, 65 deletions
diff --git a/mysql-test/t/table_value_const.test b/mysql-test/t/table_value_const.test
new file mode 100644
index 00000000000..6d338ab0353
--- /dev/null
+++ b/mysql-test/t/table_value_const.test
@@ -0,0 +1,30 @@
+values (1,2);
+
+select 1,2 union values (1,2);
+
+values (1,2) union select (1,2);
+
+select * from t1 where (t1.a,t1.b) in (select 5,7 union values (1,2),(2,3));
+
+select * from t1 where (t1.a,t1.b) in (values (1,2),(2,3) union select 5,7);
+
+let $drop_view= drop view v1;
+
+create view v1 as values (1,2);
+
+eval $drop_view;
+
+create view v1 as values (1,2) union select 3,4;
+
+eval $drop_view;
+
+create view v1 as select 1,2 union values (3,4);
+
+eval $drop_view;
+
+create view v1 as select 1,2 union values (3,4),(5,6);
+
+eval $drop_view;
+
+
+
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 87e41817857..10af1fcda9b 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -145,6 +145,7 @@ SET (SQL_SOURCE
item_windowfunc.cc sql_window.cc
sql_cte.cc
sql_sequence.cc sql_sequence.h ha_sequence.h
+ sql_tvc.cc sql_tvc.h
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 817be9d939c..609d4ad23eb 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -6034,6 +6034,64 @@ public:
};
+class Type_holder: public Sql_alloc,
+ public Item_args,
+ public Type_handler_hybrid_field_type,
+ public Type_all_attributes,
+ public Type_geometry_attributes
+{
+ TYPELIB *m_typelib;
+ bool m_maybe_null;
+public:
+ Type_holder()
+ :m_typelib(NULL),
+ m_maybe_null(false)
+ { }
+
+ void set_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; }
+ bool get_maybe_null() const { return m_maybe_null; }
+
+ uint decimal_precision() const
+ {
+ /*
+ Type_holder is not used directly to create fields, so
+ its virtual decimal_precision() is never called.
+ We should eventually extend create_result_table() to accept
+ an array of Type_holders directly, without having to allocate
+ Item_type_holder's and put them into List<Item>.
+ */
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ void set_geometry_type(uint type)
+ {
+ Type_geometry_attributes::set_geometry_type(type);
+ }
+ uint uint_geometry_type() const
+ {
+ return Type_geometry_attributes::get_geometry_type();
+ }
+ void set_typelib(TYPELIB *typelib)
+ {
+ m_typelib= typelib;
+ }
+ TYPELIB *get_typelib() const
+ {
+ return m_typelib;
+ }
+
+ bool aggregate_attributes(THD *thd)
+ {
+ for (uint i= 0; i < arg_count; i++)
+ m_maybe_null|= args[i]->maybe_null;
+ return
+ type_handler()->Item_hybrid_func_fix_attributes(thd,
+ "UNION", this, this,
+ args, arg_count);
+ }
+};
+
+
#endif /* MYSQL_SERVER */
#endif /* SQL_CLASS_INCLUDED */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 61c13814eeb..dbe881f2926 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -31,7 +31,7 @@
#include "sql_window.h"
#include "sql_trigger.h"
#include "sp.h" // enum stored_procedure_type
-
+#include "sql_tvc.h"
/* YACC and LEX Definitions */
@@ -999,6 +999,8 @@ public:
/* it is for correct printing SELECT options */
thr_lock_type lock_type;
+
+ table_value_constr *tvc;
void init_query();
void init_select();
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
new file mode 100644
index 00000000000..323ce5eacb9
--- /dev/null
+++ b/sql/sql_tvc.cc
@@ -0,0 +1,128 @@
+#include "sql_list.h"
+#include "sql_tvc.h"
+#include "sql_class.h"
+
+/**
+ The method searches types of columns for temporary table where values from TVC will be stored
+*/
+
+bool join_type_handlers_for_tvc(List_iterator_fast<List_item> &li,
+ Type_holder *holders, uint cnt)
+{
+ List_item *lst;
+ li.rewind();
+ bool first= true;
+
+ while ((lst=li++))
+ {
+ List_iterator_fast<Item> it(*lst);
+ Item *item;
+
+ if (cnt != lst->elements)
+ {
+ /*error wrong number of values*/
+ return true;
+ }
+ for (uint pos= 0; (item=it++); pos++)
+ {
+ const Type_handler *item_type_handler= item->real_type_handler();
+ if (first)
+ holders[pos].set_handler(item_type_handler);
+ else if (holders[pos].aggregate_for_result(item_type_handler))
+ {
+ /*error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION*/
+ return true;
+ }
+ }
+ first= false;
+ }
+ return false;
+}
+
+/**
+ The method searches names of columns for temporary table where values from TVC will be stored
+*/
+
+bool get_type_attributes_for_tvc(THD *thd_arg,
+ List_iterator_fast<List_item> &li,
+ Type_holder *holders, uint count)
+{
+ List_item *lst;
+ li.rewind();
+
+ lst= li++;
+ uint first_list_el_count= lst->elements;
+
+ for (uint pos= 0; pos < first_list_el_count; pos++)
+ {
+ if (holders[pos].alloc_arguments(thd_arg, count))
+ return true;
+ }
+
+ List_iterator_fast<Item> it(*lst);
+ Item *item;
+
+ for (uint holder_pos= 0 ; (item= it++); holder_pos++)
+ {
+ DBUG_ASSERT(item->fixed);
+ holders[holder_pos].add_argument(item);
+ }
+
+ for (uint pos= 0; pos < first_list_el_count; pos++)
+ {
+ if (holders[pos].aggregate_attributes(thd_arg))
+ return true;
+ }
+ return false;
+}
+
+bool table_value_constr::prepare(THD *thd_arg, SELECT_LEX *sl, select_result *tmp_result)
+{
+ List_iterator_fast<List_item> li(lists_of_values);
+
+ List_item *first_elem= li++;
+ uint cnt= first_elem->elements;
+ Type_holder *holders;
+
+ if (!(holders= new (thd_arg->mem_root)
+ Type_holder[cnt]) ||
+ join_type_handlers_for_tvc(li, holders, cnt) ||
+ get_type_attributes_for_tvc(thd_arg, li, holders, cnt))
+ return true;
+
+ List_iterator_fast<Item> it(*first_elem);
+ Item *item;
+
+ sl->item_list.empty();
+ for (uint pos= 0; (item= it++); pos++)
+ {
+ /* Error's in 'new' will be detected after loop */
+ Item_type_holder *new_holder= new (thd_arg->mem_root)
+ Item_type_holder(thd_arg,
+ &item->name,
+ holders[pos].type_handler(),
+ &holders[pos]/*Type_all_attributes*/,
+ holders[pos].get_maybe_null());
+ new_holder->fix_fields(thd_arg, 0);
+ sl->item_list.push_back(new_holder);
+ }
+
+ if (thd_arg->is_fatal_error)
+ return true; // out of memory
+
+ result= tmp_result;
+
+ return false;
+}
+
+bool table_value_constr::exec()
+{
+ List_iterator_fast<List_item> li(lists_of_values);
+ List_item *elem;
+
+ while ((elem=li++))
+ {
+ result->send_data(*elem);
+ }
+ return false;
+} \ No newline at end of file
diff --git a/sql/sql_tvc.h b/sql/sql_tvc.h
new file mode 100644
index 00000000000..e5c3477351c
--- /dev/null
+++ b/sql/sql_tvc.h
@@ -0,0 +1,27 @@
+#ifndef SQL_TVC_INCLUDED
+#define SQL_TVC_INCLUDED
+#include "sql_type.h"
+#include "item.h"
+
+typedef List<Item> List_item;
+class select_result;
+
+/**
+ @class table_value_constr
+ @brief Definition of a Table Value Construction(TVC)
+
+ It contains a list of lists of values that this TVC contains.
+*/
+
+class table_value_constr : public Sql_alloc
+{
+public:
+ List<List_item> lists_of_values;
+ select_result *result;
+
+ bool prepare(THD *thd_arg, SELECT_LEX *sl,
+ select_result *tmp_result);
+ bool exec();
+};
+
+#endif /* SQL_TVC_INCLUDED */ \ No newline at end of file
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1c2ff2b012b..c5cedf795a3 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -692,64 +692,6 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl,
}
-class Type_holder: public Sql_alloc,
- public Item_args,
- public Type_handler_hybrid_field_type,
- public Type_all_attributes,
- public Type_geometry_attributes
-{
- TYPELIB *m_typelib;
- bool m_maybe_null;
-public:
- Type_holder()
- :m_typelib(NULL),
- m_maybe_null(false)
- { }
-
- void set_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; }
- bool get_maybe_null() const { return m_maybe_null; }
-
- uint decimal_precision() const
- {
- /*
- Type_holder is not used directly to create fields, so
- its virtual decimal_precision() is never called.
- We should eventually extend create_result_table() to accept
- an array of Type_holders directly, without having to allocate
- Item_type_holder's and put them into List<Item>.
- */
- DBUG_ASSERT(0);
- return 0;
- }
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
- uint uint_geometry_type() const
- {
- return Type_geometry_attributes::get_geometry_type();
- }
- void set_typelib(TYPELIB *typelib)
- {
- m_typelib= typelib;
- }
- TYPELIB *get_typelib() const
- {
- return m_typelib;
- }
-
- bool aggregate_attributes(THD *thd)
- {
- for (uint i= 0; i < arg_count; i++)
- m_maybe_null|= args[i]->maybe_null;
- return
- type_handler()->Item_hybrid_func_fix_attributes(thd,
- "UNION", this, this,
- args, arg_count);
- }
-};
-
-
/**
Aggregate data type handlers for the "count" leftmost UNION parts.
*/
@@ -978,7 +920,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (!is_union_select && !is_recursive)
{
- if (prepare_join(thd_arg, first_sl, tmp_result, additional_options,
+ if (sl->tvc)
+ {
+ if (sl->tvc->prepare(thd_arg, sl, tmp_result))
+ goto err;
+ }
+ else if (prepare_join(thd_arg, first_sl, tmp_result, additional_options,
is_union_select))
goto err;
types= first_sl->item_list;
@@ -987,8 +934,13 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
for (;sl; sl= sl->next_select(), union_part_count++)
{
- if (prepare_join(thd_arg, sl, tmp_result, additional_options,
- is_union_select))
+ if (sl->tvc)
+ {
+ if (sl->tvc->prepare(thd_arg, sl, tmp_result))
+ goto err;
+ }
+ else if (prepare_join(thd_arg, sl, tmp_result, additional_options,
+ is_union_select))
goto err;
/*
@@ -1296,6 +1248,8 @@ bool st_select_lex_unit::optimize()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
+ if (sl->tvc)
+ continue;
thd->lex->current_select= sl;
if (optimized)
@@ -1411,6 +1365,8 @@ bool st_select_lex_unit::exec()
if (!saved_error)
{
records_at_start= table->file->stats.records;
+ if (sl->tvc)
+ sl->tvc->exec();
sl->join->exec();
if (sl == union_distinct && !(with_element && with_element->is_recursive))
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a0bbf39b138..d6aceeaa8a6 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1822,11 +1822,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <select_lex> subselect
get_select_lex get_select_lex_derived
+ simple_table
query_specification
query_term_union_not_ready
query_term_union_ready
query_expression_body
select_paren_derived
+ table_value_constructor
%type <boolfunc2creator> comp_op
@@ -8467,6 +8469,9 @@ select:
select_init:
SELECT_SYM select_options_and_item_list select_init3
+ | table_value_constructor
+ | table_value_constructor union_list
+ | table_value_constructor union_order_or_limit
| '(' select_paren ')'
| '(' select_paren ')' union_list
| '(' select_paren ')' union_order_or_limit
@@ -8474,6 +8479,9 @@ select_init:
union_list_part2:
SELECT_SYM select_options_and_item_list select_init3_union_query_term
+ | table_value_constructor
+ | table_value_constructor union_list
+ | table_value_constructor union_order_or_limit
| '(' select_paren_union_query_term ')'
| '(' select_paren_union_query_term ')' union_list
| '(' select_paren_union_query_term ')' union_order_or_limit
@@ -8481,6 +8489,14 @@ union_list_part2:
select_paren:
{
+ Lex->current_select->set_braces(true);
+ }
+ table_value_constructor
+ {
+ DBUG_ASSERT(Lex->current_select->braces);
+ }
+ |
+ {
/*
In order to correctly parse UNION's global ORDER BY we need to
set braces before parsing the clause.
@@ -9443,7 +9459,7 @@ column_default_non_parenthesized_expr:
if ($$ == NULL)
MYSQL_YYABORT;
}
- | VALUES '(' simple_ident_nospvar ')'
+ | VALUE_SYM '(' simple_ident_nospvar ')'
{
$$= new (thd->mem_root) Item_insert_value(thd, Lex->current_context(),
$3);
@@ -16250,6 +16266,21 @@ union_option:
| ALL { $$=0; }
;
+simple_table:
+ query_specification { $$= $1; }
+ | table_value_constructor { $$= $1; }
+ ;
+
+table_value_constructor:
+ VALUES values_list
+ {
+ LEX *lex=Lex;
+ $$= Lex->current_select;
+ mysql_init_select(Lex);
+ $$->tvc->lists_of_values= lex->many_values;
+ }
+ ;
+
/*
Corresponds to the SQL Standard
<query specification> ::=
@@ -16267,12 +16298,12 @@ query_specification:
;
query_term_union_not_ready:
- query_specification order_or_limit opt_select_lock_type { $$= $1; }
+ simple_table order_or_limit opt_select_lock_type { $$= $1; }
| '(' select_paren_derived ')' union_order_or_limit { $$= $2; }
;
query_term_union_ready:
- query_specification opt_select_lock_type { $$= $1; }
+ simple_table opt_select_lock_type { $$= $1; }
| '(' select_paren_derived ')' { $$= $2; }
;
@@ -16534,6 +16565,9 @@ view_select:
*/
query_expression_body_view:
SELECT_SYM select_options_and_item_list select_init3_view
+ | table_value_constructor
+ | table_value_constructor union_order_or_limit
+ | table_value_constructor union_list_view
| '(' select_paren_view ')'
| '(' select_paren_view ')' union_order_or_limit
| '(' select_paren_view ')' union_list_view