summaryrefslogtreecommitdiff
path: root/sql/sql_union.cc
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-10-19 21:45:18 +0200
committerSergei Golubchik <sergii@pisem.net>2011-10-19 21:45:18 +0200
commit76f0b94bb0b2994d639353530c5b251d0f1a204b (patch)
tree9ed50628aac34f89a37637bab2fc4915b86b5eb4 /sql/sql_union.cc
parent4e46d8e5bff140f2549841167dc4b65a3c0a645d (diff)
parent5dc1a2231f55bacc9aaf0e24816f3d9c2ee1f21d (diff)
downloadmariadb-git-76f0b94bb0b2994d639353530c5b251d0f1a204b.tar.gz
merge with 5.3
sql/sql_insert.cc: CREATE ... IF NOT EXISTS may do nothing, but it is still not a failure. don't forget to my_ok it. ****** CREATE ... IF NOT EXISTS may do nothing, but it is still not a failure. don't forget to my_ok it. sql/sql_table.cc: small cleanup ****** small cleanup
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r--sql/sql_union.cc175
1 files changed, 154 insertions, 21 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 3382eba260c..200140b5f6a 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -52,9 +52,8 @@ int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
-bool select_union::send_data(List<Item> &values)
+int select_union::send_data(List<Item> &values)
{
- int error= 0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
@@ -64,14 +63,22 @@ bool select_union::send_data(List<Item> &values)
if (thd->is_error())
return 1;
- if ((error= table->file->ha_write_row(table->record[0])))
+ if ((write_err= table->file->ha_write_tmp_row(table->record[0])))
{
+ if (write_err == HA_ERR_FOUND_DUPP_KEY)
+ {
+ /*
+ Inform upper level that we found a duplicate key, that should not
+ be counted as part of limit
+ */
+ return -1;
+ }
/* create_internal_tmp_table_from_heap will generate error if needed */
- if (table->file->is_fatal_error(error, HA_CHECK_DUP) &&
+ if (table->file->is_fatal_error(write_err, HA_CHECK_DUP) &&
create_internal_tmp_table_from_heap(thd, table,
tmp_table_param.start_recinfo,
- &tmp_table_param.recinfo, error,
- 1))
+ &tmp_table_param.recinfo,
+ write_err, 1))
return 1;
}
return 0;
@@ -108,6 +115,7 @@ bool select_union::flush()
options create options
table_alias name of the temporary table
bit_fields_as_long convert bit fields to ulonglong
+ create_table whether to physically create result table
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
@@ -122,7 +130,7 @@ bool
select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *alias,
- bool bit_fields_as_long)
+ bool bit_fields_as_long, bool create_table)
{
DBUG_ASSERT(table == 0);
tmp_table_param.init();
@@ -131,10 +139,19 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types,
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
- options, HA_POS_ERROR, alias)))
+ options, HA_POS_ERROR, alias,
+ !create_table)))
return TRUE;
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+
+ table->keys_in_use_for_query.clear_all();
+ for (uint i=0; i < table->s->fields; i++)
+ table->field[i]->flags &= ~PART_KEY_FLAG;
+
+ if (create_table)
+ {
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ }
return FALSE;
}
@@ -188,6 +205,8 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
{
(*order->item)->walk(&Item::change_context_processor, 0,
(uchar*) &fake_select_lex->context);
+ (*order->item)->walk(&Item::set_fake_select_as_master_processor, 0,
+ (uchar*) fake_select_lex);
}
}
@@ -272,6 +291,18 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit);
+ /*
+ Remove all references from the select_lex_units to the subqueries that
+ are inside the ORDER BY clause.
+ */
+ if (can_skip_order_by)
+ {
+ for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next)
+ {
+ (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL);
+ }
+ }
+
saved_error= join->prepare(&sl->ref_pointer_array,
sl->table_list.first,
sl->with_wild,
@@ -286,6 +317,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
(is_union_select ? NULL :
thd_arg->lex->proc_list.first),
sl, this);
+
/* There are no * in the statement anymore (for PS) */
sl->with_wild= 0;
last_procedure= join->procedure;
@@ -340,6 +372,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
List_iterator_fast<Item> tp(types);
Item *type;
ulonglong create_options;
+ uint save_tablenr= 0;
+ table_map save_map= 0;
+ uint save_maybe_null= 0;
while ((type= tp++))
{
@@ -392,12 +427,24 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
if (union_result->create_result_table(thd, &types, test(union_distinct),
- create_options, "", FALSE))
+ create_options, "", FALSE, TRUE))
goto err;
+ if (fake_select_lex && !fake_select_lex->first_cond_optimization)
+ {
+ save_tablenr= result_table_list.tablenr_exec;
+ save_map= result_table_list.map_exec;
+ save_maybe_null= result_table_list.maybe_null_exec;
+ }
bzero((char*) &result_table_list, sizeof(result_table_list));
result_table_list.db= (char*) "";
result_table_list.table_name= result_table_list.alias= (char*) "union";
result_table_list.table= table= union_result->table;
+ if (fake_select_lex && !fake_select_lex->first_cond_optimization)
+ {
+ result_table_list.tablenr_exec= save_tablenr;
+ result_table_list.map_exec= save_map;
+ result_table_list.maybe_null_exec= save_maybe_null;
+ }
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
@@ -462,18 +509,21 @@ err:
}
-bool st_select_lex_unit::exec()
+/**
+ Run optimization phase.
+
+ @return FALSE unit successfully passed optimization phase.
+ @return TRUE an error occur.
+*/
+bool st_select_lex_unit::optimize()
{
SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor=first_select();
- ulonglong add_rows=0;
- ha_rows examined_rows= 0;
- DBUG_ENTER("st_select_lex_unit::exec");
+ DBUG_ENTER("st_select_lex_unit::optimize");
- if (executed && !uncacheable && !describe)
+ if (optimized && !uncacheable && !describe)
DBUG_RETURN(FALSE);
- executed= 1;
-
+
if (uncacheable || !item || !item->assigned() || describe)
{
if (item)
@@ -494,7 +544,6 @@ bool st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
- ha_rows records_at_start= 0;
thd->lex->current_select= sl;
if (optimized)
@@ -521,6 +570,66 @@ bool st_select_lex_unit::exec()
sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
+
+ saved_error= sl->join->optimize();
+ }
+
+ if (saved_error)
+ {
+ thd->lex->current_select= lex_select_save;
+ DBUG_RETURN(saved_error);
+ }
+ }
+ }
+ optimized= 1;
+
+ thd->lex->current_select= lex_select_save;
+ DBUG_RETURN(saved_error);
+}
+
+
+bool st_select_lex_unit::exec()
+{
+ SELECT_LEX *lex_select_save= thd->lex->current_select;
+ SELECT_LEX *select_cursor=first_select();
+ ulonglong add_rows=0;
+ ha_rows examined_rows= 0;
+ DBUG_ENTER("st_select_lex_unit::exec");
+
+ if (executed && !uncacheable && !describe)
+ DBUG_RETURN(FALSE);
+ executed= 1;
+
+ saved_error= optimize();
+
+ if (uncacheable || !item || !item->assigned() || describe)
+ {
+ for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
+ {
+ ha_rows records_at_start= 0;
+ thd->lex->current_select= sl;
+
+ {
+ set_limit(sl);
+ if (sl == global_parameters || describe)
+ {
+ offset_limit_cnt= 0;
+ /*
+ We can't use LIMIT at this stage if we are using ORDER BY for the
+ whole query
+ */
+ if (sl->order_list.first || describe)
+ select_limit_cnt= HA_POS_ERROR;
+ }
+
+ /*
+ When using braces, SQL_CALC_FOUND_ROWS affects the whole query:
+ we don't calculate found_rows() per union part.
+ Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts.
+ */
+ sl->join->select_options=
+ (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
+ sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
}
if (!saved_error)
@@ -573,7 +682,6 @@ bool st_select_lex_unit::exec()
}
}
}
- optimized= 1;
/* Send result to 'result' */
saved_error= TRUE;
@@ -695,7 +803,8 @@ bool st_select_lex_unit::cleanup()
if ((join= fake_select_lex->join))
{
join->tables_list= 0;
- join->tables= 0;
+ join->table_count= 0;
+ join->top_join_tab_count= 0;
}
error|= fake_select_lex->cleanup();
/*
@@ -848,3 +957,27 @@ void st_select_lex::cleanup_all_joins(bool full)
for (sl= unit->first_select(); sl; sl= sl->next_select())
sl->cleanup_all_joins(full);
}
+
+
+/**
+ Set exclude_from_table_unique_test for selects of this unit and all
+ underlying selects.
+
+ @note used to exclude materialized derived tables (views) from unique
+ table check.
+*/
+
+void st_select_lex_unit::set_unique_exclude()
+{
+ for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ sl->exclude_from_table_unique_test= TRUE;
+ for (SELECT_LEX_UNIT *unit= sl->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ {
+ unit->set_unique_exclude();
+ }
+ }
+}
+