diff options
author | Galina Shalygina <galashalygina@gmail.com> | 2017-06-29 15:32:17 +0300 |
---|---|---|
committer | Galina Shalygina <galashalygina@gmail.com> | 2017-06-29 15:36:07 +0300 |
commit | 615da8f70bd61aa0918c08a256638d90d425fe0e (patch) | |
tree | 16d6d48e705db076d42f56e5c8ecd10f00dde60d | |
parent | 0fe7d8a2a221196d977e5efe3f3dedb22806bb53 (diff) | |
download | mariadb-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.test | 30 | ||||
-rw-r--r-- | sql/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 58 | ||||
-rw-r--r-- | sql/sql_lex.h | 4 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 128 | ||||
-rw-r--r-- | sql/sql_tvc.h | 27 | ||||
-rw-r--r-- | sql/sql_union.cc | 78 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 40 |
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 |