summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc190
1 files changed, 146 insertions, 44 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5cc7798fde9..aa08420931f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -165,10 +165,6 @@ static COND *optimize_cond(JOIN *join, COND *conds,
int flags= 0);
bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static int do_select(JOIN *join, Procedure *procedure);
-static bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
- MARIA_COLUMNDEF *start_recinfo,
- MARIA_COLUMNDEF **recinfo,
- ulonglong options);
static enum_nested_loop_state evaluate_join_record(JOIN *, JOIN_TAB *, int);
static enum_nested_loop_state
@@ -699,7 +695,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
DBUG_ENTER("JOIN::prepare");
// to prevent double initialization on EXPLAIN
- if (optimized)
+ if (optimization_state != JOIN::NOT_OPTIMIZED)
DBUG_RETURN(0);
conds= conds_init;
@@ -858,6 +854,13 @@ JOIN::prepare(TABLE_LIST *tables_init,
With_clause *with_clause=select_lex->get_with_clause();
if (with_clause && with_clause->prepare_unreferenced_elements(thd))
DBUG_RETURN(1);
+
+ With_element *with_elem= select_lex->get_with_element();
+ if (with_elem &&
+ select_lex->check_unrestricted_recursive(
+ thd->variables.only_standards_compliant_cte))
+ DBUG_RETURN(-1);
+ select_lex->check_subqueries_with_recursive_references();
int res= check_and_do_in_subquery_rewrites(this);
@@ -1065,24 +1068,13 @@ err:
int JOIN::optimize()
{
- bool was_optimized= optimized;
+ // to prevent double initialization on EXPLAIN
+ if (optimization_state != JOIN::NOT_OPTIMIZED)
+ return FALSE;
+ optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS;
+
int res= optimize_inner();
- /*
- If we're inside a non-correlated subquery, this function may be
- called for the second time after the subquery has been executed
- and deleted. The second call will not produce a valid query plan, it will
- short-circuit because optimized==TRUE.
-
- "was_optimized != optimized" is here to handle this case:
- - first optimization starts, gets an error (from a const. cheap
- subquery), returns 1
- - another JOIN::optimize() call made, and now join->optimize() will
- return 0, even though we never had a query plan.
-
- Can have QEP_NOT_PRESENT_YET for degenerate queries (for example,
- SELECT * FROM tbl LIMIT 0)
- */
- if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
+ if (!res && have_query_plan != QEP_DELETED)
{
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE;
@@ -1109,6 +1101,7 @@ int JOIN::optimize()
}
}
+ optimization_state= JOIN::OPTIMIZATION_DONE;
return res;
}
@@ -1128,16 +1121,15 @@ int JOIN::optimize()
int
JOIN::optimize_inner()
{
+/*
+ if (conds) { Item *it_clone= conds->build_clone(thd,thd->mem_root); }
+*/
ulonglong select_opts_for_readinfo;
uint no_jbuf_after;
JOIN_TAB *tab;
DBUG_ENTER("JOIN::optimize");
-
do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
- // to prevent double initialization on EXPLAIN
- if (optimized)
- DBUG_RETURN(0);
- optimized= 1;
+
DEBUG_SYNC(thd, "before_join_optimize");
THD_STAGE_INFO(thd, stage_optimizing);
@@ -1145,10 +1137,6 @@ JOIN::optimize_inner()
set_allowed_join_cache_types();
need_distinct= TRUE;
- /* Run optimize phase for all derived tables/views used in this SELECT. */
- if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
- DBUG_RETURN(1);
-
if (select_lex->first_cond_optimization)
{
//Do it only for the first execution
@@ -1261,8 +1249,49 @@ JOIN::optimize_inner()
if (setup_jtbm_semi_joins(this, join_list, &conds))
DBUG_RETURN(1);
+ if (select_lex->cond_pushed_into_where)
+ {
+ conds= and_conds(thd, conds, select_lex->cond_pushed_into_where);
+ if (conds && conds->fix_fields(thd, &conds))
+ DBUG_RETURN(1);
+ }
+ if (select_lex->cond_pushed_into_having)
+ {
+ having= and_conds(thd, having, select_lex->cond_pushed_into_having);
+ if (having)
+ {
+ select_lex->having_fix_field= 1;
+ if (having->fix_fields(thd, &having))
+ DBUG_RETURN(1);
+ select_lex->having_fix_field= 0;
+ }
+ }
+
conds= optimize_cond(this, conds, join_list, FALSE,
&cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS);
+
+ if (thd->lex->sql_command == SQLCOM_SELECT &&
+ optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
+ {
+ TABLE_LIST *tbl;
+ List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
+ while ((tbl= li++))
+ {
+ if (tbl->is_materialized_derived())
+ {
+ if (pushdown_cond_for_derived(thd, conds, tbl))
+ DBUG_RETURN(1);
+ if (mysql_handle_single_derived(thd->lex, tbl, DT_OPTIMIZE))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ else
+ {
+ /* Run optimize phase for all derived tables/views used in this SELECT. */
+ if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
+ DBUG_RETURN(1);
+ }
if (thd->is_error())
{
@@ -3166,6 +3195,7 @@ void JOIN::exec_inner()
{
List<Item> *columns_list= &fields_list;
DBUG_ENTER("JOIN::exec_inner");
+ DBUG_ASSERT(optimization_state == JOIN::OPTIMIZATION_DONE);
THD_STAGE_INFO(thd, stage_executing);
@@ -3668,6 +3698,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
s->checked_keys.init();
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
+ s->tab_list= tables;
table->pos_in_table_list= tables;
error= tables->fetch_number_of_rows();
set_statistics_for_table(join->thd, table);
@@ -8357,6 +8388,8 @@ JOIN_TAB *first_explain_order_tab(JOIN* join)
{
JOIN_TAB* tab;
tab= join->join_tab;
+ if (!tab)
+ return NULL; /* Can happen when when the tables were optimized away */
return (tab->bush_children) ? tab->bush_children->start : tab;
}
@@ -11419,6 +11452,11 @@ bool error_if_full_join(JOIN *join)
void JOIN_TAB::cleanup()
{
DBUG_ENTER("JOIN_TAB::cleanup");
+
+ if (tab_list && tab_list->is_with_table_recursive_reference() &&
+ tab_list->with->is_cleaned())
+ DBUG_VOID_RETURN;
+
DBUG_PRINT("enter", ("tab: %p table %s.%s",
this,
(table ? table->s->db.str : "?"),
@@ -11588,7 +11626,8 @@ bool JOIN_TAB::preread_init()
}
/* Materialize derived table/view. */
- if (!derived->get_unit()->executed &&
+ if ((!derived->get_unit()->executed ||
+ derived->is_recursive_with_table()) &&
mysql_handle_single_derived(join->thd->lex,
derived, DT_CREATE | DT_FILL))
return TRUE;
@@ -15745,7 +15784,7 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length)
Field_double(max_length, maybe_null, name, decimals, TRUE);
break;
case INT_RESULT:
- /*
+ /*
Select an integer type with the minimal fit precision.
convert_int_length is sign inclusive, don't consider the sign.
*/
@@ -15761,7 +15800,6 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length)
break;
case STRING_RESULT:
DBUG_ASSERT(collation.collation);
-
/*
GEOMETRY fields have STRING_RESULT result type.
To preserve type they needed to be handled separately.
@@ -17943,7 +17981,6 @@ int rr_sequential_and_unpack(READ_RECORD *info)
TRUE - Error
*/
-static
bool instantiate_tmp_table(TABLE *table, KEY *keyinfo,
MARIA_COLUMNDEF *start_recinfo,
MARIA_COLUMNDEF **recinfo,
@@ -19218,7 +19255,7 @@ int join_init_read_record(JOIN_TAB *tab)
report_error(tab->table, error);
return 1;
}
- if (!tab->preread_init_done && tab->preread_init())
+ if (!tab->preread_init_done && tab->preread_init())
return 1;
if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select, tab->filesort_result, 1,1, FALSE))
@@ -19451,8 +19488,6 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!end_of_records)
{
-#if 0
-#endif
if (join->table_count &&
join->join_tab->is_using_loose_index_scan())
{
@@ -24321,7 +24356,8 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
In case this is a derived table, here we remember the number of
subselect that used to produce it.
*/
- eta->derived_select_number= table->derived_select_number;
+ if (!(table_list && table_list->is_with_table_recursive_reference()))
+ eta->derived_select_number= table->derived_select_number;
/* The same for non-merged semi-joins */
eta->non_merged_sjm_number = get_non_merged_semijoin_select();
@@ -24537,11 +24573,14 @@ int JOIN::save_explain_data_intern(Explain_query *output,
(1) they are not parts of ON clauses that were eliminated by table
elimination.
(2) they are not merged derived tables
+ (3) they are not unreferenced CTE
*/
if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1)
(!tmp_unit->derived ||
- tmp_unit->derived->is_materialized_derived())) // (2)
- {
+ tmp_unit->derived->is_materialized_derived()) && // (2)
+ !(tmp_unit->with_element &&
+ !tmp_unit->with_element->is_referenced())) // (3)
+ {
explain->add_child(tmp_unit->first_select()->select_number);
}
}
@@ -24601,9 +24640,11 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
Save plans for child subqueries, when
(1) they are not parts of eliminated WHERE/ON clauses.
(2) they are not VIEWs that were "merged for INSERT".
+ (3) they are not unreferenced CTE.
*/
- if (!(unit->item && unit->item->eliminated) && // (1)
- !(unit->derived && unit->derived->merged_for_insert)) // (2)
+ if (!(unit->item && unit->item->eliminated) && // (1)
+ !(unit->derived && unit->derived->merged_for_insert) && // (2)
+ !(unit->with_element && !unit->with_element->is_referenced())) // (3)
{
if (mysql_explain_union(thd, unit, result))
DBUG_VOID_RETURN;
@@ -24627,7 +24668,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
if (unit->is_union())
{
- if (unit->union_needs_tmp_table())
+ if (unit->union_needs_tmp_table() && unit->fake_select_lex)
{
unit->fake_select_lex->select_number= FAKE_SELECT_LEX_ID; // just for initialization
unit->fake_select_lex->type= "UNION RESULT";
@@ -25147,6 +25188,12 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
// limit
print_limit(thd, str, query_type);
+ // lock type
+ if (lock_type == TL_READ_WITH_SHARED_LOCKS)
+ str->append(" lock in share mode");
+ else if (lock_type == TL_WRITE)
+ str->append(" for update");
+
// PROCEDURE unsupported here
}
@@ -26193,5 +26240,60 @@ AGGR_OP::end_send()
/**
+ @brief
+ Remove marked top conjuncts of a condition
+
+ @param thd The thread handle
+ @param cond The condition which subformulas are to be removed
+
+ @details
+ The function removes all top conjuncts marked with the flag
+ FULL_EXTRACTION_FL from the condition 'cond'. The resulting
+ formula is returned a the result of the function
+ If 'cond' s marked with such flag the function returns 0.
+ The function clear the extraction flags for the removed
+ formulas
+
+ @retval
+ condition without removed subformulas
+ 0 if the whole 'cond' is removed
+*/
+
+Item *remove_pushed_top_conjuncts(THD *thd, Item *cond)
+{
+ if (cond->get_extraction_flag() == FULL_EXTRACTION_FL)
+ {
+ cond->clear_extraction_flag();
+ return 0;
+ }
+ if (cond->type() == Item::COND_ITEM)
+ {
+ if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->get_extraction_flag() == FULL_EXTRACTION_FL)
+ {
+ item->clear_extraction_flag();
+ li.remove();
+ }
+ }
+ switch (((Item_cond*) cond)->argument_list()->elements)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return ((Item_cond*) cond)->argument_list()->head();
+ default:
+ return cond;
+ }
+ }
+ }
+ return cond;
+}
+
+/**
@} (end of group Query_Optimizer)
*/