summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2012-03-01 14:22:22 -0800
committerIgor Babaev <igor@askmonty.org>2012-03-01 14:22:22 -0800
commit8b469eb5151cb1b7da00cee3a7b42c10bd7ff51e (patch)
treea2dd09bd1fd3ba15b098eebf8b581bef7664b212 /sql
parent29b0b0b5de46c6950b8b53314c74f6f458ba1a98 (diff)
parent000deedf3b708681951af6a0629af89c1f5ee85a (diff)
downloadmariadb-git-8b469eb5151cb1b7da00cee3a7b42c10bd7ff51e.tar.gz
Merge 5.3->5.5.
Diffstat (limited to 'sql')
-rw-r--r--sql/field_conv.cc10
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_subselect.cc5
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/opt_subselect.cc8
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_select.cc54
-rw-r--r--sql/sql_union.cc8
-rw-r--r--sql/table.h23
10 files changed, 100 insertions, 21 deletions
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 89ac499b6c0..37aee93fe82 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -117,6 +117,11 @@ static void do_outer_field_to_null_str(Copy_field *copy)
int
set_field_to_null(Field *field)
{
+ if (field->table->null_catch_flags & CHECK_ROW_FOR_NULLS_TO_REJECT)
+ {
+ field->table->null_catch_flags|= REJECT_ROW_DUE_TO_NULL_FIELDS;
+ return -1;
+ }
if (field->real_maybe_null())
{
field->set_null();
@@ -160,6 +165,11 @@ set_field_to_null(Field *field)
int
set_field_to_null_with_conversions(Field *field, bool no_conversions)
{
+ if (field->table->null_catch_flags & CHECK_ROW_FOR_NULLS_TO_REJECT)
+ {
+ field->table->null_catch_flags|= REJECT_ROW_DUE_TO_NULL_FIELDS;
+ return -1;
+ }
if (field->real_maybe_null())
{
field->set_null();
diff --git a/sql/item.h b/sql/item.h
index 4af2038aa55..cf13f501c69 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1158,7 +1158,6 @@ public:
virtual bool update_table_bitmaps_processor(uchar *arg) { return 0; }
virtual bool view_used_tables_processor(uchar *arg) { return 0; }
virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; }
- virtual bool clear_sum_processor(uchar *opt_arg) { return 0; }
virtual bool is_subquery_processor (uchar *opt_arg) { return 0; }
virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg)
{
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 50625286348..f2d7d69e173 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -4194,6 +4194,11 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id)
memcpy(name, buf, len+1);
result_sink->get_tmp_table_param()->materialized_subquery= true;
+ if (item->substype() == Item_subselect::IN_SUBS &&
+ ((Item_in_subselect*)item)->is_jtbm_merged)
+ {
+ result_sink->get_tmp_table_param()->force_not_null_cols= true;
+ }
if (result_sink->create_result_table(thd, tmp_columns, TRUE,
tmp_create_options,
name, TRUE, TRUE))
diff --git a/sql/item_sum.h b/sql/item_sum.h
index ed07e3cb2b5..c8dce60c7d4 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -547,7 +547,6 @@ public:
{
return trace_unsupported_by_check_vcol_func_processor(func_name());
}
- bool clear_sum_processor(uchar *arg) { clear(); return 0; }
};
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 72c2f0442cf..dcb5181acc3 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -268,8 +268,8 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN"))
- (*) The subquery must be part of a SELECT statement. The current
- condition also excludes multi-table update statements.
+ (*) The subquery must be part of a SELECT or CREATE TABLE ... SELECT statement.
+ The current condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need
select_lex->sj_subselects list to be populated for every EXECUTE.
@@ -278,7 +278,8 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
- thd->lex->sql_command == SQLCOM_SELECT && // *
+ (thd->lex->sql_command == SQLCOM_SELECT || // *
+ thd->lex->sql_command == SQLCOM_CREATE_TABLE) && // *
child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
@@ -3184,6 +3185,7 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
sjm->sjm_table_cols.push_back(*p_item);
sjm->sjm_table_param.field_count= subq_select->item_list.elements;
+ sjm->sjm_table_param.force_not_null_cols= TRUE;
if (!(sjm->table= create_tmp_table(thd, &sjm->sjm_table_param,
sjm->sjm_table_cols, (ORDER*) 0,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 40f8bf4b611..f970f6a4f26 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3434,6 +3434,11 @@ int select_materialize_with_stats::send_data(List<Item> &items)
if ((res= select_union::send_data(items)))
return res;
+ if (table->null_catch_flags & REJECT_ROW_DUE_TO_NULL_FIELDS)
+ {
+ table->null_catch_flags&= ~REJECT_ROW_DUE_TO_NULL_FIELDS;
+ return 0;
+ }
/* Skip duplicate rows. */
if (write_err == HA_ERR_FOUND_DUPP_KEY ||
write_err == HA_ERR_FOUND_DUPP_UNIQUE)
@@ -3475,6 +3480,7 @@ void TMP_TABLE_PARAM::init()
precomputed_group_by= 0;
bit_fields_as_long= 0;
materialized_subquery= 0;
+ force_not_null_cols= 0;
skip_create_table= 0;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 52473f16b0e..5c35bc37623 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3458,6 +3458,8 @@ public:
bool schema_table;
/* TRUE if the temp table is created for subquery materialization. */
bool materialized_subquery;
+ /* TRUE if all columns of the table are guaranteed to be non-nullable */
+ bool force_not_null_cols;
/*
True if GROUP BY and its aggregate functions are already computed
by a table access method (e.g. by loose index scan). In this case
@@ -3481,7 +3483,8 @@ public:
TMP_TABLE_PARAM()
:copy_field(0), group_parts(0),
group_length(0), group_null_parts(0), convert_blob_length(0),
- schema_table(0), materialized_subquery(0), precomputed_group_by(0),
+ schema_table(0), materialized_subquery(0), force_not_null_cols(0),
+ precomputed_group_by(0),
force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0)
{}
~TMP_TABLE_PARAM()
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4c02f19926f..472f05dfb47 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -126,7 +126,7 @@ static int return_zero_rows(JOIN *join, select_result *res,
List<TABLE_LIST> &tables,
List<Item> &fields, bool send_row,
ulonglong select_options, const char *info,
- Item *having);
+ Item *having, List<Item> &all_fields);
static COND *build_equal_items(THD *thd, COND *cond,
COND_EQUAL *inherited,
List<TABLE_LIST> *join_list,
@@ -2201,6 +2201,15 @@ JOIN::exec()
!exec_const_cond->val_int())
zero_result_cause= "Impossible WHERE noticed after reading const tables";
+ /*
+ We've called exec_const_cond->val_int(). This may have caused an error.
+ */
+ if (thd->is_error())
+ {
+ error= thd->is_error();
+ DBUG_VOID_RETURN;
+ }
+
if (zero_result_cause)
{
(void) return_zero_rows(this, result, select_lex->leaf_tables,
@@ -2208,7 +2217,7 @@ JOIN::exec()
send_row_on_empty_set(),
select_options,
zero_result_cause,
- having ? having : tmp_having);
+ having ? having : tmp_having, all_fields);
DBUG_VOID_RETURN;
}
@@ -3784,15 +3793,18 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
{
/* field = expression OR field IS NULL */
old->level= and_level;
- old->optimize= KEY_OPTIMIZE_REF_OR_NULL;
+ if (old->field->maybe_null())
+ {
+ old->optimize= KEY_OPTIMIZE_REF_OR_NULL;
+ /* The referred expression can be NULL: */
+ old->null_rejecting= 0;
+ }
/*
Remember the NOT NULL value unless the value does not depend
on other tables.
*/
if (!old->val->used_tables() && old->val->is_null())
old->val= new_fields->val;
- /* The referred expression can be NULL: */
- old->null_rejecting= 0;
}
else
{
@@ -10566,7 +10578,7 @@ ORDER *simple_remove_const(ORDER *order, COND *where)
static int
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
List<Item> &fields, bool send_row, ulonglong select_options,
- const char *info, Item *having)
+ const char *info, Item *having, List<Item> &all_fields)
{
DBUG_ENTER("return_zero_rows");
@@ -10596,9 +10608,15 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
if (!table->is_jtbm())
mark_as_null_row(table->table); // All fields are NULL
}
- if (having &&
- !having->walk(&Item::clear_sum_processor, FALSE, NULL) &&
- having->val_int() == 0)
+ List_iterator_fast<Item> it(all_fields);
+ Item *item;
+ /*
+ Inform all items (especially aggregating) to calculate HAVING correctly,
+ also we will need it for sending results.
+ */
+ while ((item= it++))
+ item->no_rows_in_result();
+ if (having && having->val_int() == 0)
send_row=0;
}
if (!(result->send_result_set_metadata(fields,
@@ -10606,13 +10624,7 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
{
bool send_error= FALSE;
if (send_row)
- {
- List_iterator_fast<Item> it(fields);
- Item *item;
- while ((item= it++))
- item->no_rows_in_result();
send_error= result->send_data(fields) > 0;
- }
if (!send_error)
result->send_eof(); // Should be safe
}
@@ -12400,6 +12412,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
tbl->table->maybe_null= FALSE;
tbl->join_list= table->join_list;
repl_list.push_back(tbl);
+ tbl->dep_tables|= table->dep_tables;
}
li.replace(repl_list);
/* Need to update the name resolution table chain when flattening joins */
@@ -13819,6 +13832,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->merge_keys.init();
table->intersect_keys.init();
table->keys_in_use_for_query.init();
+ table->no_rows_with_nulls= param->force_not_null_cols;
table->s= share;
init_tmp_table_share(thd, share, "", 0, tmpname, tmpname);
@@ -13900,6 +13914,11 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
thd->mem_root= mem_root_save;
arg= sum_item->set_arg(i, thd, new Item_field(new_field));
thd->mem_root= &table->mem_root;
+ if (param->force_not_null_cols)
+ {
+ new_field->flags|= NOT_NULL_FLAG;
+ new_field->null_ptr= NULL;
+ }
if (!(new_field->flags & NOT_NULL_FLAG))
{
null_count++;
@@ -13975,6 +13994,11 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
agg_item->result_field= new_field;
}
tmp_from_field++;
+ if (param->force_not_null_cols)
+ {
+ new_field->flags|= NOT_NULL_FLAG;
+ new_field->null_ptr= NULL;
+ }
reclength+=new_field->pack_length();
if (!(new_field->flags & NOT_NULL_FLAG))
null_count++;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 9b6d3a8dda5..2118bc8c30d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -59,9 +59,17 @@ int select_union::send_data(List<Item> &values)
unit->offset_limit_cnt--;
return 0;
}
+ if (table->no_rows_with_nulls)
+ table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
fill_record(thd, table->field, values, TRUE, FALSE);
if (thd->is_error())
return 1;
+ if (table->no_rows_with_nulls)
+ {
+ table->null_catch_flags&= ~CHECK_ROW_FOR_NULLS_TO_REJECT;
+ if (table->null_catch_flags)
+ return 0;
+ }
if ((write_err= table->file->ha_write_tmp_row(table->record[0])))
{
diff --git a/sql/table.h b/sql/table.h
index 77a7f8cf6a9..a227b42f71d 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -906,6 +906,9 @@ enum index_hint_type
INDEX_HINT_FORCE
};
+#define CHECK_ROW_FOR_NULLS_TO_REJECT (1 << 0)
+#define REJECT_ROW_DUE_TO_NULL_FIELDS (1 << 1)
+
struct TABLE
{
TABLE() {} /* Remove gcc warning */
@@ -1054,6 +1057,26 @@ public:
NULL, including columns declared as "not null" (see maybe_null).
*/
bool null_row;
+ /*
+ No rows that contain null values can be placed into this table.
+ Currently this flag can be set to true only for a temporary table
+ that used to store the result of materialization of a subquery.
+ */
+ bool no_rows_with_nulls;
+ /*
+ This field can contain two bit flags:
+ CHECK_ROW_FOR_NULLS_TO_REJECT
+ REJECT_ROW_DUE_TO_NULL_FIELDS
+ The first flag is set for the dynamic contexts where it is prohibited
+ to write any null into the table.
+ The second flag is set only if the first flag is set on.
+ The informs the outer scope that there was an attept to write null
+ into a field of the table in the context where it is prohibited.
+ This flag should be set off as soon as the first flag is set on.
+ Currently these flags are used only the tables tno_rows_with_nulls set
+ to true.
+ */
+ uint8 null_catch_flags;
/*
TODO: Each of the following flags take up 8 bits. They can just as easily