summaryrefslogtreecommitdiff
path: root/sql/sql_derived.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_derived.cc')
-rw-r--r--sql/sql_derived.cc198
1 files changed, 152 insertions, 46 deletions
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 6785bf8e815..1f465a100c9 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -22,7 +22,7 @@
*/
-#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
#include "unireg.h"
#include "sql_derived.h"
@@ -175,10 +175,11 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases)
DBUG_ENTER("mysql_handle_single_derived");
DBUG_PRINT("enter", ("phases: 0x%x allowed: 0x%x alias: '%s'",
phases, allowed_phases,
- (derived->alias ? derived->alias : "<NULL>")));
+ (derived->alias.str ? derived->alias.str : "<NULL>")));
if (!lex->derived_tables)
DBUG_RETURN(FALSE);
+ derived->select_lex->changed_elements|= TOUCHED_SEL_DERIVED;
lex->thd->derived_tables_processing= TRUE;
for (uint phase= 0; phase < DT_PHASES; phase++)
@@ -336,7 +337,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
Query_arena *arena, backup;
DBUG_ENTER("mysql_derived_merge");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
if (derived->merged)
@@ -436,9 +437,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->prep_on_expr= expr->copy_andor_structure(thd);
}
if (derived->on_expr &&
- ((!derived->on_expr->fixed &&
- derived->on_expr->fix_fields(thd, &derived->on_expr)) ||
- derived->on_expr->check_cols(1)))
+ derived->on_expr->fix_fields_if_needed_for_bool(thd, &derived->on_expr))
{
res= TRUE; /* purecov: inspected */
goto exit_merge;
@@ -489,7 +488,7 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
{
DBUG_ENTER("mysql_derived_merge_for_insert");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
DBUG_PRINT("info", ("merged_for_insert: %d is_materialized_derived: %d "
"is_multitable: %d single_table_updatable: %d "
@@ -547,7 +546,7 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX_UNIT *unit= derived->get_unit();
DBUG_ENTER("mysql_derived_init");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
// Skip already prepared views/DT
@@ -622,11 +621,10 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived)
bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
{
SELECT_LEX_UNIT *unit= derived->get_unit();
- DBUG_ENTER("mysql_derived_prepare");
bool res= FALSE;
- DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
- unit));
+ DBUG_ENTER("mysql_derived_prepare");
+ DBUG_PRINT("enter", ("unit: %p table_list: %p alias: '%s'",
+ unit, derived, derived->alias.str));
if (!unit)
DBUG_RETURN(FALSE);
@@ -646,7 +644,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
table reference from a subquery for this.
*/
DBUG_ASSERT(derived->with->get_sq_rec_ref());
- if (mysql_derived_prepare(lex->thd, lex, derived->with->get_sq_rec_ref()))
+ if (unlikely(mysql_derived_prepare(lex->thd, lex,
+ derived->with->get_sq_rec_ref())))
DBUG_RETURN(TRUE);
}
@@ -659,7 +658,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
specification has been already prepared (a secondary recursive table
reference.
*/
- if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
+ if (!(derived->derived_result= new (thd->mem_root) select_unit(thd)))
DBUG_RETURN(TRUE); // out of memory
thd->create_tmp_table_for_derived= TRUE;
res= derived->derived_result->create_result_table(
@@ -667,10 +666,10 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
(first_select->options |
thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS),
- derived->alias, FALSE, FALSE);
+ &derived->alias, FALSE, FALSE, FALSE, 0);
thd->create_tmp_table_for_derived= FALSE;
- if (!res && !derived->table)
+ if (likely(!res) && !derived->table)
{
derived->derived_result->set_unit(unit);
derived->table= derived->derived_result->table;
@@ -690,7 +689,39 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
!(derived->is_multitable() &&
(thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI))))
+ {
+ /*
+ System versioned tables may still require to get versioning conditions
+ when modifying view (see vers_setup_conds()). Only UPDATE and DELETE are
+ affected because they use WHERE condition.
+ */
+ if (!unit->prepared &&
+ derived->table->versioned() &&
+ derived->merge_underlying_list &&
+ /* choose only those merged views that do not select from other views */
+ !derived->merge_underlying_list->merge_underlying_list)
+ {
+ switch (thd->lex->sql_command)
+ {
+ case SQLCOM_DELETE:
+ case SQLCOM_DELETE_MULTI:
+ case SQLCOM_UPDATE:
+ case SQLCOM_UPDATE_MULTI:
+ if ((res= first_select->vers_setup_conds(thd,
+ derived->merge_underlying_list)))
+ goto exit;
+ if (derived->merge_underlying_list->where)
+ {
+ Query_arena_stmt on_stmt_arena(thd);
+ derived->where= and_items(thd, derived->where,
+ derived->merge_underlying_list->where);
+ }
+ default:
+ break;
+ }
+ }
DBUG_RETURN(FALSE);
+ }
/* prevent name resolving out of derived table */
for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select())
@@ -719,8 +750,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
}
}
- unit->derived= derived;
-
/*
Above cascade call of prepare is important for PS protocol, but after it
is called we can check if we really need prepare for this derived
@@ -733,12 +762,12 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->fill_me= FALSE;
- if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
+ if (!(derived->derived_result= new (thd->mem_root) select_unit(thd)))
DBUG_RETURN(TRUE); // out of memory
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED;
// st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived->derived_result, 0)))
+ if ((res= unit->prepare(derived, derived->derived_result, 0)))
goto exit;
if (derived->with &&
(res= derived->with->rename_columns_of_derived_unit(thd, unit)))
@@ -761,7 +790,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
As 'distinct' parameter we always pass FALSE (0), because underlying
query will control distinct condition by itself. Correct test of
- distinct underlying query will be is_union &&
+ distinct underlying query will be is_unit_op &&
!unit->union_distinct->next_select() (i.e. it is union and last distinct
SELECT is last SELECT of UNION).
*/
@@ -771,8 +800,9 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
(first_select->options |
thd->variables.option_bits |
TMP_TABLE_ALL_COLUMNS),
- derived->alias,
- FALSE, FALSE, FALSE))
+ &derived->alias,
+ FALSE, FALSE, FALSE,
+ 0))
{
thd->create_tmp_table_for_derived= FALSE;
goto exit;
@@ -795,8 +825,8 @@ exit:
thd->get_stmt_da()->sql_errno() == ER_SP_DOES_NOT_EXIST))
{
thd->clear_error();
- my_error(ER_VIEW_INVALID, MYF(0), derived->db,
- derived->table_name);
+ my_error(ER_VIEW_INVALID, MYF(0), derived->db.str,
+ derived->table_name.str);
}
}
@@ -809,7 +839,7 @@ exit:
{
if (!derived->is_with_table_recursive_reference())
{
- if (derived->table)
+ if (derived->table && derived->table->s->tmp_table)
free_tmp_table(thd, derived->table);
delete derived->derived_result;
}
@@ -866,11 +896,10 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX_UNIT *unit= derived->get_unit();
SELECT_LEX *first_select= unit->first_select();
SELECT_LEX *save_current_select= lex->current_select;
-
bool res= FALSE;
DBUG_ENTER("mysql_derived_optimize");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
if (derived->merged)
{
@@ -878,12 +907,12 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
}
- if (unit->optimized)
- DBUG_RETURN(FALSE);
lex->current_select= first_select;
- if (unit->is_union())
+ if (unit->is_unit_op())
{
+ if (unit->optimized)
+ DBUG_RETURN(FALSE);
// optimize union without execution
res= unit->optimize();
}
@@ -893,7 +922,20 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
{
JOIN *join= first_select->join;
unit->set_limit(unit->global_parameters());
- unit->optimized= TRUE;
+ if (join &&
+ join->optimization_state == JOIN::OPTIMIZATION_PHASE_1_DONE &&
+ join->with_two_phase_optimization)
+ {
+ if (unit->optimized_2)
+ DBUG_RETURN(FALSE);
+ unit->optimized_2= TRUE;
+ }
+ else
+ {
+ if (unit->optimized)
+ DBUG_RETURN(FALSE);
+ unit->optimized= TRUE;
+ }
if ((res= join->optimize()))
goto err;
if (join->table_count == join->const_tables)
@@ -943,14 +985,14 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
{
DBUG_ENTER("mysql_derived_create");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
TABLE *table= derived->table;
SELECT_LEX_UNIT *unit= derived->get_unit();
if (table->is_created())
DBUG_RETURN(FALSE);
- select_union *result= derived->derived_result;
+ select_unit *result= derived->derived_result;
if (table->s->db_type() == TMP_ENGINE_HTON)
{
result->tmp_table_param.keyinfo= table->s->key_info;
@@ -969,6 +1011,20 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
}
+void TABLE_LIST::register_as_derived_with_rec_ref(With_element *rec_elem)
+{
+ rec_elem->derived_with_rec_ref.link_in_list(this, &this->next_with_rec_ref);
+ is_derived_with_recursive_reference= true;
+ get_unit()->uncacheable|= UNCACHEABLE_DEPENDENT;
+}
+
+
+bool TABLE_LIST::is_nonrecursive_derived_with_rec_ref()
+{
+ return is_derived_with_recursive_reference;
+}
+
+
/**
@brief
Fill the recursive with table
@@ -1044,7 +1100,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
bool res= FALSE;
DBUG_ENTER("mysql_derived_fill");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
if (unit->executed && !unit->uncacheable && !unit->describe &&
@@ -1052,9 +1108,25 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_RETURN(FALSE);
/*check that table creation passed without problems. */
DBUG_ASSERT(derived->table && derived->table->is_created());
- select_union *derived_result= derived->derived_result;
+ select_unit *derived_result= derived->derived_result;
SELECT_LEX *save_current_select= lex->current_select;
bool derived_recursive_is_filled= false;
+
+ if (unit->executed && !derived_is_recursive &&
+ (unit->uncacheable & UNCACHEABLE_DEPENDENT))
+ {
+ if ((res= derived->table->file->ha_delete_all_rows()))
+ goto err;
+ JOIN *join= unit->first_select()->join;
+ join->first_record= false;
+ for (uint i= join->top_join_tab_count;
+ i < join->top_join_tab_count + join->aggr_tables;
+ i++)
+ {
+ if ((res= join->join_tab[i].table->file->ha_delete_all_rows()))
+ goto err;
+ }
+ }
if (derived_is_recursive)
{
@@ -1070,7 +1142,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
derived_recursive_is_filled= true;
}
}
- else if (unit->is_union())
+ else if (unit->is_unit_op())
{
// execute union without clean up
res= unit->exec();
@@ -1122,10 +1194,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
}
}
}
-
- if (res || (!lex->describe &&
- (!derived_is_recursive ||
- derived_recursive_is_filled)))
+err:
+ if (res || (!lex->describe && !unit->uncacheable &&
+ (!derived_is_recursive || derived_recursive_is_filled)))
unit->cleanup();
lex->current_select= save_current_select;
@@ -1154,7 +1225,7 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived)
{
DBUG_ENTER("mysql_derived_reinit");
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
- (derived->alias ? derived->alias : "<NULL>"),
+ (derived->alias.str ? derived->alias.str : "<NULL>"),
derived->get_unit()));
st_select_lex_unit *unit= derived->get_unit();
@@ -1252,15 +1323,51 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
st_select_lex *save_curr_select= thd->lex->current_select;
for (; sl; sl= sl->next_select())
{
+ Item *extracted_cond_copy;
if (!sl->cond_pushdown_is_allowed())
continue;
thd->lex->current_select= sl;
+ if (sl->have_window_funcs())
+ {
+ if (sl->join->group_list || sl->join->implicit_grouping)
+ continue;
+ ORDER *common_partition_fields=
+ sl->find_common_window_func_partition_fields(thd);
+ if (!common_partition_fields)
+ continue;
+ extracted_cond_copy= !sl->next_select() ?
+ extracted_cond :
+ extracted_cond->build_clone(thd);
+ if (!extracted_cond_copy)
+ continue;
+
+ Item *cond_over_partition_fields;;
+ sl->collect_grouping_fields(thd, common_partition_fields);
+ sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
+ derived);
+ cond_over_partition_fields=
+ sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
+ if (cond_over_partition_fields)
+ cond_over_partition_fields= cond_over_partition_fields->transform(thd,
+ &Item::derived_grouping_field_transformer_for_where,
+ (uchar*) sl);
+ if (cond_over_partition_fields)
+ {
+ cond_over_partition_fields->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ sl->cond_pushed_into_where= cond_over_partition_fields;
+ }
+
+ continue;
+ }
+
/*
For each select of the unit except the last one
create a clone of extracted_cond
*/
- Item *extracted_cond_copy= !sl->next_select() ? extracted_cond :
- extracted_cond->build_clone(thd, thd->mem_root);
+ extracted_cond_copy= !sl->next_select() ?
+ extracted_cond :
+ extracted_cond->build_clone(thd);
if (!extracted_cond_copy)
continue;
@@ -1285,7 +1392,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
that could be pushed into the where clause of sl
*/
Item *cond_over_grouping_fields;
- sl->collect_grouping_fields(thd);
+ sl->collect_grouping_fields(thd, sl->join->group_list);
sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
derived);
cond_over_grouping_fields=
@@ -1333,4 +1440,3 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
thd->lex->current_select= save_curr_select;
DBUG_RETURN(false);
}
-