summaryrefslogtreecommitdiff
path: root/sql/sql_tvc.cc
diff options
context:
space:
mode:
authorGalina Shalygina <galashalygina@gmail.com>2017-08-29 02:32:39 +0200
committerGalina Shalygina <galashalygina@gmail.com>2017-08-29 02:32:39 +0200
commit570d2e7d0f2c48f9662804eb69e47ce12f983696 (patch)
tree76eecad3e08adf57567ee66f61414bf4551d722d /sql/sql_tvc.cc
parent3310076dbe781e0554519fba5c4a2585a463250f (diff)
downloadmariadb-git-570d2e7d0f2c48f9662804eb69e47ce12f983696.tar.gz
Summarized results of two previous commits (26 July, 25 August)
Diffstat (limited to 'sql/sql_tvc.cc')
-rw-r--r--sql/sql_tvc.cc570
1 files changed, 539 insertions, 31 deletions
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 323ce5eacb9..e9476254f9e 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -1,14 +1,40 @@
#include "sql_list.h"
#include "sql_tvc.h"
#include "sql_class.h"
+#include "opt_range.h"
+#include "sql_select.h"
+#include "sql_explain.h"
+#include "sql_parse.h"
/**
- The method searches types of columns for temporary table where values from TVC will be stored
+ @brief
+ Defines types of matrix columns elements where matrix rows are defined by
+ some lists of values.
+
+ @param
+ @param thd_arg The context of the statement
+ @param li The iterator on the list of lists
+ @param holders The structure where types of matrix columns are stored
+ @param first_list_el_count Count of the list values that should be. It should
+ be the same for each list of lists elements. It contains
+ number of elements of the first list from list of lists.
+
+ @details
+ For each list list_a from list of lists the procedure gets its elements types and
+ aggregates them with the previous ones stored in holders. If list_a is the first
+ one in the list of lists its elements types are put in holders.
+ The errors can be reported when count of list_a elements is different from the
+ first_list_el_count. Also error can be reported when aggregation can't be made.
+
+ @retval
+ true if an error was reported
+ false otherwise
*/
-bool join_type_handlers_for_tvc(List_iterator_fast<List_item> &li,
- Type_holder *holders, uint cnt)
+bool join_type_handlers_for_tvc(THD *thd_arg, List_iterator_fast<List_item> &li,
+ Type_holder *holders, uint first_list_el_count)
{
+ DBUG_ENTER("join_type_handlers_for_tvc");
List_item *lst;
li.rewind();
bool first= true;
@@ -18,10 +44,12 @@ bool join_type_handlers_for_tvc(List_iterator_fast<List_item> &li,
List_iterator_fast<Item> it(*lst);
Item *item;
- if (cnt != lst->elements)
+ if (first_list_el_count != lst->elements)
{
- /*error wrong number of values*/
- return true;
+ my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_TABLE_VALUE_CONSTRUCTOR,
+ ER_THD(thd_arg, ER_WRONG_NUMBER_OF_COLUMNS_IN_TABLE_VALUE_CONSTRUCTOR),
+ MYF(0));
+ DBUG_RETURN(true);
}
for (uint pos= 0; (item=it++); pos++)
{
@@ -30,54 +58,105 @@ bool join_type_handlers_for_tvc(List_iterator_fast<List_item> &li,
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;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
+ holders[pos].type_handler()->name().ptr(),
+ item_type_handler->name().ptr(),
+ "TABLE VALUE CONSTRUCTOR");
+ DBUG_RETURN(true);
}
}
first= false;
}
- return false;
+ DBUG_RETURN(false);
}
+
/**
- The method searches names of columns for temporary table where values from TVC will be stored
+ @brief
+ Defines attributes of matrix columns elements where matrix rows are defined by
+ some lists of values.
+
+ @param
+ @param thd_arg The context of the statement
+ @param li The iterator on the list of lists
+ @param holders The structure where names of matrix columns are stored
+ @param count_of_lists Count of list of lists elements
+ @param first_list_el_count Count of the list values that should be. It should
+ be the same for each list of lists elements. It contains
+ number of elements of the first list from list of lists.
+
+ @details
+ For each list list_a from list of lists the procedure gets its elements attributes and
+ aggregates them with the previous ones stored in holders.
+ The errors can be reported when aggregation can't be made.
+
+ @retval
+ true if an error was reported
+ false otherwise
*/
bool get_type_attributes_for_tvc(THD *thd_arg,
List_iterator_fast<List_item> &li,
- Type_holder *holders, uint count)
+ Type_holder *holders, uint count_of_lists,
+ uint first_list_el_count)
{
+ DBUG_ENTER("get_type_attributes_for_tvc");
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;
+ if (holders[pos].alloc_arguments(thd_arg, count_of_lists))
+ DBUG_RETURN(true);
}
- List_iterator_fast<Item> it(*lst);
- Item *item;
-
- for (uint holder_pos= 0 ; (item= it++); holder_pos++)
+ while ((lst=li++))
{
- DBUG_ASSERT(item->fixed);
- holders[holder_pos].add_argument(item);
+ 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;
+ DBUG_RETURN(true);
}
- return false;
+ DBUG_RETURN(false);
}
-bool table_value_constr::prepare(THD *thd_arg, SELECT_LEX *sl, select_result *tmp_result)
+
+/**
+ @brief
+ Prepare of TVC
+
+ @param
+ @param thd_arg The context of the statement
+ @param sl The select where this TVC is defined
+ @param tmp_result Structure that contains the information
+ about where result of the query should be sent
+ @param unit_arg The union where sl is defined
+
+ @details
+ Gets types and attributes of values of this TVC that will be used
+ for temporary table creation for this TVC. It creates Item_type_holders
+ for each element of the first list from list of lists (VALUES from tvc),
+ using its elements name, defined type and attribute.
+
+ @retval
+ true if an error was reported
+ false otherwise
+*/
+
+bool table_value_constr::prepare(THD *thd_arg, SELECT_LEX *sl,
+ select_result *tmp_result,
+ st_select_lex_unit *unit_arg)
{
+ DBUG_ENTER("table_value_constr::prepare");
List_iterator_fast<List_item> li(lists_of_values);
List_item *first_elem= li++;
@@ -86,9 +165,11 @@ bool table_value_constr::prepare(THD *thd_arg, SELECT_LEX *sl, select_result *tm
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;
+ join_type_handlers_for_tvc(thd_arg, li, holders,
+ cnt) ||
+ get_type_attributes_for_tvc(thd_arg, li, holders,
+ lists_of_values.elements, cnt))
+ DBUG_RETURN(true);
List_iterator_fast<Item> it(*first_elem);
Item *item;
@@ -108,21 +189,448 @@ bool table_value_constr::prepare(THD *thd_arg, SELECT_LEX *sl, select_result *tm
}
if (thd_arg->is_fatal_error)
- return true; // out of memory
+ DBUG_RETURN(true); // out of memory
result= tmp_result;
- return false;
+ if (result && result->prepare(sl->item_list, unit_arg))
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
}
-bool table_value_constr::exec()
+
+/**
+ Save Query Plan Footprint
+*/
+
+int table_value_constr::save_explain_data_intern(THD *thd_arg,
+ Explain_query *output)
{
+ const char *message= "No tables used";
+ DBUG_ENTER("table_value_constr::save_explain_data_intern");
+ DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
+ (ulong)select_lex, select_lex->type,
+ message));
+ DBUG_ASSERT(have_query_plan == QEP_AVAILABLE);
+
+ /* There should be no attempts to save query plans for merged selects */
+ DBUG_ASSERT(!select_lex->master_unit()->derived ||
+ select_lex->master_unit()->derived->is_materialized_derived() ||
+ select_lex->master_unit()->derived->is_with_table());
+
+ explain= new (output->mem_root) Explain_select(output->mem_root,
+ thd_arg->lex->analyze_stmt);
+ select_lex->set_explain_type(true);
+
+ explain->select_id= select_lex->select_number;
+ explain->select_type= select_lex->type;
+ explain->linkage= select_lex->linkage;
+ explain->using_temporary= NULL;
+ explain->using_filesort= NULL;
+ /* Setting explain->message means that all other members are invalid */
+ explain->message= message;
+
+ if (select_lex->master_unit()->derived)
+ explain->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
+
+ output->add_node(explain);
+
+ if (select_lex->is_top_level_node())
+ output->query_plan_ready();
+
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Optimization of TVC
+*/
+
+void table_value_constr::optimize(THD *thd_arg)
+{
+ create_explain_query_if_not_exists(thd_arg->lex, thd_arg->mem_root);
+ have_query_plan= QEP_AVAILABLE;
+
+ if (select_lex->select_number != UINT_MAX &&
+ select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
+ have_query_plan != QEP_NOT_PRESENT_YET &&
+ thd_arg->lex->explain && // for "SET" command in SPs.
+ (!thd_arg->lex->explain->get_select(select_lex->select_number)))
+ {
+ save_explain_data_intern(thd_arg, thd_arg->lex->explain);
+ }
+}
+
+
+/**
+ Execute of TVC
+*/
+
+bool table_value_constr::exec(SELECT_LEX *sl)
+{
+ DBUG_ENTER("table_value_constr::exec");
List_iterator_fast<List_item> li(lists_of_values);
List_item *elem;
+ if (select_options & SELECT_DESCRIBE)
+ DBUG_RETURN(false);
+
+ if (result->send_result_set_metadata(sl->item_list,
+ Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ {
+ DBUG_RETURN(true);
+ }
+
while ((elem=li++))
{
result->send_data(*elem);
}
+
+ if (result->send_eof())
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
+}
+
+/**
+ @brief
+ Print list of lists
+
+ @param str Where to print to
+ @param query_type The mode of printing
+ @param values List of lists that needed to be print
+
+ @details
+ The method prints a string representation of list of lists in the
+ string str. The parameter query_type specifies the mode of printing.
+*/
+
+void print_list_of_lists(String *str,
+ enum_query_type query_type,
+ List<List_item> *values)
+{
+ str->append(STRING_WITH_LEN("values "));
+
+ bool first= 1;
+ List_iterator_fast<List_item> li(*values);
+ List_item *list;
+ while ((list=li++))
+ {
+ if (first)
+ first= 0;
+ else
+ str->append(',');
+
+ str->append('(');
+
+ List_iterator_fast<Item> it(*list);
+ Item *item;
+ first= 1;
+
+ while ((item=it++))
+ {
+ if (first)
+ first= 0;
+ else
+ str->append(',');
+
+ item->print(str, query_type);
+ }
+ str->append(')');
+ }
+}
+
+
+/**
+ @brief
+ Print this TVC
+
+ @param thd_arg The context of the statement
+ @param str Where to print to
+ @param query_type The mode of printing
+
+ @details
+ The method prints a string representation of this TVC in the
+ string str. The parameter query_type specifies the mode of printing.
+*/
+
+void table_value_constr::print(THD *thd_arg, String *str,
+ enum_query_type query_type)
+{
+ DBUG_ASSERT(thd_arg);
+
+ print_list_of_lists(str, query_type, &lists_of_values);
+}
+
+
+/**
+ @brief
+ Creates new SELECT defined by TVC as derived table
+
+ @param thd_arg The context of the statement
+ @param values List of values that defines TVC
+
+ @details
+ The method creates this SELECT statement:
+
+ SELECT * FROM (VALUES values) AS new_tvc
+
+ If during creation of SELECT statement some action is
+ unsuccesfull backup is made to the state in which system
+ was at the beginning of the method.
+
+ @retval
+ pointer to the created SELECT statement
+ NULL - if creation was unsuccesfull
+*/
+
+st_select_lex *make_new_subselect_for_tvc(THD *thd_arg,
+ List<List_item> *values)
+{
+ LEX *lex= thd_arg->lex;
+ Item *item;
+ SELECT_LEX *sel;
+ SELECT_LEX_UNIT *unit;
+ TABLE_LIST *new_tab;
+ Table_ident *ti;
+
+ Query_arena backup;
+ Query_arena *arena= thd_arg->activate_stmt_arena_if_needed(&backup);
+
+ char buff[6];
+ LEX_CSTRING alias;
+ alias.length= my_snprintf(buff, sizeof(buff),
+ "tvc_%u", thd_arg->lex->current_select->cur_tvc);
+ alias.str= thd_arg->strmake(buff, alias.length);
+ if (!alias.str)
+ goto err;
+
+ /*
+ Creation of SELECT statement: SELECT * FROM ...
+ */
+
+ if (mysql_new_select(lex, 1, NULL))
+ goto err;
+
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= SELECT_LIST;
+
+ item= new (thd_arg->mem_root)
+ Item_field(thd_arg, &lex->current_select->context,
+ NULL, NULL, &star_clex_str);
+ if (item == NULL)
+ goto err;
+ if (add_item_to_list(thd_arg, item))
+ goto err;
+ (lex->current_select->with_wild)++;
+
+ /*
+ Creation of TVC as derived table
+ */
+
+ lex->derived_tables|= DERIVED_SUBQUERY;
+ if (mysql_new_select(lex, 1, NULL))
+ goto err;
+
+ mysql_init_select(lex);
+
+ sel= lex->current_select;
+ unit= sel->master_unit();
+ sel->linkage= DERIVED_TABLE_TYPE;
+
+ if (!(sel->tvc=
+ new (thd_arg->mem_root)
+ table_value_constr(*values,
+ sel,
+ sel->options)))
+ goto err;
+
+ lex->check_automatic_up(UNSPECIFIED_TYPE);
+ lex->current_select= sel= unit->outer_select();
+
+ ti= new (thd_arg->mem_root) Table_ident(unit);
+ if (ti == NULL)
+ goto err;
+
+ if (!(new_tab= sel->add_table_to_list(thd_arg,
+ ti, &alias, 0,
+ TL_READ, MDL_SHARED_READ)))
+ goto err;
+
+ new_tab->is_for_tvc= true; //shows that this derived table is defined by TVC
+ sel->add_joined_table(new_tab);
+
+ new_tab->select_lex->add_where_field(new_tab->derived->first_select());
+
+ sel->context.table_list=
+ sel->context.first_name_resolution_table=
+ sel->table_list.first;
+
+ sel->where= 0;
+ sel->set_braces(false);
+ unit->with_clause= 0;
+
+ return sel;
+
+err:
+ if (arena)
+ thd_arg->restore_active_arena(arena, &backup);
+ return NULL;
+}
+
+
+/**
+ @brief
+ Transforms IN-predicate in IN-subselect
+
+ @param thd_arg The context of the statement
+ @param arg Argument is 0 in this context
+
+ @details
+ The method creates this SELECT statement:
+
+ SELECT * FROM (VALUES values) AS new_tvc
+
+ If during creation of SELECT statement some action is
+ unsuccesfull backup is made to the state in which system
+ was at the beginning of the procedure.
+
+ @retval
+ pointer to the created SELECT statement
+ NULL - if creation was unsuccesfull
+*/
+
+Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
+ uchar *arg)
+{
+ SELECT_LEX *old_select= thd->lex->current_select;
+ List<List_item> values;
+ bool list_of_lists= false;
+
+ if (args[1]->type() == Item::ROW_ITEM)
+ list_of_lists= true;
+
+ for (uint i=1; i < arg_count; i++)
+ {
+ List<Item> *new_value= new (thd->mem_root) List<Item>();
+
+ if (list_of_lists)
+ {
+ Item_row *in_list= (Item_row *)(args[i]);
+
+ for (uint j=0; j < in_list->cols(); i++)
+ new_value->push_back(in_list->element_index(j), thd->mem_root);
+ }
+ else
+ new_value->push_back(args[i]);
+
+ values.push_back(new_value, thd->mem_root);
+ }
+
+ st_select_lex *new_subselect=
+ make_new_subselect_for_tvc(thd, &values);
+
+ if (new_subselect)
+ {
+ new_subselect->parsing_place= old_select->parsing_place;
+ new_subselect->table_list.first->derived_type= 10;
+
+ Item_in_subselect *in_subs= new (thd->mem_root) Item_in_subselect
+ (thd, args[0], new_subselect);
+ thd->lex->derived_tables |= DERIVED_SUBQUERY;
+ in_subs->emb_on_expr_nest= emb_on_expr_nest;
+ in_subs->fix_fields(thd, (Item **)&in_subs);
+
+ old_select->cur_tvc++;
+ thd->lex->current_select= old_select;
+ return in_subs;
+ }
+
+ thd->lex->current_select= old_select;
+ return this;
+}
+
+/**
+ @brief
+ Checks if this IN-predicate can be transformed in IN-subquery
+ with TVC
+
+ @param thd The context of the statement
+
+ @details
+ Compares the number of elements in the list of
+ values in this IN-predicate with the
+ in_subquery_conversion_threshold special variable
+
+ @retval
+ true if transformation can be made
+ false otherwise
+*/
+
+bool Item_func_in::can_be_transformed_in_tvc(THD *thd)
+{
+ uint opt_can_be_used= arg_count;
+
+ if (args[1]->type() == Item::ROW_ITEM)
+ opt_can_be_used*= ((Item_row *)(args[1]))->cols();
+
+ if (opt_can_be_used < thd->variables.in_subquery_conversion_threshold)
+ return false;
+
+ return true;
+}
+
+/**
+ @brief
+ Calls transformer that transforms IN-predicate into IN-subquery
+ for this select
+
+ @param thd_arg The context of the statement
+
+ @details
+ Calls in_predicate_to_in_subs_transformer
+ for WHERE-part and each table from join list of this SELECT
+*/
+
+bool JOIN::transform_in_predicate_into_tvc(THD *thd_arg)
+{
+ if (!select_lex->in_funcs.elements)
+ return false;
+
+ SELECT_LEX *old_select= thd_arg->lex->current_select;
+ enum_parsing_place old_parsing_place= select_lex->parsing_place;
+
+ thd_arg->lex->current_select= select_lex;
+ if (conds)
+ {
+ select_lex->parsing_place= IN_WHERE;
+ conds=
+ conds->transform(thd_arg,
+ &Item::in_predicate_to_in_subs_transformer,
+ (uchar*) 0);
+ select_lex->where= conds;
+ }
+
+ if (join_list)
+ {
+ TABLE_LIST *table;
+ List_iterator<TABLE_LIST> li(*join_list);
+ select_lex->parsing_place= IN_ON;
+
+ while ((table= li++))
+ {
+ if (table->on_expr)
+ {
+ table->on_expr=
+ table->on_expr->transform(thd_arg,
+ &Item::in_predicate_to_in_subs_transformer,
+ (uchar*) 0);
+ }
+ }
+ }
+ select_lex->parsing_place= old_parsing_place;
+ thd_arg->lex->current_select= old_select;
return false;
} \ No newline at end of file