summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2018-01-10 12:36:55 +0300
committerAleksey Midenkov <midenok@gmail.com>2018-01-10 12:36:55 +0300
commitc59c1a0736e36e9c66f798d199a124f362353377 (patch)
tree80ee18faad049687b0b4f0e2f147caf870d68390 /sql
parent26971c9aea67a62f348cd105348a8dc4407bcf4a (diff)
parent0b597d3ab2494bc1db97cc4a30d697a5fdf48c21 (diff)
downloadmariadb-git-c59c1a0736e36e9c66f798d199a124f362353377.tar.gz
System Versioning 1.0 pre8
Merge branch '10.3' into trunk
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/events.cc2
-rw-r--r--sql/field.cc40
-rw-r--r--sql/field.h4
-rw-r--r--sql/field_conv.cc11
-rw-r--r--sql/filesort.cc26
-rw-r--r--sql/filesort_utils.cc2
-rw-r--r--sql/ha_partition.cc69
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item.cc9
-rw-r--r--sql/item_cmpfunc.cc13
-rw-r--r--sql/item_cmpfunc.h1
-rw-r--r--sql/item_func.cc40
-rw-r--r--sql/item_func.h32
-rw-r--r--sql/item_jsonfunc.cc6
-rw-r--r--sql/item_sum.cc2
-rw-r--r--sql/lock.cc11
-rw-r--r--sql/log.cc177
-rw-r--r--sql/log.h9
-rw-r--r--sql/log_event.cc1630
-rw-r--r--sql/log_event.h215
-rw-r--r--sql/log_event_old.cc36
-rw-r--r--sql/log_event_old.h10
-rw-r--r--sql/mdl.cc2
-rw-r--r--sql/mysqld.cc25
-rw-r--r--sql/opt_range.cc15
-rw-r--r--sql/opt_split.cc1134
-rw-r--r--sql/opt_subselect.cc8
-rw-r--r--sql/partition_info.cc74
-rw-r--r--sql/partition_info.h23
-rw-r--r--sql/rpl_gtid.cc11
-rw-r--r--sql/semisync_master_ack_receiver.cc2
-rw-r--r--sql/share/errmsg-utf8.txt48
-rw-r--r--sql/signal_handler.cc4
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/slave.h2
-rw-r--r--sql/sp.cc4
-rw-r--r--sql/sp_head.cc8
-rw-r--r--sql/sql_acl.cc63
-rw-r--r--sql/sql_acl.h4
-rw-r--r--sql/sql_base.cc157
-rw-r--r--sql/sql_base.h2
-rw-r--r--sql/sql_cache.cc2
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h10
-rw-r--r--sql/sql_connect.cc49
-rw-r--r--sql/sql_const.h1
-rw-r--r--sql/sql_cte.cc2
-rw-r--r--sql/sql_derived.cc52
-rw-r--r--sql/sql_digest.cc2
-rw-r--r--sql/sql_explain.cc8
-rw-r--r--sql/sql_explain.h1
-rw-r--r--sql/sql_lex.cc10
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_partition.cc21
-rw-r--r--sql/sql_partition_admin.cc12
-rw-r--r--sql/sql_prepare.cc16
-rw-r--r--sql/sql_priv.h6
-rw-r--r--sql/sql_repl.cc3
-rw-r--r--sql/sql_select.cc316
-rw-r--r--sql/sql_select.h82
-rw-r--r--sql/sql_string.cc2
-rw-r--r--sql/sql_table.cc19
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_union.cc6
-rw-r--r--sql/sql_view.cc3
-rw-r--r--sql/sql_window.cc9
-rw-r--r--sql/sql_yacc.yy9
-rw-r--r--sql/sql_yacc_ora.yy1
-rw-r--r--sql/sys_vars.cc11
-rw-r--r--sql/table.cc28
-rw-r--r--sql/table.h37
-rw-r--r--sql/temporary_tables.cc12
-rw-r--r--sql/wsrep_mysqld.cc10
75 files changed, 3317 insertions, 1381 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index c362ba4a8ee..a412a65ccc9 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -146,6 +146,7 @@ SET (SQL_SOURCE
item_vers.cc
sql_sequence.cc sql_sequence.h ha_sequence.h
sql_tvc.cc sql_tvc.h
+ opt_split.cc
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc
diff --git a/sql/events.cc b/sql/events.cc
index 36f03e26125..3ad546217a7 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -421,7 +421,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
DBUG_RETURN(ret);
#ifdef WITH_WSREP
error:
- DBUG_RETURN(true);
+ DBUG_RETURN(TRUE);
#endif /* WITH_WSREP */
}
diff --git a/sql/field.cc b/sql/field.cc
index 8cc9e7d1223..642ad6a65e9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1518,7 +1518,7 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
goto out_of_range;
}
}
- if (get_thd()->count_cuted_fields &&
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_int(cs, from, len, end, error))
return 1;
return 0;
@@ -1539,7 +1539,7 @@ double Field_real::get_double(const char *str, uint length, CHARSET_INFO *cs,
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
*error= 1;
}
- else if (get_thd()->count_cuted_fields &&
+ else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_edom_and_truncation("double", str == end,
cs, str, length, end))
*error= 1;
@@ -1874,7 +1874,7 @@ void Field::make_field(Send_field *field)
if (orig_table && orig_table->s->db.str && *orig_table->s->db.str)
{
field->db_name= orig_table->s->db.str;
- if (orig_table->pos_in_table_list &&
+ if (orig_table->pos_in_table_list &&
orig_table->pos_in_table_list->schema_table)
field->org_table_name= (orig_table->pos_in_table_list->
schema_table->table_name);
@@ -2536,7 +2536,7 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
it makes the code easer to read.
*/
- if (get_thd()->count_cuted_fields)
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
// Skip end spaces
for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
@@ -2706,7 +2706,8 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
{
if (pos == right_wall)
{
- if (get_thd()->count_cuted_fields && !is_cuted_fields_incr)
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
+ !is_cuted_fields_incr)
break; // Go on below to see if we lose non zero digits
return 0;
}
@@ -3099,7 +3100,7 @@ int Field_new_decimal::store(const char *from, uint length,
DBUG_RETURN(1);
}
- if (thd->count_cuted_fields)
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
if (check_edom_and_important_data_truncation("decimal",
err && err != E_DEC_TRUNCATED,
@@ -3144,7 +3145,7 @@ int Field_new_decimal::store(const char *from, uint length,
- in err2: store_value() truncated 1.123 to 1.12, e.g. for DECIMAL(10,2)
Also, we send a note if a string had some trailing spaces: '1.12 '
*/
- if (thd->count_cuted_fields &&
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
(err == E_DEC_TRUNCATED ||
err2 == E_DEC_TRUNCATED ||
end < from + length))
@@ -4221,7 +4222,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
- else if (get_thd()->count_cuted_fields &&
+ else if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
check_int(cs, from, len, end, error))
error= 1;
else
@@ -6162,7 +6163,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
return 1;
}
- if (get_thd()->count_cuted_fields &&
+ if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
(error= check_int(cs, from, len, end, error)))
{
if (error == 1) /* empty or incorrect string */
@@ -6870,7 +6871,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
bool count_spaces)
{
THD *thd= get_thd();
- if ((pstr < end) && thd->count_cuted_fields)
+ if ((pstr < end) && thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
if (test_if_important_data(field_charset, pstr, end))
{
@@ -8804,7 +8805,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
wkb_type > (uint32) Geometry::wkb_last)
goto err;
- if (geom_type != Field::GEOM_GEOMETRY &&
+ if (geom_type != Field::GEOM_GEOMETRY &&
geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
(uint32) geom_type != wkb_type)
{
@@ -8944,7 +8945,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
set_warning(WARN_DATA_TRUNCATED, 1);
err= 1;
}
- if (!get_thd()->count_cuted_fields && !length)
+ if ((get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION) && !length)
err= 0;
}
else
@@ -8971,7 +8972,7 @@ int Field_enum::store(longlong nr, bool unsigned_val)
if ((ulonglong) nr > typelib->count || nr == 0)
{
set_warning(WARN_DATA_TRUNCATED, 1);
- if (nr != 0 || get_thd()->count_cuted_fields)
+ if (nr != 0 || get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
nr= 0;
error= 1;
@@ -10197,6 +10198,8 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
uint filter= VCOL_IMPOSSIBLE;
if (type != VCOL_GENERATED_VIRTUAL && type != VCOL_DEFAULT)
filter|= VCOL_NOT_STRICTLY_DETERMINISTIC;
+ if (type == VCOL_GENERATED_VIRTUAL)
+ filter|= VCOL_NOT_VIRTUAL;
if (ret || (res.errors & filter))
{
@@ -11023,11 +11026,12 @@ uint32 Field_blob::max_display_length()
@param cut_increment - whenever we should increase cut fields count
@note
- This function won't produce warning and increase cut fields counter
- if count_cuted_fields == CHECK_FIELD_IGNORE for current thread.
+ This function won't produce warning or notes or increase cut fields counter
+ if count_cuted_fields == CHECK_FIELD_IGNORE or CHECK_FIELD_EXPRESSION
+ for the current thread.
- if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
- This allows us to avoid notes in optimisation, like convert_constant_item().
+ This allows us to avoid notes in optimisation, like
+ convert_constant_item().
@retval
1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE
@@ -11044,7 +11048,7 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code,
will have table == NULL.
*/
THD *thd= get_thd();
- if (thd->count_cuted_fields)
+ if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
thd->cuted_fields+= cut_increment;
push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str,
diff --git a/sql/field.h b/sql/field.h
index 8b841aeeaa9..9fd584e88c2 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -50,8 +50,9 @@ class Virtual_tmp_table;
enum enum_check_fields
{
CHECK_FIELD_IGNORE,
+ CHECK_FIELD_EXPRESSION,
CHECK_FIELD_WARN,
- CHECK_FIELD_ERROR_FOR_NULL
+ CHECK_FIELD_ERROR_FOR_NULL,
};
/*
@@ -558,6 +559,7 @@ static inline const char *vcol_type_name(enum_vcol_info_type type)
#define VCOL_TIME_FUNC 8
#define VCOL_AUTO_INC 16
#define VCOL_IMPOSSIBLE 32
+#define VCOL_NOT_VIRTUAL 64 /* Function can't be virtual */
#define VCOL_NOT_STRICTLY_DETERMINISTIC \
(VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index a817db51569..db5c9429954 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -122,6 +122,7 @@ static int set_bad_null_error(Field *field, int err)
field->set_warning(Sql_condition::WARN_LEVEL_WARN, err, 1);
/* fall through */
case CHECK_FIELD_IGNORE:
+ case CHECK_FIELD_EXPRESSION:
return 0;
case CHECK_FIELD_ERROR_FOR_NULL:
if (!field->table->in_use->no_errors)
@@ -528,7 +529,8 @@ static void do_varstring1(Copy_field *copy)
if (length > copy->to_length- 1)
{
length=copy->to_length - 1;
- if (copy->from_field->table->in_use->count_cuted_fields &&
+ if (copy->from_field->table->in_use->count_cuted_fields >
+ CHECK_FIELD_EXPRESSION &&
copy->to_field)
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1);
@@ -547,7 +549,7 @@ static void do_varstring1_mb(Copy_field *copy)
Well_formed_prefix prefix(cs, (char*) from_ptr, from_length, to_char_length);
if (prefix.length() < from_length)
{
- if (current_thd->count_cuted_fields)
+ if (current_thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1);
}
@@ -562,7 +564,8 @@ static void do_varstring2(Copy_field *copy)
if (length > copy->to_length- HA_KEY_BLOB_LENGTH)
{
length=copy->to_length-HA_KEY_BLOB_LENGTH;
- if (copy->from_field->table->in_use->count_cuted_fields &&
+ if (copy->from_field->table->in_use->count_cuted_fields >
+ CHECK_FIELD_EXPRESSION &&
copy->to_field)
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1);
@@ -582,7 +585,7 @@ static void do_varstring2_mb(Copy_field *copy)
Well_formed_prefix prefix(cs, (char*) from_beg, from_length, char_length);
if (prefix.length() < from_length)
{
- if (current_thd->count_cuted_fields)
+ if (current_thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
copy->to_field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1);
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index b762773b11e..4cf2a00dbc4 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -710,6 +710,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
handler *file;
MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set;
Item *sort_cond;
+ ha_rows retval;
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",
(select ? select->quick ? "ranges" : "where":
@@ -767,7 +768,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
if (quick_select)
{
if (select->quick->reset())
- DBUG_RETURN(HA_POS_ERROR);
+ goto err;
}
DEBUG_SYNC(thd, "after_index_merge_phase1");
@@ -804,7 +805,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
(void) file->extra(HA_EXTRA_NO_CACHE);
file->ha_rnd_end();
}
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ goto err; /* purecov: inspected */
}
bool write_record= false;
@@ -852,7 +853,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
if (idx == param->max_keys_per_buffer)
{
if (write_keys(param, fs_info, idx, buffpek_pointers, tempfile))
- DBUG_RETURN(HA_POS_ERROR);
+ goto err;
idx= 0;
indexpos++;
}
@@ -878,12 +879,12 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
file->ha_rnd_end();
}
- if (thd->is_error())
- DBUG_RETURN(HA_POS_ERROR);
-
/* Signal we should use orignal column read and write maps */
sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ if (thd->is_error())
+ DBUG_RETURN(HA_POS_ERROR);
+
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE)
{
@@ -893,11 +894,15 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
if (indexpos && idx &&
write_keys(param, fs_info, idx, buffpek_pointers, tempfile))
DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
- const ha_rows retval=
- my_b_inited(tempfile) ?
- (ha_rows) (my_b_tell(tempfile)/param->rec_length) : idx;
+ retval= (my_b_inited(tempfile) ?
+ (ha_rows) (my_b_tell(tempfile)/param->rec_length) :
+ idx);
DBUG_PRINT("info", ("find_all_keys return %llu", (ulonglong) retval));
DBUG_RETURN(retval);
+
+err:
+ sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ DBUG_RETURN(HA_POS_ERROR);
} /* find_all_keys */
@@ -995,7 +1000,8 @@ Type_handler_string_result::make_sort_key(uchar *to, Item *item,
if (maybe_null)
*to++= 1;
char *tmp_buffer= param->tmp_buffer ? param->tmp_buffer : (char*) to;
- String tmp(tmp_buffer, param->sort_length, cs);
+ String tmp(tmp_buffer, param->tmp_buffer ? param->sort_length :
+ sort_field->length, cs);
String *res= item->str_result(&tmp);
if (!res)
{
diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc
index 11be9229c1d..b39bb880c15 100644
--- a/sql/filesort_utils.cc
+++ b/sql/filesort_utils.cc
@@ -105,7 +105,7 @@ uchar **Filesort_buffer::alloc_sort_buffer(uint num_records,
DBUG_EXECUTE_IF("alloc_sort_buffer_fail",
DBUG_SET("+d,simulate_out_of_memory"););
- buff_size= num_records * (record_length + sizeof(uchar*));
+ buff_size= ((size_t)num_records) * (record_length + sizeof(uchar*));
set_if_bigger(buff_size, record_length * MERGEBUFF2);
if (!m_idx_array.is_null())
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index da274bbdf67..20fa2eabea1 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2201,38 +2201,19 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
DBUG_ASSERT(sub_elem);
part= i * num_subparts + j;
DBUG_ASSERT(part < m_file_tot_parts && m_file[part]);
- if (ha_legacy_type(m_file[part]->ht) == DB_TYPE_INNODB)
- {
- dummy_info.data_file_name= dummy_info.index_file_name= NULL;
- m_file[part]->update_create_info(&dummy_info);
-
- if (dummy_info.data_file_name || sub_elem->data_file_name)
- {
- sub_elem->data_file_name= (char*) dummy_info.data_file_name;
- }
- if (dummy_info.index_file_name || sub_elem->index_file_name)
- {
- sub_elem->index_file_name= (char*) dummy_info.index_file_name;
- }
- }
+ dummy_info.data_file_name= dummy_info.index_file_name = NULL;
+ m_file[part]->update_create_info(&dummy_info);
+ sub_elem->data_file_name = (char*) dummy_info.data_file_name;
+ sub_elem->index_file_name = (char*) dummy_info.index_file_name;
}
}
else
{
DBUG_ASSERT(m_file[i]);
- if (ha_legacy_type(m_file[i]->ht) == DB_TYPE_INNODB)
- {
- dummy_info.data_file_name= dummy_info.index_file_name= NULL;
- m_file[i]->update_create_info(&dummy_info);
- if (dummy_info.data_file_name || part_elem->data_file_name)
- {
- part_elem->data_file_name= (char*) dummy_info.data_file_name;
- }
- if (dummy_info.index_file_name || part_elem->index_file_name)
- {
- part_elem->index_file_name= (char*) dummy_info.index_file_name;
- }
- }
+ dummy_info.data_file_name= dummy_info.index_file_name= NULL;
+ m_file[i]->update_create_info(&dummy_info);
+ part_elem->data_file_name = (char*) dummy_info.data_file_name;
+ part_elem->index_file_name = (char*) dummy_info.index_file_name;
}
}
DBUG_VOID_RETURN;
@@ -9703,20 +9684,36 @@ uint ha_partition::alter_table_flags(uint flags)
bool ha_partition::check_if_incompatible_data(HA_CREATE_INFO *create_info,
uint table_changes)
{
- handler **file;
- bool ret= COMPATIBLE_DATA_YES;
-
/*
The check for any partitioning related changes have already been done
in mysql_alter_table (by fix_partition_func), so it is only up to
the underlying handlers.
*/
- for (file= m_file; *file; file++)
- if ((ret= (*file)->check_if_incompatible_data(create_info,
- table_changes)) !=
- COMPATIBLE_DATA_YES)
- break;
- return ret;
+ List_iterator<partition_element> part_it(m_part_info->partitions);
+ HA_CREATE_INFO dummy_info= *create_info;
+ uint i=0;
+ while (partition_element *part_elem= part_it++)
+ {
+ if (m_is_sub_partitioned)
+ {
+ List_iterator<partition_element> subpart_it(part_elem->subpartitions);
+ while (partition_element *sub_elem= subpart_it++)
+ {
+ dummy_info.data_file_name= sub_elem->data_file_name;
+ dummy_info.index_file_name= sub_elem->index_file_name;
+ if (m_file[i++]->check_if_incompatible_data(&dummy_info, table_changes))
+ return COMPATIBLE_DATA_NO;
+ }
+ }
+ else
+ {
+ dummy_info.data_file_name= part_elem->data_file_name;
+ dummy_info.index_file_name= part_elem->index_file_name;
+ if (m_file[i++]->check_if_incompatible_data(&dummy_info, table_changes))
+ return COMPATIBLE_DATA_NO;
+ }
+ }
+ return COMPATIBLE_DATA_YES;
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 6e1001090c8..a7530723c79 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2113,7 +2113,7 @@ uint get_sql_xid(XID *xid, char *buf)
MY_INT64_NUM_DECIMAL_DIGITS, -10, xid->formatID);
}
- return buf - orig_buf;
+ return (uint)(buf - orig_buf);
}
diff --git a/sql/item.cc b/sql/item.cc
index e501fa6b488..d916e4328d7 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2185,8 +2185,10 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
String s(buf, sizeof(buf), &my_charset_bin);
s.length(0);
- if (value_item->fix_fields(thd, &value_item) ||
- name_item->fix_fields(thd, &name_item) ||
+ if ((!value_item->fixed &&
+ value_item->fix_fields(thd, &value_item)) ||
+ (!name_item->fixed &&
+ name_item->fix_fields(thd, &name_item)) ||
!value_item->const_item() ||
!name_item->const_item() ||
!(item_name= name_item->val_str(&s))) // Can't have a NULL name
@@ -5569,7 +5571,8 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
select->having_fix_field &&
- select_ref != not_found_item && !group_by_ref)
+ select_ref != not_found_item && !group_by_ref &&
+ !ref->alias_name_used)
{
/*
Report the error if fields was found only in the SELECT item list and
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 1d4a44d5326..780c60e4eb3 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1842,6 +1842,19 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
}
+bool Item_func_interval::fix_fields(THD *thd, Item **ref)
+{
+ if (Item_long_func::fix_fields(thd, ref))
+ return true;
+ for (uint i= 0 ; i < row->cols(); i++)
+ {
+ if (row->element_index(i)->check_cols(1))
+ return true;
+ }
+ return false;
+}
+
+
void Item_func_interval::fix_length_and_dec()
{
uint rows= row->cols();
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1561a78a12a..8b47f09497f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -976,6 +976,7 @@ public:
Item_func_interval(THD *thd, Item_row *a):
Item_long_func(thd, a), row(a), intervals(0)
{ }
+ bool fix_fields(THD *, Item **);
longlong val_int();
void fix_length_and_dec();
const char *func_name() const { return "interval"; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 55d141b9968..ac7ed75e7f9 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6686,14 +6686,22 @@ longlong Item_func_nextval::val_int()
longlong value;
int error;
const char *key;
- TABLE *table= table_list->table;
uint length= get_table_def_key(table_list, &key);
- THD *thd= table->in_use;
+ THD *thd;
SEQUENCE_LAST_VALUE *entry;
char buff[80];
String key_buff(buff,sizeof(buff), &my_charset_bin);
- DBUG_ASSERT(table && table->s->sequence);
DBUG_ENTER("Item_func_nextval::val_int");
+ update_table();
+ DBUG_ASSERT(table && table->s->sequence);
+ thd= table->in_use;
+
+ if (thd->count_cuted_fields == CHECK_FIELD_EXPRESSION)
+ {
+ /* Alter table checking if function works */
+ null_value= 0;
+ DBUG_RETURN(0);
+ }
if (table->s->tmp_table != NO_TMP_TABLE)
{
@@ -6745,7 +6753,7 @@ void Item_func_nextval::print(String *str, enum_query_type query_type)
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
const char *d_name= table_list->db, *t_name= table_list->table_name;
bool use_db_name= d_name && d_name[0];
- THD *thd= current_thd;
+ THD *thd= current_thd; // Don't trust 'table'
str->append(func_name());
str->append('(');
@@ -6785,12 +6793,14 @@ longlong Item_func_lastval::val_int()
const char *key;
SEQUENCE_LAST_VALUE *entry;
uint length= get_table_def_key(table_list, &key);
- THD *thd= table_list->table->in_use;
+ THD *thd;
char buff[80];
String key_buff(buff,sizeof(buff), &my_charset_bin);
DBUG_ENTER("Item_func_lastval::val_int");
+ update_table();
+ thd= table->in_use;
- if (table_list->table->s->tmp_table != NO_TMP_TABLE)
+ if (table->s->tmp_table != NO_TMP_TABLE)
{
/*
Temporary tables has an extra \0 at end to distinguish it from
@@ -6809,7 +6819,7 @@ longlong Item_func_lastval::val_int()
null_value= 1;
DBUG_RETURN(0);
}
- if (entry->check_version(table_list->table))
+ if (entry->check_version(table))
{
/* Table droped and re-created, remove current version */
my_hash_delete(&thd->sequences, (uchar*) entry);
@@ -6834,10 +6844,20 @@ longlong Item_func_setval::val_int()
{
longlong value;
int error;
- TABLE *table= table_list->table;
- DBUG_ASSERT(table && table->s->sequence);
+ THD *thd;
DBUG_ENTER("Item_func_setval::val_int");
+ update_table();
+ DBUG_ASSERT(table && table->s->sequence);
+ thd= table->in_use;
+
+ if (thd->count_cuted_fields == CHECK_FIELD_EXPRESSION)
+ {
+ /* Alter table checking if function works */
+ null_value= 0;
+ DBUG_RETURN(0);
+ }
+
value= nextval;
error= table->s->sequence->set_value(table, nextval, round, is_used);
if (error)
@@ -6856,7 +6876,7 @@ void Item_func_setval::print(String *str, enum_query_type query_type)
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
const char *d_name= table_list->db, *t_name= table_list->table_name;
bool use_db_name= d_name && d_name[0];
- THD *thd= table_list->table->in_use;
+ THD *thd= current_thd; // Don't trust 'table'
str->append(func_name());
str->append('(');
diff --git a/sql/item_func.h b/sql/item_func.h
index 4c78edcb1fa..c226d82c7b8 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -3008,9 +3008,10 @@ class Item_func_nextval :public Item_longlong_func
{
protected:
TABLE_LIST *table_list;
+ TABLE *table;
public:
- Item_func_nextval(THD *thd, TABLE_LIST *table):
- Item_longlong_func(thd), table_list(table) {}
+ Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg):
+ Item_longlong_func(thd), table_list(table_list_arg) {}
longlong val_int();
const char *func_name() const { return "nextval"; }
void fix_length_and_dec()
@@ -3019,6 +3020,22 @@ public:
max_length= MAX_BIGINT_WIDTH;
maybe_null= 1; /* In case of errors */
}
+ /*
+ update_table() function must be called during the value function
+ as in case of DEFAULT the sequence table may not yet be open
+ while fix_fields() are called
+ */
+ void update_table()
+ {
+ if (!(table= table_list->table))
+ {
+ /*
+ If nextval was used in DEFAULT then next_local points to
+ the table_list used by to open the sequence table
+ */
+ table= table_list->next_local->table;
+ }
+ }
bool const_item() const { return 0; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_nextval>(thd, this); }
@@ -3026,7 +3043,8 @@ public:
bool check_vcol_func_processor(void *arg)
{
return mark_unsupported_function(func_name(), "()", arg,
- VCOL_NON_DETERMINISTIC);
+ (VCOL_NON_DETERMINISTIC |
+ VCOL_NOT_VIRTUAL));
}
};
@@ -3036,8 +3054,8 @@ public:
class Item_func_lastval :public Item_func_nextval
{
public:
- Item_func_lastval(THD *thd, TABLE_LIST *table):
- Item_func_nextval(thd, table) {}
+ Item_func_lastval(THD *thd, TABLE_LIST *table_list_arg):
+ Item_func_nextval(thd, table_list_arg) {}
longlong val_int();
const char *func_name() const { return "lastval"; }
Item *get_copy(THD *thd)
@@ -3053,9 +3071,9 @@ class Item_func_setval :public Item_func_nextval
ulonglong round;
bool is_used;
public:
- Item_func_setval(THD *thd, TABLE_LIST *table, longlong nextval_arg,
+ Item_func_setval(THD *thd, TABLE_LIST *table_list_arg, longlong nextval_arg,
ulonglong round_arg, bool is_used_arg)
- : Item_func_nextval(thd, table),
+ : Item_func_nextval(thd, table_list_arg),
nextval(nextval_arg), round(round_arg), is_used(is_used_arg)
{}
longlong val_int();
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 7afb94ba332..4b2de7cf28b 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -781,10 +781,10 @@ String *Item_func_json_extract::read_json(String *str,
{
str->set_charset(js->charset());
str->length(0);
- }
- if (possible_multiple_values && str->append("[", 1))
- goto error;
+ if (possible_multiple_values && str->append("[", 1))
+ goto error;
+ }
json_get_path_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length(), &p);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index d4abdfc614f..945224c2623 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -4136,7 +4136,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
}
}
str->append(STRING_WITH_LEN(" separator \'"));
- str->append(*separator);
+ str->append_for_single_quote(separator->ptr(), separator->length());
str->append(STRING_WITH_LEN("\')"));
}
diff --git a/sql/lock.cc b/sql/lock.cc
index 8e43001e742..11cadb528d2 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -294,7 +294,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
if (lock_tables_check(thd, tables, count, flags))
DBUG_RETURN(NULL);
- if (!(thd->variables.option_bits & OPTION_TABLE_LOCK))
+ if (!(thd->variables.option_bits & OPTION_TABLE_LOCK) &&
+ !(flags & MYSQL_LOCK_USE_MALLOC))
gld_flags|= GET_LOCK_ON_THD;
if (! (sql_lock= get_lock_data(thd, tables, count, gld_flags)))
@@ -415,7 +416,8 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
mysql_unlock_tables(thd, sql_lock,
- thd->variables.option_bits & OPTION_TABLE_LOCK);
+ (thd->variables.option_bits & OPTION_TABLE_LOCK) ||
+ !(sql_lock->flags & GET_LOCK_ON_THD));
}
@@ -433,7 +435,10 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
if (sql_lock->lock_count)
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0);
if (free_lock)
+ {
+ DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD));
my_free(sql_lock);
+ }
if (!errors)
thd->clear_error();
THD_STAGE_INFO(thd, org_stage);
@@ -668,6 +673,7 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
sql_lock->table_count=a->table_count+b->table_count;
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
+ sql_lock->flags= 0;
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
memcpy(sql_lock->locks+a->lock_count,b->locks,
b->lock_count*sizeof(*b->locks));
@@ -782,6 +788,7 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
sql_lock->table_count= table_count;
+ sql_lock->flags= flags;
for (i=0 ; i < count ; i++)
{
diff --git a/sql/log.cc b/sql/log.cc
index bdf0b6fdc59..6923a6241cd 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2470,7 +2470,7 @@ static int find_uniq_filename(char *name, ulong next_log_number)
char buff[FN_REFLEN], ext_buf[FN_REFLEN];
struct st_my_dir *dir_info;
reg1 struct fileinfo *file_info;
- ulong max_found, next, number;
+ ulong max_found, next, UNINIT_VAR(number);
size_t buf_length, length;
char *start, *end;
int error= 0;
@@ -2993,7 +2993,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
mysql_mutex_lock(&LOCK_log);
if (is_open())
{ // Safety agains reopen
- int tmp_errno= 0;
char buff[80], *end;
char query_time_buff[22+7], lock_time_buff[22+7];
size_t buff_len;
@@ -3015,16 +3014,13 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
/* Note that my_b_write() assumes it knows the length for this */
if (my_b_write(&log_file, (uchar*) buff, buff_len))
- tmp_errno= errno;
+ goto err;
}
const uchar uh[]= "# User@Host: ";
- if (my_b_write(&log_file, uh, sizeof(uh) - 1))
- tmp_errno= errno;
- if (my_b_write(&log_file, (uchar*) user_host, user_host_len))
- tmp_errno= errno;
- if (my_b_write(&log_file, (uchar*) "\n", 1))
- tmp_errno= errno;
- }
+ if (my_b_write(&log_file, uh, sizeof(uh) - 1) ||
+ my_b_write(&log_file, (uchar*) user_host, user_host_len) ||
+ my_b_write(&log_file, (uchar*) "\n", 1))
+ goto err;
/* For slow query log */
sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
@@ -3039,9 +3035,8 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
(ulong) thd->get_sent_row_count(),
(ulong) thd->get_examined_row_count(),
(ulong) thd->get_affected_rows(),
- (ulong) (thd->status_var.bytes_sent - thd->bytes_sent_old))
- == (size_t) -1)
- tmp_errno= errno;
+ (ulong) (thd->status_var.bytes_sent - thd->bytes_sent_old)))
+ goto err;
if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN)
&& thd->tmp_tables_used &&
@@ -3050,13 +3045,13 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
"Tmp_table_sizes: %s\n",
(ulong) thd->tmp_tables_used,
(ulong) thd->tmp_tables_disk_used,
- llstr(thd->tmp_tables_size, llbuff)) == (uint) -1)
- tmp_errno= errno;
+ llstr(thd->tmp_tables_size, llbuff)))
+ goto err;
- if (thd->spcont)
- if (my_b_printf(&log_file, "# Stored_routine: %s\n",
- ErrConvDQName(thd->spcont->m_sp).ptr()) == (uint) -1)
- tmp_errno= errno;
+ if (thd->spcont &&
+ my_b_printf(&log_file, "# Stored_routine: %s\n",
+ ErrConvDQName(thd->spcont->m_sp).ptr()))
+ goto err;
if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) &&
(thd->query_plan_flags &
@@ -3078,21 +3073,22 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
thd->query_plan_fsort_passes,
((thd->query_plan_flags & QPLAN_FILESORT_PRIORITY_QUEUE) ?
"Yes" : "No")
- ) == (size_t) -1)
- tmp_errno= errno;
+ ))
+ goto err;
if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN &&
thd->lex->explain)
{
StringBuffer<128> buf;
DBUG_ASSERT(!thd->free_list);
if (!print_explain_for_slow_log(thd->lex, thd, &buf))
- my_b_printf(&log_file, "%s", buf.c_ptr_safe());
+ if (my_b_printf(&log_file, "%s", buf.c_ptr_safe()))
+ goto err;
thd->free_items();
}
if (thd->db && strcmp(thd->db, db))
{ // Database changed
- if (my_b_printf(&log_file,"use %s;\n",thd->db) == (size_t) -1)
- tmp_errno= errno;
+ if (my_b_printf(&log_file,"use %s;\n",thd->db))
+ goto err;
strmov(db,thd->db);
}
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
@@ -3128,7 +3124,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
*end='\n';
if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
- tmp_errno= errno;
+ goto err;
}
if (is_command)
{
@@ -3137,24 +3133,27 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
DBUG_EXECUTE_IF("simulate_slow_log_write_error",
{DBUG_SET("+d,simulate_file_write_error");});
if(my_b_write(&log_file, (uchar*) buff, buff_len))
- tmp_errno= errno;
+ goto err;
}
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
my_b_write(&log_file, (uchar*) ";\n",2) ||
flush_io_cache(&log_file))
- tmp_errno= errno;
- if (tmp_errno)
- {
- error= 1;
- if (! write_error)
- {
- write_error= 1;
- sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, tmp_errno);
- }
+ goto err;
+
}
}
+end:
mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
+
+err:
+ error= 1;
+ if (! write_error)
+ {
+ write_error= 1;
+ sql_print_error(ER_THD(thd, ER_ERROR_ON_WRITE), name, errno);
+ }
+ goto end;
}
@@ -3650,6 +3649,7 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
new_xid_list_entry->binlog_name= name_mem;
new_xid_list_entry->binlog_name_len= len;
new_xid_list_entry->xid_count= 0;
+ new_xid_list_entry->notify_count= 0;
/*
Find the name for the Initial binlog checkpoint.
@@ -5006,7 +5006,55 @@ MYSQL_BIN_LOG::is_xidlist_idle_nolock()
return true;
}
+#ifdef WITH_WSREP
+inline bool
+is_gtid_cached_internal(IO_CACHE *file)
+{
+ uchar data[EVENT_TYPE_OFFSET+1];
+ bool result= false;
+ my_off_t write_pos= my_b_tell(file);
+ if (reinit_io_cache(file, READ_CACHE, 0, 0, 0))
+ return false;
+ /*
+ In the cache we have gtid event if , below condition is true,
+ */
+ my_b_read(file, data, sizeof(data));
+ uint event_type= (uchar)data[EVENT_TYPE_OFFSET];
+ if (event_type == GTID_LOG_EVENT)
+ result= true;
+ /*
+ Cleanup , Why because we have not read the full buffer
+ and this will cause next to next reinit_io_cache(called in write_cache)
+ to make cache empty.
+ */
+ file->read_pos= file->read_end;
+ if (reinit_io_cache(file, WRITE_CACHE, write_pos, 0, 0))
+ return false;
+ return result;
+}
+#endif
+#ifdef WITH_WSREP
+inline bool
+MYSQL_BIN_LOG::is_gtid_cached(THD *thd)
+{
+ binlog_cache_mngr *mngr= (binlog_cache_mngr *) thd_get_ha_data(
+ thd, binlog_hton);
+ if (!mngr)
+ return false;
+ binlog_cache_data *cache_trans= mngr->get_binlog_cache_data(
+ use_trans_cache(thd, true));
+ binlog_cache_data *cache_stmt= mngr->get_binlog_cache_data(
+ use_trans_cache(thd, false));
+ if (cache_trans && !cache_trans->empty() &&
+ is_gtid_cached_internal(&cache_trans->cache_log))
+ return true;
+ if (cache_stmt && !cache_stmt->empty() &&
+ is_gtid_cached_internal(&cache_stmt->cache_log))
+ return true;
+ return false;
+}
+#endif
/**
Create a new log file name.
@@ -5611,7 +5659,36 @@ THD::binlog_start_trans_and_stmt()
cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
{
this->binlog_set_stmt_begin();
- if (in_multi_stmt_transaction_mode())
+ bool mstmt_mode= in_multi_stmt_transaction_mode();
+#ifdef WITH_WSREP
+ /* Write Gtid
+ Get domain id only when gtid mode is set
+ If this event is replicate through a master then ,
+ we will forward the same gtid another nodes
+ We have to do this only one time in mysql transaction.
+ Since this function is called multiple times , We will check for
+ ha_info->is_started()
+ */
+ Ha_trx_info *ha_info;
+ ha_info= this->ha_data[binlog_hton->slot].ha_info + (mstmt_mode ? 1 : 0);
+
+ if (!ha_info->is_started() && wsrep_gtid_mode
+ && this->variables.gtid_seq_no)
+ {
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+ binlog_cache_data *cache_data= cache_mngr->get_binlog_cache_data(1);
+ IO_CACHE *file= &cache_data->cache_log;
+ Log_event_writer writer(file, cache_data);
+ Gtid_log_event gtid_event(this, this->variables.gtid_seq_no,
+ this->variables.gtid_domain_id,
+ true, LOG_EVENT_SUPPRESS_USE_F,
+ true, 0);
+ gtid_event.server_id= this->variables.server_id;
+ writer.write(&gtid_event);
+ }
+#endif
+ if (mstmt_mode)
trans_register_ha(this, TRUE, binlog_hton);
trans_register_ha(this, FALSE, binlog_hton);
/*
@@ -5891,7 +5968,7 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
DBUG_PRINT("enter", ("standalone: %d", standalone));
#ifdef WITH_WSREP
- if (WSREP(thd) && thd->wsrep_trx_meta.gtid.seqno != -1 && wsrep_gtid_mode)
+ if (WSREP(thd) && thd->wsrep_trx_meta.gtid.seqno != -1 && wsrep_gtid_mode && !thd->variables.gtid_seq_no)
{
domain_id= wsrep_gtid_domain_id;
} else {
@@ -5945,6 +6022,12 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
/* Write the event to the binary log. */
DBUG_ASSERT(this == &mysql_bin_log);
+
+#ifdef WITH_WSREP
+ if (wsrep_gtid_mode && is_gtid_cached(thd))
+ DBUG_RETURN(false);
+#endif
+
if (write_event(&gtid_event))
DBUG_RETURN(true);
status_var_add(thd->status_var.binlog_bytes_written, gtid_event.data_written);
@@ -9720,9 +9803,20 @@ void
TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
{
xid_count_per_binlog *entry= static_cast<xid_count_per_binlog *>(cookie);
+ bool found_entry= false;
mysql_mutex_lock(&LOCK_binlog_background_thread);
- entry->next_in_queue= binlog_background_thread_queue;
- binlog_background_thread_queue= entry;
+ /* count the same notification kind from different engines */
+ for (xid_count_per_binlog *link= binlog_background_thread_queue;
+ link && !found_entry; link= link->next_in_queue)
+ {
+ if ((found_entry= (entry == link)))
+ entry->notify_count++;
+ }
+ if (!found_entry)
+ {
+ entry->next_in_queue= binlog_background_thread_queue;
+ binlog_background_thread_queue= entry;
+ }
mysql_cond_signal(&COND_binlog_background_thread);
mysql_mutex_unlock(&LOCK_binlog_background_thread);
}
@@ -9817,13 +9911,16 @@ binlog_background_thread(void *arg __attribute__((unused)))
);
while (queue)
{
+ long count= queue->notify_count;
THD_STAGE_INFO(thd, stage_binlog_processing_checkpoint_notify);
DEBUG_SYNC(thd, "binlog_background_thread_before_mark_xid_done");
/* Set the thread start time */
thd->set_time();
/* Grab next pointer first, as mark_xid_done() may free the element. */
next= queue->next_in_queue;
- mysql_bin_log.mark_xid_done(queue->binlog_id, true);
+ queue->notify_count= 0;
+ for (long i= 0; i <= count; i++)
+ mysql_bin_log.mark_xid_done(queue->binlog_id, true);
queue= next;
DBUG_EXECUTE_IF("binlog_background_checkpoint_processed",
diff --git a/sql/log.h b/sql/log.h
index 02ace7c7921..6305dd97355 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -571,7 +571,13 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
bool is_xidlist_idle_nolock();
-
+#ifdef WITH_WSREP
+ /*
+ When this mariadb node is slave and galera enabled. So in this case
+ we write the gtid in wsrep_run_commit itself.
+ */
+ inline bool is_gtid_cached(THD *thd);
+#endif
public:
/*
A list of struct xid_count_per_binlog is used to keep track of how many
@@ -591,6 +597,7 @@ public:
ulong binlog_id;
/* Total prepared XIDs and pending checkpoint requests in this binlog. */
long xid_count;
+ long notify_count;
/* For linking in requests to the binlog background thread. */
xid_count_per_binlog *next_in_queue;
xid_count_per_binlog(); /* Give link error if constructor used. */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index e01ddf6ac65..ca659085228 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -18,7 +18,6 @@
#include "mariadb.h"
#include "sql_priv.h"
-#include "mysqld_error.h"
#ifndef MYSQL_CLIENT
#include "unireg.h"
@@ -45,6 +44,8 @@
#include "compat56.h"
#include "wsrep_mysqld.h"
#include "sql_insert.h"
+#else
+#include "mysqld_error.h"
#endif /* MYSQL_CLIENT */
#include <my_bitmap.h>
@@ -217,7 +218,7 @@ is_parallel_retry_error(rpl_group_info *rgi, int err)
static void inline slave_rows_error_report(enum loglevel level, int ha_error,
rpl_group_info *rgi, THD *thd,
TABLE *table, const char * type,
- const char *log_name, ulong pos)
+ const char *log_name, my_off_t pos)
{
const char *handler_error= (ha_error ? HA_ERR(ha_error) : NULL);
char buff[MAX_SLAVE_ERRMSG], *slider;
@@ -251,14 +252,14 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
rli->report(level, errcode, rgi->gtid_info(),
"Could not execute %s event on table %s.%s;"
"%s handler error %s; "
- "the event's master log %s, end_log_pos %lu",
+ "the event's master log %s, end_log_pos %llu",
type, table->s->db.str, table->s->table_name.str,
buff, handler_error == NULL ? "<unknown>" : handler_error,
log_name, pos);
else
rli->report(level, errcode, rgi->gtid_info(),
"Could not execute %s event on table %s.%s;"
- "%s the event's master log %s, end_log_pos %lu",
+ "%s the event's master log %s, end_log_pos %llu",
type, table->s->db.str, table->s->table_name.str,
buff, log_name, pos);
}
@@ -291,10 +292,9 @@ public:
flags Flags for the cache
DESCRIPTION
-
- Class used to guarantee copy of cache to file before exiting the
- current block. On successful copy of the cache, the cache will
- be reinited as a WRITE_CACHE.
+ Cache common parameters and ensure common flush_data() code
+ on successful copy of the cache, the cache will be reinited as a
+ WRITE_CACHE.
Currently, a pointer to the cache is provided in the
constructor, but it would be possible to create a subclass
@@ -306,28 +306,35 @@ public:
reinit_io_cache(m_cache, WRITE_CACHE, 0L, FALSE, TRUE);
}
- ~Write_on_release_cache()
+ ~Write_on_release_cache() {}
+
+ bool flush_data()
{
#ifdef MYSQL_CLIENT
- if(m_ev == NULL)
+ if (m_ev == NULL)
{
- copy_event_cache_to_file_and_reinit(m_cache, m_file);
- if (m_flags & FLUSH_F)
- fflush(m_file);
+ if (copy_event_cache_to_file_and_reinit(m_cache, m_file))
+ return 1;
+ if ((m_flags & FLUSH_F) && fflush(m_file))
+ return 1;
}
else // if m_ev<>NULL, then storing the output in output_buf
{
LEX_STRING tmp_str;
+ bool res;
if (copy_event_cache_to_string_and_reinit(m_cache, &tmp_str))
- exit(1);
- m_ev->output_buf.append(&tmp_str);
+ return 1;
+ res= m_ev->output_buf.append(&tmp_str) != 0;
my_free(tmp_str.str);
+ return res ? res : 0;
}
#else /* MySQL_SERVER */
- copy_event_cache_to_file_and_reinit(m_cache, m_file);
- if (m_flags & FLUSH_F)
- fflush(m_file);
+ if (copy_event_cache_to_file_and_reinit(m_cache, m_file))
+ return 1;
+ if ((m_flags & FLUSH_F) && fflush(m_file))
+ return 1;
#endif
+ return 0;
}
/*
@@ -365,27 +372,36 @@ private:
*/
#ifdef MYSQL_CLIENT
-static void pretty_print_str(IO_CACHE* cache, const char* str, int len)
+static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
{
const char* end = str + len;
- my_b_write_byte(cache, '\'');
+ if (my_b_write_byte(cache, '\''))
+ goto err;
+
while (str < end)
{
char c;
+ int error;
+
switch ((c=*str++)) {
- case '\n': my_b_write(cache, (uchar*)"\\n", 2); break;
- case '\r': my_b_write(cache, (uchar*)"\\r", 2); break;
- case '\\': my_b_write(cache, (uchar*)"\\\\", 2); break;
- case '\b': my_b_write(cache, (uchar*)"\\b", 2); break;
- case '\t': my_b_write(cache, (uchar*)"\\t", 2); break;
- case '\'': my_b_write(cache, (uchar*)"\\'", 2); break;
- case 0 : my_b_write(cache, (uchar*)"\\0", 2); break;
+ case '\n': error= my_b_write(cache, (uchar*)"\\n", 2); break;
+ case '\r': error= my_b_write(cache, (uchar*)"\\r", 2); break;
+ case '\\': error= my_b_write(cache, (uchar*)"\\\\", 2); break;
+ case '\b': error= my_b_write(cache, (uchar*)"\\b", 2); break;
+ case '\t': error= my_b_write(cache, (uchar*)"\\t", 2); break;
+ case '\'': error= my_b_write(cache, (uchar*)"\\'", 2); break;
+ case 0 : error= my_b_write(cache, (uchar*)"\\0", 2); break;
default:
- my_b_write_byte(cache, c);
+ error= my_b_write_byte(cache, c);
break;
}
+ if (error)
+ goto err;
}
- my_b_write_byte(cache, '\'');
+ return my_b_write_byte(cache, '\'');
+
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -1145,19 +1161,25 @@ int append_query_string(CHARSET_INFO *csinfo, String *to,
#ifdef MYSQL_CLIENT
-static void print_set_option(IO_CACHE* file, uint32 bits_changed,
+static bool print_set_option(IO_CACHE* file, uint32 bits_changed,
uint32 option, uint32 flags, const char* name,
bool* need_comma)
{
if (bits_changed & option)
{
if (*need_comma)
- my_b_write(file, (uchar*)", ", 2);
- my_b_printf(file, "%s=%d", name, MY_TEST(flags & option));
+ if (my_b_write(file, (uchar*)", ", 2))
+ goto err;
+ if (my_b_printf(file, "%s=%d", name, MY_TEST(flags & option)))
+ goto err;
*need_comma= 1;
}
+ return 0;
+err:
+ return 1;
}
#endif
+
/**************************************************************************
Log_event methods (= the parent class of all events)
**************************************************************************/
@@ -1328,7 +1350,7 @@ Log_event::Log_event(const char* buf,
*/
log_pos+= data_written; /* purecov: inspected */
}
- DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
+ DBUG_PRINT("info", ("log_pos: %llu", log_pos));
flags= uint2korr(buf + FLAGS_OFFSET);
if (((uchar)buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) ||
@@ -1457,7 +1479,7 @@ void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
mem_root);
field_list->push_back(new (mem_root)
Item_return_int(thd, "Pos",
- MY_INT32_NUM_DECIMAL_DIGITS,
+ MY_INT64_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG),
mem_root);
field_list->push_back(new (mem_root)
@@ -1469,7 +1491,7 @@ void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
mem_root);
field_list->push_back(new (mem_root)
Item_return_int(thd, "End_log_pos",
- MY_INT32_NUM_DECIMAL_DIGITS,
+ MY_INT64_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG),
mem_root);
field_list->push_back(new (mem_root) Item_empty_string(thd, "Info", 20),
@@ -1910,9 +1932,9 @@ err:
#endif
if (event.length() >= OLD_HEADER_LEN)
sql_print_error("Error in Log_event::read_log_event(): '%s',"
- " data_len: %lu, event_type: %d", error,
- uint4korr(&event[EVENT_LEN_OFFSET]),
- (uchar)event[EVENT_TYPE_OFFSET]);
+ " data_len: %lu, event_type: %u", error,
+ (ulong) uint4korr(&event[EVENT_LEN_OFFSET]),
+ (uint) (uchar)event[EVENT_TYPE_OFFSET]);
else
sql_print_error("Error in Log_event::read_log_event(): '%s'", error);
/*
@@ -2242,7 +2264,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
#ifdef MYSQL_CLIENT
-static void hexdump_minimal_header_to_io_cache(IO_CACHE *file,
+static bool hexdump_minimal_header_to_io_cache(IO_CACHE *file,
my_off_t offset,
uchar *ptr)
{
@@ -2255,15 +2277,18 @@ static void hexdump_minimal_header_to_io_cache(IO_CACHE *file,
more headers (which must be printed by other methods, if desired).
*/
char emit_buf[120]; // Enough for storing one line
- my_b_printf(file,
- "# "
- "|Timestamp "
- "|Type "
- "|Master ID "
- "|Size "
- "|Master Pos "
- "|Flags\n");
- size_t const emit_buf_written=
+ size_t emit_buf_written;
+
+ if (my_b_printf(file,
+ "# "
+ "|Timestamp "
+ "|Type "
+ "|Master ID "
+ "|Size "
+ "|Master Pos "
+ "|Flags\n"))
+ goto err;
+ emit_buf_written=
my_snprintf(emit_buf, sizeof(emit_buf),
"# %8llx " /* Position */
"|%02x %02x %02x %02x " /* Timestamp */
@@ -2281,8 +2306,13 @@ static void hexdump_minimal_header_to_io_cache(IO_CACHE *file,
ptr[17], ptr[18]); /* Flags */
DBUG_ASSERT(static_cast<size_t>(emit_buf_written) < sizeof(emit_buf));
- my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written);
- my_b_write(file, (uchar*)"#\n", 2);
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written) ||
+ my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
}
@@ -2307,7 +2337,7 @@ static void format_hex_line(char *emit_buff)
HEXDUMP_BYTES_PER_LINE + 2]= '\0';
}
-static void hexdump_data_to_io_cache(IO_CACHE *file,
+static bool hexdump_data_to_io_cache(IO_CACHE *file,
my_off_t offset,
uchar *ptr,
my_off_t size)
@@ -2329,7 +2359,7 @@ static void hexdump_data_to_io_cache(IO_CACHE *file,
my_off_t i;
if (size == 0)
- return;
+ return 0; // ok, nothing to do
format_hex_line(emit_buffer);
/*
@@ -2359,8 +2389,9 @@ static void hexdump_data_to_io_cache(IO_CACHE *file,
(ulonglong) starting_offset);
/* remove \0 left after printing address */
emit_buffer[2 + emit_buf_written]= ' ';
- my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- sizeof(emit_buffer) - 1);
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ sizeof(emit_buffer) - 1))
+ goto err;
c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2;
h= emit_buffer + 2 + 8 + 2;
format_hex_line(emit_buffer);
@@ -2395,17 +2426,23 @@ static void hexdump_data_to_io_cache(IO_CACHE *file,
/* pad unprinted area */
memset(h, ' ',
(HEXDUMP_BYTES_PER_LINE * 3 + 1) - (h - (emit_buffer + 2 + 8 + 2)));
- my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- c - emit_buffer);
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ c - emit_buffer))
+ goto err;
}
- my_b_write(file, (uchar*)"#\n", 2);
+ if (my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
}
/*
Log_event::print_header()
*/
-void Log_event::print_header(IO_CACHE* file,
+bool Log_event::print_header(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info,
bool is_more __attribute__((unused)))
{
@@ -2413,10 +2450,11 @@ void Log_event::print_header(IO_CACHE* file,
my_off_t hexdump_from= print_event_info->hexdump_from;
DBUG_ENTER("Log_event::print_header");
- my_b_write_byte(file, '#');
- print_timestamp(file);
- my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
- llstr(log_pos,llbuff));
+ if (my_b_write_byte(file, '#') ||
+ print_timestamp(file) ||
+ my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
+ llstr(log_pos,llbuff)))
+ goto err;
/* print the checksum */
@@ -2426,8 +2464,10 @@ void Log_event::print_header(IO_CACHE* file,
char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "%p "
size_t const bytes_written=
my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08x ", crc);
- my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib, checksum_alg));
- my_b_printf(file, checksum_buf, bytes_written);
+ if (my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib,
+ checksum_alg)) ||
+ my_b_printf(file, checksum_buf, bytes_written))
+ goto err;
}
/* mysqlbinlog --hexdump */
@@ -2440,24 +2480,32 @@ void Log_event::print_header(IO_CACHE* file,
size-= hdr_len;
- my_b_printf(file, "# Position\n");
+ if (my_b_printf(file, "# Position\n"))
+ goto err;
/* Write the header, nicely formatted by field. */
- hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr);
+ if (hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr))
+ goto err;
ptr+= hdr_len;
hexdump_from+= hdr_len;
/* Print the rest of the data, mimicking "hexdump -C" output. */
- hexdump_data_to_io_cache(file, hexdump_from, ptr, size);
+ if (hexdump_data_to_io_cache(file, hexdump_from, ptr, size))
+ goto err;
/*
Prefix the next line so that the output from print_helper()
will appear as a comment.
*/
- my_b_write(file, (uchar*)"# Event: ", 9);
+ if (my_b_write(file, (uchar*)"# Event: ", 9))
+ goto err;
}
- DBUG_VOID_RETURN;
+
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
}
@@ -2465,7 +2513,7 @@ void Log_event::print_header(IO_CACHE* file,
Prints a quoted string to io cache.
Control characters are displayed as hex sequence, e.g. \x00
Single-quote and backslash characters are escaped with a \
-
+
@param[in] file IO cache
@param[in] prt Pointer to string
@param[in] length String length
@@ -2552,12 +2600,14 @@ my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length)
@param[in] sl Signed number
@param[in] ul Unsigned number
*/
-static void
+static bool
my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
{
- my_b_printf(file, "%d", si);
+ bool res= my_b_printf(file, "%d", si);
if (si < 0)
- my_b_printf(file, " (%u)", ui);
+ if (my_b_printf(file, " (%u)", ui))
+ res= 1;
+ return res;
}
@@ -2576,8 +2626,8 @@ my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
*/
static size_t
-log_event_print_value(IO_CACHE *file, const uchar *ptr,
- uint type, uint meta,
+log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
+ const uchar *ptr, uint type, uint meta,
char *typestr, size_t typestr_length)
{
uint32 length= 0;
@@ -2960,19 +3010,15 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr,
return my_b_write_quoted_with_length(file, ptr, length);
case MYSQL_TYPE_DECIMAL:
- my_b_printf(file,
- "!! Old DECIMAL (mysql-4.1 or earlier). "
- "Not enough metadata to display the value. ");
+ print_event_info->flush_for_error();
+ fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
+ "Not enough metadata to display the value.\n");
break;
-
default:
- {
- char tmp[5];
- my_snprintf(tmp, sizeof(tmp), "%04x", meta);
- my_b_printf(file,
- "!! Don't know how to handle column type=%d meta=%d (%s)",
- type, meta, tmp);
- }
+ print_event_info->flush_for_error();
+ fprintf(stderr,
+ "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n",
+ type, meta, meta);
break;
}
*typestr= 0;
@@ -2993,7 +3039,8 @@ return_null:
@param[in] value Pointer to packed row
@param[in] prefix Row's SQL clause ("SET", "WHERE", etc)
- @retval - number of bytes scanned.
+ @retval 0 error
+ # number of bytes scanned.
*/
@@ -3023,7 +3070,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
if (!no_fill_output)
- my_b_printf(file, "%s", prefix);
+ if (my_b_printf(file, "%s", prefix))
+ goto err;
for (size_t i= 0; i < td->size(); i ++)
{
@@ -3035,7 +3083,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
continue;
if (!no_fill_output)
- my_b_printf(file, "### @%d=", static_cast<int>(i + 1));
+ if (my_b_printf(file, "### @%d=", static_cast<int>(i + 1)))
+ goto err;
if (!is_null)
{
@@ -3043,8 +3092,9 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
if (value + fsize > m_rows_end)
{
if (!no_fill_output)
- my_b_printf(file, "***Corrupted replication event was detected."
- " Not printing the value***\n");
+ if (my_b_printf(file, "***Corrupted replication event was detected."
+ " Not printing the value***\n"))
+ goto err;
value+= fsize;
return 0;
}
@@ -3052,7 +3102,7 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
if (!no_fill_output)
{
- size= log_event_print_value(file,is_null? NULL: value,
+ size= log_event_print_value(file, print_event_info, is_null? NULL: value,
td->type(i), td->field_metadata(i),
typestr, sizeof(typestr));
#ifdef WHEN_FLASHBACK_REVIEW_READY
@@ -3063,12 +3113,14 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
// Using a tmp IO_CACHE to get the value output
open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache, is_null? NULL: value,
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
td->type(i), td->field_metadata(i),
typestr, sizeof(typestr));
- if (copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str))
- exit(1);
+ error= copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str);
close_cached_file(&tmp_cache);
+ if (error)
+ return 0;
switch (td->type(i)) // Converting a string to HEX format
{
@@ -3086,12 +3138,14 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
exit(1);
}
octet2hex((char*) hex_str.ptr(), tmp_str.ptr(), tmp_str.length());
- my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr());
+ if (my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr()))
+ goto err;
break;
default:
tmp_str.free();
- tmp_str.append(review_str.str, review_str.length);
- my_b_printf(review_sql, ", %s", tmp_str.ptr());
+ if (tmp_str.append(review_str.str, review_str.length) ||
+ my_b_printf(review_sql, ", %s", tmp_str.ptr()))
+ goto err;
break;
}
my_free(revieww_str.str);
@@ -3102,36 +3156,40 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
{
IO_CACHE tmp_cache;
open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache,is_null? NULL: value,
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
td->type(i), td->field_metadata(i),
typestr, sizeof(typestr));
close_cached_file(&tmp_cache);
}
if (!size)
- return 0;
+ goto err;
if (!is_null)
value+= size;
if (print_event_info->verbose > 1 && !no_fill_output)
{
- my_b_write(file, (uchar*)" /* ", 4);
-
- my_b_printf(file, "%s ", typestr);
-
- my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
- td->field_metadata(i),
- td->maybe_null(i), is_null);
- my_b_write(file, (uchar*)"*/", 2);
+ if (my_b_write(file, (uchar*)" /* ", 4) ||
+ my_b_printf(file, "%s ", typestr) ||
+ my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
+ td->field_metadata(i),
+ td->maybe_null(i), is_null) ||
+ my_b_write(file, (uchar*)"*/", 2))
+ goto err;
}
if (!no_fill_output)
- my_b_write_byte(file, '\n');
+ if (my_b_write_byte(file, '\n'))
+ goto err;
null_bit_index++;
}
return value - value0;
+
+err:
+ return 0;
}
@@ -3170,10 +3228,10 @@ void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_inf
if (!(length1= print_verbose_one_row(NULL, td, print_event_info,
&m_cols, value,
(const uchar*) "", TRUE)))
- {
- fprintf(stderr, "\nError row length: %zu\n", length1);
- exit(1);
- }
+ {
+ fprintf(stderr, "\nError row length: %zu\n", length1);
+ exit(1);
+ }
value+= length1;
swap_buff1= (uchar *) my_malloc(length1, MYF(0));
@@ -3252,18 +3310,230 @@ end:
delete td;
}
+/**
+ Calc length of a packed value of the given SQL type
+
+ @param[in] ptr Pointer to string
+ @param[in] type Column type
+ @param[in] meta Column meta information
+
+ @retval - number of bytes scanned from ptr.
+ Except in case of NULL, in which case we return 1 to indicate ok
+*/
+
+static size_t calc_field_event_length(const uchar *ptr, uint type, uint meta)
+{
+ uint32 length= 0;
+
+ if (type == MYSQL_TYPE_STRING)
+ {
+ if (meta >= 256)
+ {
+ uint byte0= meta >> 8;
+ uint byte1= meta & 0xFF;
+
+ if ((byte0 & 0x30) != 0x30)
+ {
+ /* a long CHAR() field: see #37426 */
+ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
+ type= byte0 | 0x30;
+ }
+ else
+ length = meta & 0xFF;
+ }
+ else
+ length= meta;
+ }
+
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_TIMESTAMP:
+ return 4;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_YEAR:
+ return 1;
+ case MYSQL_TYPE_SHORT:
+ return 2;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ return 3;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_DATETIME:
+ return 8;
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint precision= meta >> 8;
+ uint decimals= meta & 0xFF;
+ uint bin_size= my_decimal_get_binary_size(precision, decimals);
+ return bin_size;
+ }
+ case MYSQL_TYPE_FLOAT:
+ return 4;
+ case MYSQL_TYPE_DOUBLE:
+ return 8;
+ case MYSQL_TYPE_BIT:
+ {
+ /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
+ uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
+ length= (nbits + 7) / 8;
+ return length;
+ }
+ case MYSQL_TYPE_TIMESTAMP2:
+ return my_timestamp_binary_length(meta);
+ case MYSQL_TYPE_DATETIME2:
+ return my_datetime_binary_length(meta);
+ case MYSQL_TYPE_TIME2:
+ return my_time_binary_length(meta);
+ case MYSQL_TYPE_ENUM:
+ switch (meta & 0xFF) {
+ case 1:
+ case 2:
+ return (meta & 0xFF);
+ default:
+ /* Unknown ENUM packlen=%d", meta & 0xFF */
+ return 0;
+ }
+ break;
+ case MYSQL_TYPE_SET:
+ return meta & 0xFF;
+ case MYSQL_TYPE_BLOB:
+ return (meta <= 4 ? meta : 0);
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ length= meta;
+ /* fall through */
+ case MYSQL_TYPE_STRING:
+ if (length < 256)
+ return (uint) *ptr + 1;
+ return uint2korr(ptr) + 2;
+ case MYSQL_TYPE_DECIMAL:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+size_t
+Rows_log_event::calc_row_event_length(table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value)
+{
+ const uchar *value0= value;
+ const uchar *null_bits= value;
+ uint null_bit_index= 0;
+
+ /*
+ Skip metadata bytes which gives the information about nullabity of master
+ columns. Master writes one bit for each affected column.
+ */
+
+ value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
+
+ for (size_t i= 0; i < td->size(); i ++)
+ {
+ int is_null;
+ is_null= (null_bits[null_bit_index / 8] >> (null_bit_index % 8)) & 0x01;
+
+ if (bitmap_is_set(cols_bitmap, i) == 0)
+ continue;
+
+ if (!is_null)
+ {
+ size_t size;
+ size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
+ if (value + fsize > m_rows_end)
+ {
+ /* Corrupted replication event was detected, skipping entry */
+ return 0;
+ }
+ if (!(size= calc_field_event_length(value, td->type(i),
+ td->field_metadata(i))))
+ return 0;
+ value+= size;
+ }
+ null_bit_index++;
+ }
+ return value - value0;
+}
+
+
+/**
+ Calculate how many rows there are in the event
+
+ @param[in] file IO cache
+ @param[in] print_event_into Print parameters
+*/
+
+void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info)
+{
+ Table_map_log_event *map;
+ table_def *td;
+ uint row_events;
+ Log_event_type general_type_code= get_general_type_code();
+
+ switch (general_type_code) {
+ case WRITE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT:
+ row_events= 1;
+ break;
+ case UPDATE_ROWS_EVENT:
+ row_events= 2;
+ break;
+ default:
+ DBUG_ASSERT(0); /* Not possible */
+ return;
+ }
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ {
+ /* Row event for unknown table */
+ return;
+ }
+
+ for (const uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ size_t length;
+ print_event_info->row_events++;
+
+ /* Print the first image */
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+
+ /* Print the second image (for UPDATE only) */
+ if (row_events == 2)
+ {
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols_ai, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+ }
+ }
+ delete td;
+}
+
/**
Print a row event into IO cache in human readable form (in SQL format)
-
+
@param[in] file IO cache
@param[in] print_event_into Print parameters
*/
-void Rows_log_event::print_verbose(IO_CACHE *file,
+
+bool Rows_log_event::print_verbose(IO_CACHE *file,
PRINT_EVENT_INFO *print_event_info)
{
Table_map_log_event *map;
- table_def *td;
+ table_def *td= 0;
const char *sql_command, *sql_clause1, *sql_clause2;
const char *sql_command_short __attribute__((unused));
Log_event_type general_type_code= get_general_type_code();
@@ -3277,9 +3547,10 @@ void Rows_log_event::print_verbose(IO_CACHE *file,
uint8 extra_payload_len= extra_data_len - EXTRA_ROW_INFO_HDR_BYTES;
assert(extra_data_len >= EXTRA_ROW_INFO_HDR_BYTES);
- my_b_printf(file, "### Extra row data format: %u, len: %u :",
- m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
- extra_payload_len);
+ if (my_b_printf(file, "### Extra row data format: %u, len: %u :",
+ m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
+ extra_payload_len))
+ goto err;
if (extra_payload_len)
{
/*
@@ -3290,9 +3561,11 @@ void Rows_log_event::print_verbose(IO_CACHE *file,
char buff[buff_len];
str_to_hex(buff, (const char*) &m_extra_row_data[EXTRA_ROW_INFO_HDR_BYTES],
extra_payload_len);
- my_b_printf(file, "%s", buff);
+ if (my_b_printf(file, "%s", buff))
+ goto err;
}
- my_b_printf(file, "\n");
+ if (my_b_printf(file, "\n"))
+ goto err;
}
switch (general_type_code) {
@@ -3319,41 +3592,45 @@ void Rows_log_event::print_verbose(IO_CACHE *file,
sql_command_short= "";
DBUG_ASSERT(0); /* Not possible */
}
-
+
if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
!(td= map->create_table_def()))
{
- my_b_printf(file, "### Row event for unknown table #%lu",
- (ulong) m_table_id);
- return;
+ return (my_b_printf(file, "### Row event for unknown table #%lu",
+ (ulong) m_table_id));
}
/* If the write rows event contained no values for the AI */
if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
{
- my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
- map->get_db_name(), map->get_table_name());
+ if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
+ map->get_db_name(), map->get_table_name()))
+ goto err;
goto end;
}
for (const uchar *value= m_rows_buf; value < m_rows_end; )
{
size_t length;
- my_b_printf(file, "### %s %`s.%`s\n",
- sql_command,
- map->get_db_name(), map->get_table_name());
+ print_event_info->row_events++;
+ if (my_b_printf(file, "### %s %`s.%`s\n",
+ sql_command,
+ map->get_db_name(), map->get_table_name()))
+ goto err;
#ifdef WHEN_FLASHBACK_REVIEW_READY
if (need_flashback_review)
- my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
- map->get_review_dbname(), map->get_review_tablename(), sql_command_short);
+ if (my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
+ map->get_review_dbname(), map->get_review_tablename(),
+ sql_command_short))
+ goto err;
#endif
/* Print the first image */
if (!(length= print_verbose_one_row(file, td, print_event_info,
&m_cols, value,
(const uchar*) sql_clause1)))
- goto end;
+ goto err;
value+= length;
/* Print the second image (for UPDATE only) */
@@ -3362,7 +3639,7 @@ void Rows_log_event::print_verbose(IO_CACHE *file,
if (!(length= print_verbose_one_row(file, td, print_event_info,
&m_cols_ai, value,
(const uchar*) sql_clause2)))
- goto end;
+ goto err;
value+= length;
}
#ifdef WHEN_FLASHBACK_REVIEW_READY
@@ -3370,16 +3647,22 @@ void Rows_log_event::print_verbose(IO_CACHE *file,
{
if (need_flashback_review)
for (size_t i= 0; i < td->size(); i ++)
- my_b_printf(review_sql, ", NULL");
+ if (my_b_printf(review_sql, ", NULL"))
+ goto err;
}
if (need_flashback_review)
- my_b_printf(review_sql, ")%s\n", print_event_info->delimiter);
+ if (my_b_printf(review_sql, ")%s\n", print_event_info->delimiter))
+ goto err;
#endif
}
end:
delete td;
+ return 0;
+err:
+ delete td;
+ return 1;
}
void free_table_map_log_event(Table_map_log_event *event)
@@ -3387,7 +3670,7 @@ void free_table_map_log_event(Table_map_log_event *event)
delete event;
}
-void Log_event::print_base64(IO_CACHE* file,
+bool Log_event::print_base64(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info,
bool more)
{
@@ -3395,14 +3678,6 @@ void Log_event::print_base64(IO_CACHE* file,
uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
DBUG_ENTER("Log_event::print_base64");
- size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
- char *const tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME));
- if (!tmp_str) {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not print correct binlog event.\n");
- DBUG_VOID_RETURN;
- }
-
if (is_flashback)
{
uint tmp_size= size;
@@ -3448,27 +3723,41 @@ void Log_event::print_base64(IO_CACHE* file,
delete ev;
}
- if (my_base64_encode(ptr, (size_t) size, tmp_str))
+ if (print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
+ ! print_event_info->short_form)
{
- DBUG_ASSERT(0);
- }
-
- if (print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
- {
- if (my_b_tell(file) == 0)
- my_b_write_string(file, "\nBINLOG '\n");
+ size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
+ bool error= 0;
+ char *tmp_str;
+ if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME))))
+ goto err;
- my_b_printf(file, "%s\n", tmp_str);
+ if (my_base64_encode(ptr, (size_t) size, tmp_str))
+ {
+ DBUG_ASSERT(0);
+ }
- if (!more)
- my_b_printf(file, "'%s\n", print_event_info->delimiter);
+ if (my_b_tell(file) == 0)
+ if (my_b_write_string(file, "\nBINLOG '\n"))
+ error= 1;
+ if (!error && my_b_printf(file, "%s\n", tmp_str))
+ error= 1;
+ if (!more && !error)
+ if (my_b_printf(file, "'%s\n", print_event_info->delimiter))
+ error= 1;
+ my_free(tmp_str);
+ if (error)
+ goto err;
}
#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (print_event_info->verbose || need_flashback_review)
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ need_flashback_review)
#else
// Flashback need the table_map to parse the event
- if (print_event_info->verbose || is_flashback)
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ is_flashback)
#endif
{
Rows_log_event *ev= NULL;
@@ -3543,27 +3832,49 @@ void Log_event::print_base64(IO_CACHE* file,
if (ev)
{
+ bool error= 0;
+
#ifdef WHEN_FLASHBACK_REVIEW_READY
ev->need_flashback_review= need_flashback_review;
if (print_event_info->verbose)
- ev->print_verbose(file, print_event_info);
+ {
+ if (ev->print_verbose(file, print_event_info))
+ goto err;
+ }
else
{
IO_CACHE tmp_cache;
- open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- ev->print_verbose(&tmp_cache, print_event_info);
+
+ if (open_cached_file(&tmp_cache, NULL, NULL, 0,
+ MYF(MY_WME | MY_NABP)))
+ {
+ delete ev;
+ goto err;
+ }
+
+ error= ev->print_verbose(&tmp_cache, print_event_info);
close_cached_file(&tmp_cache);
+ if (error)
+ {
+ delete ev;
+ goto err;
+ }
}
#else
if (print_event_info->verbose)
- ev->print_verbose(file, print_event_info);
+ error= ev->print_verbose(file, print_event_info);
+ else
+ ev->count_row_events(print_event_info);
#endif
delete ev;
+ if (error)
+ goto err;
}
}
+ DBUG_RETURN(0);
- my_free(tmp_str);
- DBUG_VOID_RETURN;
+err:
+ DBUG_RETURN(1);
}
@@ -3571,7 +3882,7 @@ void Log_event::print_base64(IO_CACHE* file,
Log_event::print_timestamp()
*/
-void Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
+bool Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
{
struct tm *res;
time_t my_when= when;
@@ -3580,14 +3891,13 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
ts = &my_when;
res=localtime(ts);
- my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
- res->tm_year % 100,
- res->tm_mon+1,
- res->tm_mday,
- res->tm_hour,
- res->tm_min,
- res->tm_sec);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
+ res->tm_year % 100,
+ res->tm_mon+1,
+ res->tm_mday,
+ res->tm_hour,
+ res->tm_min,
+ res->tm_sec));
}
#endif /* MYSQL_CLIENT */
@@ -4746,7 +5056,7 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
@todo
print the catalog ??
*/
-void Query_log_event::print_query_header(IO_CACHE* file,
+bool Query_log_event::print_query_header(IO_CACHE* file,
PRINT_EVENT_INFO* print_event_info)
{
// TODO: print the catalog ??
@@ -4756,10 +5066,12 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (!print_event_info->short_form)
{
- print_header(file, print_event_info, FALSE);
- my_b_printf(file, "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
- get_type_str(), (ulong) thread_id, (ulong) exec_time,
- error_code);
+ if (print_header(file, print_event_info, FALSE) ||
+ my_b_printf(file,
+ "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
+ get_type_str(), (ulong) thread_id, (ulong) exec_time,
+ error_code))
+ goto err;
}
if ((flags & LOG_EVENT_SUPPRESS_USE_F))
@@ -4773,7 +5085,8 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (different_db)
memcpy(print_event_info->db, db, db_len + 1);
if (db[0] && different_db)
- my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter);
+ if (my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter))
+ goto err;
}
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
@@ -4784,15 +5097,17 @@ void Query_log_event::print_query_header(IO_CACHE* file,
}
end= strmov(end, print_event_info->delimiter);
*end++='\n';
- my_b_write(file, (uchar*) buff, (uint) (end-buff));
+ if (my_b_write(file, (uchar*) buff, (uint) (end-buff)))
+ goto err;
if ((!print_event_info->thread_id_printed ||
((flags & LOG_EVENT_THREAD_SPECIFIC_F) &&
thread_id != print_event_info->thread_id)))
{
// If --short-form, print deterministic value instead of pseudo_thread_id.
- my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
- short_form ? 999999999 : (ulong)thread_id,
- print_event_info->delimiter);
+ if (my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
+ short_form ? 999999999 : (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
print_event_info->thread_id= thread_id;
print_event_info->thread_id_printed= 1;
}
@@ -4817,18 +5132,20 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (unlikely(tmp)) /* some bits have changed */
{
bool need_comma= 0;
- my_b_write_string(file, "SET ");
- print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
- "@@session.foreign_key_checks", &need_comma);
- print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
- "@@session.sql_auto_is_null", &need_comma);
- print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
- "@@session.unique_checks", &need_comma);
- print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
- "@@session.autocommit", &need_comma);
- print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS, ~flags2,
- "@@session.check_constraint_checks", &need_comma);
- my_b_printf(file,"%s\n", print_event_info->delimiter);
+ if (my_b_write_string(file, "SET ") ||
+ print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
+ "@@session.foreign_key_checks", &need_comma)||
+ print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
+ "@@session.sql_auto_is_null", &need_comma) ||
+ print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
+ "@@session.unique_checks", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
+ "@@session.autocommit", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
+ ~flags2,
+ "@@session.check_constraint_checks", &need_comma) ||
+ my_b_printf(file,"%s\n", print_event_info->delimiter))
+ goto err;
print_event_info->flags2= flags2;
}
}
@@ -4851,17 +5168,19 @@ void Query_log_event::print_query_header(IO_CACHE* file,
!print_event_info->sql_mode_inited)))
{
char llbuff[22];
- my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
- ullstr(sql_mode, llbuff), print_event_info->delimiter);
+ if (my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
+ ullstr(sql_mode, llbuff), print_event_info->delimiter))
+ goto err;
print_event_info->sql_mode= sql_mode;
print_event_info->sql_mode_inited= 1;
}
if (print_event_info->auto_increment_increment != auto_increment_increment ||
print_event_info->auto_increment_offset != auto_increment_offset)
{
- my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
- auto_increment_increment,auto_increment_offset,
- print_event_info->delimiter);
+ if (my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
+ auto_increment_increment,auto_increment_offset,
+ print_event_info->delimiter))
+ goto err;
print_event_info->auto_increment_increment= auto_increment_increment;
print_event_info->auto_increment_offset= auto_increment_offset;
}
@@ -4876,18 +5195,20 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (cs_info)
{
/* for mysql client */
- my_b_printf(file, "/*!\\C %s */%s\n",
- cs_info->csname, print_event_info->delimiter);
- }
- my_b_printf(file,"SET "
- "@@session.character_set_client=%d,"
- "@@session.collation_connection=%d,"
- "@@session.collation_server=%d"
- "%s\n",
- uint2korr(charset),
- uint2korr(charset+2),
- uint2korr(charset+4),
- print_event_info->delimiter);
+ if (my_b_printf(file, "/*!\\C %s */%s\n",
+ cs_info->csname, print_event_info->delimiter))
+ goto err;
+ }
+ if (my_b_printf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ "%s\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4),
+ print_event_info->delimiter))
+ goto err;
memcpy(print_event_info->charset, charset, 6);
print_event_info->charset_inited= 1;
}
@@ -4896,31 +5217,40 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (memcmp(print_event_info->time_zone_str,
time_zone_str, time_zone_len+1))
{
- my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
- time_zone_str, print_event_info->delimiter);
+ if (my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
+ time_zone_str, print_event_info->delimiter))
+ goto err;
memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
}
}
if (lc_time_names_number != print_event_info->lc_time_names_number)
{
- my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
- lc_time_names_number, print_event_info->delimiter);
+ if (my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
+ lc_time_names_number, print_event_info->delimiter))
+ goto err;
print_event_info->lc_time_names_number= lc_time_names_number;
}
if (charset_database_number != print_event_info->charset_database_number)
{
if (charset_database_number)
- my_b_printf(file, "SET @@session.collation_database=%d%s\n",
- charset_database_number, print_event_info->delimiter);
- else
- my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
- print_event_info->delimiter);
+ {
+ if (my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+ charset_database_number, print_event_info->delimiter))
+ goto err;
+ }
+ else if (my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+ print_event_info->delimiter))
+ goto err;
print_event_info->charset_database_number= charset_database_number;
}
+ return 0;
+
+err:
+ return 1;
}
-void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this);
@@ -4930,25 +5260,32 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
*/
DBUG_EXECUTE_IF ("simulate_file_write_error",
{(&cache)->write_pos= (&cache)->write_end- 500;});
- print_query_header(&cache, print_event_info);
+ if (print_query_header(&cache, print_event_info))
+ goto err;
if (!is_flashback)
{
- my_b_write(&cache, (uchar*) query, q_len);
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
}
else // is_flashback == 1
{
if (strcmp("BEGIN", query) == 0)
{
- my_b_write(&cache, (uchar*) "COMMIT", 6);
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
+ if (my_b_write(&cache, (uchar*) "COMMIT", 6) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
}
else if (strcmp("COMMIT", query) == 0)
{
- my_b_write(&cache, (uchar*) "BEGIN", 5);
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
+ if (my_b_write(&cache, (uchar*) "BEGIN", 5) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
}
}
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -5559,7 +5896,7 @@ void Start_log_event_v3::pack_info(Protocol *protocol)
*/
#ifdef MYSQL_CLIENT
-void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
DBUG_ENTER("Start_log_event_v3::print");
@@ -5568,16 +5905,21 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
if (!print_event_info->short_form)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
- binlog_version, server_version);
- print_timestamp(&cache);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
+ binlog_version, server_version) ||
+ print_timestamp(&cache))
+ goto err;
if (created)
- my_b_printf(&cache," at startup");
- my_b_printf(&cache, "\n");
+ if (my_b_printf(&cache," at startup"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
if (flags & LOG_EVENT_BINLOG_IN_USE_F)
- my_b_printf(&cache, "# Warning: this binlog is either in use or was not "
- "closed properly.\n");
+ if (my_b_printf(&cache,
+ "# Warning: this binlog is either in use or was not "
+ "closed properly.\n"))
+ goto err;
}
if (!is_artificial_event() && created)
{
@@ -5588,9 +5930,12 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
and rollback unfinished transaction.
Probably this can be done with RESET CONNECTION (syntax to be defined).
*/
- my_b_printf(&cache,"RESET CONNECTION%s\n", print_event_info->delimiter);
+ if (my_b_printf(&cache,"RESET CONNECTION%s\n",
+ print_event_info->delimiter))
+ goto err;
#else
- my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter);
+ if (my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter))
+ goto err;
#endif
}
if (temp_buf &&
@@ -5598,11 +5943,15 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
!print_event_info->short_form)
{
if (print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
- my_b_printf(&cache, "BINLOG '\n");
- print_base64(&cache, print_event_info, FALSE);
+ if (my_b_printf(&cache, "BINLOG '\n"))
+ goto err;
+ if (print_base64(&cache, print_event_info, FALSE))
+ goto err;
print_event_info->printed_fd_event= TRUE;
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
}
#endif /* MYSQL_CLIENT */
@@ -6285,7 +6634,7 @@ int Start_encryption_log_event::do_update_pos(rpl_group_info *rgi)
#endif
#ifndef MYSQL_SERVER
-void Start_encryption_log_event::print(FILE* file,
+bool Start_encryption_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file);
@@ -6297,7 +6646,9 @@ void Start_encryption_log_event::print(FILE* file,
buf.append(STRING_WITH_LEN(", nonce: "));
buf.append_hex(nonce, BINLOG_NONCE_LENGTH);
buf.append(STRING_WITH_LEN("\n# The rest of the binlog is encrypted!\n"));
- my_b_write(&cache, (uchar*)buf.ptr(), buf.length());
+ if (my_b_write(&cache, (uchar*)buf.ptr(), buf.length()))
+ return 1;
+ return (cache.flush_data());
}
#endif
/**************************************************************************
@@ -6322,7 +6673,7 @@ void Start_encryption_log_event::print(FILE* file,
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
+bool Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
String *buf, my_off_t *fn_start,
my_off_t *fn_end, const char *qualify_db)
{
@@ -6418,6 +6769,7 @@ void Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
}
buf->append(STRING_WITH_LEN(")"));
}
+ return 0;
}
@@ -6661,26 +7013,27 @@ err:
*/
#ifdef MYSQL_CLIENT
-void Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
- print(file, print_event_info, 0);
+ return print(file, print_event_info, 0);
}
-void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
+bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
bool commented)
{
Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
-
+ bool different_db= 1;
DBUG_ENTER("Load_log_event::print");
+
if (!print_event_info->short_form)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
- thread_id, exec_time);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
+ thread_id, exec_time))
+ goto err;
}
- bool different_db= 1;
if (db)
{
/*
@@ -6693,69 +7046,86 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
!commented)
memcpy(print_event_info->db, db, db_len + 1);
}
-
+
if (db && db[0] && different_db)
- my_b_printf(&cache, "%suse %`s%s\n",
- commented ? "# " : "",
- db, print_event_info->delimiter);
+ if (my_b_printf(&cache, "%suse %`s%s\n",
+ commented ? "# " : "",
+ db, print_event_info->delimiter))
+ goto err;
if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
- my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
- commented ? "# " : "", (ulong)thread_id,
- print_event_info->delimiter);
- my_b_printf(&cache, "%sLOAD DATA ",
- commented ? "# " : "");
+ if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
+ commented ? "# " : "", (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
+ if (my_b_printf(&cache, "%sLOAD DATA ",
+ commented ? "# " : ""))
+ goto err;
if (check_fname_outside_temp_buf())
- my_b_write_string(&cache, "LOCAL ");
- my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname);
+ if (my_b_write_string(&cache, "LOCAL "))
+ goto err;
+ if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
+ goto err;
if (sql_ex.opt_flags & REPLACE_FLAG)
- my_b_write_string(&cache, "REPLACE ");
+ {
+ if (my_b_write_string(&cache, "REPLACE "))
+ goto err;
+ }
else if (sql_ex.opt_flags & IGNORE_FLAG)
- my_b_write_string(&cache, "IGNORE ");
-
- my_b_printf(&cache, "INTO TABLE `%s`", table_name);
- my_b_write_string(&cache, " FIELDS TERMINATED BY ");
- pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len);
+ if (my_b_write_string(&cache, "IGNORE "))
+ goto err;
- if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
- my_b_write_string(&cache, " OPTIONALLY ");
- my_b_write_string(&cache, " ENCLOSED BY ");
- pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len);
-
- my_b_write_string(&cache, " ESCAPED BY ");
- pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len);
-
- my_b_write_string(&cache, " LINES TERMINATED BY ");
- pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len);
+ if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
+ my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
+ goto err;
+ if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
+ if (my_b_write_string(&cache, " OPTIONALLY "))
+ goto err;
+ if (my_b_write_string(&cache, " ENCLOSED BY ") ||
+ pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
+ my_b_write_string(&cache, " ESCAPED BY ") ||
+ pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
+ my_b_write_string(&cache, " LINES TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
+ goto err;
if (sql_ex.line_start)
{
- my_b_write_string(&cache," STARTING BY ");
- pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len);
+ if (my_b_write_string(&cache," STARTING BY ") ||
+ pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
+ goto err;
}
if ((long) skip_lines > 0)
- my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines);
+ if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
+ goto err;
if (num_fields)
{
uint i;
const char* field = fields;
- my_b_write_string(&cache, " (");
+ if (my_b_write_string(&cache, " ("))
+ goto err;
for (i = 0; i < num_fields; i++)
{
if (i)
- my_b_write_byte(&cache, ',');
- my_b_printf(&cache, "%`s", field);
-
+ if (my_b_write_byte(&cache, ','))
+ goto err;
+ if (my_b_printf(&cache, "%`s", field))
+ goto err;
field += field_lens[i] + 1;
}
- my_b_write_byte(&cache, ')');
+ if (my_b_write_byte(&cache, ')'))
+ goto err;
}
- my_b_printf(&cache, "%s\n", print_event_info->delimiter);
- DBUG_VOID_RETURN;
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
}
#endif /* MYSQL_CLIENT */
@@ -7114,19 +7484,25 @@ void Rotate_log_event::pack_info(Protocol *protocol)
*/
#ifdef MYSQL_CLIENT
-void Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
char buf[22];
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
-
- if (print_event_info->short_form)
- return;
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tRotate to ");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRotate to "))
+ goto err;
if (new_log_ident)
- my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len);
- my_b_printf(&cache, " pos: %s\n", llstr(pos, buf));
+ if (my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len))
+ goto err;
+ if (my_b_printf(&cache, " pos: %s\n", llstr(pos, buf)))
+ goto err;
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -7331,18 +7707,21 @@ Binlog_checkpoint_log_event::do_shall_skip(rpl_group_info *rgi)
#ifdef MYSQL_CLIENT
-void Binlog_checkpoint_log_event::print(FILE *file,
+bool Binlog_checkpoint_log_event::print(FILE *file,
PRINT_EVENT_INFO *print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
- if (print_event_info->short_form)
- return;
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tBinlog checkpoint ");
- my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len);
- my_b_write_byte(&cache, '\n');
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tBinlog checkpoint ") ||
+ my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len) ||
+ my_b_write_byte(&cache, '\n'))
+ return 1;
+ return cache.flush_data();
}
#endif /* MYSQL_CLIENT */
@@ -7660,7 +8039,7 @@ Gtid_log_event::do_shall_skip(rpl_group_info *rgi)
#else /* !MYSQL_SERVER */
-void
+bool
Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file,
@@ -7672,26 +8051,34 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
{
print_header(&cache, print_event_info, FALSE);
longlong10_to_str(seq_no, buf, 10);
- my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf);
+ if (my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf))
+ goto err;
if (flags2 & FL_GROUP_COMMIT_ID)
{
longlong10_to_str(commit_id, buf2, 10);
- my_b_printf(&cache, " cid=%s", buf2);
+ if (my_b_printf(&cache, " cid=%s", buf2))
+ goto err;
}
if (flags2 & FL_DDL)
- my_b_write_string(&cache, " ddl");
+ if (my_b_write_string(&cache, " ddl"))
+ goto err;
if (flags2 & FL_TRANSACTIONAL)
- my_b_write_string(&cache, " trans");
+ if (my_b_write_string(&cache, " trans"))
+ goto err;
if (flags2 & FL_WAITED)
- my_b_write_string(&cache, " waited");
- my_b_printf(&cache, "\n");
+ if (my_b_write_string(&cache, " waited"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
if (!print_event_info->allow_parallel_printed ||
print_event_info->allow_parallel != !!(flags2 & FL_ALLOW_PARALLEL))
{
- my_b_printf(&cache,
+ if (my_b_printf(&cache,
"/*!100101 SET @@session.skip_parallel_replication=%u*/%s\n",
- !(flags2 & FL_ALLOW_PARALLEL), print_event_info->delimiter);
+ !(flags2 & FL_ALLOW_PARALLEL),
+ print_event_info->delimiter))
+ goto err;
print_event_info->allow_parallel= !!(flags2 & FL_ALLOW_PARALLEL);
print_event_info->allow_parallel_printed= true;
}
@@ -7699,8 +8086,10 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
if (!print_event_info->domain_id_printed ||
print_event_info->domain_id != domain_id)
{
- my_b_printf(&cache, "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
- domain_id, print_event_info->delimiter);
+ if (my_b_printf(&cache,
+ "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
+ domain_id, print_event_info->delimiter))
+ goto err;
print_event_info->domain_id= domain_id;
print_event_info->domain_id_printed= true;
}
@@ -7708,18 +8097,25 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
if (!print_event_info->server_id_printed ||
print_event_info->server_id != server_id)
{
- my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
- server_id, print_event_info->delimiter);
+ if (my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
+ server_id, print_event_info->delimiter))
+ goto err;
print_event_info->server_id= server_id;
print_event_info->server_id_printed= true;
}
if (!is_flashback)
- my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
- buf, print_event_info->delimiter);
+ if (my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
+ buf, print_event_info->delimiter))
+ goto err;
}
if (!(flags2 & FL_STANDALONE))
- my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter);
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_SERVER */
@@ -7957,28 +8353,37 @@ Gtid_list_log_event::pack_info(Protocol *protocol)
#else /* !MYSQL_SERVER */
-void
+bool
Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
{
- if (!print_event_info->short_form)
- {
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
- char buf[21];
- uint32 i;
+ if (print_event_info->short_form)
+ return 0;
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\tGtid list [");
- for (i= 0; i < count; ++i)
- {
- longlong10_to_str(list[i].seq_no, buf, 10);
- my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
- list[i].server_id, buf);
- if (i < count-1)
- my_b_printf(&cache, ",\n# ");
- }
- my_b_printf(&cache, "]\n");
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+ char buf[21];
+ uint32 i;
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tGtid list ["))
+ goto err;
+
+ for (i= 0; i < count; ++i)
+ {
+ longlong10_to_str(list[i].seq_no, buf, 10);
+ if (my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
+ list[i].server_id, buf))
+ goto err;
+ if (i < count-1)
+ if (my_b_printf(&cache, ",\n# "))
+ goto err;
}
+ if (my_b_printf(&cache, "]\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_SERVER */
@@ -8110,7 +8515,7 @@ bool Intvar_log_event::write()
*/
#ifdef MYSQL_CLIENT
-void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
char llbuff[22];
const char *UNINIT_VAR(msg);
@@ -8119,11 +8524,13 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
if (!print_event_info->short_form)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tIntvar\n");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tIntvar\n"))
+ goto err;
}
- my_b_printf(&cache, "SET ");
+ if (my_b_printf(&cache, "SET "))
+ goto err;
switch (type) {
case LAST_INSERT_ID_EVENT:
msg="LAST_INSERT_ID";
@@ -8136,8 +8543,13 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
msg="INVALID_INT";
break;
}
- my_b_printf(&cache, "%s=%s%s\n",
- msg, llstr(val,llbuff), print_event_info->delimiter);
+ if (my_b_printf(&cache, "%s=%s%s\n",
+ msg, llstr(val,llbuff), print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif
@@ -8236,7 +8648,7 @@ bool Rand_log_event::write()
#ifdef MYSQL_CLIENT
-void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
@@ -8244,12 +8656,18 @@ void Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char llbuff[22],llbuff2[22];
if (!print_event_info->short_form)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tRand\n");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRand\n"))
+ goto err;
}
- my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
- llstr(seed1, llbuff),llstr(seed2, llbuff2),
- print_event_info->delimiter);
+ if (my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
+ llstr(seed1, llbuff),llstr(seed2, llbuff2),
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -8361,7 +8779,7 @@ bool Xid_log_event::write()
#ifdef MYSQL_CLIENT
-void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F, this);
@@ -8371,10 +8789,17 @@ void Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char buf[64];
longlong10_to_str(xid, buf, 10);
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\tXid = %s\n", buf);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tXid = %s\n", buf))
+ goto err;
}
- my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n", print_event_info->delimiter);
+ if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -8763,23 +9188,26 @@ bool User_var_log_event::write()
*/
#ifdef MYSQL_CLIENT
-void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F);
if (!print_event_info->short_form)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tUser_var\n");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tUser_var\n"))
+ goto err;
}
- my_b_write_string(&cache, "SET @");
- my_b_write_backtick_quote(&cache, name, name_len);
+ if (my_b_write_string(&cache, "SET @") ||
+ my_b_write_backtick_quote(&cache, name, name_len))
+ goto err;
if (is_null)
{
- my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter);
+ if (my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter))
+ goto err;
}
else
{
@@ -8789,13 +9217,17 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
char real_buf[FMT_G_BUFSIZE(14)];
float8get(real_val, val);
sprintf(real_buf, "%.14g", real_val);
- my_b_printf(&cache, ":=%s%s\n", real_buf, print_event_info->delimiter);
+ if (my_b_printf(&cache, ":=%s%s\n", real_buf,
+ print_event_info->delimiter))
+ goto err;
break;
case INT_RESULT:
char int_buf[22];
longlong10_to_str(uint8korr(val), int_buf,
((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
- my_b_printf(&cache, ":=%s%s\n", int_buf, print_event_info->delimiter);
+ if (my_b_printf(&cache, ":=%s%s\n", int_buf,
+ print_event_info->delimiter))
+ goto err;
break;
case DECIMAL_RESULT:
{
@@ -8811,7 +9243,9 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
bin2decimal((uchar*) val+2, &dec, precision, scale);
decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
str_buf[str_len]= 0;
- my_b_printf(&cache, ":=%s%s\n", str_buf, print_event_info->delimiter);
+ if (my_b_printf(&cache, ":=%s%s\n", str_buf,
+ print_event_info->delimiter))
+ goto err;
break;
}
case STRING_RESULT:
@@ -8832,11 +9266,12 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
*/
char *hex_str;
CHARSET_INFO *cs;
+ bool error;
// 2 hex digits / byte
hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME));
if (!hex_str)
- return;
+ goto err;
str_to_hex(hex_str, val, val_len);
/*
For proper behaviour when mysqlbinlog|mysql, we need to explicitly
@@ -8845,24 +9280,31 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
character set. But there's not much to do about this and it's unlikely.
*/
if (!(cs= get_charset(charset_number, MYF(0))))
- /*
+ { /*
Generate an unusable command (=> syntax error) is probably the best
thing we can do here.
*/
- my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
+ error= my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
+ }
else
- my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
- cs->csname, hex_str, cs->name,
- print_event_info->delimiter);
+ error= my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
+ cs->csname, hex_str, cs->name,
+ print_event_info->delimiter);
my_free(hex_str);
- }
+ if (error)
+ goto err;
break;
+ }
case ROW_RESULT:
default:
DBUG_ASSERT(0);
- return;
+ break;
}
}
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif
@@ -8985,19 +9427,25 @@ User_var_log_event::do_shall_skip(rpl_group_info *rgi)
#ifdef HAVE_REPLICATION
#ifdef MYSQL_CLIENT
-void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
+bool Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
- if (print_event_info->short_form)
- return;
if (what != ENCRYPTED)
{
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n# Unknown event\n");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Unknown event\n"))
+ goto err;
}
- else
- my_b_printf(&cache, "# Encrypted event\n");
+ else if (my_b_printf(&cache, "# Encrypted event\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif
@@ -9010,16 +9458,18 @@ void Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info
*/
#ifdef MYSQL_CLIENT
-void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file,
Write_on_release_cache::FLUSH_F, this);
- if (print_event_info->short_form)
- return;
-
- print_header(&cache, print_event_info, FALSE);
- my_b_write_string(&cache, "\tStop\n");
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tStop\n"))
+ return 1;
+ return cache.flush_data();
}
#endif /* MYSQL_CLIENT */
@@ -9201,22 +9651,25 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
*/
#ifdef MYSQL_CLIENT
-void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
bool enable_local)
{
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
if (print_event_info->short_form)
{
if (enable_local && check_fname_outside_temp_buf())
- Load_log_event::print(file, print_event_info);
- return;
+ return Load_log_event::print(file, print_event_info);
+ return 0;
}
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
if (enable_local)
{
- Load_log_event::print(file, print_event_info,
- !check_fname_outside_temp_buf());
+ if (Load_log_event::print(file, print_event_info,
+ !check_fname_outside_temp_buf()))
+ goto err;
+
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
@@ -9228,16 +9681,24 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
*/
- my_b_write_byte(&cache, '#');
+ if (my_b_write_byte(&cache, '#'))
+ goto err;
}
- my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len);
+ if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+
}
-void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
{
- print(file, print_event_info, 0);
+ return print(file, print_event_info, 0);
}
#endif /* MYSQL_CLIENT */
@@ -9303,7 +9764,7 @@ int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
fname_buf);
goto err;
}
-
+
// a trick to avoid allocating another buffer
fname= fname_buf;
fname_len= (uint) (strmov(ext, ".data") - fname);
@@ -9318,7 +9779,7 @@ int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
}
end_io_cache(&file);
mysql_file_close(fd, MYF(0));
-
+
// fname_buf now already has .data, not .info, because we did our trick
/* old copy may exist already */
mysql_file_delete(key_file_log_event_data, fname_buf, MYF(0));
@@ -9416,16 +9877,22 @@ bool Append_block_log_event::write()
*/
#ifdef MYSQL_CLIENT
-void Append_block_log_event::print(FILE* file,
+bool Append_block_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file);
- if (print_event_info->short_form)
- return;
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
- get_type_str(), file_id, block_len);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
+ get_type_str(), file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif /* MYSQL_CLIENT */
@@ -9575,15 +10042,19 @@ bool Delete_file_log_event::write()
*/
#ifdef MYSQL_CLIENT
-void Delete_file_log_event::print(FILE* file,
+bool Delete_file_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file);
- if (print_event_info->short_form)
- return;
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id))
+ return 1;
+
+ return cache.flush_data();
}
#endif /* MYSQL_CLIENT */
@@ -9675,16 +10146,20 @@ bool Execute_load_log_event::write()
*/
#ifdef MYSQL_CLIENT
-void Execute_load_log_event::print(FILE* file,
+bool Execute_load_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info)
{
+ if (print_event_info->short_form)
+ return 0;
+
Write_on_release_cache cache(&print_event_info->head_cache, file);
- if (print_event_info->short_form)
- return;
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
- file_id);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
+ file_id))
+ return 1;
+
+ return cache.flush_data();
}
#endif
@@ -9906,22 +10381,24 @@ Execute_load_query_log_event::write_post_header_for_derived()
#ifdef MYSQL_CLIENT
-void Execute_load_query_log_event::print(FILE* file,
+bool Execute_load_query_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info)
{
- print(file, print_event_info, 0);
+ return print(file, print_event_info, 0);
}
/**
Prints the query as LOAD DATA LOCAL and with rewritten filename.
*/
-void Execute_load_query_log_event::print(FILE* file,
+bool Execute_load_query_log_event::print(FILE* file,
PRINT_EVENT_INFO* print_event_info,
const char *local_fname)
{
Write_on_release_cache cache(&print_event_info->head_cache, file);
- print_query_header(&cache, print_event_info);
+ if (print_query_header(&cache, print_event_info))
+ goto err;
+
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
@@ -9932,24 +10409,33 @@ void Execute_load_query_log_event::print(FILE* file,
if (local_fname)
{
- my_b_write(&cache, (uchar*) query, fn_pos_start);
- my_b_write_string(&cache, " LOCAL INFILE ");
- pretty_print_str(&cache, local_fname, strlen(local_fname));
+ if (my_b_write(&cache, (uchar*) query, fn_pos_start) ||
+ my_b_write_string(&cache, " LOCAL INFILE ") ||
+ pretty_print_str(&cache, local_fname, strlen(local_fname)))
+ goto err;
if (dup_handling == LOAD_DUP_REPLACE)
- my_b_write_string(&cache, " REPLACE");
- my_b_write_string(&cache, " INTO");
- my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end);
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
+ if (my_b_write_string(&cache, " REPLACE"))
+ goto err;
+
+ if (my_b_write_string(&cache, " INTO") ||
+ my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
}
else
{
- my_b_write(&cache, (uchar*) query, q_len);
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter);
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
}
if (!print_event_info->short_form)
my_b_printf(&cache, "# file_id: %d \n", file_id);
+
+ return cache.flush_data();
+err:
+ return 1;
}
#endif
@@ -10929,7 +11415,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
if (global_system_variables.log_warnings)
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
get_type_str(),
- RPL_LOG_NAME, (ulong) log_pos);
+ RPL_LOG_NAME, log_pos);
thd->clear_error(1);
error= 0;
if (idempotent_error == 0)
@@ -10981,7 +11467,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
if (global_system_variables.log_warnings)
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
get_type_str(),
- RPL_LOG_NAME, (ulong) log_pos);
+ RPL_LOG_NAME, log_pos);
thd->clear_error(1);
error= 0;
}
@@ -10992,7 +11478,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
{
slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table,
get_type_str(),
- RPL_LOG_NAME, (ulong) log_pos);
+ RPL_LOG_NAME, log_pos);
/*
@todo We should probably not call
reset_current_stmt_binlog_format_row() from here.
@@ -11022,7 +11508,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
thd->is_error() ? 0 : error,
rgi, thd, table,
get_type_str(),
- RPL_LOG_NAME, (ulong) log_pos);
+ RPL_LOG_NAME, log_pos);
DBUG_RETURN(error);
err:
@@ -11262,7 +11748,7 @@ void Rows_log_event::pack_info(Protocol *protocol)
#endif
#ifdef MYSQL_CLIENT
-void Rows_log_event::print_helper(FILE *file,
+bool Rows_log_event::print_helper(FILE *file,
PRINT_EVENT_INFO *print_event_info,
char const *const name)
{
@@ -11271,33 +11757,51 @@ void Rows_log_event::print_helper(FILE *file,
#ifdef WHEN_FLASHBACK_REVIEW_READY
IO_CACHE *const sql= &print_event_info->review_sql_cache;
#endif
+ bool const last_stmt_event= get_flags(STMT_END_F);
if (!print_event_info->short_form)
{
- bool const last_stmt_event= get_flags(STMT_END_F);
print_header(head, print_event_info, !last_stmt_event);
- my_b_printf(head, "\t%s: table id %lu%s\n",
- name, m_table_id,
- last_stmt_event ? " flags: STMT_END_F" : "");
- print_base64(body, print_event_info, !last_stmt_event);
+ if (my_b_printf(head, "\t%s: table id %lu%s\n",
+ name, m_table_id,
+ last_stmt_event ? " flags: STMT_END_F" : ""))
+ goto err;
}
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ if (print_base64(body, print_event_info, !last_stmt_event))
+ goto err;
- if (get_flags(STMT_END_F))
+ if (last_stmt_event)
{
- LEX_STRING tmp_str;
-
- copy_event_cache_to_string_and_reinit(head, &tmp_str);
- output_buf.append(&tmp_str);
- my_free(tmp_str.str);
- copy_event_cache_to_string_and_reinit(body, &tmp_str);
- output_buf.append(&tmp_str);
- my_free(tmp_str.str);
+ if (!is_flashback)
+ {
+ if (copy_event_cache_to_file_and_reinit(head, file) ||
+ copy_event_cache_to_file_and_reinit(body, file))
+ goto err;
+ }
+ else
+ {
+ LEX_STRING tmp_str;
+ if (copy_event_cache_to_string_and_reinit(head, &tmp_str))
+ return 1;
+ output_buf.append(&tmp_str);
+ my_free(tmp_str.str);
+ if (copy_event_cache_to_string_and_reinit(body, &tmp_str))
+ return 1;
+ output_buf.append(&tmp_str);
+ my_free(tmp_str.str);
#ifdef WHEN_FLASHBACK_REVIEW_READY
- copy_event_cache_to_string_and_reinit(sql, &tmp_str);
- output_buf.append(&tmp_str);
- my_free(tmp_str.str);
+ if (copy_event_cache_to_string_and_reinit(sql, &tmp_str))
+ return 1;
+ output_buf.append(&tmp_str);
+ my_free(tmp_str.str);
#endif
+ }
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -11385,25 +11889,28 @@ void Annotate_rows_log_event::pack_info(Protocol* protocol)
#endif
#ifdef MYSQL_CLIENT
-void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
+bool Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
- if (pinfo->short_form)
- return;
-
- print_header(&pinfo->head_cache, pinfo, TRUE);
- my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n");
-
char *pbeg; // beginning of the next line
char *pend; // end of the next line
uint cnt= 0; // characters counter
+ if (!pinfo->short_form)
+ {
+ if (print_header(&pinfo->head_cache, pinfo, TRUE) ||
+ my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n"))
+ goto err;
+ }
+ else if (my_b_printf(&pinfo->head_cache, "# Annotate_rows:\n"))
+ goto err;
+
for (pbeg= m_query_txt; ; pbeg= pend)
{
// skip all \r's and \n's at the beginning of the next line
for (;; pbeg++)
{
if (++cnt > m_query_len)
- return;
+ return 0;
if (*pbeg != '\r' && *pbeg != '\n')
break;
@@ -11416,10 +11923,15 @@ void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
;
// print next line
- my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4);
- my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg);
- my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1);
+ if (my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1))
+ goto err;
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -11716,7 +12228,7 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
ptr_after_colcnt= ptr_after_colcnt + m_colcnt;
bytes_read= (uint) (ptr_after_colcnt - (uchar *)buf);
- DBUG_PRINT("info", ("Bytes read: %d.\n", bytes_read));
+ DBUG_PRINT("info", ("Bytes read: %d", bytes_read));
if (bytes_read < event_len)
{
m_field_metadata_size= net_field_length(&ptr_after_colcnt);
@@ -12154,19 +12666,29 @@ void Table_map_log_event::pack_info(Protocol *protocol)
#ifdef MYSQL_CLIENT
-void Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
{
if (!print_event_info->short_form)
{
print_header(&print_event_info->head_cache, print_event_info, TRUE);
- my_b_printf(&print_event_info->head_cache,
- "\tTable_map: %`s.%`s mapped to number %lu%s\n",
- m_dbnam, m_tblnam, m_table_id,
- ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
- " (has triggers)" : ""));
- print_base64(&print_event_info->body_cache, print_event_info, TRUE);
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, file);
+ if (my_b_printf(&print_event_info->head_cache,
+ "\tTable_map: %`s.%`s mapped to number %lu%s\n",
+ m_dbnam, m_tblnam, m_table_id,
+ ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
+ " (has triggers)" : "")))
+ goto err;
+ }
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ {
+ if (print_base64(&print_event_info->body_cache, print_event_info, TRUE) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ goto err;
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -12747,14 +13269,14 @@ Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
#ifdef MYSQL_CLIENT
-void Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
+bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
{
DBUG_EXECUTE_IF("simulate_cache_read_error",
{DBUG_SET("+d,simulate_my_b_fill_error");});
- Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
}
-void Write_rows_compressed_log_event::print(FILE *file,
+bool Write_rows_compressed_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
char *new_buf;
@@ -12766,14 +13288,20 @@ void Write_rows_compressed_log_event::print(FILE *file,
{
free_temp_buf();
register_temp_buf(new_buf, true);
- Rows_log_event::print_helper(file, print_event_info,
- "Write_compressed_rows");
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Write_compressed_rows"))
+ goto err;
}
else
{
- my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress write_compressed_rows failed\n");
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress write_compressed_rows failed\n"))
+ goto err;
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -13457,13 +13985,13 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
#ifdef MYSQL_CLIENT
-void Delete_rows_log_event::print(FILE *file,
+bool Delete_rows_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
- Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
}
-void Delete_rows_compressed_log_event::print(FILE *file,
+bool Delete_rows_compressed_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
char *new_buf;
@@ -13475,14 +14003,20 @@ void Delete_rows_compressed_log_event::print(FILE *file,
{
free_temp_buf();
register_temp_buf(new_buf, true);
- Rows_log_event::print_helper(file, print_event_info,
- "Delete_compressed_rows");
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Delete_compressed_rows"))
+ goto err;
}
else
{
- my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress delete_compressed_rows failed\n");
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress delete_compressed_rows failed\n"))
+ goto err;
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -13726,13 +14260,15 @@ err:
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
#ifdef MYSQL_CLIENT
-void Update_rows_log_event::print(FILE *file,
+bool Update_rows_log_event::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
- Rows_log_event::print_helper(file, print_event_info, "Update_rows");
+ return Rows_log_event::print_helper(file, print_event_info, "Update_rows");
}
-void Update_rows_compressed_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+bool
+Update_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
{
char *new_buf;
ulong len;
@@ -13743,14 +14279,20 @@ void Update_rows_compressed_log_event::print(FILE *file, PRINT_EVENT_INFO *print
{
free_temp_buf();
register_temp_buf(new_buf, true);
- Rows_log_event::print_helper(file, print_event_info,
- "Update_compressed_rows");
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Update_compressed_rows"))
+ goto err;
}
else
{
- my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress update_compressed_rows failed\n");
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress update_compressed_rows failed\n"))
+ goto err;
}
+
+ return 0;
+err:
+ return 1;
}
#endif
@@ -13889,16 +14431,18 @@ err:
#ifdef MYSQL_CLIENT
-void
-Incident_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
+bool Incident_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
{
if (print_event_info->short_form)
- return;
+ return 0;
Write_on_release_cache cache(&print_event_info->head_cache, file);
- print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description());
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description()))
+ return 1;
+ return cache.flush_data();
}
#endif
@@ -13974,19 +14518,20 @@ void Ignorable_log_event::pack_info(Protocol *protocol)
#ifdef MYSQL_CLIENT
/* Print for its unrecognized ignorable event */
-void
-Ignorable_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
+bool Ignorable_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
{
if (print_event_info->short_form)
- return;
+ return 0;
- print_header(&print_event_info->head_cache, print_event_info, FALSE);
- my_b_printf(&print_event_info->head_cache, "\tIgnorable\n");
- my_b_printf(&print_event_info->head_cache,
- "# Ignorable event type %d (%s)\n", number, description);
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
- file);
+ if (print_header(&print_event_info->head_cache, print_event_info, FALSE) ||
+ my_b_printf(&print_event_info->head_cache, "\tIgnorable\n") ||
+ my_b_printf(&print_event_info->head_cache,
+ "# Ignorable event type %d (%s)\n", number, description) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ return 1;
+ return 0;
}
#endif
@@ -13998,15 +14543,8 @@ Ignorable_log_event::print(FILE *file,
they will always be printed for the first event.
*/
st_print_event_info::st_print_event_info()
- :flags2_inited(0), sql_mode_inited(0), sql_mode(0),
- auto_increment_increment(0),auto_increment_offset(0), charset_inited(0),
- lc_time_names_number(~0),
- charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER),
- thread_id(0), thread_id_printed(false), server_id(0),
- server_id_printed(false), domain_id(0), domain_id_printed(false),
- allow_parallel(true), allow_parallel_printed(false), skip_replication(0),
- base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE)
{
+ myf const flags = MYF(MY_WME | MY_NABP);
/*
Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
program's startup, but these explicit bzero() is for the day someone
@@ -14017,14 +14555,68 @@ st_print_event_info::st_print_event_info()
bzero(time_zone_str, sizeof(time_zone_str));
delimiter[0]= ';';
delimiter[1]= 0;
- myf const flags = MYF(MY_WME | MY_NABP);
+ flags2_inited= 0;
+ sql_mode_inited= 0;
+ row_events= 0;
+ sql_mode= 0;
+ auto_increment_increment= 0;
+ auto_increment_offset= 0;
+ charset_inited= 0;
+ lc_time_names_number= ~0;
+ charset_database_number= ILLEGAL_CHARSET_INFO_NUMBER;
+ thread_id= 0;
+ server_id= 0;
+ domain_id= 0;
+ thread_id_printed= false;
+ server_id_printed= false;
+ domain_id_printed= false;
+ allow_parallel= true;
+ allow_parallel_printed= false;
+ found_row_event= false;
+ print_row_count= false;
+ short_form= false;
+ skip_replication= 0;
+ printed_fd_event=FALSE;
+ file= 0;
+ base64_output_mode=BASE64_OUTPUT_UNSPEC;
open_cached_file(&head_cache, NULL, NULL, 0, flags);
open_cached_file(&body_cache, NULL, NULL, 0, flags);
#ifdef WHEN_FLASHBACK_REVIEW_READY
open_cached_file(&review_sql_cache, NULL, NULL, 0, flags);
#endif
}
-#endif
+
+
+bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
+{
+ reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
+ if (cache->end_of_file > SIZE_T_MAX ||
+ !(to->str= (char*) my_malloc((to->length= (size_t)cache->end_of_file), MYF(0))))
+ {
+ perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
+ goto err;
+ }
+ if (my_b_read(cache, (uchar*) to->str, to->length))
+ {
+ my_free(to->str);
+ perror("Can't read data from IO_CACHE");
+ return true;
+ }
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+ return false;
+
+err:
+ to->str= 0;
+ to->length= 0;
+ return true;
+}
+#endif /* MYSQL_CLIENT */
+
+bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file)
+{
+ return (my_b_copy_to_file(cache, file) ||
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE));
+}
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
@@ -14062,4 +14654,4 @@ bool event_that_should_be_ignored(const char *buf)
return 1;
return 0;
}
-#endif
+#endif /* MYSQL_SERVER */
diff --git a/sql/log_event.h b/sql/log_event.h
index 29cae604678..700301a7f34 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -802,6 +802,8 @@ class Format_description_log_event;
class Relay_log_info;
class binlog_cache_data;
+bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file);
+
#ifdef MYSQL_CLIENT
enum enum_base64_output_mode {
BASE64_OUTPUT_NEVER= 0,
@@ -813,6 +815,8 @@ enum enum_base64_output_mode {
BASE64_OUTPUT_MODE_COUNT
};
+bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to);
+
/*
A structure for mysqlbinlog to know how to print events
@@ -832,53 +836,38 @@ typedef struct st_print_event_info
that was printed. We cache these so that we don't have to print
them if they are unchanged.
*/
- // TODO: have the last catalog here ??
char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is
- bool flags2_inited;
- uint32 flags2;
- bool sql_mode_inited;
- sql_mode_t sql_mode; /* must be same as THD.variables.sql_mode */
- ulong auto_increment_increment, auto_increment_offset;
- bool charset_inited;
char charset[6]; // 3 variables, each of them storable in 2 bytes
char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
+ char delimiter[16];
+ sql_mode_t sql_mode; /* must be same as THD.variables.sql_mode */
+ my_thread_id thread_id;
+ ulonglong row_events;
+ ulong auto_increment_increment, auto_increment_offset;
uint lc_time_names_number;
uint charset_database_number;
- my_thread_id thread_id;
- bool thread_id_printed;
+ uint verbose;
+ uint32 flags2;
uint32 server_id;
- bool server_id_printed;
uint32 domain_id;
+ uint8 common_header_len;
+ enum_base64_output_mode base64_output_mode;
+ my_off_t hexdump_from;
+
+ table_mapping m_table_map;
+ table_mapping m_table_map_ignored;
+ bool flags2_inited;
+ bool sql_mode_inited;
+ bool charset_inited;
+ bool thread_id_printed;
+ bool server_id_printed;
bool domain_id_printed;
bool allow_parallel;
bool allow_parallel_printed;
-
- /*
- Track when @@skip_replication changes so we need to output a SET
- statement for it.
- */
- int skip_replication;
-
- st_print_event_info();
-
- ~st_print_event_info() {
- close_cached_file(&head_cache);
- close_cached_file(&body_cache);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- close_cached_file(&review_sql_cache);
-#endif
- }
- bool init_ok() /* tells if construction was successful */
- { return my_b_inited(&head_cache) && my_b_inited(&body_cache)
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- && my_b_inited(&review_sql_cache)
-#endif
- ; }
-
-
+ bool found_row_event;
+ bool print_row_count;
/* Settings on how to print the events */
bool short_form;
- enum_base64_output_mode base64_output_mode;
/*
This is set whenever a Format_description_event is printed.
Later, when an event is printed in base64, this flag is tested: if
@@ -886,13 +875,11 @@ typedef struct st_print_event_info
the base64 event, so an error message is generated.
*/
bool printed_fd_event;
- my_off_t hexdump_from;
- uint8 common_header_len;
- char delimiter[16];
-
- uint verbose;
- table_mapping m_table_map;
- table_mapping m_table_map_ignored;
+ /*
+ Track when @@skip_replication changes so we need to output a SET
+ statement for it.
+ */
+ bool skip_replication;
/*
These two caches are used by the row-based replication events to
@@ -905,6 +892,28 @@ typedef struct st_print_event_info
/* Storing the SQL for reviewing */
IO_CACHE review_sql_cache;
#endif
+ FILE *file;
+ st_print_event_info();
+
+ ~st_print_event_info() {
+ close_cached_file(&head_cache);
+ close_cached_file(&body_cache);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ close_cached_file(&review_sql_cache);
+#endif
+ }
+ bool init_ok() /* tells if construction was successful */
+ { return my_b_inited(&head_cache) && my_b_inited(&body_cache)
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ && my_b_inited(&review_sql_cache)
+#endif
+ ; }
+ void flush_for_error()
+ {
+ if (!copy_event_cache_to_file_and_reinit(&head_cache, file))
+ copy_event_cache_to_file_and_reinit(&body_cache, file);
+ fflush(file);
+ }
} PRINT_EVENT_INFO;
#endif
@@ -1250,11 +1259,11 @@ public:
Log_event() : temp_buf(0), when(0), flags(0) {}
ha_checksum crc;
/* print*() functions are used by mysqlbinlog */
- virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
- void print_timestamp(IO_CACHE* file, time_t *ts = 0);
- void print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
+ virtual bool print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
+ bool print_timestamp(IO_CACHE* file, time_t *ts = 0);
+ bool print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
- void print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
+ bool print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
#endif /* MYSQL_SERVER */
@@ -2112,8 +2121,8 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Query_log_event();
@@ -2452,7 +2461,7 @@ protected:
const Format_description_log_event* description_event);
public:
- void print_query(THD *thd, bool need_db, const char *cs, String *buf,
+ bool print_query(THD *thd, bool need_db, const char *cs, String *buf,
my_off_t *fn_start, my_off_t *fn_end,
const char *qualify_db);
my_thread_id thread_id;
@@ -2518,8 +2527,8 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool commented);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info, bool commented);
#endif
/*
@@ -2616,7 +2625,7 @@ public:
#endif /* HAVE_REPLICATION */
#else
Start_log_event_v3() {}
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Start_log_event_v3(const char* buf, uint event_len,
@@ -2685,7 +2694,7 @@ public:
write_data(nonce, BINLOG_NONCE_LENGTH);
}
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Start_encryption_log_event(
@@ -2873,7 +2882,7 @@ Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg,
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Intvar_log_event(const char* buf,
@@ -2954,7 +2963,7 @@ class Rand_log_event: public Log_event
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Rand_log_event(const char* buf,
@@ -3004,7 +3013,7 @@ class Xid_log_event: public Log_event
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Xid_log_event(const char* buf,
@@ -3066,7 +3075,7 @@ public:
}
void pack_info(Protocol* protocol);
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
User_var_log_event(const char* buf, uint event_len,
@@ -3114,7 +3123,7 @@ public:
Stop_log_event() :Log_event()
{}
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Stop_log_event(const char* buf,
@@ -3210,7 +3219,7 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Rotate_log_event(const char* buf, uint event_len,
@@ -3250,7 +3259,7 @@ public:
void pack_info(Protocol *protocol);
#endif
#else
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
Binlog_checkpoint_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
@@ -3375,7 +3384,7 @@ public:
virtual enum_skip_reason do_shall_skip(rpl_group_info *rgi);
#endif
#else
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
Gtid_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
@@ -3489,7 +3498,7 @@ public:
void pack_info(Protocol *protocol);
#endif
#else
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
Gtid_list_log_event(const char *buf, uint event_len,
const Format_description_log_event *description_event);
@@ -3553,8 +3562,8 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
bool enable_local);
#endif
@@ -3626,7 +3635,7 @@ public:
virtual int get_create_or_append() const;
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Append_block_log_event(const char* buf, uint event_len,
@@ -3666,8 +3675,8 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
bool enable_local);
#endif
@@ -3707,7 +3716,7 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
Execute_load_log_event(const char* buf, uint event_len,
@@ -3803,9 +3812,9 @@ public:
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
#else
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
/* Prints the query as LOAD DATA LOCAL and with rewritten filename */
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info,
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info,
const char *local_fname);
#endif
Execute_load_query_log_event(const char* buf, uint event_len,
@@ -3850,7 +3859,7 @@ public:
/* constructor for hopelessly corrupted events */
Unknown_log_event(): Log_event(), what(ENCRYPTED) {}
~Unknown_log_event() {}
- void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+ bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
Log_event_type get_type_code() { return UNKNOWN_EVENT;}
bool is_valid() const { return 1; }
};
@@ -3895,7 +3904,7 @@ public:
#endif
#ifdef MYSQL_CLIENT
- virtual void print(FILE*, PRINT_EVENT_INFO*);
+ virtual bool print(FILE*, PRINT_EVENT_INFO*);
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -4315,7 +4324,7 @@ public:
#endif
#ifdef MYSQL_CLIENT
- virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
@@ -4436,15 +4445,21 @@ public:
#ifdef MYSQL_CLIENT
/* not for direct call, each derived has its own ::print() */
- virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0;
+ virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0;
void change_to_flashback_event(PRINT_EVENT_INFO *print_event_info, uchar *rows_buff, Log_event_type ev_type);
- void print_verbose(IO_CACHE *file,
+ bool print_verbose(IO_CACHE *file,
PRINT_EVENT_INFO *print_event_info);
size_t print_verbose_one_row(IO_CACHE *file, table_def *td,
PRINT_EVENT_INFO *print_event_info,
MY_BITMAP *cols_bitmap,
const uchar *ptr, const uchar *prefix,
const my_bool no_fill_output= 0); // if no_fill_output=1, then print result is unnecessary
+ size_t calc_row_event_length(table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value);
+ void count_row_events(PRINT_EVENT_INFO *print_event_info);
+
#endif
#ifdef MYSQL_SERVER
@@ -4551,7 +4566,7 @@ protected:
void uncompress_buf();
#ifdef MYSQL_CLIENT
- void print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
+ bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
#endif
#ifdef MYSQL_SERVER
@@ -4758,7 +4773,7 @@ private:
virtual Log_event_type get_general_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -4782,7 +4797,7 @@ public:
#endif
private:
#if defined(MYSQL_CLIENT)
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
};
@@ -4846,7 +4861,7 @@ protected:
virtual Log_event_type get_general_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -4870,7 +4885,7 @@ public:
#endif
private:
#if defined(MYSQL_CLIENT)
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
};
@@ -4931,7 +4946,7 @@ protected:
virtual Log_event_type get_general_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -4954,7 +4969,7 @@ public:
#endif
private:
#if defined(MYSQL_CLIENT)
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
};
@@ -5048,7 +5063,7 @@ public:
virtual ~Incident_log_event();
#ifdef MYSQL_CLIENT
- virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@@ -5115,7 +5130,7 @@ public:
#endif
#ifdef MYSQL_CLIENT
- virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
virtual Log_event_type get_type_code() { return IGNORABLE_LOG_EVENT; }
@@ -5125,38 +5140,6 @@ public:
virtual int get_data_size() { return IGNORABLE_HEADER_LEN; }
};
-
-static inline bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
-{
- String tmp;
-
- reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
- if (tmp.append(cache, (uint32)cache->end_of_file))
- goto err;
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
-
- /*
- Can't change the order, because the String::release() will clear the
- length.
- */
- to->length= tmp.length();
- to->str= tmp.release();
-
- return false;
-
-err:
- perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
- return true;
-}
-
-static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
- FILE *file)
-{
- return
- my_b_copy_to_file(cache, file) ||
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
-}
-
#ifdef MYSQL_SERVER
/*****************************************************************************
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 2c079a34d56..20986050203 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1845,7 +1845,7 @@ void Old_rows_log_event::pack_info(Protocol *protocol)
#ifdef MYSQL_CLIENT
-void Old_rows_log_event::print_helper(FILE *file,
+bool Old_rows_log_event::print_helper(FILE *file,
PRINT_EVENT_INFO *print_event_info,
char const *const name)
{
@@ -1854,18 +1854,23 @@ void Old_rows_log_event::print_helper(FILE *file,
if (!print_event_info->short_form)
{
bool const last_stmt_event= get_flags(STMT_END_F);
- print_header(head, print_event_info, !last_stmt_event);
- my_b_printf(head, "\t%s: table id %lu%s\n",
- name, m_table_id,
- last_stmt_event ? " flags: STMT_END_F" : "");
- print_base64(body, print_event_info, !last_stmt_event);
+ if (print_header(head, print_event_info, !last_stmt_event) ||
+ my_b_printf(head, "\t%s: table id %lu%s\n",
+ name, m_table_id,
+ last_stmt_event ? " flags: STMT_END_F" : "") ||
+ print_base64(body, print_event_info, !last_stmt_event))
+ goto err;
}
if (get_flags(STMT_END_F))
{
- copy_event_cache_to_file_and_reinit(head, file);
- copy_event_cache_to_file_and_reinit(body, file);
+ if (copy_event_cache_to_file_and_reinit(head, file) ||
+ copy_event_cache_to_file_and_reinit(body, file))
+ goto err;
}
+ return 0;
+err:
+ return 1;
}
#endif
@@ -2491,10 +2496,11 @@ Write_rows_log_event_old::do_exec_row(rpl_group_info *rgi)
#ifdef MYSQL_CLIENT
-void Write_rows_log_event_old::print(FILE *file,
+bool Write_rows_log_event_old::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
- Old_rows_log_event::print_helper(file, print_event_info, "Write_rows_old");
+ return Old_rows_log_event::print_helper(file, print_event_info,
+ "Write_rows_old");
}
#endif
@@ -2598,10 +2604,11 @@ int Delete_rows_log_event_old::do_exec_row(rpl_group_info *rgi)
#ifdef MYSQL_CLIENT
-void Delete_rows_log_event_old::print(FILE *file,
+bool Delete_rows_log_event_old::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
- Old_rows_log_event::print_helper(file, print_event_info, "Delete_rows_old");
+ return Old_rows_log_event::print_helper(file, print_event_info,
+ "Delete_rows_old");
}
#endif
@@ -2736,9 +2743,10 @@ Update_rows_log_event_old::do_exec_row(rpl_group_info *rgi)
#ifdef MYSQL_CLIENT
-void Update_rows_log_event_old::print(FILE *file,
+bool Update_rows_log_event_old::print(FILE *file,
PRINT_EVENT_INFO* print_event_info)
{
- Old_rows_log_event::print_helper(file, print_event_info, "Update_rows_old");
+ return Old_rows_log_event::print_helper(file, print_event_info,
+ "Update_rows_old");
}
#endif
diff --git a/sql/log_event_old.h b/sql/log_event_old.h
index 40e01d37318..d18c980bdfe 100644
--- a/sql/log_event_old.h
+++ b/sql/log_event_old.h
@@ -116,7 +116,7 @@ public:
#ifdef MYSQL_CLIENT
/* not for direct call, each derived has its own ::print() */
- virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0;
+ virtual bool print(FILE *file, PRINT_EVENT_INFO *print_event_info)= 0;
#endif
#ifndef MYSQL_CLIENT
@@ -166,7 +166,7 @@ protected:
const Format_description_log_event *description_event);
#ifdef MYSQL_CLIENT
- void print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
+ bool print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
#endif
#ifndef MYSQL_CLIENT
@@ -379,7 +379,7 @@ public:
private:
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -455,7 +455,7 @@ public:
protected:
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -529,7 +529,7 @@ public:
protected:
#ifdef MYSQL_CLIENT
- void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+ bool print(FILE *file, PRINT_EVENT_INFO *print_event_info);
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 4efc8b0e361..bf708c945f4 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -20,7 +20,7 @@
#include "sql_array.h"
#include "rpl_rli.h"
#include <lf.h>
-#include <mysqld_error.h>
+#include "unireg.h"
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#include <mysql/psi/mysql_stage.h>
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 15dfcfdb649..c0d55306871 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3683,8 +3683,6 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
extern "C" void *my_str_malloc_mysqld(size_t size);
-extern "C" void my_str_free_mysqld(void *ptr);
-extern "C" void *my_str_realloc_mysqld(void *ptr, size_t size);
void *my_str_malloc_mysqld(size_t size)
{
@@ -3692,17 +3690,6 @@ void *my_str_malloc_mysqld(size_t size)
}
-void my_str_free_mysqld(void *ptr)
-{
- my_free(ptr);
-}
-
-void *my_str_realloc_mysqld(void *ptr, size_t size)
-{
- return my_realloc(ptr, size, MYF(MY_FAE));
-}
-
-
#ifdef __WIN__
pthread_handler_t handle_shutdown(void *arg)
@@ -3758,14 +3745,8 @@ check_enough_stack_size(int recurse_level)
}
-/*
- Initialize my_str_malloc() and my_str_free()
-*/
static void init_libstrings()
{
- my_str_malloc= &my_str_malloc_mysqld;
- my_str_free= &my_str_free_mysqld;
- my_str_realloc= &my_str_realloc_mysqld;
#ifndef EMBEDDED_LIBRARY
my_string_stack_guard= check_enough_stack_size;
#endif
@@ -3776,7 +3757,7 @@ ulonglong my_pcre_frame_size;
static void init_pcre()
{
pcre_malloc= pcre_stack_malloc= my_str_malloc_mysqld;
- pcre_free= pcre_stack_free= my_str_free_mysqld;
+ pcre_free= pcre_stack_free= my_free;
pcre_stack_guard= check_enough_stack_size_slow;
/* See http://pcre.org/original/doc/html/pcrestack.html */
my_pcre_frame_size= -pcre_exec(NULL, NULL, NULL, -999, -999, 0, NULL, 0);
@@ -4735,6 +4716,8 @@ static int init_common_variables()
return 1;
}
+ global_system_variables.in_subquery_conversion_threshold= IN_SUBQUERY_CONVERSION_THRESHOLD;
+
return 0;
}
@@ -7367,7 +7350,7 @@ struct my_option my_long_options[]=
"The value has to be a multiple of 256.",
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size,
0, GET_ULONG, REQUIRED_ARG,
- /* def_value */ 8192, /* min_value */ 256, /* max_value */ ULONG_MAX,
+ /* def_value */ 8192, /* min_value */ 256, /* max_value */ UINT_MAX32-1,
/* sub_size */ 0, /* block_size */ 256,
/* app_type */ 0
},
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index fba449e7ce2..369729127dd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1541,7 +1541,7 @@ end:
head->file= org_file;
/* Restore head->read_set (and write_set) to what they had before the call */
- head->column_bitmaps_set(save_read_set, save_write_set);
+ head->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
if (reset())
{
@@ -6738,7 +6738,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
bool update_tbl_stats,
double read_time)
{
- uint idx, best_idx;
+ uint idx, UNINIT_VAR(best_idx);
SEL_ARG *key_to_read= NULL;
ha_rows UNINIT_VAR(best_records); /* protected by key_to_read */
uint UNINIT_VAR(best_mrr_flags), /* protected by key_to_read */
@@ -10273,8 +10273,8 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
ulong count=count_key_part_usage(root,pos->next_key_part);
if (count > pos->next_key_part->use_count)
{
- sql_print_information("Use_count: Wrong count for key at %p, %lu "
- "should be %lu", (long unsigned int)pos,
+ sql_print_information("Use_count: Wrong count for key at %p: %lu "
+ "should be %lu", pos,
pos->next_key_part->use_count, count);
return;
}
@@ -10283,7 +10283,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
if (e_count != elements)
sql_print_warning("Wrong use count: %u (should be %u) for tree at %p",
- e_count, elements, (long unsigned int) this);
+ e_count, elements, this);
}
#endif
@@ -11396,7 +11396,10 @@ int QUICK_RANGE_SELECT::reset()
buf_size/= 2;
}
if (!mrr_buf_desc)
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ {
+ error= HA_ERR_OUT_OF_MEM;
+ goto err;
+ }
/* Initialize the handler buffer. */
mrr_buf_desc->buffer= mrange_buff;
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
new file mode 100644
index 00000000000..ac2972f4264
--- /dev/null
+++ b/sql/opt_split.cc
@@ -0,0 +1,1134 @@
+/*
+ Copyright (c) 2017 MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/*
+ This file contains functions to support the splitting technique.
+ This optimization technique can be applied to equi-joins involving
+ materialized tables such as materialized views, materialized derived tables
+ and materialized CTEs. The technique also could be applied to materialized
+ semi-joins though the code below does not support this usage yet.
+
+ Here are the main ideas behind this technique that we'll call SM optimization
+ (SplitMaterialization).
+
+ Consider the query
+ SELECT t1.a, t.min
+ FROM t1, (SELECT t2.a, MIN(t2.b) as min FROM t2 GROUP BY t2.a) t
+ WHERE t1.a = t.a and t1.b < const
+
+ Re-write the query into
+ SELECT t1.a, t.min
+ FROM t1, LATERAL (SELECT t2.a, MIN(t2.b) as min
+ FROM t2 WHERE t2.a = t1.a GROUP BY t2.a) t
+ WHERE t1.b < const
+
+ The execution of the original query (Q1) does the following:
+ 1. Executes the query in the specification of the derived table
+ and puts the result set into a temporary table with an index
+ on the first column.
+ 2. Joins t1 with the temporary table using the its index.
+
+ The execution of the transformed query (Q1R) follows these steps:
+ 1. For each row of t1 where t1.b < const a temporary table
+ containing all rows of of t2 with t2.a = t1.a is created
+ 2. If there are any rows in the temporary table aggregation
+ is performed for them
+ 3. The result of the aggregation is joined with t1.
+
+ The second execution can win if:
+ a) There is an efficient way to select rows of t2 for which t2.a = t1.a
+ (For example if there is an index on t2.a)
+ and
+ b) The number of temporary tables created for partitions
+ is much smaller that the total number of partitions
+
+ It should be noted that for the transformed query aggregation
+ for a partition may be performed several times.
+
+ As we can see the optimization basically splits table t2 into
+ partitions and performs aggregation over each of them
+ independently.
+
+ If we have only one equi-join condition then we either push it as
+ for Q1R or we don't. In a general case we may have much more options.
+ Consider the query (Q3)
+ SELECT
+ FROM t1,t2 (SELECT t3.a, t3.b, MIN(t3.c) as min
+ FROM t3 GROUP BY a,b) t
+ WHERE t.a = t1.a AND t.b = t2.b
+ AND t1.c < c1 and t2.c < c2
+ AND P(t1,t2);
+ (P(t1,t2) designates some additional conditions over columns of t1,t2).
+
+ Assuming that there indexes on t3(a,b) and t3(b) here we have several
+ reasonable options to push equi-join conditions into the derived.
+ All these options should be taken into account when the optimizer
+ evaluates different join orders. When the join order (t1,t,t2) is
+ evaluated there is only one way of splitting : to push the condition
+ t.a = t1.a into t. With the join order (t2,t,t1) only the condition
+ t.b = t2.b can be pushed. When the join orders (t1,t2,t) and (t2,t1,t)
+ are evaluated then the optimizer should consider pushing t.a = t1.a,
+ t.b = t2.b and (t.a = t1.a AND t.b = t2.b) to choose the best condition
+ for splitting. Apparently here last condition is the best one because
+ it provides the miximum possible number of partitions.
+
+ If we dropped the index on t3(a,b) and created the index on t3(a) instead
+ then we would have two options for splitting: to push t.a = t1.a or to
+ push t.b = t2.b. If the selectivity of the index t3(a) is better than
+ the selectivity of t3(b) then the first option is preferred.
+
+ Although the condition (t.a = t1.a AND t.b = t2.b) provides a better
+ splitting than the condition t.a = t1.a the latter will be used for
+ splitting if the execution plan with the join order (t1,t,t2) turns out
+ to be the cheapest one. It's quite possible when the join condition
+ P(t1,t2) has a bad selectivity.
+
+ Whenever the optimizer evaluates the cost of using a splitting it
+ compares it with the cost of materialization without splitting.
+
+ If we just drop the index on t3(a,b) the chances that the splitting
+ will be used becomes much lower but they still exists providing that
+ the fanout of the partial join of t1 and t2 is small enough.
+*/
+
+/*
+ Splitting can be applied to a materialized table specified by the query
+ with post-join operations that require partitioning of the result set produced
+ by the join expression used in the FROM clause the query such as GROUP BY
+ operation and window function operation. In any of these cases the post-join
+ operation can be executed independently for any partition only over the rows
+ of this partition. Also if the set of all partitions is divided into disjoint
+ subsets the operation can applied to each subset independently. In this case
+ all rows are first partitioned into the groups each of which contains all the
+ rows from the partitions belonging the same subset and then each group
+ is subpartitioned into groups in the the post join operation.
+
+ The set of all rows belonging to the union of several partitions is called
+ here superpartition. If a grouping operation is defined by the list
+ e_1,...,e_n then any set S = {e_i1,...,e_ik} can be used to devide all rows
+ into superpartions such that for any two rows r1, r2 the following holds:
+ e_ij(r1) = e_ij(r2) for each e_ij from S. We use the splitting technique
+ only if S consists of references to colums of the joined tables.
+ For example if the GROUP BY list looks like this a, g(b), c we can consider
+ applying the splitting technique to the superpartitions defined by {a,c},
+ {a}, {c} (a and c here may be the references to the columns from different
+ tables).
+*/
+
+ /*
+ The following describes when and how the optimizer decides whether it
+ makes sense to employ the splitting technique.
+
+ 1. For each instance of a materialized table (derived/view/CTE) it is
+ checked that it is potentially splittable. Now it is done right after the
+ execution plan for the select specifying this table has been chosen.
+
+ 2. Any potentially splittable materialized table T is subject to two-phase
+ optimization. It means that the optimizer first builds the best execution
+ plan for join that specifies T. Then the control is passed back to the
+ optimization process of the embedding select Q. After the execution plan
+ for Q has been chosen the optimizer finishes the optimization of the join
+ specifying T.
+
+ 3. When the optimizer builds the container with the KEYUSE structures
+ for the join of embedding select it detects the equi-join conditions
+ PC that potentially could be pushed into a potentially splittable
+ materialized table T. The collected information about such conditions
+ is stored together with other facts on potential splittings for table T.
+
+ 4. When the optimizer starts looking for the best execution plan for the
+ embedding select Q for each potentially splittable materialized table T
+ it creates special KEYUSE structures for pushable equi-join conditions
+ PC. These structures are used to add new elements to the container
+ of KEYUSE structures built for T. The specifics of these elements is
+ that they can be ebabled and disabled during the process of choosing
+ the best plan for Q.
+
+ 5. When the optimizer extends a partial join order with a potentially
+ splittable materialized table T (in function best_access_path) it
+ first evaluates a new execution plan for the modified specification
+ of T that adds all equi-join conditions that can be pushed with
+ current join prefix to the WHERE conditions of the original
+ specification of T. If the cost of the new plan is better than the
+ the cost of the original materialized table then the optimizer
+ prefers to use splitting for the current join prefix. As the cost
+ of the plan depends only on the pushed conditions it makes sense
+ to cache this plan for other prefixes.
+
+ 6. The optimizer takes into account the cost of splitting / materialization
+ of a potentially splittable materialized table T as a startup cost
+ to access table T.
+
+ 7. When the optimizer finally chooses the best execution plan for
+ the embedding select Q and this plan prefers using splitting
+ for table T with pushed equi-join conditions PC then the execution
+ plan for the underlying join with these conditions is chosen for T.
+*/
+
+/*
+ The implementation of the splitting technique below allows to apply
+ the technique only to a materialized derived table / view / CTE whose
+ specification is either a select with GROUP BY or a non-grouping select
+ with window functions that share the same PARTITION BY list.
+*/
+
+#include "mariadb.h"
+#include "sql_select.h"
+
+/* Info on a splitting field */
+struct SplM_field_info
+{
+ /* Splitting field in the materialized table T */
+ Field *mat_field;
+ /* The item from the select list of the specification of T */
+ Item *producing_item;
+ /* The corresponding splitting field from the specification of T */
+ Field *underlying_field;
+};
+
+
+/* Info on the splitting execution plan saved in SplM_opt_info::cache */
+struct SplM_plan_info
+{
+ /* The cached splitting execution plan P */
+ struct st_position *best_positions;
+ /* The cost of the above plan */
+ double cost;
+ /* Selectivity of splitting used in P */
+ double split_sel;
+ /* For fast search of KEYUSE_EXT elements used for splitting in P */
+ struct KEYUSE_EXT *keyuse_ext_start;
+ /* The tables that contains the fields used for splitting in P */
+ TABLE *table;
+ /* The number of the key from 'table' used for splitting in P */
+ uint key;
+ /* Number of the components of 'key' used for splitting in P */
+ uint parts;
+};
+
+
+/*
+ The structure contains the information that is used by the optimizer
+ for potentially splittable materialization of T that is a materialized
+ derived_table / view / CTE
+*/
+class SplM_opt_info : public Sql_alloc
+{
+public:
+ /* The join for the select specifying T */
+ JOIN *join;
+ /* The map of tables from 'join' whose columns can be used for partitioning */
+ table_map tables_usable_for_splitting;
+ /* Info about the fields of the joined tables usable for splitting */
+ SplM_field_info *spl_fields;
+ /* The number of elements in the above list */
+ uint spl_field_cnt;
+ /* Contains the structures to generate all KEYUSEs for pushable equalities */
+ List<KEY_FIELD> added_key_fields;
+ /* The cache of evaluated execution plans for 'join' with pushed equalities */
+ List<SplM_plan_info> plan_cache;
+ /* Cost of best execution plan for join when nothing is pushed */
+ double unsplit_cost;
+ /* Cardinality of T when nothing is pushed */
+ double unsplit_card;
+ /* Lastly evaluated execution plan for 'join' with pushed equalities */
+ SplM_plan_info *last_plan;
+
+ SplM_plan_info *find_plan(TABLE *table, uint key, uint parts);
+};
+
+
+void TABLE::set_spl_opt_info(SplM_opt_info *spl_info)
+{
+ if (spl_info)
+ spl_info->join->spl_opt_info= spl_info;
+ spl_opt_info= spl_info;
+}
+
+
+void TABLE::deny_splitting()
+{
+ DBUG_ASSERT(spl_opt_info != NULL);
+ spl_opt_info->join->spl_opt_info= NULL;
+ spl_opt_info= NULL;
+}
+
+
+/* This structure is auxiliary and used only in the function that follows it */
+struct SplM_field_ext_info: public SplM_field_info
+{
+ uint item_no;
+ bool is_usable_for_ref_access;
+};
+
+
+/**
+ @brief
+ Check whether this join is one for potentially splittable materialized table
+
+ @details
+ The function checks whether this join is for select that specifies
+ a potentially splittable materialized table T. If so, the collected
+ info on potential splittability of T is attached to the field spl_opt_info
+ of the TABLE structure for T.
+
+ The function returns a positive answer if the following holds:
+ 1. the optimizer switch 'split_materialized' is set 'on'
+ 2. the select owning this join specifies a materialized derived/view/cte T
+ 3. this is the only select in the specification of T
+ 4. condition pushdown is not prohibited into T
+ 5. T is not recursive
+ 6. not all of this join are constant or optimized away
+ 7. T is either
+ 7.1. a grouping table with GROUP BY list P
+ or
+ 7.2. a non-grouping table with window functions over the same non-empty
+ partition specified by the PARTITION BY list P
+ 8. P contains some references on the columns of the joined tables C
+ occurred also in the select list of this join
+ 9. There are defined some keys usable for ref access of fields from C
+ with available statistics.
+
+ @retval
+ true if the answer is positive
+ false otherwise
+*/
+
+bool JOIN::check_for_splittable_materialized()
+{
+ ORDER *partition_list= 0;
+ st_select_lex_unit *unit= select_lex->master_unit();
+ TABLE_LIST *derived= unit->derived;
+ if (!(optimizer_flag(thd, OPTIMIZER_SWITCH_SPLIT_MATERIALIZED)) || // !(1)
+ !(derived && derived->is_materialized_derived()) || // !(2)
+ (unit->first_select()->next_select()) || // !(3)
+ (derived->prohibit_cond_pushdown) || // !(4)
+ (derived->is_recursive_with_table()) || // !(5)
+ (table_count == 0 || const_tables == top_join_tab_count)) // !(6)
+ return false;
+ if (group_list) // (7.1)
+ {
+ if (!select_lex->have_window_funcs())
+ partition_list= group_list;
+ }
+ else if (select_lex->have_window_funcs() &&
+ select_lex->window_specs.elements == 1) // (7.2)
+ {
+ partition_list=
+ select_lex->window_specs.head()->partition_list->first;
+ }
+ if (!partition_list)
+ return false;
+
+ ORDER *ord;
+ Dynamic_array<SplM_field_ext_info> candidates;
+
+ /*
+ Select from partition_list all candidates for splitting.
+ A candidate must be
+ - field item or refer to such (8.1)
+ - item mentioned in the select list (8.2)
+ Put info about such candidates into the array candidates
+ */
+ table_map usable_tables= 0; // tables that contains the candidate
+ for (ord= partition_list; ord; ord= ord->next)
+ {
+ Item *ord_item= *ord->item;
+ if (ord_item->real_item()->type() != Item::FIELD_ITEM) // !(8.1)
+ continue;
+
+ Field *ord_field= ((Item_field *) (ord_item->real_item()))->field;
+
+ JOIN_TAB *tab= ord_field->table->reginfo.join_tab;
+ if (tab->is_inner_table_of_outer_join())
+ continue;
+
+ List_iterator<Item> li(fields_list);
+ Item *item;
+ uint item_no= 0;
+ while ((item= li++))
+ {
+ if ((*ord->item)->eq(item, 0)) // (8.2)
+ {
+ SplM_field_ext_info new_elem;
+ new_elem.producing_item= item;
+ new_elem.item_no= item_no;
+ new_elem.mat_field= derived->table->field[item_no];
+ new_elem.underlying_field= ord_field;
+ new_elem.is_usable_for_ref_access= false;
+ candidates.push(new_elem);
+ usable_tables|= ord_field->table->map;
+ break;
+ }
+ item_no++;
+ }
+ }
+ if (candidates.elements() == 0) // no candidates satisfying (8.1) && (8.2)
+ return false;
+
+ /*
+ For each table from this join find the keys that can be used for ref access
+ of the fields mentioned in the 'array candidates'
+ */
+
+ SplM_field_ext_info *cand;
+ SplM_field_ext_info *cand_start= &candidates.at(0);
+ SplM_field_ext_info *cand_end= cand_start + candidates.elements();
+
+ for (JOIN_TAB *tab= join_tab;
+ tab < join_tab + top_join_tab_count; tab++)
+ {
+ TABLE *table= tab->table;
+ if (!(table->map & usable_tables))
+ continue;
+
+ table->keys_usable_for_splitting.clear_all();
+ uint i;
+ for (i= 0; i < table->s->keys; i++)
+ {
+ if (!table->keys_in_use_for_query.is_set(i))
+ continue;
+ KEY *key_info= table->key_info + i;
+ uint key_parts= table->actual_n_key_parts(key_info);
+ uint usable_kp_cnt= 0;
+ for ( ; usable_kp_cnt < key_parts; usable_kp_cnt++)
+ {
+ if (key_info->actual_rec_per_key(usable_kp_cnt) == 0)
+ break;
+ int fldnr= key_info->key_part[usable_kp_cnt].fieldnr;
+
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (cand->underlying_field->field_index + 1 == fldnr)
+ {
+ cand->is_usable_for_ref_access= true;
+ break;
+ }
+ }
+ if (cand == cand_end)
+ break;
+ }
+ if (usable_kp_cnt)
+ table->keys_usable_for_splitting.set_bit(i);
+ }
+ }
+
+ /* Count the candidate fields that can be accessed by ref */
+ uint spl_field_cnt= candidates.elements();
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (!cand->is_usable_for_ref_access)
+ spl_field_cnt--;
+ }
+
+ if (!spl_field_cnt) // No candidate field can be accessed by ref => !(9)
+ return false;
+
+ /*
+ Create a structure of the type SplM_opt_info and fill it with
+ the collected info on potential splittability of T
+ */
+ SplM_opt_info *spl_opt_info= new (thd->mem_root) SplM_opt_info();
+ SplM_field_info *spl_field=
+ (SplM_field_info *) (thd->calloc(sizeof(SplM_field_info) *
+ spl_field_cnt));
+
+ if (!(spl_opt_info && spl_field)) // consider T as not good for splitting
+ return false;
+
+ spl_opt_info->join= this;
+ spl_opt_info->tables_usable_for_splitting= 0;
+ spl_opt_info->spl_field_cnt= spl_field_cnt;
+ spl_opt_info->spl_fields= spl_field;
+ for (cand= cand_start; cand < cand_end; cand++)
+ {
+ if (!cand->is_usable_for_ref_access)
+ continue;
+ spl_field->producing_item= cand->producing_item;
+ spl_field->underlying_field= cand->underlying_field;
+ spl_field->mat_field= cand->mat_field;
+ spl_opt_info->tables_usable_for_splitting|=
+ cand->underlying_field->table->map;
+ spl_field++;
+ }
+
+ /* Attach this info to the table T */
+ derived->table->set_spl_opt_info(spl_opt_info);
+
+ return true;
+}
+
+
+/**
+ @brief
+ Collect info on KEY_FIELD usable for splitting
+
+ @param
+ key_field KEY_FIELD to collect info on
+
+ @details
+ The function assumes that this table is potentially splittable.
+ The function checks whether the KEY_FIELD structure key_field built for
+ this table was created for a splitting field f. If so, the function does
+ the following using info from key_field:
+ 1. Builds an equality of the form f = key_field->val that could be
+ pushed into this table.
+ 2. Creates a new KEY_FIELD structure for this equality and stores
+ a reference to this structure in this->spl_opt_info.
+*/
+
+void TABLE::add_splitting_info_for_key_field(KEY_FIELD *key_field)
+{
+ DBUG_ASSERT(spl_opt_info != NULL);
+ JOIN *join= spl_opt_info->join;
+ Field *field= key_field->field;
+ SplM_field_info *spl_field= spl_opt_info->spl_fields;
+ uint i= spl_opt_info->spl_field_cnt;
+ for ( ; i; i--, spl_field++)
+ {
+ if (spl_field->mat_field == field)
+ break;
+ }
+ if (!i) // field is not usable for splitting
+ return;
+
+ /*
+ Any equality condition that can be potentially pushed into the
+ materialized derived table is constructed now though later it may turn out
+ that it is not needed, because it is not used for splitting.
+ The reason for this is that the failure to construct it when it has to be
+ injected causes denial for further processing of the query.
+ Formally this equality is needed in the KEY_FIELD structure constructed
+ here that will be used to generate additional keyuses usable for splitting.
+ However key_field.cond could be used for this purpose (see implementations
+ of virtual function can_optimize_keypart_ref()).
+
+ The condition is built in such a form that it can be added to the WHERE
+ condition of the select that specifies this table.
+ */
+ THD *thd= in_use;
+ Item *left_item= spl_field->producing_item->build_clone(thd);
+ Item *right_item= key_field->val->build_clone(thd);
+ Item_func_eq *eq_item= 0;
+ if (left_item && right_item)
+ {
+ right_item->walk(&Item::set_fields_as_dependent_processor,
+ false, join->select_lex);
+ right_item->update_used_tables();
+ eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item);
+ }
+ if (!eq_item)
+ return;
+ KEY_FIELD *added_key_field=
+ (KEY_FIELD *) thd->alloc(sizeof(KEY_FIELD));
+ if (!added_key_field ||
+ spl_opt_info->added_key_fields.push_back(added_key_field,thd->mem_root))
+ return;
+ added_key_field->field= spl_field->underlying_field;
+ added_key_field->cond= eq_item;
+ added_key_field->val= key_field->val;
+ added_key_field->level= 0;
+ added_key_field->optimize= KEY_OPTIMIZE_EQ;
+ added_key_field->eq_func= true;
+ added_key_field->null_rejecting= true;
+ added_key_field->cond_guard= NULL;
+ added_key_field->sj_pred_no= UINT_MAX;
+ return;
+}
+
+
+static bool
+add_ext_keyuse_for_splitting(Dynamic_array<KEYUSE_EXT> *ext_keyuses,
+ KEY_FIELD *added_key_field, uint key, uint part)
+{
+ KEYUSE_EXT keyuse_ext;
+ Field *field= added_key_field->field;
+
+ JOIN_TAB *tab=field->table->reginfo.join_tab;
+ key_map possible_keys=field->get_possible_keys();
+ possible_keys.intersect(field->table->keys_usable_for_splitting);
+ tab->keys.merge(possible_keys);
+
+ Item_func_eq *eq_item= (Item_func_eq *) (added_key_field->cond);
+ keyuse_ext.table= field->table;
+ keyuse_ext.val= eq_item->arguments()[1];
+ keyuse_ext.key= key;
+ keyuse_ext.keypart=part;
+ keyuse_ext.keypart_map= (key_part_map) 1 << part;
+ keyuse_ext.used_tables= keyuse_ext.val->used_tables();
+ keyuse_ext.optimize= added_key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
+ keyuse_ext.ref_table_rows= 0;
+ keyuse_ext.null_rejecting= added_key_field->null_rejecting;
+ keyuse_ext.cond_guard= added_key_field->cond_guard;
+ keyuse_ext.sj_pred_no= added_key_field->sj_pred_no;
+ keyuse_ext.validity_ref= 0;
+ keyuse_ext.needed_in_prefix= added_key_field->val->used_tables();
+ keyuse_ext.validity_var= false;
+ return ext_keyuses->push(keyuse_ext);
+}
+
+
+static int
+sort_ext_keyuse(KEYUSE_EXT *a, KEYUSE_EXT *b)
+{
+ if (a->table->tablenr != b->table->tablenr)
+ return (int) (a->table->tablenr - b->table->tablenr);
+ if (a->key != b->key)
+ return (int) (a->key - b->key);
+ return (int) (a->keypart - b->keypart);
+}
+
+
+static void
+sort_ext_keyuses(Dynamic_array<KEYUSE_EXT> *keyuses)
+{
+ KEYUSE_EXT *first_keyuse= &keyuses->at(0);
+ my_qsort(first_keyuse, keyuses->elements(), sizeof(KEYUSE_EXT),
+ (qsort_cmp) sort_ext_keyuse);
+}
+
+
+/**
+ @brief
+ Add info on keyuses usable for splitting into an array
+*/
+
+static bool
+add_ext_keyuses_for_splitting_field(Dynamic_array<KEYUSE_EXT> *ext_keyuses,
+ KEY_FIELD *added_key_field)
+{
+ Field *field= added_key_field->field;
+ TABLE *table= field->table;
+ for (uint key= 0; key < table->s->keys; key++)
+ {
+ if (!(table->keys_usable_for_splitting.is_set(key)))
+ continue;
+ KEY *key_info= table->key_info + key;
+ uint key_parts= table->actual_n_key_parts(key_info);
+ KEY_PART_INFO *key_part_info= key_info->key_part;
+ for (uint part=0; part < key_parts; part++, key_part_info++)
+ {
+ if (!field->eq(key_part_info->field))
+ continue;
+ if (add_ext_keyuse_for_splitting(ext_keyuses, added_key_field, key, part))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/*
+ @brief
+ Cost of the post join operation used in specification of splittable table
+*/
+
+static
+double spl_postjoin_oper_cost(THD *thd, double join_record_count, uint rec_len)
+{
+ double cost;
+ cost= get_tmp_table_write_cost(thd, join_record_count,rec_len) *
+ join_record_count; // cost to fill tmp table
+ cost+= get_tmp_table_lookup_cost(thd, join_record_count,rec_len) *
+ join_record_count; // cost to perform post join operation used here
+ cost+= get_tmp_table_lookup_cost(thd, join_record_count, rec_len) +
+ join_record_count * log2 (join_record_count) *
+ SORT_INDEX_CMP_COST; // cost to perform sorting
+ return cost;
+}
+
+/**
+ @brief
+ Add KEYUSE structures that can be usable for splitting
+
+ @details
+ This function is called only for joins created for potentially
+ splittable materialized tables. The function does the following:
+ 1. Creates the dynamic array ext_keyuses_for_splitting of KEYUSE_EXT
+ structures and fills is with info about all keyuses that
+ could be used for splitting.
+ 2. Sort the array ext_keyuses_for_splitting for fast access by key
+ on certain columns.
+ 3. Collects and stores cost and cardinality info on the best execution
+ plan that does not use splitting and save this plan together with
+ corresponding array of keyuses.
+ 4. Expand this array with KEYUSE elements built from the info stored
+ in ext_keyuses_for_splitting that could be produced by pushed
+ equalities employed for splitting.
+ 5. Prepare the extended array of keyuses to be used in the function
+ best_access_plan()
+*/
+
+void JOIN::add_keyuses_for_splitting()
+{
+ uint i;
+ uint idx;
+ KEYUSE_EXT *keyuse_ext;
+ KEYUSE_EXT keyuse_ext_end;
+ double oper_cost;
+ uint rec_len;
+ uint added_keyuse_count;
+ TABLE *table= select_lex->master_unit()->derived->table;
+ List_iterator_fast<KEY_FIELD> li(spl_opt_info->added_key_fields);
+ KEY_FIELD *added_key_field;
+ if (!spl_opt_info->added_key_fields.elements)
+ goto err;
+ if (!(ext_keyuses_for_splitting= new Dynamic_array<KEYUSE_EXT>))
+ goto err;
+ while ((added_key_field= li++))
+ {
+ (void) add_ext_keyuses_for_splitting_field(ext_keyuses_for_splitting,
+ added_key_field);
+ }
+ added_keyuse_count= ext_keyuses_for_splitting->elements();
+ if (!added_keyuse_count)
+ goto err;
+ sort_ext_keyuses(ext_keyuses_for_splitting);
+ bzero((char*) &keyuse_ext_end, sizeof(keyuse_ext_end));
+ if (ext_keyuses_for_splitting->push(keyuse_ext_end))
+ goto err;
+
+ spl_opt_info->unsplit_card= join_record_count;
+
+ rec_len= table->s->rec_buff_length;
+
+ oper_cost= spl_postjoin_oper_cost(thd, join_record_count, rec_len);
+
+ spl_opt_info->unsplit_cost= best_positions[table_count-1].read_time +
+ oper_cost;
+
+ if (!(save_qep= new Join_plan_state(table_count + 1)))
+ goto err;
+
+ save_query_plan(save_qep);
+
+ if (!keyuse.buffer &&
+ my_init_dynamic_array(&keyuse, sizeof(KEYUSE), 20, 64,
+ MYF(MY_THREAD_SPECIFIC)))
+ goto err;
+
+ if (allocate_dynamic(&keyuse,
+ save_qep->keyuse.elements +
+ added_keyuse_count))
+ goto err;
+
+ memcpy(keyuse.buffer,
+ save_qep->keyuse.buffer,
+ (size_t) save_qep->keyuse.elements * keyuse.size_of_element);
+ keyuse.elements= save_qep->keyuse.elements;
+
+ keyuse_ext= &ext_keyuses_for_splitting->at(0);
+ idx= save_qep->keyuse.elements;
+ for (i=0; i < added_keyuse_count; i++, keyuse_ext++, idx++)
+ {
+ set_dynamic(&keyuse, (KEYUSE *) keyuse_ext, idx);
+ KEYUSE *added_keyuse= ((KEYUSE *) (keyuse.buffer)) + idx;
+ added_keyuse->validity_ref= &keyuse_ext->validity_var;
+ }
+
+ if (sort_and_filter_keyuse(thd, &keyuse, true))
+ goto err;
+ optimize_keyuse(this, &keyuse);
+
+ for (uint i= 0; i < table_count; i++)
+ {
+ JOIN_TAB *tab= join_tab + i;
+ map2table[tab->table->tablenr]= tab;
+ }
+
+ return;
+
+err:
+ if (save_qep)
+ restore_query_plan(save_qep);
+ table->deny_splitting();
+ return;
+}
+
+
+/**
+ @brief
+ Add KEYUSE structures that can be usable for splitting of this joined table
+*/
+
+void JOIN_TAB::add_keyuses_for_splitting()
+{
+ DBUG_ASSERT(table->spl_opt_info != NULL);
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ spl_opt_info->join->add_keyuses_for_splitting();
+}
+
+
+/*
+ @brief
+ Find info on the splitting plan by the splitting key
+*/
+
+SplM_plan_info *SplM_opt_info::find_plan(TABLE *table, uint key, uint parts)
+{
+ List_iterator_fast<SplM_plan_info> li(plan_cache);
+ SplM_plan_info *spl_plan;
+ while ((spl_plan= li++))
+ {
+ if (spl_plan->table == table &&
+ spl_plan->key == key &&
+ spl_plan->parts == parts)
+ break;
+ }
+ return spl_plan;
+}
+
+
+/*
+ @breaf
+ Enable/Disable a keyuses that can be used for splitting
+ */
+
+static
+void reset_validity_vars_for_keyuses(KEYUSE_EXT *key_keyuse_ext_start,
+ TABLE *table, uint key,
+ table_map remaining_tables,
+ bool validity_val)
+{
+ KEYUSE_EXT *keyuse_ext= key_keyuse_ext_start;
+ do
+ {
+ if (!(keyuse_ext->needed_in_prefix & remaining_tables))
+ {
+ /*
+ The enabling/disabling flags are set just in KEYUSE_EXT structures.
+ Yet keyuses that are used by best_access_path() have pointers
+ to these flags.
+ */
+ keyuse_ext->validity_var= validity_val;
+ }
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+}
+
+
+/**
+ @brief
+ Choose the best splitting to extend the evaluated partial join
+
+ @param
+ record_count estimated cardinality of the extended partial join
+ remaining_tables tables not joined yet
+
+ @details
+ This function is called during the search for the best execution
+ plan of the join that contains this table T. The function is called
+ every time when the optimizer tries to extend a partial join by
+ joining it with table T. Depending on what tables are already in the
+ partial join different equalities usable for splitting can be pushed
+ into T. The function evaluates different variants and chooses the
+ best one. Then the function finds the plan for the materializing join
+ with the chosen equality conditions pushed into it. If the cost of the
+ plan turns out to be less than the cost of the best plan without
+ splitting the function set it as the true plan of materialization
+ of the table T.
+ The function caches the found plans for materialization of table T
+ together if the info what key was used for splitting. Next time when
+ the optimizer prefers to use the same key the plan is taken from
+ the cache of plans
+
+ @retval
+ Pointer to the info on the found plan that employs the pushed equalities
+ if the plan has been chosen, NULL - otherwise.
+*/
+
+SplM_plan_info * JOIN_TAB::choose_best_splitting(double record_count,
+ table_map remaining_tables)
+{
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ DBUG_ASSERT(spl_opt_info != NULL);
+ JOIN *join= spl_opt_info->join;
+ THD *thd= join->thd;
+ table_map tables_usable_for_splitting=
+ spl_opt_info->tables_usable_for_splitting;
+ KEYUSE_EXT *keyuse_ext= &join->ext_keyuses_for_splitting->at(0);
+ KEYUSE_EXT *best_key_keyuse_ext_start;
+ TABLE *best_table= 0;
+ double best_rec_per_key= DBL_MAX;
+ SplM_plan_info *spl_plan= 0;
+ uint best_key;
+ uint best_key_parts;
+
+ /*
+ Check whether there are keys that can be used to join T employing splitting
+ and if so, select the best out of such keys
+ */
+ for (uint tablenr= 0; tablenr < join->table_count; tablenr++)
+ {
+ if (!((1ULL << tablenr) & tables_usable_for_splitting))
+ continue;
+ JOIN_TAB *tab= join->map2table[tablenr];
+ TABLE *table= tab->table;
+ do
+ {
+ uint key= keyuse_ext->key;
+ KEYUSE_EXT *key_keyuse_ext_start= keyuse_ext;
+ key_part_map found_parts= 0;
+ do
+ {
+ if (keyuse_ext->needed_in_prefix & remaining_tables)
+ {
+ keyuse_ext++;
+ continue;
+ }
+ if (!(keyuse_ext->keypart_map & found_parts))
+ {
+ if ((!found_parts && !keyuse_ext->keypart) ||
+ (found_parts && ((keyuse_ext->keypart_map >> 1) & found_parts)))
+ found_parts|= keyuse_ext->keypart_map;
+ else
+ {
+ do
+ {
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+ break;
+ }
+ }
+ KEY *key_info= table->key_info + key;
+ double rec_per_key=
+ key_info->actual_rec_per_key(keyuse_ext->keypart);
+ if (rec_per_key < best_rec_per_key)
+ {
+ best_table= keyuse_ext->table;
+ best_key= keyuse_ext->key;
+ best_key_parts= keyuse_ext->keypart + 1;
+ best_rec_per_key= rec_per_key;
+ best_key_keyuse_ext_start= key_keyuse_ext_start;
+ }
+ keyuse_ext++;
+ }
+ while (keyuse_ext->key == key && keyuse_ext->table == table);
+ }
+ while (keyuse_ext->table == table);
+ }
+ spl_opt_info->last_plan= 0;
+ if (best_table)
+ {
+ /*
+ The key for splitting was chosen, look for the plan for this key
+ in the cache
+ */
+ spl_plan= spl_opt_info->find_plan(best_table, best_key, best_key_parts);
+ if (!spl_plan &&
+ (spl_plan= (SplM_plan_info *) thd->alloc(sizeof(SplM_plan_info))) &&
+ (spl_plan->best_positions=
+ (POSITION *) thd->alloc(sizeof(POSITION) * join->table_count)) &&
+ !spl_opt_info->plan_cache.push_back(spl_plan))
+ {
+ /*
+ The plan for the chosen key has not been found in the cache.
+ Build a new plan and save info on it in the cache
+ */
+ table_map all_table_map= (1 << join->table_count) - 1;
+ reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table,
+ best_key, remaining_tables, true);
+ choose_plan(join, all_table_map & ~join->const_table_map);
+ spl_plan->keyuse_ext_start= best_key_keyuse_ext_start;
+ spl_plan->table= best_table;
+ spl_plan->key= best_key;
+ spl_plan->parts= best_key_parts;
+ spl_plan->split_sel= best_rec_per_key / spl_opt_info->unsplit_card;
+
+ uint rec_len= table->s->rec_buff_length;
+
+ double split_card= spl_opt_info->unsplit_card * spl_plan->split_sel;
+ double oper_cost= split_card *
+ spl_postjoin_oper_cost(thd, split_card, rec_len);
+ spl_plan->cost= join->best_positions[join->table_count-1].read_time +
+ + oper_cost;
+
+ memcpy((char *) spl_plan->best_positions,
+ (char *) join->best_positions,
+ sizeof(POSITION) * join->table_count);
+ reset_validity_vars_for_keyuses(best_key_keyuse_ext_start, best_table,
+ best_key, remaining_tables, false);
+ }
+ if (spl_plan)
+ {
+ if(record_count * spl_plan->cost < spl_opt_info->unsplit_cost)
+ {
+ /*
+ The best plan that employs splitting is cheaper than
+ the plan without splitting
+ */
+ spl_opt_info->last_plan= spl_plan;
+ }
+ }
+ }
+
+ /* Set the cost of the preferred materialization for this partial join */
+ records= (ha_rows)spl_opt_info->unsplit_card;
+ spl_plan= spl_opt_info->last_plan;
+ if (spl_plan)
+ {
+ startup_cost= record_count * spl_plan->cost;
+ records= (ha_rows) (records * spl_plan->split_sel);
+ }
+ else
+ startup_cost= spl_opt_info->unsplit_cost;
+ return spl_plan;
+}
+
+
+/**
+ @brief
+ Inject equalities for splitting used by the materialization join
+
+ @param
+ remaining_tables used to filter out the equalities that cannot
+ be pushed.
+
+ @details
+ This function is called by JOIN_TAB::fix_splitting that is used
+ to fix the chosen splitting of a splittable materialized table T
+ in the final query execution plan. In this plan the table T
+ is joined just before the 'remaining_tables'. So all equalities
+ usable for splitting whose right parts do not depend on any of
+ remaining tables can be pushed into join for T.
+ The function also marks the select that specifies T as
+ UNCACHEABLE_DEPENDENT_INJECTED.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
+{
+ Item *inj_cond= 0;
+ List<Item> inj_cond_list;
+ List_iterator<KEY_FIELD> li(spl_opt_info->added_key_fields);
+ KEY_FIELD *added_key_field;
+ while ((added_key_field= li++))
+ {
+ if (remaining_tables & added_key_field->val->used_tables())
+ continue;
+ if (inj_cond_list.push_back(added_key_field->cond, thd->mem_root))
+ return true;
+ }
+ DBUG_ASSERT(inj_cond_list.elements);
+ switch (inj_cond_list.elements) {
+ case 1:
+ inj_cond= inj_cond_list.head(); break;
+ default:
+ inj_cond= new (thd->mem_root) Item_cond_and(thd, inj_cond_list);
+ if (!inj_cond)
+ return true;
+ }
+ if (inj_cond)
+ inj_cond->fix_fields(thd,0);
+
+ if (inject_cond_into_where(inj_cond))
+ return true;
+
+ select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
+ st_select_lex_unit *unit= select_lex->master_unit();
+ unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
+
+ return false;
+}
+
+
+/**
+ @brief
+ Fix the splitting chosen for a splittable table in the final query plan
+
+ @param
+ spl_plan info on the splitting plan chosen for the splittable table T
+ remaining_tables the table T is joined just before these tables
+
+ @details
+ If in the final query plan the optimizer has chosen a splitting plan
+ then the function sets this plan as the final execution plan to
+ materialized the table T. Otherwise the plan that does not use
+ splitting is set for the materialization.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan,
+ table_map remaining_tables)
+{
+ SplM_opt_info *spl_opt_info= table->spl_opt_info;
+ DBUG_ASSERT(table->spl_opt_info != 0);
+ JOIN *md_join= spl_opt_info->join;
+ if (spl_plan)
+ {
+ memcpy((char *) md_join->best_positions,
+ (char *) spl_plan->best_positions,
+ sizeof(POSITION) * md_join->table_count);
+ if (md_join->inject_best_splitting_cond(remaining_tables))
+ return true;
+ /*
+ This is called for a proper work of JOIN::get_best_combination()
+ called for the join that materializes T
+ */
+ reset_validity_vars_for_keyuses(spl_plan->keyuse_ext_start,
+ spl_plan->table,
+ spl_plan->key,
+ remaining_tables,
+ true);
+ }
+ else
+ {
+ md_join->restore_query_plan(md_join->save_qep);
+ }
+ return false;
+}
+
+
+/**
+ @brief
+ Fix the splittings chosen splittable tables in the final query plan
+
+ @details
+ The function calls JOIN_TAB::fix_splittins for all potentially
+ splittable tables in this join to set all final materialization
+ plans chosen for these tables.
+
+ @retval
+ false on success
+ true on failure
+*/
+
+bool JOIN::fix_all_splittings_in_plan()
+{
+ table_map prev_tables= 0;
+ table_map all_tables= (1 << table_count) - 1;
+ for (uint tablenr=0 ; tablenr < table_count ; tablenr++)
+ {
+ POSITION *cur_pos= &best_positions[tablenr];
+ JOIN_TAB *tab= cur_pos->table;
+ if (tab->table->is_splittable())
+ {
+ SplM_plan_info *spl_plan= cur_pos->spl_plan;
+ if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables))
+ return true;
+ }
+ prev_tables|= tab->table->map;
+ }
+ return false;
+}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 9cd2eedb55d..dada23508b5 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -446,10 +446,6 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
Item_in_subselect *subq_pred, bool *remove);
static TABLE_LIST *alloc_join_nest(THD *thd);
static uint get_tmp_table_rec_length(Ref_ptr_array p_list, uint elements);
-static double get_tmp_table_lookup_cost(THD *thd, double row_count,
- uint row_size);
-static double get_tmp_table_write_cost(THD *thd, double row_count,
- uint row_size);
bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables);
static SJ_MATERIALIZATION_INFO *
at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
@@ -2468,7 +2464,7 @@ static uint get_tmp_table_rec_length(Ref_ptr_array p_items, uint elements)
@return the cost of one lookup
*/
-static double
+double
get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size)
{
if (row_count * row_size > thd->variables.max_heap_table_size)
@@ -2488,7 +2484,7 @@ get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size)
@return the cost of writing one row
*/
-static double
+double
get_tmp_table_write_cost(THD *thd, double row_count, uint row_size)
{
double lookup_cost= get_tmp_table_lookup_cost(thd, row_count, row_size);
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 890385d0e87..8133f15012c 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2989,6 +2989,25 @@ end:
DBUG_RETURN(result);
}
+
+bool partition_info::error_if_requires_values() const
+{
+ switch (part_type) {
+ case NOT_A_PARTITION:
+ case HASH_PARTITION:
+ case VERSIONING_PARTITION:
+ break;
+ case RANGE_PARTITION:
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
+ return true;
+ case LIST_PARTITION:
+ my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
+ return true;
+ }
+ return false;
+}
+
+
/**
Fix partition data from parser.
@@ -3079,6 +3098,8 @@ bool partition_info::fix_parser_data(THD *thd)
part_elem= it++;
List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
num_elements= part_elem->list_val_list.elements;
+ if (!num_elements && error_if_requires_values())
+ DBUG_RETURN(true);
DBUG_ASSERT(part_type == RANGE_PARTITION ?
num_elements == 1U : TRUE);
@@ -3420,33 +3441,6 @@ bool partition_info::has_same_partitioning(partition_info *new_part_info)
}
-static bool has_same_column_order(List<Create_field> *create_list,
- Field** field_array)
-{
- Field **f_ptr;
- List_iterator_fast<Create_field> new_field_it;
- Create_field *new_field= NULL;
- new_field_it.init(*create_list);
-
- for (f_ptr= field_array; *f_ptr; f_ptr++)
- {
- while ((new_field= new_field_it++))
- {
- if (new_field->field == *f_ptr)
- break;
- }
- if (!new_field)
- break;
- }
-
- if (!new_field)
- {
- /* Not same order!*/
- return false;
- }
- return true;
-}
-
bool partition_info::vers_trx_id_to_ts(THD* thd, Field* in_trx_id, Field_timestamp& out_ts)
{
DBUG_ASSERT(table);
@@ -3471,32 +3465,6 @@ bool partition_info::vers_trx_id_to_ts(THD* thd, Field* in_trx_id, Field_timesta
}
-/**
- Check if the partitioning columns are in the same order as the given list.
-
- Used to see if INPLACE alter can be allowed or not. If the order is
- different then the rows must be redistributed for KEY [sub]partitioning.
-
- @param[in] create_list Column list after ALTER TABLE.
- @return true is same order as before ALTER TABLE, else false.
-*/
-bool partition_info::same_key_column_order(List<Create_field> *create_list)
-{
- /* Only need to check for KEY [sub] partitioning. */
- if (list_of_part_fields && !column_list)
- {
- if (!has_same_column_order(create_list, part_field_array))
- return false;
- }
- if (list_of_subpart_fields)
- {
- if (!has_same_column_order(create_list, subpart_field_array))
- return false;
- }
- return true;
-}
-
-
void partition_info::print_debug(const char *str, uint *value)
{
DBUG_ENTER("print_debug");
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 3883fac5181..6f1414efb02 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -374,28 +374,7 @@ public:
size_t file_name_size, uint32 *part_id);
void report_part_expr_error(bool use_subpart_expr);
bool has_same_partitioning(partition_info *new_part_info);
- inline bool is_partition_used(uint part_id) const
- {
- return bitmap_is_set(&read_partitions, part_id);
- }
- inline bool is_partition_locked(uint part_id) const
- {
- return bitmap_is_set(&lock_partitions, part_id);
- }
- inline uint num_partitions_used()
- {
- return bitmap_bits_set(&read_partitions);
- }
- inline uint get_first_used_partition() const
- {
- return bitmap_get_first_set(&read_partitions);
- }
- inline uint get_next_used_partition(uint part_id) const
- {
- return bitmap_get_next_set(&read_partitions, part_id);
- }
- bool same_key_column_order(List<Create_field> *create_list);
-
+ bool error_if_requires_values() const;
private:
static int list_part_cmp(const void* a, const void* b);
bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info,
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 369b072ab47..9f48f908102 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -1673,7 +1673,6 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
mysql_mutex_lock(&LOCK_binlog_state);
for (i= 0; i < hash.records; ++i)
{
- size_t res;
element *e= (element *)my_hash_element(&hash, i);
if (!e->last_gtid)
{
@@ -1693,8 +1692,8 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
gtid= e->last_gtid;
longlong10_to_str(gtid->seq_no, buf, 10);
- res= my_b_printf(dest, "%u-%u-%s\n", gtid->domain_id, gtid->server_id, buf);
- if (res == (size_t) -1)
+ if (my_b_printf(dest, "%u-%u-%s\n", gtid->domain_id, gtid->server_id,
+ buf))
{
res= 1;
goto end;
@@ -2140,10 +2139,7 @@ slave_connection_state::load(const char *slave_request, size_t len)
for (;;)
{
if (!(rec= (uchar *)my_malloc(sizeof(entry), MYF(MY_WME))))
- {
- my_error(ER_OUTOFMEMORY, MYF(0), (int) sizeof(*gtid));
return 1;
- }
gtid= &((entry *)rec)->gtid;
if (gtid_parser_helper(&p, end, gtid))
{
@@ -2759,10 +2755,7 @@ gtid_waiting::get_entry(uint32 domain_id)
return e;
if (!(e= (hash_element *)my_malloc(sizeof(*e), MYF(MY_WME))))
- {
- my_error(ER_OUTOFMEMORY, MYF(0), (int) sizeof(*e));
return NULL;
- }
if (init_queue(&e->queue, 8, offsetof(queue_element, wait_seq_no), 0,
cmp_queue_elem, NULL, 1+offsetof(queue_element, queue_idx), 1))
diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc
index 244e9396889..aa588a5f300 100644
--- a/sql/semisync_master_ack_receiver.cc
+++ b/sql/semisync_master_ack_receiver.cc
@@ -258,7 +258,7 @@ void Ack_receiver::run()
struct timeval tv= {1, 0};
fds= read_fds;
/* select requires max fd + 1 for the first argument */
- ret= select(max_fd+1, &fds, NULL, NULL, &tv);
+ ret= select((int)(max_fd+1), &fds, NULL, NULL, &tv);
if (ret <= 0)
{
mysql_mutex_unlock(&m_mutex);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8522efaba48..5a404997a56 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1804,30 +1804,30 @@ ER_WRONG_AUTO_KEY 42000 S1009
ER_BINLOG_CANT_DELETE_GTID_DOMAIN
eng "Could not delete gtid domain. Reason: %s."
ER_NORMAL_SHUTDOWN
- cze "%s (%s): normální ukončení\n"
- dan "%s (%s): Normal nedlukning\n"
- nla "%s (%s): Normaal afgesloten \n"
- eng "%s (%s): Normal shutdown\n"
- est "%s (%s): MariaDB lõpetas\n"
- fre "%s (%s): Arrêt normal du serveur\n"
- ger "%s (%s): Normal heruntergefahren\n"
- greek "%s (%s): Φυσιολογική διαδικασία shutdown\n"
- hindi "%s (%s): सामान्य शटडाउन\n"
- hun "%s (%s): Normal leallitas\n"
- ita "%s (%s): Shutdown normale\n"
- jpn "%s (%s): 通常シャットダウン\n"
- kor "%s (%s): 정상적인 shutdown\n"
- nor "%s (%s): Normal avslutning\n"
- norwegian-ny "%s (%s): Normal nedkopling\n"
- pol "%s (%s): Standardowe zakończenie działania\n"
- por "%s (%s): 'Shutdown' normal\n"
- rum "%s (%s): Terminare normala\n"
- rus "%s (%s): Корректная остановка\n"
- serbian "%s (%s): Normalno gašenje\n"
- slo "%s (%s): normálne ukončenie\n"
- spa "%s (%s): Apagado normal\n"
- swe "%s (%s): Normal avslutning\n"
- ukr "%s (%s): Нормальне завершення\n"
+ cze "%s (%s): normální ukončení"
+ dan "%s (%s): Normal nedlukning"
+ nla "%s (%s): Normaal afgesloten "
+ eng "%s (%s): Normal shutdown"
+ est "%s (%s): MariaDB lõpetas"
+ fre "%s (%s): Arrêt normal du serveur"
+ ger "%s (%s): Normal heruntergefahren"
+ greek "%s (%s): Φυσιολογική διαδικασία shutdown"
+ hindi "%s (%s): सामान्य शटडाउन"
+ hun "%s (%s): Normal leallitas"
+ ita "%s (%s): Shutdown normale"
+ jpn "%s (%s): 通常シャットダウン"
+ kor "%s (%s): 정상적인 shutdown"
+ nor "%s (%s): Normal avslutning"
+ norwegian-ny "%s (%s): Normal nedkopling"
+ pol "%s (%s): Standardowe zakończenie działania"
+ por "%s (%s): 'Shutdown' normal"
+ rum "%s (%s): Terminare normala"
+ rus "%s (%s): Корректная остановка"
+ serbian "%s (%s): Normalno gašenje"
+ slo "%s (%s): normálne ukončenie"
+ spa "%s (%s): Apagado normal"
+ swe "%s (%s): Normal avslutning"
+ ukr "%s (%s): Нормальне завершення"
ER_GOT_SIGNAL
cze "%s: přijat signal %d, končím\n"
dan "%s: Fangede signal %d. Afslutter!!\n"
diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc
index c99ad088e9f..0452e181e22 100644
--- a/sql/signal_handler.cc
+++ b/sql/signal_handler.cc
@@ -298,7 +298,9 @@ extern "C" sig_handler handle_fatal_signal(int sig)
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
- my_safe_printf_stderr("%s", "Writing a core file\n");
+ char buff[80];
+ my_getwd(buff, sizeof(buff), 0);
+ my_safe_printf_stderr("Writing a core file at %s\n", buff);
fflush(stderr);
my_write_core(sig);
}
diff --git a/sql/slave.cc b/sql/slave.cc
index f36af66f780..90ad8bbdef1 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -41,7 +41,7 @@
#include <sql_common.h>
#include <errmsg.h>
#include <ssl_compat.h>
-#include <mysqld_error.h>
+#include "unireg.h"
#include <mysys_err.h>
#include <signal.h>
#include <mysql.h>
diff --git a/sql/slave.h b/sql/slave.h
index 74bb4356dfb..649d55b45b9 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -52,7 +52,7 @@
#define SLAVE_NET_TIMEOUT 60
-#define MAX_SLAVE_ERROR 2000
+#define MAX_SLAVE_ERROR ER_ERROR_LAST+1
#define MAX_REPLICATION_THREAD 64
diff --git a/sql/sp.cc b/sql/sp.cc
index 58dd8cfee3d..843c40cf2b6 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1345,8 +1345,8 @@ log:
{
thd->clear_error();
- String log_query;
- log_query.set_charset(system_charset_info);
+ StringBuffer<128> log_query(thd->variables.character_set_client);
+ DBUG_ASSERT(log_query.charset()->mbminlen == 1);
if (show_create_sp(thd, &log_query,
sp->m_explicit_name ? sp->m_db : null_clex_str,
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index e1a28602a44..decf007b2d8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2418,10 +2418,9 @@ sp_head::check_unresolved_goto()
if (m_backpatch_goto.elements > 0)
{
List_iterator_fast<bp_t> li(m_backpatch_goto);
- bp_t *bp;
- while ((bp= li++))
+ while (bp_t* bp= li++)
{
- if ((bp->instr_type == GOTO))
+ if (bp->instr_type == GOTO)
{
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "GOTO", bp->lab->name.str);
has_unresolved_label=true;
@@ -4652,7 +4651,8 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->init_one_table_for_prelocking(key_buff, stab->db_length,
key_buff + stab->db_length + 1, stab->table_name_length,
key_buff + stab->db_length + stab->table_name_length + 2,
- stab->lock_type, true, belong_to_view, stab->trg_event_map,
+ stab->lock_type, TABLE_LIST::PRELOCK_ROUTINE, belong_to_view,
+ stab->trg_event_map,
query_tables_last_ptr);
tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST));
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index f402892e18e..d3edaa2b56a 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2869,37 +2869,42 @@ static void acl_insert_user(const char *user, const char *host,
}
-static void acl_update_db(const char *user, const char *host, const char *db,
+static bool acl_update_db(const char *user, const char *host, const char *db,
ulong privileges)
{
mysql_mutex_assert_owner(&acl_cache->lock);
+ bool updated= false;
+
for (uint i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
if ((!acl_db->user && !user[0]) ||
- (acl_db->user &&
- !strcmp(user,acl_db->user)))
+ (acl_db->user &&
+ !strcmp(user,acl_db->user)))
{
if ((!acl_db->host.hostname && !host[0]) ||
- (acl_db->host.hostname &&
- !strcmp(host, acl_db->host.hostname)))
+ (acl_db->host.hostname &&
+ !strcmp(host, acl_db->host.hostname)))
{
- if ((!acl_db->db && !db[0]) ||
- (acl_db->db && !strcmp(db,acl_db->db)))
+ if ((!acl_db->db && !db[0]) ||
+ (acl_db->db && !strcmp(db,acl_db->db)))
- {
- if (privileges)
+ {
+ if (privileges)
{
acl_db->access= privileges;
acl_db->initial_access= acl_db->access;
}
- else
- delete_dynamic_element(&acl_dbs,i);
- }
+ else
+ delete_dynamic_element(&acl_dbs,i);
+ updated= true;
+ }
}
}
}
+
+ return updated;
}
@@ -4391,9 +4396,21 @@ static int replace_db_table(TABLE *table, const char *db,
acl_cache->clear(1); // Clear privilege cache
if (old_row_exists)
acl_update_db(combo.user.str,combo.host.str,db,rights);
- else
- if (rights)
- acl_insert_db(combo.user.str,combo.host.str,db,rights);
+ else if (rights)
+ {
+ /*
+ If we did not have an already existing row, for users, we must always
+ insert an ACL_DB entry. For roles however, it is possible that one was
+ already created when DB privileges were propagated from other granted
+ roles onto the current role. For this case, first try to update the
+ existing entry, otherwise insert a new one.
+ */
+ if (!combo.is_role() ||
+ !acl_update_db(combo.user.str, combo.host.str, db, rights))
+ {
+ acl_insert_db(combo.user.str,combo.host.str,db,rights);
+ }
+ }
DBUG_RETURN(0);
/* This could only happen if the grant tables got corrupted */
@@ -6316,9 +6333,12 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)),
{
PRIVS_TO_MERGE *data= (PRIVS_TO_MERGE *)context;
+ DBUG_ASSERT(grantee->counter > 0);
if (--grantee->counter)
return 1; // don't recurse into grantee just yet
+ grantee->counter= 1; // Mark the grantee as merged.
+
/* if we'll do db/table/routine privileges, create a hash of role names */
role_hash_t role_hash(role_key);
if (data->what != PRIVS_TO_MERGE::GLOBAL)
@@ -7410,11 +7430,10 @@ end_index_init:
DBUG_RETURN(return_val);
}
-
-static my_bool role_propagate_grants_action(void *ptr,
- void *unused __attribute__((unused)))
+static my_bool propagate_role_grants_action(void *role_ptr,
+ void *ptr __attribute__((unused)))
{
- ACL_ROLE *role= (ACL_ROLE *)ptr;
+ ACL_ROLE *role= static_cast<ACL_ROLE *>(role_ptr);
if (role->counter)
return 0;
@@ -7490,7 +7509,7 @@ bool grant_reload(THD *thd)
}
mysql_mutex_lock(&acl_cache->lock);
- my_hash_iterate(&acl_roles, role_propagate_grants_action, NULL);
+ my_hash_iterate(&acl_roles, propagate_role_grants_action, NULL);
mysql_mutex_unlock(&acl_cache->lock);
mysql_rwlock_unlock(&LOCK_grant);
@@ -8589,7 +8608,7 @@ bool mysql_show_create_user(THD *thd, LEX_USER *lex_user)
hostname, NullS) - buff);
Item_string *field = new (thd->mem_root) Item_string_ascii(thd, "", 0);
if (!field)
- DBUG_RETURN(true);
+ DBUG_RETURN(true); // Error given my my_alloc()
field->name.str= buff;
field->name.length= head_length;
@@ -10233,13 +10252,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
}
}
- binlog= true;
if (replace_user_table(thd, tables.user_table(), *user_name, 0, 0, 1, 0))
{
append_user(thd, &wrong_users, user_name);
result= TRUE;
continue;
}
+ binlog= true;
// every created role is automatically granted to its creator-admin
if (handle_as_role)
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index cff59036867..bafb9ca23d8 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -198,8 +198,12 @@ extern LEX_CSTRING current_user_and_current_role;
static inline int access_denied_error_code(int passwd_used)
{
+#ifdef mysqld_error_find_printf_error_used
+ return 0;
+#else
return passwd_used == 2 ? ER_ACCESS_DENIED_NO_PASSWORD_ERROR
: ER_ACCESS_DENIED_ERROR;
+#endif
}
/* prototypes */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e5191feba14..69b867da0cb 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3528,7 +3528,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
*/
if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
! has_prelocking_list &&
- tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ (tables->lock_type >= TL_WRITE_ALLOW_WRITE || thd->lex->default_used))
{
bool need_prelocking= FALSE;
TABLE_LIST **save_query_tables_last= lex->query_tables_last;
@@ -4234,7 +4234,7 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
for (; tl; tl= tl->next_global )
{
if (tl->lock_type >= lock_type &&
- tl->prelocking_placeholder == TABLE_LIST::FK &&
+ tl->prelocking_placeholder == TABLE_LIST::PRELOCK_FK &&
strcmp(tl->db, db->str) == 0 &&
strcmp(tl->table_name, table->str) == 0)
return true;
@@ -4243,6 +4243,55 @@ static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_CSTRING *db,
}
+static bool internal_table_exists(TABLE_LIST *global_list,
+ const char *table_name)
+{
+ do
+ {
+ if (global_list->table_name == table_name)
+ return 1;
+ } while ((global_list= global_list->next_global));
+ return 0;
+}
+
+
+static bool
+add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
+ TABLE_LIST *tables)
+{
+ TABLE_LIST *global_table_list= prelocking_ctx->query_tables;
+
+ do
+ {
+ /*
+ Skip table if already in the list. Can happen with prepared statements
+ */
+ if (tables->next_local &&
+ internal_table_exists(global_table_list, tables->table_name))
+ continue;
+
+ TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
+ if (!tl)
+ return TRUE;
+ tl->init_one_table_for_prelocking(tables->db,
+ strlen(tables->db),
+ tables->table_name,
+ strlen(tables->table_name),
+ NULL, tables->lock_type,
+ TABLE_LIST::PRELOCK_NONE,
+ 0, 0,
+ &prelocking_ctx->query_tables_last);
+ /*
+ Store link to the new table_list that will be used by open so that
+ Item_func_nextval() can find it
+ */
+ tables->next_local= tl;
+ } while ((tables= tables->next_global));
+ return FALSE;
+}
+
+
+
/**
Defines how prelocking algorithm for DML statements should handle table list
elements:
@@ -4269,21 +4318,23 @@ bool DML_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking)
{
+ TABLE *table= table_list->table;
/* We rely on a caller to check that table is going to be changed. */
- DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);
+ DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE ||
+ thd->lex->default_used);
if (table_list->trg_event_map)
{
- if (table_list->table->triggers)
+ if (table->triggers)
{
*need_prelocking= TRUE;
- if (table_list->table->triggers->
+ if (table->triggers->
add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list))
return TRUE;
}
- if (table_list->table->file->referenced_by_foreign_key())
+ if (table->file->referenced_by_foreign_key())
{
List <FOREIGN_KEY_INFO> fk_list;
List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
@@ -4292,7 +4343,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
arena= thd->activate_stmt_arena_if_needed(&backup);
- table_list->table->file->get_parent_foreign_key_list(thd, &fk_list);
+ table->file->get_parent_foreign_key_list(thd, &fk_list);
if (thd->is_error())
{
if (arena)
@@ -4321,21 +4372,96 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
continue;
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
- tl->init_one_table_for_prelocking(fk->foreign_db->str, fk->foreign_db->length,
- fk->foreign_table->str, fk->foreign_table->length,
- NULL, lock_type, false, table_list->belong_to_view,
- op, &prelocking_ctx->query_tables_last);
+ tl->init_one_table_for_prelocking(fk->foreign_db->str,
+ fk->foreign_db->length,
+ fk->foreign_table->str,
+ fk->foreign_table->length,
+ NULL, lock_type,
+ TABLE_LIST::PRELOCK_FK,
+ table_list->belong_to_view, op,
+ &prelocking_ctx->query_tables_last);
}
if (arena)
thd->restore_active_arena(arena, &backup);
}
}
+ /* Open any tables used by DEFAULT (like sequence tables) */
+ if (table->internal_tables &&
+ ((sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) ||
+ thd->lex->default_used))
+ {
+ Query_arena *arena, backup;
+ bool error;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
+ error= add_internal_tables(thd, prelocking_ctx,
+ table->internal_tables);
+ if (arena)
+ thd->restore_active_arena(arena, &backup);
+ if (error)
+ {
+ *need_prelocking= TRUE;
+ return TRUE;
+ }
+ }
return FALSE;
}
/**
+ Open all tables used by DEFAULT functions.
+
+ This is different from normal open_and_lock_tables() as we may
+ already have other tables opened and locked and we have to merge the
+ new table with the old ones.
+*/
+
+bool open_and_lock_internal_tables(TABLE *table, bool lock_table)
+{
+ THD *thd= table->in_use;
+ TABLE_LIST *tl;
+ MYSQL_LOCK *save_lock,*new_lock;
+ DBUG_ENTER("open_internal_tables");
+
+ /* remove pointer to old select_lex which is already destroyed */
+ for (tl= table->internal_tables ; tl ; tl= tl->next_global)
+ tl->select_lex= 0;
+
+ uint counter;
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ TABLE_LIST *tmp= table->internal_tables;
+ DML_prelocking_strategy prelocking_strategy;
+
+ if (open_tables(thd, thd->lex->create_info, &tmp, &counter, 0,
+ &prelocking_strategy))
+ goto err;
+
+ if (lock_table)
+ {
+ save_lock= thd->lock;
+ thd->lock= 0;
+ if (lock_tables(thd, table->internal_tables, counter,
+ MYSQL_LOCK_USE_MALLOC))
+ goto err;
+
+ if (!(new_lock= mysql_lock_merge(save_lock, thd->lock)))
+ {
+ thd->lock= save_lock;
+ mysql_unlock_tables(thd, save_lock, 1);
+ /* We don't have to close tables as caller will do that */
+ goto err;
+ }
+ thd->lock= new_lock;
+ }
+ DBUG_RETURN(0);
+
+err:
+ thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ DBUG_RETURN(1);
+}
+
+
+/**
Defines how prelocking algorithm for DML statements should handle view -
all view routines should be added to the prelocking set.
@@ -4486,7 +4612,7 @@ static bool check_lock_and_start_stmt(THD *thd,
Prelocking placeholder is not set for TABLE_LIST that
are directly used by TOP level statement.
*/
- DBUG_ASSERT(table_list->prelocking_placeholder == false);
+ DBUG_ASSERT(table_list->prelocking_placeholder == TABLE_LIST::PRELOCK_NONE);
/*
TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only
@@ -4499,7 +4625,6 @@ static bool check_lock_and_start_stmt(THD *thd,
Last argument routine_modifies_data for read_lock_type_for_table()
is ignored, as prelocking placeholder will never be set here.
*/
- DBUG_ASSERT(table_list->prelocking_placeholder == false);
if (table_list->lock_type == TL_WRITE_DEFAULT)
lock_type= thd->update_lock_default;
else if (table_list->lock_type == TL_READ_DEFAULT)
@@ -4507,8 +4632,8 @@ static bool check_lock_and_start_stmt(THD *thd,
else
lock_type= table_list->lock_type;
- if ((int) lock_type > (int) TL_WRITE_ALLOW_WRITE &&
- (int) table_list->table->reginfo.lock_type <= (int) TL_WRITE_ALLOW_WRITE)
+ if ((int) lock_type >= (int) TL_WRITE_ALLOW_WRITE &&
+ (int) table_list->table->reginfo.lock_type < (int) TL_WRITE_ALLOW_WRITE)
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
table_list->table->alias.c_ptr());
@@ -5532,7 +5657,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
DBUG_EVALUATE_IF("test_completely_invisible", 0, 1))
DBUG_RETURN((Field*)0);
- *cached_field_index_ptr= field_ptr - table->field;
+ *cached_field_index_ptr= (uint)(field_ptr - table->field);
field= *field_ptr;
}
else
diff --git a/sql/sql_base.h b/sql/sql_base.h
index bb33af66590..bf140cb5d17 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -100,6 +100,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
*/
#define MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK 0x1000
#define MYSQL_LOCK_NOT_TEMPORARY 0x2000
+#define MYSQL_LOCK_USE_MALLOC 0x4000
/**
Only check THD::killed if waits happen (e.g. wait on MDL, wait on
table flush, wait on thr_lock.c locks) while opening and locking table.
@@ -257,6 +258,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags,
uint dt_phases);
bool open_tables_only_view_structure(THD *thd, TABLE_LIST *tables,
bool can_deadlock);
+bool open_and_lock_internal_tables(TABLE *table, bool lock);
bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
int decide_logging_format(THD *thd, TABLE_LIST *tables);
void close_thread_table(THD *thd, TABLE **table_ptr);
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 2dc977c9b5d..766aa8099ba 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1814,7 +1814,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length)
sql++;
continue;
}
- /* fall trough */
+ /* fall through */
default:
break;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 00144a9a12d..84fdaf8b1b6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2750,6 +2750,8 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
MEM_ROOT *runtime_memroot)
{
Item_change_record *change;
+ DBUG_ENTER("THD::nocheck_register_item_tree_change");
+ DBUG_PRINT("enter", ("Register %p <- %p", old_value, (*place)));
/*
Now we use one node per change, which adds some memory overhead,
but still is rather fast as we use alloc_root for allocations.
@@ -2762,12 +2764,13 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
OOM, thd->fatal_error() is called by the error handler of the
memroot. Just return.
*/
- return;
+ DBUG_VOID_RETURN;
}
change= new (change_mem) Item_change_record;
change->place= place;
change->old_value= old_value;
change_list.append(change);
+ DBUG_VOID_RETURN;
}
/**
@@ -2808,7 +2811,11 @@ void THD::rollback_item_tree_changes()
DBUG_ENTER("rollback_item_tree_changes");
while ((change= it++))
+ {
+ DBUG_PRINT("info", ("revert %p -> %p",
+ change->old_value, (*change->place)));
*change->place= change->old_value;
+ }
/* We can forget about changes memory: it's allocated in runtime memroot */
change_list.empty();
DBUG_VOID_RETURN;
@@ -4688,7 +4695,7 @@ TABLE *find_fk_open_table(THD *thd, const char *db, size_t db_len,
{
if (t->s->db.length == db_len && t->s->table_name.length == table_len &&
!strcmp(t->s->db.str, db) && !strcmp(t->s->table_name.str, table) &&
- t->pos_in_table_list->prelocking_placeholder == TABLE_LIST::FK)
+ t->pos_in_table_list->prelocking_placeholder == TABLE_LIST::PRELOCK_FK)
return t;
}
return NULL;
@@ -6081,7 +6088,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
replicated_tables_count++;
if (table->lock_type <= TL_READ_NO_INSERT &&
- table->prelocking_placeholder != TABLE_LIST::FK)
+ table->prelocking_placeholder != TABLE_LIST::PRELOCK_FK)
has_read_tables= true;
else if (table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
diff --git a/sql/sql_class.h b/sql/sql_class.h
index ebb98ac9407..c15bbe54a1b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -373,8 +373,9 @@ public:
typedef struct st_mysql_lock
{
TABLE **table;
- uint table_count,lock_count;
THR_LOCK_DATA **locks;
+ uint table_count,lock_count;
+ uint flags;
} MYSQL_LOCK;
@@ -704,7 +705,7 @@ typedef struct system_variables
uint idle_write_transaction_timeout;
uint column_compression_threshold;
uint column_compression_zlib_level;
- ulong in_subquery_conversion_threshold;
+ uint in_subquery_conversion_threshold;
vers_asof_timestamp_t vers_asof_timestamp;
#ifdef VERS_EXPERIMENTAL
@@ -4479,7 +4480,8 @@ public:
const char *path,
const char *db,
const char *table_name,
- bool open_in_engine);
+ bool open_in_engine,
+ bool open_internal_tables);
TABLE *find_temporary_table(const char *db, const char *table_name);
TABLE *find_temporary_table(const TABLE_LIST *tl);
@@ -5586,8 +5588,6 @@ public:
};
-
-
/*
Optimizer and executor structure for the materialized semi-join info. This
structure contains
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index e428d969db0..1e3994dea66 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -316,13 +316,9 @@ extern "C" void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (my_hash_init(&hash_user_connections,system_charset_info,max_connections,
- 0,0, (my_hash_get_key) get_key_conn,
- (my_hash_free_key) free_user, 0))
- {
- sql_print_error("Initializing hash_user_connections failed.");
- exit(1);
- }
+ my_hash_init(&hash_user_connections, system_charset_info, max_connections,
+ 0, 0, (my_hash_get_key) get_key_conn,
+ (my_hash_free_key) free_user, 0);
#endif
}
@@ -481,24 +477,16 @@ void init_user_stats(USER_STATS *user_stats,
void init_global_user_stats(void)
{
- if (my_hash_init(&global_user_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_user_stats,
- (my_hash_free_key)free_user_stats, 0))
- {
- sql_print_error("Initializing global_user_stats failed.");
- exit(1);
- }
+ my_hash_init(&global_user_stats, system_charset_info, max_connections,
+ 0, 0, (my_hash_get_key) get_key_user_stats,
+ (my_hash_free_key) free_user_stats, 0);
}
void init_global_client_stats(void)
{
- if (my_hash_init(&global_client_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_user_stats,
- (my_hash_free_key)free_user_stats, 0))
- {
- sql_print_error("Initializing global_client_stats failed.");
- exit(1);
- }
+ my_hash_init(&global_client_stats, system_charset_info, max_connections,
+ 0, 0, (my_hash_get_key) get_key_user_stats,
+ (my_hash_free_key) free_user_stats, 0);
}
extern "C" uchar *get_key_table_stats(TABLE_STATS *table_stats, size_t *length,
@@ -515,12 +503,9 @@ extern "C" void free_table_stats(TABLE_STATS* table_stats)
void init_global_table_stats(void)
{
- if (my_hash_init(&global_table_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_table_stats,
- (my_hash_free_key)free_table_stats, 0)) {
- sql_print_error("Initializing global_table_stats failed.");
- exit(1);
- }
+ my_hash_init(&global_table_stats, system_charset_info, max_connections,
+ 0, 0, (my_hash_get_key) get_key_table_stats,
+ (my_hash_free_key) free_table_stats, 0);
}
extern "C" uchar *get_key_index_stats(INDEX_STATS *index_stats, size_t *length,
@@ -537,13 +522,9 @@ extern "C" void free_index_stats(INDEX_STATS* index_stats)
void init_global_index_stats(void)
{
- if (my_hash_init(&global_index_stats, system_charset_info, max_connections,
- 0, 0, (my_hash_get_key) get_key_index_stats,
- (my_hash_free_key)free_index_stats, 0))
- {
- sql_print_error("Initializing global_index_stats failed.");
- exit(1);
- }
+ my_hash_init(&global_index_stats, system_charset_info, max_connections,
+ 0, 0, (my_hash_get_key) get_key_index_stats,
+ (my_hash_free_key) free_index_stats, 0);
}
diff --git a/sql/sql_const.h b/sql/sql_const.h
index 007b7faeebb..65742235bee 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -231,6 +231,7 @@
*/
#define HEAP_TEMPTABLE_LOOKUP_COST 0.05
#define DISK_TEMPTABLE_LOOKUP_COST 1.0
+#define SORT_INDEX_CMP_COST 0.02
#define MY_CHARSET_BIN_MB_MAXLEN 1
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index ff80e198023..9608436226c 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -681,7 +681,7 @@ void With_element::move_anchors_ahead()
{
st_select_lex *next_sl;
st_select_lex *new_pos= spec->first_select();
- st_select_lex *last_sl;
+ st_select_lex *UNINIT_VAR(last_sl);
new_pos->linkage= UNION_TYPE;
for (st_select_lex *sl= new_pos; sl; sl= next_sl)
{
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 0d237b94af2..f9801d2bf36 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -364,6 +364,9 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX *parent_lex= derived->select_lex;
Query_arena *arena, backup;
DBUG_ENTER("mysql_derived_merge");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ derived->get_unit()));
if (derived->merged)
DBUG_RETURN(FALSE);
@@ -510,7 +513,9 @@ unconditional_materialization:
bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
{
DBUG_ENTER("mysql_derived_merge_for_insert");
- DBUG_PRINT("enter", ("derived: %p", derived));
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ derived->get_unit()));
DBUG_PRINT("info", ("merged_for_insert: %d is_materialized_derived: %d "
"is_multitable: %d single_table_updatable: %d "
"merge_underlying_list: %d",
@@ -566,7 +571,9 @@ 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", ("derived: %p", derived));
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ derived->get_unit()));
// Skip already prepared views/DT
if (!unit || unit->prepared)
@@ -642,8 +649,9 @@ 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", ("unit: %p table_list: %p Alias '%s'",
- unit, derived, derived->alias));
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ unit));
if (!unit)
DBUG_RETURN(FALSE);
@@ -876,6 +884,9 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
bool res= FALSE;
DBUG_ENTER("mysql_derived_optimize");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ derived->get_unit()));
lex->current_select= first_select;
@@ -954,6 +965,9 @@ err:
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->get_unit()));
TABLE *table= derived->table;
SELECT_LEX_UNIT *unit= derived->get_unit();
@@ -1047,10 +1061,14 @@ bool TABLE_LIST::fill_recursive(THD *thd)
bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
{
- DBUG_ENTER("mysql_derived_fill");
+ Field_iterator_table field_iterator;
SELECT_LEX_UNIT *unit= derived->get_unit();
bool derived_is_recursive= derived->is_recursive_with_table();
bool res= FALSE;
+ DBUG_ENTER("mysql_derived_fill");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (derived->alias ? derived->alias : "<NULL>"),
+ derived->get_unit()));
if (unit->executed && !unit->uncacheable && !unit->describe &&
!derived_is_recursive)
@@ -1121,9 +1139,28 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived_result->flush())
res= TRUE;
unit->executed= TRUE;
+
+ if (derived->field_translation)
+ {
+ /* reset translation table to materialized table */
+ field_iterator.set_table(derived->table);
+ for (uint i= 0;
+ !field_iterator.end_of_fields();
+ field_iterator.next(), i= i + 1)
+ {
+ Item *item;
+
+ if (!(item= field_iterator.create_item(thd)))
+ {
+ res= TRUE;
+ break;
+ }
+ thd->change_item_tree(&derived->field_translation[i].item, item);
+ }
+ }
}
err:
- if (res || (!lex->describe && !derived_is_recursive && !unit->uncacheable))
+ if (res || (!lex->describe && !derived_is_recursive && !unit->uncacheable))
unit->cleanup();
lex->current_select= save_current_select;
@@ -1151,6 +1188,9 @@ err:
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->get_unit()));
st_select_lex_unit *unit= derived->get_unit();
derived->merged_for_insert= FALSE;
diff --git a/sql/sql_digest.cc b/sql/sql_digest.cc
index 65edcc122f1..2f88d62fbbb 100644
--- a/sql/sql_digest.cc
+++ b/sql/sql_digest.cc
@@ -20,7 +20,7 @@
#include "mariadb.h"
#include "my_md5.h"
-#include "mysqld_error.h"
+#include "unireg.h"
#include "sql_string.h"
#include "sql_class.h"
diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index fed38a5f4f4..ad80303e1b3 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -974,6 +974,7 @@ Explain_aggr_filesort::Explain_aggr_filesort(MEM_ROOT *mem_root,
for (ORDER *ord= filesort->order; ord; ord= ord->next)
{
sort_items.push_back(ord->item[0], mem_root);
+ sort_directions.push_back(&ord->direction, mem_root);
}
filesort->tracker= &tracker;
}
@@ -987,10 +988,13 @@ void Explain_aggr_filesort::print_json_members(Json_writer *writer,
str.length(0);
List_iterator_fast<Item> it(sort_items);
- Item *item;
+ List_iterator_fast<ORDER::enum_order> it_dir(sort_directions);
+ Item* item;
+ ORDER::enum_order *direction;
bool first= true;
while ((item= it++))
{
+ direction= it_dir++;
if (first)
first= false;
else
@@ -998,6 +1002,8 @@ void Explain_aggr_filesort::print_json_members(Json_writer *writer,
str.append(", ");
}
append_item_to_str(&str, item);
+ if (*direction == ORDER::ORDER_DESC)
+ str.append(" desc");
}
writer->add_member("sort_key").add_str(str.c_ptr_safe());
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 895c059f1b0..7fb50a6cb04 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -286,6 +286,7 @@ public:
class Explain_aggr_filesort : public Explain_aggr_node
{
List<Item> sort_items;
+ List<ORDER::enum_order> sort_directions;
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_FILESORT; }
Filesort_tracker tracker;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 7384831d5e3..197fe86957c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -196,8 +196,9 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
lex_start(thd);
context->init();
if ((!(table_ident= new Table_ident(thd,
+ &table->s->db,
&table->s->table_name,
- &table->s->db, TRUE))) ||
+ TRUE))) ||
(!(table_list= select_lex->add_table_to_list(thd,
table_ident,
NULL,
@@ -737,6 +738,7 @@ void LEX::start(THD *thd_arg)
spcont= NULL;
proc_list.first= 0;
escape_used= FALSE;
+ default_used= FALSE;
query_tables= 0;
reset_query_tables_list(FALSE);
expr_allows_subselect= TRUE;
@@ -2453,10 +2455,8 @@ void st_select_lex_node::move_as_slave(st_select_lex_node *new_master)
prev= &curr->next;
}
else
- {
prev= &new_master->slave;
- new_master->slave= this;
- }
+ *prev= this;
next= 0;
master= new_master;
}
@@ -3051,7 +3051,7 @@ void Query_tables_list::destroy_query_tables_list()
LEX::LEX()
: explain(NULL), result(0), arena_for_set_stmt(0), mem_root_for_set_stmt(0),
option_type(OPT_DEFAULT), context_analysis_only(0), sphead(0),
- is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX)
+ default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX)
{
init_dynamic_array2(&plugins, sizeof(plugin_ref), plugins_static_buffer,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 79c0f377a20..1465465a56c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2960,6 +2960,7 @@ public:
st_alter_tablespace *alter_tablespace_info;
bool escape_used;
+ bool default_used; /* using default() function */
bool is_lex_started; /* If lex_start() did run. For debugging. */
/*
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4c05c5cb98d..b058af531c6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1575,7 +1575,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->wsrep_conflict_state == ABORTED &&
command != COM_STMT_CLOSE && command != COM_QUIT)
{
- my_message(ER_LOCK_DEADLOCK, "wsrep aborted transaction", MYF(0));
+ my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
+ MYF(0));
WSREP_DEBUG("Deadlock error for: %s", thd->query());
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
thd->reset_killed();
@@ -7851,7 +7852,8 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
(longlong) thd->thread_id, is_autocommit,
thd->wsrep_retry_counter,
thd->variables.wsrep_retry_autocommit, thd->query());
- my_message(ER_LOCK_DEADLOCK, "wsrep aborted transaction", MYF(0));
+ my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
+ MYF(0));
thd->reset_killed();
thd->wsrep_conflict_state= NO_CONFLICT;
if (thd->wsrep_conflict_state != REPLAYING)
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 24cd5fc5123..d1da9823aa4 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4743,16 +4743,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
{
my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
}
- else if (tab_part_info->part_type == RANGE_PARTITION)
- {
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN");
- }
else
{
- DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
- my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "LIST", "IN");
+ DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION ||
+ tab_part_info->part_type == LIST_PARTITION);
+ (void) tab_part_info->error_if_requires_values();
}
goto err;
}
@@ -8368,8 +8363,11 @@ int create_partition_name(char *out, size_t outlen, const char *in1,
end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS);
else if (name_variant == TEMP_PART_NAME)
end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#TMP#", NullS);
- else if (name_variant == RENAMED_PART_NAME)
+ else
+ {
+ DBUG_ASSERT(name_variant == RENAMED_PART_NAME);
end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#REN#", NullS);
+ }
if (end - out == static_cast<ptrdiff_t>(outlen-1))
{
my_error(ER_PATH_LENGTH, MYF(0), longest_str(in1, transl_part));
@@ -8409,9 +8407,12 @@ int create_subpartition_name(char *out, size_t outlen,
else if (name_variant == TEMP_PART_NAME)
end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
"#SP#", transl_subpart_name, "#TMP#", NullS);
- else if (name_variant == RENAMED_PART_NAME)
+ else
+ {
+ DBUG_ASSERT(name_variant == RENAMED_PART_NAME);
end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
"#SP#", transl_subpart_name, "#REN#", NullS);
+ }
if (end - out == static_cast<ptrdiff_t>(outlen-1))
{
my_error(ER_PATH_LENGTH, MYF(0),
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index efddcbf3857..8168397da85 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -379,15 +379,13 @@ static bool exchange_name_with_ddl_log(THD *thd,
*/
/* call rename table from table to tmp-name */
DBUG_EXECUTE_IF("exchange_partition_fail_3",
- my_error(ER_ERROR_ON_RENAME, MYF(0),
- name, tmp_name, 0);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, 0);
error_set= TRUE;
goto err_rename;);
DBUG_EXECUTE_IF("exchange_partition_abort_3", DBUG_SUICIDE(););
if (file->ha_rename_table(name, tmp_name))
{
- my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name,
- my_errno);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, my_errno);
error_set= TRUE;
goto err_rename;
}
@@ -398,8 +396,7 @@ static bool exchange_name_with_ddl_log(THD *thd,
/* call rename table from partition to table */
DBUG_EXECUTE_IF("exchange_partition_fail_5",
- my_error(ER_ERROR_ON_RENAME, MYF(0),
- from_name, name, 0);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), from_name, name, 0);
error_set= TRUE;
goto err_rename;);
DBUG_EXECUTE_IF("exchange_partition_abort_5", DBUG_SUICIDE(););
@@ -416,8 +413,7 @@ static bool exchange_name_with_ddl_log(THD *thd,
/* call rename table from tmp-nam to partition */
DBUG_EXECUTE_IF("exchange_partition_fail_7",
- my_error(ER_ERROR_ON_RENAME, MYF(0),
- tmp_name, from_name, 0);
+ my_error(ER_ERROR_ON_RENAME, MYF(0), tmp_name, from_name, 0);
error_set= TRUE;
goto err_rename;);
DBUG_EXECUTE_IF("exchange_partition_abort_7", DBUG_SUICIDE(););
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 243d9d524c2..b31c2f36db1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2230,10 +2230,8 @@ static int mysql_test_handler_read(Prepared_statement *stmt,
if (!stmt->is_sql_prepare())
{
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send(thd)))
- {
- my_error(ER_OUTOFMEMORY, MYF(0), (int) sizeof(select_send));
DBUG_RETURN(1);
- }
+
if (send_prep_stmt(stmt, ha_table->fields.elements) ||
lex->result->send_result_set_metadata(ha_table->fields, Protocol::SEND_EOF) ||
thd->protocol->flush())
@@ -4732,7 +4730,19 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
if (error == 0 && this->lex->sql_command == SQLCOM_CALL)
{
if (is_sql_prepare())
+ {
+ /*
+ Here we have the diagnostics area status already set to DA_OK.
+ sent_out_parameters() can raise errors when assigning OUT parameters:
+ DECLARE a DATETIME;
+ EXECUTE IMMEDIATE 'CALL p1(?)' USING a;
+ when the procedure p1 assigns a DATETIME-incompatible value (e.g. 10)
+ to the out parameter. Allow to overwrite status (to DA_ERROR).
+ */
+ thd->get_stmt_da()->set_overwrite_status(true);
thd->protocol_text.send_out_parameters(&this->lex->param_list);
+ thd->get_stmt_da()->set_overwrite_status(false);
+ }
else
thd->protocol->send_out_parameters(&this->lex->param_list);
}
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index b3b041a3602..ba37d933f12 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -227,7 +227,7 @@
#define OPTIMIZER_SWITCH_EXISTS_TO_IN (1ULL << 28)
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
-#define OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED (1ULL << 31)
+#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -254,7 +254,7 @@
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
- OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED)
+ OPTIMIZER_SWITCH_SPLIT_MATERIALIZED)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
@@ -327,6 +327,8 @@
/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
#define UNDEF_POS (-1)
+#define IN_SUBQUERY_CONVERSION_THRESHOLD 1000
+
#endif /* !MYSQL_CLIENT */
/* BINLOG_DUMP options */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 1d6aa0aaab1..7db9f49f25e 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3414,7 +3414,8 @@ static bool get_string_parameter(char *to, const char *from, size_t length,
uint from_numchars= cs->cset->numchars(cs, from, from + from_length);
if (from_numchars > length / cs->mbmaxlen)
{
- my_error(ER_WRONG_STRING_LENGTH, MYF(0), from, name, (int) (length / cs->mbmaxlen));
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0), from, name,
+ (int) (length / cs->mbmaxlen));
return 1;
}
memcpy(to, from, from_length+1);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 51f577aa6b0..135e27a3a38 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -89,7 +89,6 @@ LEX_CSTRING distinct_key= {STRING_WITH_LEN("distinct_key")};
struct st_sargable_param;
-static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join, List<TABLE_LIST> &leaves,
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
@@ -97,8 +96,6 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
uint tables, COND *conds,
table_map table_map, SELECT_LEX *select_lex,
SARGABLE_PARAM **sargables);
-static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
- bool skip_unprefixed_keyparts);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
@@ -1267,6 +1264,22 @@ JOIN::prepare(TABLE_LIST *tables_init,
}
}
+ /*
+ After setting up window functions, we may have discovered additional
+ used tables from the PARTITION BY and ORDER BY list. Update all items
+ that contain window functions.
+ */
+ if (select_lex->have_window_funcs())
+ {
+ List_iterator_fast<Item> it(select_lex->item_list);
+ Item *item;
+ while ((item= it++))
+ {
+ if (item->with_window_func)
+ item->update_used_tables();
+ }
+ }
+
With_clause *with_clause=select_lex->get_with_clause();
if (with_clause && with_clause->prepare_unreferenced_elements(thd))
DBUG_RETURN(1);
@@ -1533,7 +1546,6 @@ int JOIN::optimize()
if (optimization_state != JOIN::NOT_OPTIMIZED)
return FALSE;
optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS;
- is_for_splittable_grouping_derived= false;
res= optimize_inner();
}
if (!with_two_phase_optimization ||
@@ -1605,7 +1617,7 @@ JOIN::optimize_inner()
/*
Needed in case optimizer short-cuts,
- set properly in make_tmp_tables_info()
+ set properly in make_aggr_tables_info()
*/
fields= &select_lex->item_list;
@@ -1979,9 +1991,6 @@ int JOIN::optimize_stage2()
if (subq_exit_fl)
goto setup_subq_exit;
- if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
- DBUG_RETURN(1);
-
if (thd->check_killed())
DBUG_RETURN(1);
@@ -1989,6 +1998,9 @@ int JOIN::optimize_stage2()
if (get_best_combination())
DBUG_RETURN(1);
+ if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
+ DBUG_RETURN(1);
+
if (optimizer_flag(thd, OPTIMIZER_SWITCH_DERIVED_WITH_KEYS))
drop_unused_derived_keys();
@@ -4090,7 +4102,11 @@ JOIN::destroy()
cleanup_item_list(tmp_all_fields1);
cleanup_item_list(tmp_all_fields3);
destroy_sj_tmp_tables(this);
- delete_dynamic(&keyuse);
+ delete_dynamic(&keyuse);
+ if (save_qep)
+ delete(save_qep);
+ if (ext_keyuses_for_splitting)
+ delete(ext_keyuses_for_splitting);
delete procedure;
DBUG_RETURN(error);
}
@@ -4544,6 +4560,12 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
}
+ for (s= stat; s < stat_end; s++)
+ {
+ if (s->table->is_splittable())
+ s->add_keyuses_for_splitting();
+ }
+
join->const_table_map= no_rows_const_tables;
join->const_tables= const_count;
eliminate_tables(join);
@@ -5017,9 +5039,6 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->choose_subquery_plan(all_table_map & ~join->const_table_map))
goto error;
- if (join->improve_chosen_plan(join->thd))
- goto error;
-
DEBUG_SYNC(join->thd, "inside_make_join_statistics");
DBUG_RETURN(0);
@@ -5049,23 +5068,6 @@ error:
keyuse Pointer to possible keys
*****************************************************************************/
-/// Used when finding key fields
-struct KEY_FIELD {
- Field *field;
- Item_bool_func *cond;
- Item *val; ///< May be empty if diff constant
- uint level;
- uint optimize;
- bool eq_func;
- /**
- If true, the condition this struct represents will not be satisfied
- when val IS NULL.
- */
- bool null_rejecting;
- bool *cond_guard; /* See KEYUSE::cond_guard */
- uint sj_pred_no; /* See KEYUSE::sj_pred_no */
-};
-
/**
Merge new key definitions to old ones, remove those not used in both.
@@ -5716,7 +5718,7 @@ Item_func_ne::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
/*
QQ: perhaps test for !is_local_field(args[1]) is not really needed here.
Other comparison functions, e.g. Item_func_le, Item_func_gt, etc,
- do not have this test. See Item_bool_func2::add_key_field_optimize_op().
+ do not have this test. See Item_bool_func2::add_key_fieldoptimize_op().
Check with the optimizer team.
*/
if (is_local_field(args[0]) && !is_local_field(args[1]))
@@ -5899,6 +5901,7 @@ add_keyuse(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field,
keyuse.null_rejecting= key_field->null_rejecting;
keyuse.cond_guard= key_field->cond_guard;
keyuse.sj_pred_no= key_field->sj_pred_no;
+ keyuse.validity_ref= 0;
return (insert_dynamic(keyuse_array,(uchar*) &keyuse));
}
@@ -5944,7 +5947,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
key_field->val->used_tables())
{
if (!field->can_optimize_hash_join(key_field->cond, key_field->val))
- return false;
+ return false;
+ if (form->is_splittable())
+ form->add_splitting_info_for_key_field(key_field);
/*
If a key use is extracted from an equi-join predicate then it is
added not only as a key use for every index whose component can
@@ -5958,7 +5963,6 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
return FALSE;
}
-
static bool
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
JOIN_TAB *stat,COND *cond,table_map usable_tables)
@@ -6020,6 +6024,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
keyuse.optimize= 0;
keyuse.keypart_map= 0;
keyuse.sj_pred_no= UINT_MAX;
+ keyuse.validity_ref= 0;
return insert_dynamic(keyuse_array,(uchar*) &keyuse);
}
@@ -6307,8 +6312,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
Special treatment for ft-keys.
*/
-static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
- bool skip_unprefixed_keyparts)
+bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
+ bool skip_unprefixed_keyparts)
{
KEYUSE key_end, *prev, *save_pos, *use;
uint found_eq_constant, i;
@@ -6376,7 +6381,7 @@ static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
Update some values in keyuse for faster choose_plan() loop.
*/
-static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
+void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
{
KEYUSE *end,*keyuse= dynamic_element(keyuse_array, 0, KEYUSE*);
@@ -6417,7 +6422,6 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
-
/**
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
to loose index scan.
@@ -6725,6 +6729,7 @@ best_access_path(JOIN *join,
bool best_uses_jbuf= FALSE;
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
KEYUSE *hj_start_key= 0;
+ SplM_plan_info *spl_plan= 0;
disable_jbuf= disable_jbuf || idx == join->const_tables;
@@ -6734,7 +6739,10 @@ best_access_path(JOIN *join,
bitmap_clear_all(eq_join_set);
loose_scan_opt.init(join, s, remaining_tables);
-
+
+ if (s->table->is_splittable())
+ spl_plan= s->choose_best_splitting(record_count, remaining_tables);
+
if (s->keyuse)
{ /* Use key if possible */
KEYUSE *keyuse;
@@ -6799,6 +6807,7 @@ best_access_path(JOIN *join,
2. we won't get two ref-or-null's
*/
if (!(remaining_tables & keyuse->used_tables) &&
+ (!keyuse->validity_ref || *keyuse->validity_ref) &&
s->access_from_tables_is_allowed(keyuse->used_tables,
join->sjm_lookup_tables) &&
!(ref_or_null_part && (keyuse->optimize &
@@ -7111,6 +7120,7 @@ best_access_path(JOIN *join,
tmp += s->startup_cost;
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
} /* not ft_key */
+
if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE)
{
best_time= tmp + records/(double) TIME_FOR_COMPARE;
@@ -7298,6 +7308,7 @@ best_access_path(JOIN *join,
pos->ref_depend_map= best_ref_depends_map;
pos->loosescan_picker.loosescan_key= MAX_KEY;
pos->use_join_buffer= best_uses_jbuf;
+ pos->spl_plan= spl_plan;
loose_scan_opt.save_to_position(s, loose_scan_pos);
@@ -9352,192 +9363,15 @@ JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab)
return tab;
}
-static
-bool key_can_be_used_to_split_by_fields(KEY *key_info, uint used_key_parts,
- List<Field> &fields)
-{
- if (used_key_parts < fields.elements)
- return false;
- List_iterator_fast<Field> li(fields);
- Field *fld;
- KEY_PART_INFO *start= key_info->key_part;
- KEY_PART_INFO *end= start + fields.elements;
- while ((fld= li++))
- {
- KEY_PART_INFO *key_part;
- for (key_part= start; key_part < end; key_part++)
- {
- if (key_part->fieldnr == fld->field_index + 1)
- break;
- }
- if (key_part == end)
- return false;
- }
- return true;
-}
-
-bool JOIN::check_for_splittable_grouping_derived(THD *thd)
-{
- partition_list= 0;
- st_select_lex_unit *unit= select_lex->master_unit();
- TABLE_LIST *derived= unit->derived;
- if (!optimizer_flag(thd, OPTIMIZER_SWITCH_SPLIT_GROUPING_DERIVED))
- return false;
- if (!(derived && derived->is_materialized_derived()))
- return false;
- if (unit->first_select()->next_select())
- return false;
- if (derived->prohibit_cond_pushdown)
- return false;
- if (derived->is_recursive_with_table())
- return false;
- if (group_list)
- {
- if (!select_lex->have_window_funcs())
- partition_list= group_list;
- }
- else if (select_lex->have_window_funcs() &&
- select_lex->window_specs.elements == 1)
- {
- partition_list=
- select_lex->window_specs.head()->partition_list->first;
- }
- if (!partition_list)
- return false;
-
- ORDER *ord;
- TABLE *table= 0;
- key_map ref_keys;
- uint group_fields= 0;
- ref_keys.set_all();
- for (ord= partition_list; ord; ord= ord->next, group_fields++)
- {
- Item *ord_item= *ord->item;
- if (ord_item->real_item()->type() != Item::FIELD_ITEM)
- return false;
- Field *ord_field= ((Item_field *) (ord_item->real_item()))->field;
- if (!table)
- table= ord_field->table;
- else if (table != ord_field->table)
- return false;
- ref_keys.intersect(ord_field->part_of_key);
- }
- if (ref_keys.is_clear_all())
- return false;
-
- uint i;
- List<Field> grouping_fields;
- List<Field> splitting_fields;
- List_iterator<Item> li(fields_list);
- for (ord= partition_list; ord; ord= ord->next)
- {
- Item *item;
- i= 0;
- while ((item= li++))
- {
- if ((*ord->item)->eq(item, 0))
- break;
- i++;
- }
- if (!item)
- return false;
- if (splitting_fields.push_back(derived->table->field[i], thd->mem_root))
- return false;
- Item_field *ord_field= (Item_field *)(item->real_item());
- if (grouping_fields.push_back(ord_field->field, thd->mem_root))
- return false;
- li.rewind();
- }
-
- for (i= 0; i < table->s->keys; i++)
- {
- if (!(ref_keys.is_set(i)))
- continue;
- KEY *key_info= table->key_info + i;
- if (key_can_be_used_to_split_by_fields(key_info,
- table->actual_n_key_parts(key_info),
- grouping_fields))
- break;
- }
- if (i == table->s->keys)
- return false;
-
- derived->table->splitting_fields= splitting_fields;
- is_for_splittable_grouping_derived= true;
- return true;
-}
-
bool JOIN::check_two_phase_optimization(THD *thd)
{
- if (!check_for_splittable_grouping_derived(thd))
- return false;
- return true;
+ if (check_for_splittable_materialized())
+ return true;
+ return false;
}
-Item *JOIN_TAB::get_splitting_cond_for_grouping_derived(THD *thd)
-{
- /* this is a stub */
- TABLE_LIST *derived= table->pos_in_table_list;
- st_select_lex *sel= derived->get_unit()->first_select();
- Item *cond= 0;
- table_map used_tables= OUTER_REF_TABLE_BIT;
- POSITION *pos= join->best_positions;
- for (; pos->table != this; pos++)
- {
- used_tables|= pos->table->table->map;
- }
-
- if (!pos->key)
- return 0;
-
- KEY *key_info= table->key_info + pos->key->key;
- if (!key_can_be_used_to_split_by_fields(key_info,
- key_info->user_defined_key_parts,
- table->splitting_fields))
- return 0;
-
- create_ref_for_key(join, this, pos->key,
- false, used_tables);
- List<Item> cond_list;
- KEY_PART_INFO *start= key_info->key_part;
- KEY_PART_INFO *end= start + table->splitting_fields.elements;
- List_iterator_fast<Field> li(table->splitting_fields);
- Field *fld= li++;
- for (ORDER *ord= sel->join->partition_list; ord;
- ord= ord->next, fld= li++)
- {
- Item *left_item= (*ord->item)->build_clone(thd);
- uint i= 0;
- for (KEY_PART_INFO *key_part= start; key_part < end; key_part++, i++)
- {
- if (key_part->fieldnr == fld->field_index + 1)
- break;
- }
- Item *right_item= ref.items[i]->build_clone(thd);
- Item_func_eq *eq_item= 0;
- right_item= right_item->build_clone(thd);
- if (left_item && right_item)
- {
- right_item->walk(&Item::set_fields_as_dependent_processor,
- false, join->select_lex);
- right_item->update_used_tables();
- eq_item= new (thd->mem_root) Item_func_eq(thd, left_item, right_item);
- }
- if (!eq_item || cond_list.push_back(eq_item, thd->mem_root))
- return 0;
- }
- switch (cond_list.elements) {
- case 0: break;
- case 1: cond= cond_list.head(); break;
- default: cond= new (thd->mem_root) Item_cond_and(thd, cond_list);
- }
- if (cond)
- cond->fix_fields(thd,0);
- return cond;
-}
-
bool JOIN::inject_cond_into_where(Item *injected_cond)
{
Item *where_item= injected_cond;
@@ -9572,48 +9406,6 @@ bool JOIN::inject_cond_into_where(Item *injected_cond)
}
-bool JOIN::push_splitting_cond_into_derived(THD *thd, Item *cond)
-{
- enum_reopt_result reopt_result= REOPT_NONE;
- table_map all_table_map= 0;
- for (JOIN_TAB *tab= join_tab;
- tab < join_tab + top_join_tab_count; tab++)
- all_table_map|= tab->table->map;
- reopt_result= reoptimize(cond, all_table_map & ~const_table_map, NULL);
- if (reopt_result == REOPT_ERROR)
- return true;
- if (inject_cond_into_where(cond))
- return true;
- if (cond->used_tables() & OUTER_REF_TABLE_BIT)
- {
- select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
- st_select_lex_unit *unit= select_lex->master_unit();
- unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED;
- }
- return false;
-}
-
-bool JOIN::improve_chosen_plan(THD *thd)
-{
- for (JOIN_TAB *tab= join_tab + const_tables;
- tab < join_tab + table_count; tab++)
- {
- TABLE_LIST *tbl= tab->table->pos_in_table_list;
- if (tbl->is_materialized_derived())
- {
- st_select_lex *sel= tbl->get_unit()->first_select();
- JOIN *derived_join= sel->join;
- if (derived_join && derived_join->is_for_splittable_grouping_derived)
- {
- Item *cond= tab->get_splitting_cond_for_grouping_derived(thd);
- if (cond && derived_join->push_splitting_cond_into_derived(thd, cond))
- return true;
- }
- }
- }
- return false;
-}
-
static Item * const null_ptr= NULL;
@@ -9682,6 +9474,9 @@ bool JOIN::get_best_combination()
full_join=0;
hash_join= FALSE;
+ if (fix_all_splittings_in_plan())
+ DBUG_RETURN(TRUE);
+
fix_semijoin_strategies_for_picked_join_order(this);
JOIN_TAB_RANGE *root_range;
@@ -10022,6 +9817,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
do
{
if (!(~used_tables & keyuse->used_tables) &&
+ (!keyuse->validity_ref || *keyuse->validity_ref) &&
j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
{
if (are_tables_local(j, keyuse->val->used_tables()))
@@ -10092,6 +9888,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
+ (keyuse->validity_ref && !(*keyuse->validity_ref)) ||
!j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
@@ -18092,7 +17889,6 @@ err:
}
-
/****************************************************************************/
void *Virtual_tmp_table::operator new(size_t size, THD *thd) throw()
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 662047c02e3..fbadca2255d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -73,9 +73,45 @@ typedef struct keyuse_t {
*/
uint sj_pred_no;
+ /*
+ If this is NULL than KEYUSE is always enabled.
+ Otherwise it points to the enabling flag for this keyuse (true <=> enabled)
+ */
+ bool *validity_ref;
+
bool is_for_hash_join() { return is_hash_join_key_no(key); }
} KEYUSE;
+
+struct KEYUSE_EXT: public KEYUSE
+{
+ /*
+ This keyuse can be used only when the partial join being extended
+ contains the tables from this table map
+ */
+ table_map needed_in_prefix;
+ /* The enabling flag for keyuses usable for splitting */
+ bool validity_var;
+};
+
+/// Used when finding key fields
+struct KEY_FIELD {
+ Field *field;
+ Item_bool_func *cond;
+ Item *val; ///< May be empty if diff constant
+ uint level;
+ uint optimize;
+ bool eq_func;
+ /**
+ If true, the condition this struct represents will not be satisfied
+ when val IS NULL.
+ */
+ bool null_rejecting;
+ bool *cond_guard; /* See KEYUSE::cond_guard */
+ uint sj_pred_no; /* See KEYUSE::sj_pred_no */
+};
+
+
#define NO_KEYPART ((uint)(-1))
class store_key;
@@ -201,6 +237,8 @@ class SJ_TMP_TABLE;
class JOIN_TAB_RANGE;
class AGGR_OP;
class Filesort;
+struct SplM_plan_info;
+class SplM_opt_info;
typedef struct st_join_table {
st_join_table() {}
@@ -438,7 +476,7 @@ typedef struct st_join_table {
will be turned to fields. These variables are pointing to
tmp_fields_list[123]. Valid only for tmp tables and the last non-tmp
table in the query plan.
- @see JOIN::make_tmp_tables_info()
+ @see JOIN::make_aggr_tables_info()
*/
List<Item> *fields;
/** List of all expressions in the select list */
@@ -614,8 +652,10 @@ typedef struct st_join_table {
bool use_order() const; ///< Use ordering provided by chosen index?
bool sort_table();
bool remove_duplicates();
- Item *get_splitting_cond_for_grouping_derived(THD *thd);
-
+ void add_keyuses_for_splitting();
+ SplM_plan_info *choose_best_splitting(double record_count,
+ table_map remaining_tables);
+ bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables);
} JOIN_TAB;
@@ -920,6 +960,9 @@ typedef struct st_position
Firstmatch_picker firstmatch_picker;
LooseScan_picker loosescan_picker;
Sj_materialization_picker sjmat_picker;
+
+ /* Info on splitting plan used at this position */
+ SplM_plan_info *spl_plan;
} POSITION;
typedef Bounds_checked_array<Item_null_result*> Item_null_array;
@@ -1053,11 +1096,13 @@ protected:
/* Support for plan reoptimization with rewritten conditions. */
enum_reopt_result reoptimize(Item *added_where, table_map join_tables,
Join_plan_state *save_to);
+ /* Choose a subquery plan for a table-less subquery. */
+ bool choose_tableless_subquery_plan();
+
+public:
void save_query_plan(Join_plan_state *save_to);
void reset_query_plan();
void restore_query_plan(Join_plan_state *restore_from);
- /* Choose a subquery plan for a table-less subquery. */
- bool choose_tableless_subquery_plan();
public:
JOIN_TAB *join_tab, **best_ref;
@@ -1415,9 +1460,14 @@ public:
*/
bool implicit_grouping;
- bool is_for_splittable_grouping_derived;
bool with_two_phase_optimization;
- ORDER *partition_list;
+
+ /* Saved execution plan for this join */
+ Join_plan_state *save_qep;
+ /* Info on splittability of the table materialized by this plan*/
+ SplM_opt_info *spl_opt_info;
+ /* Contains info on keyuses usable for splitting */
+ Dynamic_array<KEYUSE_EXT> *ext_keyuses_for_splitting;
JOIN_TAB *sort_and_group_aggr_tab;
@@ -1465,7 +1515,10 @@ public:
need_distinct= 0;
skip_sort_order= 0;
with_two_phase_optimization= 0;
- is_for_splittable_grouping_derived= 0;
+ save_qep= 0;
+ spl_opt_info= 0;
+ ext_keyuses_for_splitting= 0;
+ spl_opt_info= 0;
need_tmp= 0;
hidden_group_fields= 0; /*safety*/
error= 0;
@@ -1674,10 +1727,12 @@ public:
const char *message);
JOIN_TAB *first_breadth_first_tab() { return join_tab; }
bool check_two_phase_optimization(THD *thd);
- bool check_for_splittable_grouping_derived(THD *thd);
bool inject_cond_into_where(Item *injected_cond);
- bool push_splitting_cond_into_derived(THD *thd, Item *cond);
- bool improve_chosen_plan(THD *thd);
+ bool check_for_splittable_materialized();
+ void add_keyuses_for_splitting();
+ bool inject_best_splitting_cond(table_map remaining_tables);
+ bool fix_all_splittings_in_plan();
+
bool transform_in_predicates_into_in_subq(THD *thd);
private:
/**
@@ -2300,6 +2355,11 @@ bool open_tmp_table(TABLE *table);
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps);
double prev_record_reads(POSITION *positions, uint idx, table_map found_ref);
void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist);
+double get_tmp_table_lookup_cost(THD *thd, double row_count, uint row_size);
+double get_tmp_table_write_cost(THD *thd, double row_count, uint row_size);
+void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
+bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
+ bool skip_unprefixed_keyparts);
struct st_cond_statistic
{
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 70ddf7b1241..d0d0e35000d 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -606,7 +606,7 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
return TRUE;
if (my_b_read(file, (uchar*) Ptr + str_length, arg_length))
{
- shrink(str_length);
+ shrink(str_length ? str_length : 1);
return TRUE;
}
str_length+=arg_length;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 50b551a904f..58e29ad9b18 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4993,7 +4993,8 @@ int create_table_impl(THD *thd,
if (!frm_only && create_info->tmp_table())
{
TABLE *table= thd->create_and_open_tmp_table(create_info->db_type, frm,
- path, db, table_name, true);
+ path, db, table_name, true,
+ false);
if (!table)
{
@@ -5089,7 +5090,8 @@ int mysql_create_table_no_lock(THD *thd,
// Check if we hit FN_REFLEN bytes along with file extension.
if (length+reg_ext_length > FN_REFLEN)
{
- my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(path)-1, path);
+ my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(path)-1,
+ path);
return true;
}
}
@@ -5228,7 +5230,7 @@ err:
/* Write log if no error or if we already deleted a table */
if (!result || thd->log_current_statement)
{
- if (result && create_info->table_was_deleted)
+ if (result && create_info->table_was_deleted && pos_in_locked_tables)
{
/*
Possible locked table was dropped. We should remove meta data locks
@@ -9582,7 +9584,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
thd->create_and_open_tmp_table(new_db_type, &frm,
alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
- false)))
+ false, true)))
goto err_new_table_cleanup;
/* Set markers for fields in TABLE object for altered table. */
@@ -9597,10 +9599,12 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
&altered_table->s->all_set);
restore_record(altered_table, s->default_values); // Create empty record
/* Check that we can call default functions with default field values */
+ thd->count_cuted_fields= CHECK_FIELD_EXPRESSION;
altered_table->reset_default_fields();
if (altered_table->default_field &&
altered_table->update_default_fields(0, 1))
goto err_new_table_cleanup;
+ thd->count_cuted_fields= CHECK_FIELD_IGNORE;
// Ask storage engine whether to use copy or in-place
enum_alter_inplace_result inplace_supported=
@@ -9725,7 +9729,8 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
}
// It's now safe to take the table level lock.
- if (lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
+ if (lock_tables(thd, table_list, alter_ctx.tables_opened,
+ MYSQL_LOCK_USE_MALLOC))
goto err_new_table_cleanup;
if (ha_create_table(thd, alter_ctx.get_tmp_path(),
@@ -9742,7 +9747,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
thd->create_and_open_tmp_table(new_db_type, &frm,
alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
- true);
+ true, true);
if (!tmp_table)
{
goto err_new_table_cleanup;
@@ -9776,7 +9781,7 @@ bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name,
thd->create_and_open_tmp_table(new_db_type, &frm,
alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
- true);
+ true, true);
}
if (!new_table)
goto err_new_table_cleanup;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 53bc05e7c47..8a1cc1ada7a 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1603,7 +1603,7 @@ err_with_lex_cleanup:
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
thd->reset_db(save_db.str, save_db.length);
- /* Fall trough to error */
+ /* Fall through to error */
}
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index b3a7227678d..82745b61929 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -68,14 +68,14 @@ void select_unit::change_select()
curr_sel= current_select_number;
/* New SELECT processing starts */
DBUG_ASSERT(table->file->inited == 0);
- switch (thd->lex->current_select->linkage)
+ step= thd->lex->current_select->linkage;
+ switch (step)
{
case INTERSECT_TYPE:
intersect_mark->value= prev_step= curr_step;
curr_step= current_select_number;
- /* fall through */
+ break;
case EXCEPT_TYPE:
- step= thd->lex->current_select->linkage;
break;
default:
step= UNION_TYPE;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 50ea5581cc9..c36c1fa2a93 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -651,7 +651,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (!res && mysql_bin_log.is_open())
{
- String buff;
+ StringBuffer<128> buff(thd->variables.character_set_client);
+ DBUG_ASSERT(buff.charset()->mbminlen == 1);
const LEX_STRING command[3]=
{{ C_STRING_WITH_LEN("CREATE ") },
{ C_STRING_WITH_LEN("ALTER ") },
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index bf393ab1c4d..db34b77ddcb 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -315,14 +315,7 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
}
List_iterator_fast<Item_window_func> li(win_funcs);
- Item_window_func *win_func_item;
- while ((win_func_item= li++))
- {
- win_func_item->update_used_tables();
- }
-
- li.rewind();
- while ((win_func_item= li++))
+ while (Item_window_func * win_func_item= li++)
{
if (win_func_item->check_result_type_of_order_item())
DBUG_RETURN(1);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 64b6ca6dd54..5dd5493203e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5424,12 +5424,8 @@ opt_part_values:
partition_info *part_info= lex->part_info;
if (! lex->is_partition_management())
{
- if (part_info->part_type == RANGE_PARTITION)
- my_yyabort_error((ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "RANGE", "LESS THAN"));
- if (part_info->part_type == LIST_PARTITION)
- my_yyabort_error((ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
- "LIST", "IN"));
+ if (part_info->error_if_requires_values())
+ MYSQL_YYABORT;
if (part_info->part_type == VERSIONING_PARTITION)
my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0),
lex->create_last_non_select_table->table_name));
@@ -9975,6 +9971,7 @@ column_default_non_parenthesized_expr:
$3);
if ($$ == NULL)
MYSQL_YYABORT;
+ Lex->default_used= TRUE;
}
| VALUE_SYM '(' simple_ident_nospvar ')'
{
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 61002142014..e96e8bdcb9a 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -9509,6 +9509,7 @@ column_default_non_parenthesized_expr:
$3);
if ($$ == NULL)
MYSQL_YYABORT;
+ Lex->default_used= TRUE;
}
| VALUE_SYM '(' simple_ident_nospvar ')'
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 43a016a524a..3b37fac5c39 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2512,7 +2512,7 @@ export const char *optimizer_switch_names[]=
"exists_to_in",
"orderby_uses_equalities",
"condition_pushdown_for_derived",
- "split_grouping_derived",
+ "split_materialized",
"default",
NullS
};
@@ -6053,10 +6053,11 @@ static Sys_var_mybool Sys_session_track_state_change(
#endif //EMBEDDED_LIBRARY
-static Sys_var_ulong Sys_in_subquery_conversion_threshold(
- "in_subquery_conversion_threshold",
+#ifndef DBUG_OFF
+static Sys_var_uint Sys_in_subquery_conversion_threshold(
+ "in_predicate_conversion_threshold",
"The minimum number of scalar elements in the value list of "
"IN predicate that triggers its conversion to IN subquery",
SESSION_VAR(in_subquery_conversion_threshold), CMD_LINE(OPT_ARG),
- VALID_RANGE(0, ULONG_MAX), DEFAULT(1000), BLOCK_SIZE(1));
-
+ VALID_RANGE(0, UINT_MAX), DEFAULT(IN_SUBQUERY_CONVERSION_THRESHOLD), BLOCK_SIZE(1));
+#endif
diff --git a/sql/table.cc b/sql/table.cc
index 052b3e2fe01..d7e7e3f0a89 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -997,7 +997,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
Virtual_column_info **check_constraint_ptr= table->check_constraints;
sql_mode_t saved_mode= thd->variables.sql_mode;
Query_arena backup_arena;
- Virtual_column_info *vcol;
+ Virtual_column_info *vcol= 0;
StringBuffer<MAX_FIELD_WIDTH> expr_str;
bool res= 1;
DBUG_ENTER("parse_vcol_defs");
@@ -1168,7 +1168,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint new_frm_ver, field_pack_length, new_field_pack_flag;
uint interval_count, interval_parts, read_length, int_length;
uint db_create_options, keys, key_parts, n_length;
- uint com_length, null_bit_pos, mysql57_vcol_null_bit_pos, bitmap_count;
+ uint com_length, null_bit_pos, UNINIT_VAR(mysql57_vcol_null_bit_pos), bitmap_count;
uint i;
bool use_hash, mysql57_null_bits= 0;
char *keynames, *names, *comment_pos;
@@ -2214,6 +2214,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
}
+ key_first_info= keyinfo;
for (uint key=0 ; key < keys ; key++,keyinfo++)
{
uint usable_parts= 0;
@@ -2231,9 +2232,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
keyinfo->name.length+1);
}
- if (!key)
- key_first_info= keyinfo;
-
if (ext_key_parts > share->key_parts && key)
{
KEY_PART_INFO *new_key_part= (keyinfo-1)->key_part +
@@ -3054,6 +3052,14 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table,
if (error)
goto end;
+ if (lex.current_select->table_list.first[0].next_global)
+ {
+ /* We are using NEXT VALUE FOR sequence. Remember table name for open */
+ TABLE_LIST *sequence= lex.current_select->table_list.first[0].next_global;
+ sequence->next_global= table->internal_tables;
+ table->internal_tables= sequence;
+ }
+
vcol_storage.vcol_info->set_vcol_type(vcol->get_vcol_type());
vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db;
vcol_storage.vcol_info->name= vcol->name;
@@ -4751,6 +4757,9 @@ bool TABLE_LIST::create_field_translation(THD *thd)
Query_arena *arena, backup;
bool res= FALSE;
DBUG_ENTER("TABLE_LIST::create_field_translation");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (alias ? alias : "<NULL>"),
+ get_unit()));
if (thd->stmt_arena->is_conventional() ||
thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
@@ -6985,6 +6994,14 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info,
might be reused.
*/
key_part_info->store_length= key_part_info->length;
+ /*
+ For BIT fields null_bit is not set to 0 even if the field is defined
+ as NOT NULL, look at Field_bit::Field_bit
+ */
+ if (!field->real_maybe_null())
+ {
+ key_part_info->null_bit= 0;
+ }
/*
The total store length of the key part is the raw length of the field +
@@ -7624,7 +7641,6 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
swap_values= 1;
break;
case VCOL_UPDATE_FOR_DELETE:
- /* Fall trough */
case VCOL_UPDATE_FOR_WRITE:
update= bitmap_is_set(vcol_set, vf->field_index);
break;
diff --git a/sql/table.h b/sql/table.h
index 53391559de3..6899b65eb57 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1104,6 +1104,8 @@ struct st_cond_statistic;
/* Bitmap of table's fields */
typedef Bitmap<MAX_FIELDS> Field_map;
+class SplM_opt_info;
+
struct TABLE
{
TABLE() {} /* Remove gcc warning */
@@ -1168,6 +1170,8 @@ public:
TABLE_LIST *pos_in_table_list;/* Element referring to this table */
/* Position in thd->locked_table_list under LOCK TABLES */
TABLE_LIST *pos_in_locked_tables;
+ /* Tables used in DEFAULT and CHECK CONSTRAINT (normally sequence tables) */
+ TABLE_LIST *internal_tables;
/*
Not-null for temporary tables only. Non-null values means this table is
@@ -1381,7 +1385,13 @@ public:
bool stats_is_read; /* Persistent statistics is read for the table */
bool histograms_are_read;
MDL_ticket *mdl_ticket;
- List<Field> splitting_fields;
+
+ /*
+ This is used only for potentially splittable materialized tables and it
+ points to the info used by the optimizer to apply splitting optimization
+ */
+ SplM_opt_info *spl_opt_info;
+ key_map keys_usable_for_splitting;
void init(THD *thd, TABLE_LIST *tl);
bool fill_item_list(List<Item> *item_list) const;
@@ -1526,6 +1536,10 @@ public:
bool with_cleanup);
Field *find_field_by_name(LEX_CSTRING *str) const;
bool export_structure(THD *thd, class Row_definition_list *defs);
+ bool is_splittable() { return spl_opt_info != NULL; }
+ void set_spl_opt_info(SplM_opt_info *spl_info);
+ void deny_splitting();
+ void add_splitting_info_for_key_field(struct KEY_FIELD *key_field);
/**
System Versioning support
@@ -1914,6 +1928,11 @@ struct TABLE_LIST
{
TABLE_LIST() {} /* Remove gcc warning */
+ enum prelocking_types
+ {
+ PRELOCK_NONE, PRELOCK_ROUTINE, PRELOCK_FK
+ };
+
/**
Prepare TABLE_LIST that consists of one table instance to use in
open_and_lock_tables
@@ -1954,7 +1973,7 @@ struct TABLE_LIST
size_t table_name_length_arg,
const char *alias_arg,
enum thr_lock_type lock_type_arg,
- bool routine,
+ prelocking_types prelocking_type,
TABLE_LIST *belong_to_view_arg,
uint8 trg_event_map_arg,
TABLE_LIST ***last_ptr)
@@ -1962,8 +1981,10 @@ struct TABLE_LIST
init_one_table(db_name_arg, db_length_arg, table_name_arg,
table_name_length_arg, alias_arg, lock_type_arg);
cacheable_table= 1;
- prelocking_placeholder= routine ? ROUTINE : FK;
- open_type= routine ? OT_TEMPORARY_OR_BASE : OT_BASE_ONLY;
+ prelocking_placeholder= prelocking_type;
+ open_type= (prelocking_type == PRELOCK_ROUTINE ?
+ OT_TEMPORARY_OR_BASE :
+ OT_BASE_ONLY);
belong_to_view= belong_to_view_arg;
trg_event_map= trg_event_map_arg;
@@ -2252,7 +2273,7 @@ struct TABLE_LIST
This TABLE_LIST object is just placeholder for prelocking, it will be
used for implicit LOCK TABLES only and won't be used in real statement.
*/
- enum { USER, ROUTINE, FK } prelocking_placeholder;
+ prelocking_types prelocking_placeholder;
/**
Indicates that if TABLE_LIST object corresponds to the table/view
which requires special handling.
@@ -2507,6 +2528,9 @@ struct TABLE_LIST
inline void set_merged_derived()
{
DBUG_ENTER("set_merged_derived");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (alias ? alias : "<NULL>"),
+ get_unit()));
derived_type= ((derived_type & DTYPE_MASK) |
DTYPE_TABLE | DTYPE_MERGE);
set_check_merged();
@@ -2519,6 +2543,9 @@ struct TABLE_LIST
void set_materialized_derived()
{
DBUG_ENTER("set_materialized_derived");
+ DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
+ (alias ? alias : "<NULL>"),
+ get_unit()));
derived_type= ((derived_type & (derived ? DTYPE_MASK : DTYPE_VIEW)) |
DTYPE_TABLE | DTYPE_MATERIALIZE);
set_check_materialized();
diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc
index 2c3cd0fe24e..a5088a012ae 100644
--- a/sql/temporary_tables.cc
+++ b/sql/temporary_tables.cc
@@ -65,7 +65,8 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton,
const char *path,
const char *db,
const char *table_name,
- bool open_in_engine)
+ bool open_in_engine,
+ bool open_internal_tables)
{
DBUG_ENTER("THD::create_and_open_tmp_table");
@@ -90,6 +91,15 @@ TABLE *THD::create_and_open_tmp_table(handlerton *hton,
/* Free the TMP_TABLE_SHARE. */
free_tmp_table_share(share, false);
+ DBUG_RETURN(0);
+ }
+
+ /* Open any related tables */
+ if (open_internal_tables && table->internal_tables &&
+ open_and_lock_internal_tables(table, open_in_engine))
+ {
+ drop_temporary_table(table, NULL, false);
+ DBUG_RETURN(0);
}
}
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index da92aa9bedb..54313281625 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1264,6 +1264,16 @@ int wsrep_to_buf_helper(
if (!ret && writer.write(&gtid_ev)) ret= 1;
}
#endif /* GTID_SUPPORT */
+ if (wsrep_gtid_mode && thd->variables.gtid_seq_no)
+ {
+ Gtid_log_event gtid_event(thd, thd->variables.gtid_seq_no,
+ thd->variables.gtid_domain_id,
+ true, LOG_EVENT_SUPPRESS_USE_F,
+ true, 0);
+ gtid_event.server_id= thd->variables.server_id;
+ if (!gtid_event.is_valid()) ret= 0;
+ ret= writer.write(&gtid_event);
+ }
/* if there is prepare query, add event for it */
if (!ret && thd->wsrep_TOI_pre_query)