summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc2
-rw-r--r--sql/event_db_repository.cc7
-rwxr-xr-x[-rw-r--r--]sql/event_scheduler.cc3
-rw-r--r--sql/events.cc43
-rw-r--r--sql/field.cc3
-rw-r--r--sql/field.h7
-rw-r--r--sql/filesort.cc2
-rw-r--r--sql/ha_partition.cc207
-rw-r--r--sql/ha_partition.h12
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h33
-rw-r--r--sql/item_cmpfunc.cc48
-rw-r--r--sql/item_cmpfunc.h4
-rw-r--r--sql/item_create.cc10
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_func.h28
-rw-r--r--sql/item_strfunc.cc106
-rw-r--r--sql/item_strfunc.h13
-rw-r--r--sql/item_timefunc.cc6
-rw-r--r--sql/item_timefunc.h10
-rw-r--r--sql/log.cc498
-rw-r--r--sql/log.h26
-rw-r--r--sql/log_event.cc68
-rw-r--r--sql/log_event.h19
-rw-r--r--sql/log_event_old.cc15
-rw-r--r--sql/mysql_priv.h24
-rw-r--r--sql/mysqld.cc84
-rw-r--r--sql/rpl_injector.cc41
-rw-r--r--sql/rpl_record.cc16
-rw-r--r--sql/rpl_rli.cc12
-rw-r--r--sql/rpl_rli.h2
-rw-r--r--sql/rpl_utility.h1
-rw-r--r--sql/set_var.cc15
-rw-r--r--sql/share/errmsg.txt12
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp.cc28
-rw-r--r--sql/sp_head.cc12
-rw-r--r--sql/sp_pcontext.h2
-rw-r--r--sql/sql_acl.cc112
-rw-r--r--sql/sql_base.cc21
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_connect.cc2
-rw-r--r--sql/sql_crypt.cc9
-rw-r--r--sql/sql_crypt.h8
-rw-r--r--sql/sql_db.cc51
-rw-r--r--sql/sql_delete.cc12
-rw-r--r--sql/sql_insert.cc62
-rw-r--r--sql/sql_load.cc38
-rw-r--r--sql/sql_parse.cc85
-rw-r--r--sql/sql_partition.cc99
-rw-r--r--sql/sql_partition.h3
-rw-r--r--sql/sql_plugin.cc2
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_rename.cc9
-rw-r--r--sql/sql_repl.cc22
-rw-r--r--sql/sql_select.cc65
-rw-r--r--sql/sql_select.h12
-rw-r--r--sql/sql_servers.cc10
-rw-r--r--sql/sql_show.cc17
-rw-r--r--sql/sql_table.cc87
-rw-r--r--sql/sql_tablespace.cc4
-rw-r--r--sql/sql_test.cc24
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_udf.cc34
-rw-r--r--sql/sql_union.cc31
-rw-r--r--sql/sql_update.cc15
-rw-r--r--sql/sql_view.cc14
-rw-r--r--sql/sql_yacc.yy201
-rw-r--r--sql/table.cc5
69 files changed, 1764 insertions, 728 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 92427c0ba41..cdd1d0abff3 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -1400,7 +1400,7 @@ Event_job_data::execute(THD *thd, bool drop)
#endif
if (check_access(thd, EVENT_ACL, dbname.str,
- 0, 0, 0, is_schema_db(dbname.str)))
+ 0, 0, 0, is_schema_db(dbname.str, dbname.length)))
{
/*
This aspect of behavior is defined in the worklog,
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 9f3863eb2b0..753e9d21b65 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -1045,6 +1045,7 @@ update_timing_fields_for_event(THD *thd,
TABLE *table= NULL;
Field **fields;
int ret= 1;
+ bool save_binlog_row_based;
DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
@@ -1052,8 +1053,8 @@ update_timing_fields_for_event(THD *thd,
Turn off row binlogging of event timing updates. These are not used
for RBR of events replicated to the slave.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
@@ -1095,6 +1096,8 @@ update_timing_fields_for_event(THD *thd,
end:
if (table)
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(test(ret));
}
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 06b7bd3fc6a..8446fe75c8f 100644..100755
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -235,8 +235,9 @@ event_scheduler_thread(void *arg)
if (!res)
scheduler->run(thd);
+ DBUG_LEAVE; // Against gcc warnings
my_thread_end();
- DBUG_RETURN(0); // Against gcc warnings
+ return 0;
}
diff --git a/sql/events.cc b/sql/events.cc
index 49c7adbaa8e..d167a3dd4e9 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -388,6 +388,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
bool if_not_exists)
{
int ret;
+ bool save_binlog_row_based;
DBUG_ENTER("Events::create_event");
/*
@@ -414,7 +415,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
- is_schema_db(parse_data->dbname.str)))
+ is_schema_db(parse_data->dbname.str,
+ parse_data->dbname.length)))
DBUG_RETURN(TRUE);
if (check_db_dir_existence(parse_data->dbname.str))
@@ -429,8 +431,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for CREATE EVENT command.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
pthread_mutex_lock(&LOCK_event_metadata);
@@ -470,14 +472,18 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
{
sql_print_error("Event Error: An error occurred while creating query string, "
"before writing it into binary log.");
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(TRUE);
}
/* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
will be written into the binary log as the definer for the SQL thread. */
- write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
+ ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -507,6 +513,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
LEX_STRING *new_dbname, LEX_STRING *new_name)
{
int ret;
+ bool save_binlog_row_based;
Event_queue_element *new_element;
DBUG_ENTER("Events::update_event");
@@ -525,7 +532,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
DBUG_RETURN(TRUE);
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
- is_schema_db(parse_data->dbname.str)))
+ is_schema_db(parse_data->dbname.str,
+ parse_data->dbname.length)))
DBUG_RETURN(TRUE);
if (new_dbname) /* It's a rename */
@@ -547,7 +555,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
access it.
*/
if (check_access(thd, EVENT_ACL, new_dbname->str, 0, 0, 0,
- is_schema_db(new_dbname->str)))
+ is_schema_db(new_dbname->str, new_dbname->length)))
DBUG_RETURN(TRUE);
/* Check that the target database exists */
@@ -562,8 +570,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for UPDATE EVENT command.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
pthread_mutex_lock(&LOCK_event_metadata);
@@ -595,10 +603,12 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
new_element);
/* Binlog the alter event. */
DBUG_ASSERT(thd->query() && thd->query_length());
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -632,6 +642,7 @@ bool
Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
{
int ret;
+ bool save_binlog_row_based;
DBUG_ENTER("Events::drop_event");
/*
@@ -652,15 +663,15 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
DBUG_RETURN(TRUE);
if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
- is_schema_db(dbname.str)))
+ is_schema_db(dbname.str, dbname.length)))
DBUG_RETURN(TRUE);
/*
Turn off row binlogging of this statement and use statement-based so
that all supporting tables are updated for DROP EVENT command.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
@@ -670,9 +681,11 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
event_queue->drop_event(thd, dbname, name);
/* Binlog the drop event. */
DBUG_ASSERT(thd->query() && thd->query_length());
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
pthread_mutex_unlock(&LOCK_event_metadata);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -809,7 +822,7 @@ Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
DBUG_RETURN(TRUE);
if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
- is_schema_db(dbname.str)))
+ is_schema_db(dbname.str, dbname.length)))
DBUG_RETURN(TRUE);
/*
@@ -867,7 +880,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
DBUG_ASSERT(thd->lex->select_lex.db);
- if (!is_schema_db(thd->lex->select_lex.db) && // There is no events in I_S
+ if (!is_schema_db(thd->lex->select_lex.db) && // There is no events in I_S
check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, 0))
DBUG_RETURN(1);
db= thd->lex->select_lex.db;
diff --git a/sql/field.cc b/sql/field.cc
index 44ca3d8b078..ac095b07117 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -8287,8 +8287,7 @@ uint Field_blob::is_equal(Create_field *new_field)
return ((new_field->sql_type == get_blob_type_from_length(max_data_length()))
&& new_field->charset == field_charset &&
- ((Field_blob *)new_field->field)->max_data_length() ==
- max_data_length());
+ new_field->pack_length == pack_length());
}
diff --git a/sql/field.h b/sql/field.h
index 8f3d3bbb059..04d534114e6 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1926,7 +1926,12 @@ public:
uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
Item_result result_type () const { return INT_RESULT; }
- int reset(void) { bzero(ptr, bytes_in_rec); return 0; }
+ int reset(void) {
+ bzero(ptr, bytes_in_rec);
+ if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits
+ clr_rec_bits(bit_ptr, bit_ofs, bit_len);
+ return 0;
+ }
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 552ea27970f..76777d78085 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -142,6 +142,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
error= 1;
bzero((char*) &param,sizeof(param));
param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset);
+ /* filesort cannot handle zero-length records. */
+ DBUG_ASSERT(param.sort_length);
param.ref_length= table->file->ref_length;
param.addon_field= 0;
param.addon_length= 0;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index c8361888146..22b01fe38fa 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1215,17 +1215,28 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
partition_element *p_elem)
{
int error;
- bool create_flag= FALSE;
DBUG_ENTER("prepare_new_partition");
if ((error= set_up_table_before_create(tbl, part_name, create_info,
0, p_elem)))
- goto error;
+ goto error_create;
if ((error= file->ha_create(part_name, tbl, create_info)))
- goto error;
- create_flag= TRUE;
+ {
+ /*
+ Added for safety, InnoDB reports HA_ERR_FOUND_DUPP_KEY
+ if the table/partition already exists.
+ If we return that error code, then print_error would try to
+ get_dup_key on a non-existing partition.
+ So return a more reasonable error code.
+ */
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ error= HA_ERR_TABLE_EXIST;
+ goto error_create;
+ }
+ DBUG_PRINT("info", ("partition %s created", part_name));
if ((error= file->ha_open(tbl, part_name, m_mode, m_open_test_lock)))
- goto error;
+ goto error_open;
+ DBUG_PRINT("info", ("partition %s opened", part_name));
/*
Note: if you plan to add another call that may return failure,
better to do it before external_lock() as cleanup_new_partition()
@@ -1233,12 +1244,15 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
Otherwise see description for cleanup_new_partition().
*/
if ((error= file->ha_external_lock(ha_thd(), m_lock_type)))
- goto error;
+ goto error_external_lock;
+ DBUG_PRINT("info", ("partition %s external locked", part_name));
DBUG_RETURN(0);
-error:
- if (create_flag)
- VOID(file->ha_delete_table(part_name));
+error_external_lock:
+ VOID(file->close());
+error_open:
+ VOID(file->ha_delete_table(part_name));
+error_create:
DBUG_RETURN(error);
}
@@ -1272,19 +1286,23 @@ error:
void ha_partition::cleanup_new_partition(uint part_count)
{
- handler **save_m_file= m_file;
DBUG_ENTER("ha_partition::cleanup_new_partition");
- if (m_added_file && m_added_file[0])
+ if (m_added_file)
{
- m_file= m_added_file;
- m_added_file= NULL;
+ THD *thd= ha_thd();
+ handler **file= m_added_file;
+ while ((part_count > 0) && (*file))
+ {
+ (*file)->ha_external_lock(thd, F_UNLCK);
+ (*file)->close();
- external_lock(ha_thd(), F_UNLCK);
- /* delete_table also needed, a bit more complex */
- close();
+ /* Leave the (*file)->ha_delete_table(part_name) to the ddl-log */
- m_file= save_m_file;
+ file++;
+ part_count--;
+ }
+ m_added_file= NULL;
}
DBUG_VOID_RETURN;
}
@@ -1590,7 +1608,15 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
part_elem->part_state= PART_TO_BE_DROPPED;
}
m_new_file= new_file_array;
- DBUG_RETURN(copy_partitions(copied, deleted));
+ if ((error= copy_partitions(copied, deleted)))
+ {
+ /*
+ Close and unlock the new temporary partitions.
+ They will later be deleted through the ddl-log.
+ */
+ cleanup_new_partition(part_count);
+ }
+ DBUG_RETURN(error);
}
@@ -1679,6 +1705,7 @@ int ha_partition::copy_partitions(ulonglong * const copied,
}
DBUG_RETURN(FALSE);
error:
+ m_reorged_file[reorg_part]->ha_rnd_end();
DBUG_RETURN(result);
}
@@ -5746,6 +5773,23 @@ const key_map *ha_partition::keys_to_use_for_scanning()
DBUG_RETURN(m_file[0]->keys_to_use_for_scanning());
}
+#define MAX_PARTS_FOR_OPTIMIZER_CALLS 10
+/*
+ Prepare start variables for estimating optimizer costs.
+
+ @param[out] num_used_parts Number of partitions after pruning.
+ @param[out] check_min_num Number of partitions to call.
+ @param[out] first first used partition.
+*/
+void ha_partition::partitions_optimizer_call_preparations(uint *first,
+ uint *num_used_parts,
+ uint *check_min_num)
+{
+ *first= bitmap_get_first_set(&(m_part_info->used_partitions));
+ *num_used_parts= bitmap_bits_set(&(m_part_info->used_partitions));
+ *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts);
+}
+
/*
Return time for a scan of the table
@@ -5759,43 +5803,67 @@ const key_map *ha_partition::keys_to_use_for_scanning()
double ha_partition::scan_time()
{
- double scan_time= 0;
- handler **file;
+ double scan_time= 0.0;
+ uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
DBUG_ENTER("ha_partition::scan_time");
- for (file= m_file; *file; file++)
- if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
- scan_time+= (*file)->scan_time();
+ partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
+ for (part_id= first; partitions_called < num_used_parts ; part_id++)
+ {
+ if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
+ continue;
+ scan_time+= m_file[part_id]->scan_time();
+ partitions_called++;
+ if (partitions_called >= check_min_num && scan_time != 0.0)
+ {
+ DBUG_RETURN(scan_time *
+ (double) num_used_parts / (double) partitions_called);
+ }
+ }
DBUG_RETURN(scan_time);
}
/*
- Get time to read
+ Estimate rows for records_in_range or estimate_rows_upper_bound.
- SYNOPSIS
- read_time()
- index Index number used
- ranges Number of ranges
- rows Number of rows
-
- RETURN VALUE
- time for read
+ @param is_records_in_range call records_in_range instead of
+ estimate_rows_upper_bound.
+ @param inx (only for records_in_range) index to use.
+ @param min_key (only for records_in_range) start of range.
+ @param max_key (only for records_in_range) end of range.
- DESCRIPTION
- This will be optimised later to include whether or not the index can
- be used with partitioning. To achieve we need to add another parameter
- that specifies how many of the index fields that are bound in the ranges.
- Possibly added as a new call to handlers.
+ @return Number of rows or HA_POS_ERROR.
*/
-
-double ha_partition::read_time(uint index, uint ranges, ha_rows rows)
+ha_rows ha_partition::estimate_rows(bool is_records_in_range, uint inx,
+ key_range *min_key, key_range *max_key)
{
- DBUG_ENTER("ha_partition::read_time");
+ ha_rows rows, estimated_rows= 0;
+ uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
+ DBUG_ENTER("ha_partition::records_in_range");
- DBUG_RETURN(m_file[0]->read_time(index, ranges, rows));
+ partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
+ for (part_id= first; partitions_called < num_used_parts ; part_id++)
+ {
+ if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
+ continue;
+ if (is_records_in_range)
+ rows= m_file[part_id]->records_in_range(inx, min_key, max_key);
+ else
+ rows= m_file[part_id]->estimate_rows_upper_bound();
+ if (rows == HA_POS_ERROR)
+ DBUG_RETURN(HA_POS_ERROR);
+ estimated_rows+= rows;
+ partitions_called++;
+ if (partitions_called >= check_min_num && estimated_rows)
+ {
+ DBUG_RETURN(estimated_rows * num_used_parts / partitions_called);
+ }
+ }
+ DBUG_RETURN(estimated_rows);
}
+
/*
Find number of records in a range
@@ -5823,22 +5891,9 @@ double ha_partition::read_time(uint index, uint ranges, ha_rows rows)
ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
key_range *max_key)
{
- handler **file;
- ha_rows in_range= 0;
DBUG_ENTER("ha_partition::records_in_range");
- file= m_file;
- do
- {
- if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
- {
- ha_rows tmp_in_range= (*file)->records_in_range(inx, min_key, max_key);
- if (tmp_in_range == HA_POS_ERROR)
- DBUG_RETURN(tmp_in_range);
- in_range+= tmp_in_range;
- }
- } while (*(++file));
- DBUG_RETURN(in_range);
+ DBUG_RETURN(estimate_rows(TRUE, inx, min_key, max_key));
}
@@ -5854,22 +5909,36 @@ ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
ha_rows ha_partition::estimate_rows_upper_bound()
{
- ha_rows rows, tot_rows= 0;
- handler **file;
DBUG_ENTER("ha_partition::estimate_rows_upper_bound");
- file= m_file;
- do
- {
- if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
- {
- rows= (*file)->estimate_rows_upper_bound();
- if (rows == HA_POS_ERROR)
- DBUG_RETURN(HA_POS_ERROR);
- tot_rows+= rows;
- }
- } while (*(++file));
- DBUG_RETURN(tot_rows);
+ DBUG_RETURN(estimate_rows(FALSE, 0, NULL, NULL));
+}
+
+
+/*
+ Get time to read
+
+ SYNOPSIS
+ read_time()
+ index Index number used
+ ranges Number of ranges
+ rows Number of rows
+
+ RETURN VALUE
+ time for read
+
+ DESCRIPTION
+ This will be optimised later to include whether or not the index can
+ be used with partitioning. To achieve we need to add another parameter
+ that specifies how many of the index fields that are bound in the ranges.
+ Possibly added as a new call to handlers.
+*/
+
+double ha_partition::read_time(uint index, uint ranges, ha_rows rows)
+{
+ DBUG_ENTER("ha_partition::read_time");
+
+ DBUG_RETURN(m_file[0]->read_time(index, ranges, rows));
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 5ded3a0f877..f37587f2b71 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -547,6 +547,18 @@ public:
-------------------------------------------------------------------------
*/
+private:
+ /*
+ Helper function to get the minimum number of partitions to use for
+ the optimizer hints/cost calls.
+ */
+ void partitions_optimizer_call_preparations(uint *num_used_parts,
+ uint *check_min_num,
+ uint *first);
+ ha_rows estimate_rows(bool is_records_in_range, uint inx,
+ key_range *min_key, key_range *max_key);
+public:
+
/*
keys_to_use_for_scanning can probably be implemented as the
intersection of all underlying handlers if mixed handlers are used.
diff --git a/sql/item.cc b/sql/item.cc
index b8215ffe2d1..68a9b853af5 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -5150,7 +5150,7 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
error=field->store(nr, unsigned_flag);
}
- return error;
+ return error ? error : (field->table->in_use->is_error() ? 2 : 0);
}
diff --git a/sql/item.h b/sql/item.h
index 79cf5fd06ed..b8e7bf9f65c 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -506,6 +506,13 @@ public:
char * name; /* Name from select */
/* Original item name (if it was renamed)*/
char * orig_name;
+ /**
+ Intrusive list pointer for free list. If not null, points to the next
+ Item on some Query_arena's free list. For instance, stored procedures
+ have their own Query_arena's.
+
+ @see Query_arena::free_list
+ */
Item *next;
uint32 max_length;
uint name_length; /* Length of name */
@@ -963,6 +970,32 @@ public:
virtual Item *equal_fields_propagator(uchar * arg) { return this; }
virtual bool set_no_const_sub(uchar *arg) { return FALSE; }
virtual Item *replace_equal_field(uchar * arg) { return this; }
+ /*
+ Check if an expression value depends on the current timezone. Used by
+ partitioning code to reject timezone-dependent expressions in a
+ (sub)partitioning function.
+ */
+ virtual bool is_timezone_dependent_processor(uchar *bool_arg)
+ {
+ return FALSE;
+ }
+
+ /**
+ Find a function of a given type
+
+ @param arg the function type to search (enum Item_func::Functype)
+ @return
+ @retval TRUE the function type we're searching for is found
+ @retval FALSE the function type wasn't found
+
+ @description
+ This function can be used (together with Item::walk()) to find functions
+ in an item tree fragment.
+ */
+ virtual bool find_function_processor (uchar *arg)
+ {
+ return FALSE;
+ }
/*
For SP local variable returns pointer to Item representing its
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 30aa4ee1cdc..fcd9ebdc938 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4251,7 +4251,7 @@ Item *Item_cond::compile(Item_analyzer analyzer, uchar **arg_p,
uchar *arg_v= *arg_p;
Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && new_item != item)
- li.replace(new_item);
+ current_thd->change_item_tree(li.ref(), new_item);
}
return Item_func::transform(transformer, arg_t);
}
@@ -5252,7 +5252,8 @@ Item *Item_bool_rowready_func2::negated_item()
}
Item_equal::Item_equal(Item_field *f1, Item_field *f2)
- : Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
+ : Item_bool_func(), const_item(0), eval_item(0), cond_false(0),
+ compare_as_dates(FALSE)
{
const_item_cache= 0;
fields.push_back(f1);
@@ -5265,6 +5266,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
const_item_cache= 0;
fields.push_back(f);
const_item= c;
+ compare_as_dates= f->is_datetime();
}
@@ -5279,9 +5281,45 @@ Item_equal::Item_equal(Item_equal *item_equal)
fields.push_back(item);
}
const_item= item_equal->const_item;
+ compare_as_dates= item_equal->compare_as_dates;
cond_false= item_equal->cond_false;
}
+
+void Item_equal::compare_const(Item *c)
+{
+ if (compare_as_dates)
+ {
+ cmp.set_datetime_cmp_func(this, &c, &const_item);
+ cond_false= cmp.compare();
+ }
+ else
+ {
+ Item_func_eq *func= new Item_func_eq(c, const_item);
+ func->set_cmp_func();
+ func->quick_fix_field();
+ cond_false= !func->val_int();
+ }
+ if (cond_false)
+ const_item_cache= 1;
+}
+
+
+void Item_equal::add(Item *c, Item_field *f)
+{
+ if (cond_false)
+ return;
+ if (!const_item)
+ {
+ DBUG_ASSERT(f);
+ const_item= c;
+ compare_as_dates= f->is_datetime();
+ return;
+ }
+ compare_const(c);
+}
+
+
void Item_equal::add(Item *c)
{
if (cond_false)
@@ -5291,11 +5329,7 @@ void Item_equal::add(Item *c)
const_item= c;
return;
}
- Item_func_eq *func= new Item_func_eq(c, const_item);
- func->set_cmp_func();
- func->quick_fix_field();
- if ((cond_false= !func->val_int()))
- const_item_cache= 1;
+ compare_const(c);
}
void Item_equal::add(Item_field *f)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index f58b8f9be78..01d4ae67a3f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1580,7 +1580,9 @@ class Item_equal: public Item_bool_func
List<Item_field> fields; /* list of equal field items */
Item *const_item; /* optional constant item equal to fields items */
cmp_item *eval_item;
+ Arg_comparator cmp;
bool cond_false;
+ bool compare_as_dates;
public:
inline Item_equal()
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
@@ -1589,6 +1591,8 @@ public:
Item_equal(Item *c, Item_field *f);
Item_equal(Item_equal *item_equal);
inline Item* get_const() { return const_item; }
+ void compare_const(Item *c);
+ void add(Item *c, Item_field *f);
void add(Item *c);
void add(Item_field *f);
uint members();
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e2aacf9a27d..89dbdd98262 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -4178,6 +4178,16 @@ Create_func_rand::create_native(THD *thd, LEX_STRING name,
if (item_list != NULL)
arg_count= item_list->elements;
+ /*
+ When RAND() is binlogged, the seed is binlogged too. So the
+ sequence of random numbers is the same on a replication slave as
+ on the master. However, if several RAND() values are inserted
+ into a table, the order in which the rows are modified may differ
+ between master and slave, because the order is undefined. Hence,
+ the statement is unsafe to log in statement format.
+ */
+ thd->lex->set_stmt_unsafe();
+
switch (arg_count) {
case 0:
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b99e2281641..6c295635d6c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -605,7 +605,7 @@ void Item_func::signal_divide_by_null()
Item *Item_func::get_tmp_table_item(THD *thd)
{
- if (!with_sum_func && !const_item() && functype() != SUSERVAR_FUNC)
+ if (!with_sum_func && !const_item())
return new Item_field(result_field);
return copy_or_same(thd);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index f34c7b64be5..b7994bd941e 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -189,6 +189,34 @@ public:
null_value=1;
return 0.0;
}
+ bool has_timestamp_args()
+ {
+ DBUG_ASSERT(fixed == TRUE);
+ for (uint i= 0; i < arg_count; i++)
+ {
+ if (args[i]->type() == Item::FIELD_ITEM &&
+ args[i]->field_type() == MYSQL_TYPE_TIMESTAMP)
+ return TRUE;
+ }
+ return FALSE;
+ }
+ /*
+ We assume the result of any function that has a TIMESTAMP argument to be
+ timezone-dependent, since a TIMESTAMP value in both numeric and string
+ contexts is interpreted according to the current timezone.
+ The only exception is UNIX_TIMESTAMP() which returns the internal
+ representation of a TIMESTAMP argument verbatim, and thus does not depend on
+ the timezone.
+ */
+ virtual bool is_timezone_dependent_processor(uchar *bool_arg)
+ {
+ return has_timestamp_args();
+ }
+
+ virtual bool find_function_processor (uchar *arg)
+ {
+ return functype() == *(Functype *) arg;
+ }
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index ac15ac93f7d..b4dd2905fa4 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -42,6 +42,20 @@ C_MODE_END
String my_empty_string("",default_charset_info);
+/*
+ Convert an array of bytes to a hexadecimal representation.
+
+ Used to generate a hexadecimal representation of a message digest.
+*/
+static void array_to_hex(char *to, const char *str, uint len)
+{
+ const char *str_end= str + len;
+ for (; str != str_end; ++str)
+ {
+ *to++= _dig_vec_lower[((uchar) *str) >> 4];
+ *to++= _dig_vec_lower[((uchar) *str) & 0x0F];
+ }
+}
bool Item_str_func::fix_fields(THD *thd, Item **ref)
@@ -114,12 +128,7 @@ String *Item_func_md5::val_str(String *str)
null_value=1;
return 0;
}
- sprintf((char *) str->ptr(),
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- digest[0], digest[1], digest[2], digest[3],
- digest[4], digest[5], digest[6], digest[7],
- digest[8], digest[9], digest[10], digest[11],
- digest[12], digest[13], digest[14], digest[15]);
+ array_to_hex((char *) str->ptr(), (const char*) digest, 16);
str->length((uint) 32);
return str;
}
@@ -160,15 +169,7 @@ String *Item_func_sha::val_str(String *str)
if (!( str->alloc(SHA1_HASH_SIZE*2) ||
(mysql_sha1_result(&context,digest))))
{
- sprintf((char *) str->ptr(),
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\
-%02x%02x%02x%02x%02x%02x%02x%02x",
- digest[0], digest[1], digest[2], digest[3],
- digest[4], digest[5], digest[6], digest[7],
- digest[8], digest[9], digest[10], digest[11],
- digest[12], digest[13], digest[14], digest[15],
- digest[16], digest[17], digest[18], digest[19]);
-
+ array_to_hex((char *) str->ptr(), (const char*) digest, SHA1_HASH_SIZE);
str->length((uint) SHA1_HASH_SIZE*2);
null_value=0;
return str;
@@ -678,8 +679,8 @@ String *Item_func_concat_ws::val_str(String *str)
res->length() + sep_str->length() + res2->length())
{
/* We have room in str; We can't get any errors here */
- if (str == res2)
- { // This is quote uncommon!
+ if (str->ptr() == res2->ptr())
+ { // This is quite uncommon!
str->replace(0,0,*sep_str);
str->replace(0,0,*res);
}
@@ -1721,68 +1722,65 @@ String *Item_func_encrypt::val_str(String *str)
#endif /* HAVE_CRYPT */
}
+bool Item_func_encode::seed()
+{
+ char buf[80];
+ ulong rand_nr[2];
+ String *key, tmp(buf, sizeof(buf), system_charset_info);
+
+ if (!(key= args[1]->val_str(&tmp)))
+ return TRUE;
+
+ hash_password(rand_nr, key->ptr(), key->length());
+ sql_crypt.init(rand_nr);
+
+ return FALSE;
+}
+
void Item_func_encode::fix_length_and_dec()
{
max_length=args[0]->max_length;
maybe_null=args[0]->maybe_null || args[1]->maybe_null;
collation.set(&my_charset_bin);
+ /* Precompute the seed state if the item is constant. */
+ seeded= args[1]->const_item() &&
+ (args[1]->result_type() == STRING_RESULT) && !seed();
}
String *Item_func_encode::val_str(String *str)
{
String *res;
- char pw_buff[80];
- String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info);
- String *password;
DBUG_ASSERT(fixed == 1);
if (!(res=args[0]->val_str(str)))
{
- null_value=1; /* purecov: inspected */
- return 0; /* purecov: inspected */
+ null_value= 1;
+ return NULL;
}
- if (!(password=args[1]->val_str(& tmp_pw_value)))
+ if (!seeded && seed())
{
- null_value=1;
- return 0;
+ null_value= 1;
+ return NULL;
}
- null_value=0;
- res=copy_if_not_alloced(str,res,res->length());
- SQL_CRYPT sql_crypt(password->ptr(), password->length());
- sql_crypt.init();
- sql_crypt.encode((char*) res->ptr(),res->length());
- res->set_charset(&my_charset_bin);
+ null_value= 0;
+ res= copy_if_not_alloced(str, res, res->length());
+ crypto_transform(res);
+ sql_crypt.reinit();
+
return res;
}
-String *Item_func_decode::val_str(String *str)
+void Item_func_encode::crypto_transform(String *res)
{
- String *res;
- char pw_buff[80];
- String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info);
- String *password;
- DBUG_ASSERT(fixed == 1);
-
- if (!(res=args[0]->val_str(str)))
- {
- null_value=1; /* purecov: inspected */
- return 0; /* purecov: inspected */
- }
-
- if (!(password=args[1]->val_str(& tmp_pw_value)))
- {
- null_value=1;
- return 0;
- }
+ sql_crypt.encode((char*) res->ptr(),res->length());
+ res->set_charset(&my_charset_bin);
+}
- null_value=0;
- res=copy_if_not_alloced(str,res,res->length());
- SQL_CRYPT sql_crypt(password->ptr(), password->length());
- sql_crypt.init();
+void Item_func_decode::crypto_transform(String *res)
+{
sql_crypt.decode((char*) res->ptr(),res->length());
- return res;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 8625add8d2d..59e7c0df5b6 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -351,12 +351,22 @@ public:
class Item_func_encode :public Item_str_func
{
+private:
+ /** Whether the PRNG has already been seeded. */
+ bool seeded;
+protected:
+ SQL_CRYPT sql_crypt;
public:
Item_func_encode(Item *a, Item *seed):
Item_str_func(a, seed) {}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "encode"; }
+protected:
+ virtual void crypto_transform(String *);
+private:
+ /** Provide a seed for the PRNG sequence. */
+ bool seed();
};
@@ -364,8 +374,9 @@ class Item_func_decode :public Item_func_encode
{
public:
Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {}
- String *val_str(String *);
const char *func_name() const { return "decode"; }
+protected:
+ void crypto_transform(String *);
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 964edba4988..a244a674bbf 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2560,9 +2560,9 @@ void Item_char_typecast::fix_length_and_dec()
from_cs != &my_charset_bin &&
cast_cs != &my_charset_bin);
collation.set(cast_cs, DERIVATION_IMPLICIT);
- char_length= (cast_length >= 0) ?
- cast_length :
- args[0]->max_length / args[0]->collation.collation->mbmaxlen;
+ char_length= (cast_length >= 0) ? cast_length :
+ args[0]->max_length /
+ (cast_cs == &my_charset_bin ? 1 : args[0]->collation.collation->mbmaxlen);
max_length= char_length * cast_cs->mbmaxlen;
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 9e3c2e8c89f..a7a64090f6c 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -305,6 +305,16 @@ public:
Item_func_unix_timestamp(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "unix_timestamp"; }
+ bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+ /*
+ UNIX_TIMESTAMP() depends on the current timezone
+ (and thus may not be used as a partitioning function)
+ when its argument is NOT of the TIMESTAMP type.
+ */
+ bool is_timezone_dependent_processor(uchar *int_arg)
+ {
+ return !has_timestamp_args();
+ }
void fix_length_and_dec()
{
decimals=0;
diff --git a/sql/log.cc b/sql/log.cc
index cfd8ad7b62d..95b38f7ccd7 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1475,7 +1475,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
{
if (trx_data->has_incident())
- mysql_bin_log.write_incident(thd, TRUE);
+ error= mysql_bin_log.write_incident(thd, TRUE);
trx_data->reset();
}
else // ...statement
@@ -1910,6 +1910,22 @@ void MYSQL_LOG::init(enum_log_type log_type_arg,
}
+bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
+ const char *new_name,
+ enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg)
+{
+ init(log_type_arg, io_cache_type_arg);
+
+ if (new_name && !strmov(log_file_name, new_name))
+ return TRUE;
+ else if (!new_name && generate_new_name(log_file_name, log_name))
+ return TRUE;
+
+ return FALSE;
+}
+
+
/*
Open a (new) log file.
@@ -1942,17 +1958,14 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
write_error= 0;
- init(log_type_arg, io_cache_type_arg);
-
if (!(name= my_strdup(log_name, MYF(MY_WME))))
{
name= (char *)log_name; // for the error message
goto err;
}
- if (new_name)
- strmov(log_file_name, new_name);
- else if (generate_new_name(log_file_name, name))
+ if (init_and_set_log_file_name(name, new_name,
+ log_type_arg, io_cache_type_arg))
goto err;
if (io_cache_type == SEQ_READ_APPEND)
@@ -2440,7 +2453,7 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
{
char *p= fn_ext(log_name);
uint length= (uint) (p - log_name);
- strmake(buff, log_name, min(length, FN_REFLEN));
+ strmake(buff, log_name, min(length, FN_REFLEN-1));
return (const char*)buff;
}
return log_name;
@@ -2462,7 +2475,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG()
*/
index_file_name[0] = 0;
bzero((char*) &index_file, sizeof(index_file));
- bzero((char*) &purge_temp, sizeof(purge_temp));
+ bzero((char*) &purge_index_file, sizeof(purge_index_file));
}
/* this is called only once */
@@ -2511,7 +2524,7 @@ void MYSQL_BIN_LOG::init_pthread_objects()
bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
- const char *log_name)
+ const char *log_name, bool need_mutex)
{
File index_file_nr= -1;
DBUG_ASSERT(!my_b_inited(&index_file));
@@ -2536,7 +2549,8 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
init_io_cache(&index_file, index_file_nr,
IO_SIZE, WRITE_CACHE,
my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
+ DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
{
/*
TODO: all operations creating/deleting the index file or a log, should
@@ -2547,6 +2561,28 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
my_close(index_file_nr,MYF(0));
return TRUE;
}
+
+#ifdef HAVE_REPLICATION
+ /*
+ Sync the index by purging any binary log file that is not registered.
+ In other words, either purge binary log files that were removed from
+ the index but not purged from the file system due to a crash or purge
+ any binary log file that was created but not register in the index
+ due to a crash.
+ */
+
+ if (set_purge_index_file_name(index_file_name_arg) ||
+ open_purge_index_file(FALSE) ||
+ purge_index_entry(NULL, NULL, need_mutex) ||
+ close_purge_index_file() ||
+ DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
+ {
+ sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
+ "file.");
+ return TRUE;
+ }
+#endif
+
return FALSE;
}
@@ -2571,17 +2607,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
enum cache_type io_cache_type_arg,
bool no_auto_events_arg,
ulong max_size_arg,
- bool null_created_arg)
+ bool null_created_arg,
+ bool need_mutex)
{
File file= -1;
+
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
- write_error=0;
+ if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
+ io_cache_type_arg))
+ {
+ sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
+ DBUG_RETURN(1);
+ }
+
+#ifdef HAVE_REPLICATION
+ if (open_purge_index_file(TRUE) ||
+ register_create_index_entry(log_file_name) ||
+ sync_purge_index_file() ||
+ DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
+ {
+ sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
+ DBUG_RETURN(1);
+ }
+ DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort(););
+#endif
+
+ write_error= 0;
/* open the main log file */
- if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
+ if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
+ io_cache_type_arg))
+ {
+#ifdef HAVE_REPLICATION
+ close_purge_index_file();
+#endif
DBUG_RETURN(1); /* all warnings issued */
+ }
init(no_auto_events_arg, max_size_arg);
@@ -2607,9 +2670,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
write_file_name_to_index_file= 1;
}
- DBUG_ASSERT(my_b_inited(&index_file) != 0);
- reinit_io_cache(&index_file, WRITE_CACHE,
- my_b_filelength(&index_file), 0, 0);
if (need_start_event && !no_auto_events)
{
/*
@@ -2667,23 +2727,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (write_file_name_to_index_file)
{
+#ifdef HAVE_REPLICATION
+ DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort(););
+#endif
+
+ DBUG_ASSERT(my_b_inited(&index_file) != 0);
+ reinit_io_cache(&index_file, WRITE_CACHE,
+ my_b_filelength(&index_file), 0, 0);
/*
As this is a new log file, we write the file name to the index
file. As every time we write to the index file, we sync it.
*/
- if (my_b_write(&index_file, (uchar*) log_file_name,
- strlen(log_file_name)) ||
- my_b_write(&index_file, (uchar*) "\n", 1) ||
- flush_io_cache(&index_file) ||
+ if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
+ my_b_write(&index_file, (uchar*) log_file_name,
+ strlen(log_file_name)) ||
+ my_b_write(&index_file, (uchar*) "\n", 1) ||
+ flush_io_cache(&index_file) ||
my_sync(index_file.file, MYF(MY_WME)))
- goto err;
+ goto err;
+
+#ifdef HAVE_REPLICATION
+ DBUG_EXECUTE_IF("crash_create_after_update_index", abort(););
+#endif
}
}
log_state= LOG_OPENED;
+#ifdef HAVE_REPLICATION
+ close_purge_index_file();
+#endif
+
DBUG_RETURN(0);
err:
+#ifdef HAVE_REPLICATION
+ if (is_inited_purge_index_file())
+ purge_index_entry(NULL, NULL, need_mutex);
+ close_purge_index_file();
+#endif
sql_print_error("Could not use %s for logging (error %d). \
Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
@@ -2940,8 +3021,15 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
name=0; // Protect against free
close(LOG_CLOSE_TO_BE_OPENED);
- /* First delete all old log files */
+ /*
+ First delete all old log files and then update the index file.
+ As we first delete the log files and do not use sort of logging,
+ a crash may lead to an inconsistent state where the index has
+ references to non-existent files.
+ We need to invert the steps and use the purge_index_file methods
+ in order to make the operation safe.
+ */
if (find_log_pos(&linfo, NullS, 0))
{
error=1;
@@ -2964,7 +3052,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
}
else
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with deleting %s; "
"consider examining correspondence "
@@ -2995,7 +3083,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
}
else
{
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with deleting %s; "
"consider examining correspondence "
@@ -3008,8 +3096,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
}
if (!thd->slave_thread)
need_start_event=1;
- if (!open_index_file(index_file_name, 0))
- open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
+ if (!open_index_file(index_file_name, 0, FALSE))
+ open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
my_free((uchar*) save_name, MYF(0));
err:
@@ -3196,7 +3284,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
bool need_update_threads,
ulonglong *decrease_log_space)
{
- int error;
+ int error= 0;
bool exit_loop= 0;
LOG_INFO log_info;
THD *thd= current_thd;
@@ -3207,33 +3295,15 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
{
- sql_print_error("MYSQL_LOG::purge_logs was called with file %s not "
+ sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
"listed in the index.", to_log);
goto err;
}
- /*
- For crash recovery reasons the index needs to be updated before
- any files are deleted. Move files to be deleted into a temp file
- to be processed after the index is updated.
- */
- if (!my_b_inited(&purge_temp))
- {
- if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX,
- DISK_BUFFER_SIZE, MYF(MY_WME))))
- {
- sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp");
- goto err;
- }
- }
- else
+ if ((error= open_purge_index_file(TRUE)))
{
- if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1)))
- {
- sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp "
- "for write");
- goto err;
- }
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
+ goto err;
}
/*
@@ -3243,51 +3313,177 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
+ !is_active(log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
{
- if ((error=my_b_write(&purge_temp, (const uchar*)log_info.log_file_name,
- strlen(log_info.log_file_name))) ||
- (error=my_b_write(&purge_temp, (const uchar*)"\n", 1)))
+ if ((error= register_purge_index_entry(log_info.log_file_name)))
{
- sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp",
+ sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register file.",
log_info.log_file_name);
goto err;
}
if (find_next_log(&log_info, 0) || exit_loop)
break;
- }
+ }
+
+ DBUG_EXECUTE_IF("crash_purge_before_update_index", abort(););
+
+ if ((error= sync_purge_index_file()))
+ {
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
+ goto err;
+ }
/* We know how many files to delete. Update index file. */
if ((error=update_log_index(&log_info, need_update_threads)))
{
- sql_print_error("MSYQL_LOG::purge_logs failed to update the index file");
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
goto err;
}
- DBUG_EXECUTE_IF("crash_after_update_index", abort(););
+ DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort(););
- /* Switch purge_temp for read. */
- if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0)))
+err:
+ /* Read each entry from purge_index_file and delete the file. */
+ if (is_inited_purge_index_file() &&
+ (error= purge_index_entry(thd, decrease_log_space, FALSE)))
+ sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
+ " that would be purged.");
+ close_purge_index_file();
+
+ DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort(););
+
+ if (need_mutex)
+ pthread_mutex_unlock(&LOCK_index);
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
+ if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
+ ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
+ MY_REPLACE_EXT)) == NULL)
+ {
+ error= 1;
+ sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
+ "file name.");
+ }
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
+{
+ int error= 0;
+ File file= -1;
+
+ DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
+
+ if (destroy)
+ close_purge_index_file();
+
+ if (!my_b_inited(&purge_index_file))
{
- sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp "
+ if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
+ MYF(MY_WME | ME_WAITTANG))) < 0 ||
+ init_io_cache(&purge_index_file, file, IO_SIZE,
+ (destroy ? WRITE_CACHE : READ_CACHE),
+ 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ error= 1;
+ sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register "
+ " file.");
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::close_purge_index_file()
+{
+ int error= 0;
+
+ DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
+
+ if (my_b_inited(&purge_index_file))
+ {
+ end_io_cache(&purge_index_file);
+ error= my_close(purge_index_file.file, MYF(0));
+ }
+ my_delete(purge_index_file_name, MYF(0));
+ bzero((char*) &purge_index_file, sizeof(purge_index_file));
+
+ DBUG_RETURN(error);
+}
+
+bool MYSQL_BIN_LOG::is_inited_purge_index_file()
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
+ DBUG_RETURN (my_b_inited(&purge_index_file));
+}
+
+int MYSQL_BIN_LOG::sync_purge_index_file()
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
+
+ if ((error= flush_io_cache(&purge_index_file)) ||
+ (error= my_sync(purge_index_file.file, MYF(MY_WME))))
+ DBUG_RETURN(error);
+
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
+{
+ int error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
+
+ if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry))) ||
+ (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
+ DBUG_RETURN (error);
+
+ DBUG_RETURN(error);
+}
+
+int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
+ DBUG_RETURN(register_purge_index_entry(entry));
+}
+
+int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
+ bool need_mutex)
+{
+ MY_STAT s;
+ int error= 0;
+ LOG_INFO log_info;
+ LOG_INFO check_log_info;
+
+ DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
+
+ DBUG_ASSERT(my_b_inited(&purge_index_file));
+
+ if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
+ {
+ sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file "
"for read");
goto err;
}
- /* Read each entry from purge_temp and delete the file. */
for (;;)
{
uint length;
- if ((length=my_b_gets(&purge_temp, log_info.log_file_name,
+ if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
FN_REFLEN)) <= 1)
{
- if (purge_temp.error)
+ if (purge_index_file.error)
{
- error= purge_temp.error;
- sql_print_error("MSYQL_LOG::purge_logs error %d reading from "
- "purge_temp", error);
+ error= purge_index_file.error;
+ sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
+ "register file.", error);
goto err;
}
@@ -3298,9 +3494,6 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
/* Get rid of the trailing '\n' */
log_info.log_file_name[length-1]= 0;
- ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
-
- MY_STAT s;
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
{
if (my_errno == ENOENT)
@@ -3326,7 +3519,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
*/
if (thd)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with getting info on being purged %s; "
"consider examining correspondence "
@@ -3348,64 +3541,92 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
}
else
{
- DBUG_PRINT("info",("purging %s",log_info.log_file_name));
- if (!my_delete(log_info.log_file_name, MYF(0)))
- {
- if (decrease_log_space)
- *decrease_log_space-= s.st_size;
- }
- else
+ if ((error= find_log_pos(&check_log_info, log_info.log_file_name, need_mutex)))
{
- if (my_errno == ENOENT)
+ if (error != LOG_INFO_EOF)
{
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+ ER_BINLOG_PURGE_FATAL_ERR,
+ "a problem with deleting %s and "
+ "reading the binlog index file",
log_info.log_file_name);
}
- sql_print_information("Failed to delete file '%s'",
- log_info.log_file_name);
- my_errno= 0;
+ else
+ {
+ sql_print_information("Failed to delete file '%s' and "
+ "read the binlog index file",
+ log_info.log_file_name);
+ }
+ goto err;
+ }
+
+ error= 0;
+ if (!need_mutex)
+ {
+ /*
+ This is to avoid triggering an error in NDB.
+ */
+ ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
+ }
+
+ DBUG_PRINT("info",("purging %s",log_info.log_file_name));
+ if (!my_delete(log_info.log_file_name, MYF(0)))
+ {
+ if (decrease_log_space)
+ *decrease_log_space-= s.st_size;
}
else
{
- if (thd)
+ if (my_errno == ENOENT)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
- ER_BINLOG_PURGE_FATAL_ERR,
- "a problem with deleting %s; "
- "consider examining correspondence "
- "of your binlog index file "
- "to the actual binlog files",
- log_info.log_file_name);
+ if (thd)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+ log_info.log_file_name);
+ }
+ sql_print_information("Failed to delete file '%s'",
+ log_info.log_file_name);
+ my_errno= 0;
}
else
{
- sql_print_information("Failed to delete file '%s'; "
+ if (thd)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_BINLOG_PURGE_FATAL_ERR,
+ "a problem with deleting %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
- }
- if (my_errno == EMFILE)
- {
- DBUG_PRINT("info",
- ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
- error= LOG_INFO_EMFILE;
+ }
+ else
+ {
+ sql_print_information("Failed to delete file '%s'; "
+ "consider examining correspondence "
+ "of your binlog index file "
+ "to the actual binlog files",
+ log_info.log_file_name);
+ }
+ if (my_errno == EMFILE)
+ {
+ DBUG_PRINT("info",
+ ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
+ error= LOG_INFO_EMFILE;
+ goto err;
+ }
+ error= LOG_INFO_FATAL;
goto err;
}
- error= LOG_INFO_FATAL;
- goto err;
}
}
}
}
err:
- close_cached_file(&purge_temp);
- if (need_mutex)
- pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -3445,7 +3666,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
goto err;
while (strcmp(log_file_name, log_info.log_file_name) &&
- !log_in_use(log_info.log_file_name))
+ !is_active(log_info.log_file_name) &&
+ !log_in_use(log_info.log_file_name))
{
if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
{
@@ -3454,14 +3676,6 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
/*
It's not fatal if we can't stat a log file that does not exist.
*/
- if (thd)
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
- log_info.log_file_name);
- }
- sql_print_information("Failed to execute my_stat on file '%s'",
- log_info.log_file_name);
my_errno= 0;
}
else
@@ -3471,7 +3685,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
*/
if (thd)
{
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with getting info on being purged %s; "
"consider examining correspondence "
@@ -3493,7 +3707,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
if (stat_area.st_mtime < purge_time)
strmake(to_log,
log_info.log_file_name,
- sizeof(log_info.log_file_name));
+ sizeof(log_info.log_file_name) - 1);
else
break;
}
@@ -3656,9 +3870,9 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
*/
/* reopen index binlog file, BUG#34582 */
- if (!open_index_file(index_file_name, 0))
- open(old_name, log_type, new_name_ptr,
- io_cache_type, no_auto_events, max_size, 1);
+ if (!open_index_file(index_file_name, 0, FALSE))
+ open(old_name, log_type, new_name_ptr,
+ io_cache_type, no_auto_events, max_size, 1, FALSE);
my_free(old_name,MYF(0));
end:
@@ -4108,12 +4322,20 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
#if defined(USING_TRANSACTIONS)
/*
Should we write to the binlog cache or to the binlog on disk?
+
Write to the binlog cache if:
- - it is already not empty (meaning we're in a transaction; note that the
- present event could be about a non-transactional table, but still we need
- to write to the binlog cache in that case to handle updates to mixed
- trans/non-trans table types the best possible in binlogging)
- - or if the event asks for it (cache_stmt == TRUE).
+ 1 - a transactional engine/table is updated (stmt_has_updated_trans_table == TRUE);
+ 2 - or the event asks for it (cache_stmt == TRUE);
+ 3 - or the cache is already not empty (meaning we're in a transaction;
+ note that the present event could be about a non-transactional table, but
+ still we need to write to the binlog cache in that case to handle updates
+ to mixed trans/non-trans table types).
+
+ Write to the binlog on disk if only a non-transactional engine is
+ updated and:
+ 1 - the binlog cache is empty or;
+ 2 - --binlog-direct-non-transactional-updates is set and we are about to
+ use the statement format. When using the row format (cache_stmt == TRUE).
*/
if (opt_using_transactions && thd)
{
@@ -4124,8 +4346,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
IO_CACHE *trans_log= &trx_data->trans_log;
my_off_t trans_log_pos= my_b_tell(trans_log);
- if (event_info->get_cache_stmt() || trans_log_pos != 0 ||
- stmt_has_updated_trans_table(thd))
+ if (event_info->get_cache_stmt() || stmt_has_updated_trans_table(thd) ||
+ (!thd->variables.binlog_direct_non_trans_update &&
+ trans_log_pos != 0))
{
DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu",
event_info->get_cache_stmt(),
@@ -4305,6 +4528,9 @@ bool general_log_write(THD *thd, enum enum_server_command command,
void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{
+#ifdef HAVE_REPLICATION
+ bool check_purge= false;
+#endif
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
pthread_mutex_lock(&LOCK_log);
if ((flags & RP_FORCE_ROTATE) ||
@@ -4312,16 +4538,24 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{
new_file_without_locking();
#ifdef HAVE_REPLICATION
- if (expire_logs_days)
- {
- time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
- if (purge_time >= 0)
- purge_logs_before_date(purge_time);
- }
+ check_purge= true;
#endif
}
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
pthread_mutex_unlock(&LOCK_log);
+
+#ifdef HAVE_REPLICATION
+ /*
+ NOTE: Run purge_logs wo/ holding LOCK_log
+ as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
+ */
+ if (check_purge && expire_logs_days)
+ {
+ time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ purge_logs_before_date(purge_time);
+ }
+#endif
}
uint MYSQL_BIN_LOG::next_file_id()
@@ -4514,7 +4748,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
Incident_log_event ev(thd, incident, write_error_msg);
if (lock)
pthread_mutex_lock(&LOCK_log);
- ev.write(&log_file);
+ error= ev.write(&log_file);
if (lock)
{
if (!error && !(error= flush_and_sync()))
@@ -4834,11 +5068,11 @@ bool flush_error_log()
if (opt_error_log)
{
char err_renamed[FN_REFLEN], *end;
- end= strmake(err_renamed,log_error_file,FN_REFLEN-4);
+ end= strmake(err_renamed,log_error_file,FN_REFLEN-5);
strmov(end, "-old");
VOID(pthread_mutex_lock(&LOCK_error_log));
#ifdef __WIN__
- char err_temp[FN_REFLEN+4];
+ char err_temp[FN_REFLEN+5];
/*
On Windows is necessary a temporary file for to rename
the current error file.
@@ -5563,7 +5797,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
if (using_heuristic_recover())
{
/* generate a new binlog to mask a corrupted one */
- open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
+ open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE);
cleanup();
return 1;
}
diff --git a/sql/log.h b/sql/log.h
index d306d6f7182..8b5dfcb3935 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -172,6 +172,10 @@ public:
enum_log_type log_type,
const char *new_name,
enum cache_type io_cache_type_arg);
+ bool init_and_set_log_file_name(const char *log_name,
+ const char *new_name,
+ enum_log_type log_type_arg,
+ enum cache_type io_cache_type_arg);
void init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg);
void close(uint exiting);
@@ -233,14 +237,15 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
pthread_cond_t update_cond;
ulonglong bytes_written;
IO_CACHE index_file;
+ char index_file_name[FN_REFLEN];
/*
- purge_temp is a temp file used in purge_logs so that the index file
+ purge_file is a temp file used in purge_logs so that the index file
can be updated before deleting files from disk, yielding better crash
recovery. It is created on demand the first time purge_logs is called
and then reused for subsequent calls. It is cleaned up in cleanup().
*/
- IO_CACHE purge_temp;
- char index_file_name[FN_REFLEN];
+ IO_CACHE purge_index_file;
+ char purge_index_file_name[FN_REFLEN];
/*
The max size before rotation (usable only if log_type == LOG_BIN: binary
logs and relay logs).
@@ -349,9 +354,10 @@ public:
const char *new_name,
enum cache_type io_cache_type_arg,
bool no_auto_events_arg, ulong max_size,
- bool null_created);
+ bool null_created,
+ bool need_mutex);
bool open_index_file(const char *index_file_name_arg,
- const char *log_name);
+ const char *log_name, bool need_mutex);
/* Use this to start writing a new log file */
void new_file();
@@ -384,6 +390,16 @@ public:
ulonglong *decrease_log_space);
int purge_logs_before_date(time_t purge_time);
int purge_first_log(Relay_log_info* rli, bool included);
+ int set_purge_index_file_name(const char *base_file_name);
+ int open_purge_index_file(bool destroy);
+ bool is_inited_purge_index_file();
+ int close_purge_index_file();
+ int clean_purge_index_file();
+ int sync_purge_index_file();
+ int register_purge_index_entry(const char* entry);
+ int register_create_index_entry(const char* entry);
+ int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
+ bool need_mutex);
bool reset_logs(THD* thd);
void close(uint exiting);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 726983c7304..94b6b35ec8c 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2294,10 +2294,22 @@ bool Query_log_event::write(IO_CACHE* file)
int8store(start, table_map_for_update);
start+= 8;
}
+ if (master_data_written != 0)
+ {
+ /*
+ Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master
+ has binlog_version<4 and the slave has binlog_version=4. See comment
+ for master_data_written in log_event.h for details.
+ */
+ *start++= Q_MASTER_DATA_WRITTEN_CODE;
+ int4store(start, master_data_written);
+ start+= 4;
+ }
+
/*
NOTE: When adding new status vars, please don't forget to update
- the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function
- code_name in this file.
+ the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
+ code_name() in this file.
Here there could be code like
if (command-line-option-which-says-"log_this_variable" && inited)
@@ -2373,7 +2385,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
auto_increment_offset(thd_arg->variables.auto_increment_offset),
lc_time_names_number(thd_arg->variables.lc_time_names->number),
charset_database_number(0),
- table_map_for_update((ulonglong)thd_arg->table_map_for_update)
+ table_map_for_update((ulonglong)thd_arg->table_map_for_update),
+ master_data_written(0)
{
time_t end_time;
@@ -2497,6 +2510,7 @@ code_name(int code)
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE";
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE";
+ case Q_MASTER_DATA_WRITTEN_CODE: return "Q_MASTER_DATA_WRITTEN_CODE";
}
sprintf(buf, "CODE#%d", code);
return buf;
@@ -2534,7 +2548,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
auto_increment_increment(1), auto_increment_offset(1),
time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
- table_map_for_update(0)
+ table_map_for_update(0), master_data_written(0)
{
ulong data_len;
uint32 tmp;
@@ -2590,6 +2604,18 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
(uint) status_vars_len));
tmp-= 2;
+ }
+ else
+ {
+ /*
+ server version < 5.0 / binlog_version < 4 master's event is
+ relay-logged with storing the original size of the event in
+ Q_MASTER_DATA_WRITTEN_CODE status variable.
+ The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked
+ event from the relay log.
+ */
+ DBUG_ASSERT(description_event->binlog_version < 4);
+ master_data_written= data_written;
}
/*
We have parsed everything we know in the post header for QUERY_EVENT,
@@ -2681,6 +2707,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
table_map_for_update= uint8korr(pos);
pos+= 8;
break;
+ case Q_MASTER_DATA_WRITTEN_CODE:
+ CHECK_SPACE(pos, end, 4);
+ data_written= master_data_written= uint4korr(pos);
+ pos+= 4;
+ break;
default:
/* That's why you must write status vars in growing order of code */
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
@@ -3170,7 +3201,18 @@ START SLAVE; . Query: '%s'", expected_error, thd->query());
compare_errors:
- /*
+ /*
+ In the slave thread, we may sometimes execute some DROP / * 40005
+ TEMPORARY * / TABLE that come from parts of binlogs (likely if we
+ use RESET SLAVE or CHANGE MASTER TO), while the temporary table
+ has already been dropped. To ignore such irrelevant "table does
+ not exist errors", we silently clear the error if TEMPORARY was used.
+ */
+ if (thd->lex->sql_command == SQLCOM_DROP_TABLE && thd->lex->drop_temporary &&
+ thd->is_error() && thd->main_da.sql_errno() == ER_BAD_TABLE_ERROR &&
+ !expected_error)
+ thd->main_da.reset_diagnostics_area();
+ /*
If we expected a non-zero error code, and we don't get the same error
code, and it should be ignored or is related to a concurrency issue.
*/
@@ -4005,6 +4047,7 @@ uint Load_log_event::get_query_buffer_length()
return
5 + db_len + 3 + // "use DB; "
18 + fname_len + 2 + // "LOAD DATA INFILE 'file''"
+ 11 + // "CONCURRENT "
7 + // LOCAL
9 + // " REPLACE or IGNORE "
13 + table_name_len*2 + // "INTO TABLE `table`"
@@ -4032,6 +4075,9 @@ void Load_log_event::print_query(bool need_db, const char *cs, char *buf,
pos= strmov(pos, "LOAD DATA ");
+ if (thd->lex->lock_option == TL_WRITE_CONCURRENT_INSERT)
+ pos= strmov(pos, "CONCURRENT ");
+
if (fn_start)
*fn_start= pos;
@@ -5851,7 +5897,7 @@ Slave_log_event::Slave_log_event(const char* buf, uint event_len)
int Slave_log_event::do_apply_event(Relay_log_info const *rli)
{
if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
+ return mysql_bin_log.write(this);
return 0;
}
#endif /* !MYSQL_CLIENT */
@@ -7598,7 +7644,7 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
- thd->binlog_flush_pending_rows_event(true);
+ error= thd->binlog_flush_pending_rows_event(true);
/*
If this event is not in a transaction, the call below will, if some
@@ -7609,7 +7655,7 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- error= ha_autocommit_or_rollback(thd, 0);
+ error|= ha_autocommit_or_rollback(thd, error);
/*
Now what if this is not a transactional engine? we still need to
@@ -7913,10 +7959,10 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
plus one or three bytes (see pack.c:net_store_length) for number of
elements in the field metadata array.
*/
- if (m_field_metadata_size > 255)
- m_data_size+= m_field_metadata_size + 3;
- else
+ if (m_field_metadata_size < 251)
m_data_size+= m_field_metadata_size + 1;
+ else
+ m_data_size+= m_field_metadata_size + 3;
bzero(m_null_bits, num_null_bytes);
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
diff --git a/sql/log_event.h b/sql/log_event.h
index c675aa1342b..36715b1d151 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -263,7 +263,8 @@ struct sql_ex_info
1 + 1 + 255 /* type, length, time_zone */ + \
1 + 2 /* type, lc_time_names_number */ + \
1 + 2 /* type, charset_database_number */ + \
- 1 + 8 /* type, table_map_for_update */)
+ 1 + 8 /* type, table_map_for_update */ + \
+ 1 + 4 /* type, master_data_written */)
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
LOG_EVENT_HEADER_LEN + /* write_header */ \
QUERY_HEADER_LEN + /* write_data */ \
@@ -330,6 +331,10 @@ struct sql_ex_info
#define Q_TABLE_MAP_FOR_UPDATE_CODE 9
+#define Q_MASTER_DATA_WRITTEN_CODE 10
+
+/* Intvar event post-header */
+
/* Intvar event data */
#define I_TYPE_OFFSET 0
#define I_VAL_OFFSET 1
@@ -1620,6 +1625,16 @@ public:
statement, for other query statements, this will be zero.
*/
ulonglong table_map_for_update;
+ /*
+ Holds the original length of a Query_log_event that comes from a
+ master of version < 5.0 (i.e., binlog_version < 4). When the IO
+ thread writes the relay log, it augments the Query_log_event with a
+ Q_MASTER_DATA_WRITTEN_CODE status_var that holds the original event
+ length. This field is initialized to non-zero in the SQL thread when
+ it reads this augmented event. SQL thread does not write
+ Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog.
+ */
+ uint32 master_data_written;
#ifndef MYSQL_CLIENT
@@ -1766,7 +1781,7 @@ private:
@verbatim
(1) USE db;
- (2) LOAD DATA [LOCAL] INFILE 'file_name'
+ (2) LOAD DATA [CONCURRENT] [LOCAL] INFILE 'file_name'
(3) [REPLACE | IGNORE]
(4) INTO TABLE 'table_name'
(5) [FIELDS
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 040b71b94e0..cda550f3c92 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1541,7 +1541,15 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
NOTE: For this new scheme there should be no pending event:
need to add code to assert that is the case.
*/
- thd->binlog_flush_pending_rows_event(false);
+ error= thd->binlog_flush_pending_rows_event(false);
+ if (error)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER(ER_SLAVE_FATAL_ERROR),
+ "call to binlog_flush_pending_rows_event() failed");
+ thd->is_slave_error= 1;
+ DBUG_RETURN(error);
+ }
TABLE_LIST *tables= rli->tables_to_lock;
close_tables_for_reopen(thd, &tables);
@@ -1831,7 +1839,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
- thd->binlog_flush_pending_rows_event(true);
+ int binlog_error= thd->binlog_flush_pending_rows_event(true);
/*
If this event is not in a transaction, the call below will, if some
@@ -1842,12 +1850,13 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
are involved, commit the transaction and flush the pending event to the
binlog.
*/
- if ((error= ha_autocommit_or_rollback(thd, 0)))
+ if ((error= ha_autocommit_or_rollback(thd, binlog_error)))
rli->report(ERROR_LEVEL, error,
"Error in %s event: commit of row events failed, "
"table `%s`.`%s`",
get_type_str(), m_table->s->db.str,
m_table->s->table_name.str);
+ error|= binlog_error;
/*
Now what if this is not a transactional engine? we still need to
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index d11fc4f900b..499d7d2fc24 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -112,6 +112,10 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
+/* Version numbers for deprecation messages */
+#define VER_BETONY "5.5"
+#define VER_CELOSIA "5.6"
+
#define WARN_DEPRECATED(Thd,Ver,Old,New) \
do { \
DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \
@@ -121,7 +125,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
(Old), (Ver), (New)); \
else \
sql_print_warning("The syntax '%s' is deprecated and will be removed " \
- "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
+ "in a future release. Please use %s instead.", (Old), (New)); \
} while(0)
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
@@ -1045,8 +1049,8 @@ check_and_unset_inject_value(int value)
#endif
-void write_bin_log(THD *thd, bool clear_error,
- char const *query, ulong query_length);
+int write_bin_log(THD *thd, bool clear_error,
+ char const *query, ulong query_length);
/* sql_connect.cc */
int check_user(THD *thd, enum enum_server_command command,
@@ -1434,8 +1438,18 @@ bool get_schema_tables_result(JOIN *join,
enum enum_schema_table_state executed_place);
enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
-#define is_schema_db(X) \
- !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X))
+inline bool is_schema_db(const char *name, size_t len)
+{
+ return (INFORMATION_SCHEMA_NAME.length == len &&
+ !my_strcasecmp(system_charset_info,
+ INFORMATION_SCHEMA_NAME.str, name));
+}
+
+inline bool is_schema_db(const char *name)
+{
+ return !my_strcasecmp(system_charset_info,
+ INFORMATION_SCHEMA_NAME.str, name);
+}
/* sql_prepare.cc */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5eb18ddda80..dea59c1c5ef 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1322,7 +1322,6 @@ void clean_up(bool print_message)
lex_free(); /* Free some memory */
item_create_cleanup();
set_var_free();
- free_charsets();
if (!opt_noacl)
{
#ifdef HAVE_DLOPEN
@@ -2033,10 +2032,10 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
/* It's safe to broadcast outside a lock (COND... is not deleted here) */
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
+ DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end();
(void) pthread_cond_broadcast(&COND_thread_count);
- DBUG_LEAVE; // Must match DBUG_ENTER()
pthread_exit(0);
return 0; // Avoid compiler warnings
}
@@ -4053,7 +4052,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
my_free(opt_bin_logname, MYF(MY_ALLOW_ZERO_PTR));
opt_bin_logname=my_strdup(buf, MYF(0));
}
- if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln))
+ if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE))
{
unireg_abort(1);
}
@@ -4225,7 +4224,7 @@ a file name for --log-bin-index option", opt_binlog_index_name);
}
if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
- WRITE_CACHE, 0, max_binlog_size, 0))
+ WRITE_CACHE, 0, max_binlog_size, 0, TRUE))
unireg_abort(1);
#ifdef HAVE_REPLICATION
@@ -5761,6 +5760,7 @@ enum options_mysqld
OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
+ OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD,
OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDB_CONNECTSTRING,
OPT_NDB_USE_EXACT_COUNT, OPT_NDB_USE_TRANSACTIONS,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
@@ -5810,6 +5810,7 @@ enum options_mysqld
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_MYISAM_USE_MMAP, OPT_MYISAM_REPAIR_THREADS,
+ OPT_MYISAM_MMAP_SIZE,
OPT_MYISAM_STATS_METHOD,
OPT_PAGECACHE_BUFFER_SIZE,
@@ -5845,6 +5846,7 @@ enum options_mysqld
OPT_EXPIRE_LOGS_DAYS,
OPT_GROUP_CONCAT_MAX_LEN,
OPT_DEFAULT_COLLATION,
+ OPT_DEFAULT_COLLATION_OLD,
OPT_CHARACTER_SET_CLIENT_HANDSHAKE,
OPT_CHARACTER_SET_FILESYSTEM,
OPT_LC_TIME_NAMES,
@@ -5871,6 +5873,9 @@ enum options_mysqld
OPT_TABLE_LOCK_WAIT_TIMEOUT,
OPT_PLUGIN_LOAD,
OPT_PLUGIN_DIR,
+ OPT_SYMBOLIC_LINKS,
+ OPT_WARNINGS,
+ OPT_RECORD_BUFFER_OLD,
OPT_LOG_OUTPUT,
OPT_PORT_OPEN_TIMEOUT,
OPT_PROFILING,
@@ -5897,7 +5902,9 @@ enum options_mysqld
OPT_LOG_SLOW_FILTER,
OPT_GENERAL_LOG_FILE,
OPT_SLOW_QUERY_LOG_FILE,
- OPT_IGNORE_BUILTIN_INNODB
+ OPT_IGNORE_BUILTIN_INNODB,
+ OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
+ OPT_DEFAULT_CHARACTER_SET_OLD
};
@@ -6050,10 +6057,11 @@ struct my_option my_long_options[] =
{"debug-flush", OPT_DEBUG_FLUSH, "Default debug log with flush after write",
(uchar**) 0, (uchar**) 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"default-character-set", 'C', "Set the default character set (deprecated option, use --character-set-server instead).",
+ {"default-character-set", OPT_DEFAULT_CHARACTER_SET_OLD,
+ "Set the default character set (deprecated option, use --character-set-server instead).",
(uchar**) &default_character_set_name, (uchar**) &default_character_set_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation (deprecated option, use --collation-server instead).",
+ {"default-collation", OPT_DEFAULT_COLLATION_OLD, "Set the default collation (deprecated option, use --collation-server instead).",
(uchar**) &default_collation_name, (uchar**) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"default-storage-engine", OPT_STORAGE_ENGINE,
@@ -6152,7 +6160,8 @@ Disable with --skip-large-pages.",
#endif
{"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed when a slave connects to this master",
+ {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed by a slave server \
+each time the SQL thread starts.",
(uchar**) &opt_init_slave, (uchar**) &opt_init_slave, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"language", 'L',
@@ -6192,7 +6201,7 @@ Disable with --skip-large-pages.",
compatibility; the behaviour was also changed to apply only to functions
(and triggers). In a future release this old name could be removed.
*/
- {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
+ {"log-bin-trust-routine-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD,
"(deprecated) Use log-bin-trust-function-creators.",
(uchar**) &trust_function_creators, (uchar**) &trust_function_creators, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -6745,7 +6754,7 @@ log and this option does nothing anymore.",
{"transaction-isolation", OPT_TX_ISOLATION,
"Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
- {"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; use --symbolic-links instead.",
+ {"use-symbolic-links", OPT_SYMBOLIC_LINKS, "Enable symbolic link support. Deprecated option; use --symbolic-links instead.",
(uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG,
IF_VALGRIND(0,1), 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
@@ -6755,7 +6764,7 @@ log and this option does nothing anymore.",
0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
- {"warnings", 'W', "Deprecated; use --log-warnings instead.",
+ {"warnings", OPT_WARNINGS, "Deprecated; use --log-warnings instead.",
(uchar**) &global_system_variables.log_warnings,
(uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG,
1, 0, (longlong) ULONG_MAX, 0, 0, 0},
@@ -7033,6 +7042,10 @@ The minimum value for this variable is 4096.",
(uchar**) &max_system_variables.myisam_max_sort_file_size, 0,
GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE,
0, 1024*1024, 0},
+ {"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE,
+ "Can be used to restrict the total memory used for memory mmaping of myisam files",
+ (uchar**) &myisam_mmap_size, (uchar**) &myisam_mmap_size, 0,
+ GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0},
{"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS,
"Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.",
(uchar**) &global_system_variables.myisam_repair_threads,
@@ -7180,8 +7193,8 @@ The minimum value for this variable is 4096.",
(uchar**) &max_system_variables.read_rnd_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
- {"record_buffer", OPT_RECORD_BUFFER,
- "Alias for read_buffer_size",
+ {"record_buffer", OPT_RECORD_BUFFER_OLD,
+ "Alias for read_buffer_size. This variable is deprecated and will be removed in a future release.",
(uchar**) &global_system_variables.read_buff_size,
(uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0},
@@ -7305,6 +7318,10 @@ The minimum value for this variable is 4096.",
(uchar**) &max_system_variables.net_wait_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT),
0, 1, 0},
+ {"binlog-direct-non-transactional-updates", OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
+ "Causes updates to non-transactional engines using statement format to be written directly to binary log. Before using this option make sure that there are no dependencies between transactional and non-transactional tables such as in the statement INSERT INTO t_myisam SELECT * FROM t_innodb; otherwise, slaves may diverge from the master.",
+ (uchar**) &global_system_variables.binlog_direct_non_trans_update, (uchar**) &max_system_variables.binlog_direct_non_trans_update, 0, GET_BOOL, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -8192,6 +8209,9 @@ mysqld_get_one_option(int optid,
opt_endinfo=1; /* unireg: memory allocation */
break;
#endif
+ case '0':
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-long-format", "--log-short-format");
+ break;
case 'a':
global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
@@ -8199,6 +8219,11 @@ mysqld_get_one_option(int optid,
case 'b':
strmake(mysql_home,argument,sizeof(mysql_home)-1);
break;
+ case OPT_DEFAULT_CHARACTER_SET_OLD: // --default-character-set
+ WARN_DEPRECATED(NULL, VER_CELOSIA,
+ "--default-character-set",
+ "--character-set-server");
+ /* Fall through */
case 'C':
if (default_collation_name == compiled_default_collation_name)
default_collation_name= 0;
@@ -8222,6 +8247,9 @@ mysqld_get_one_option(int optid,
case 'L':
strmake(language, argument, sizeof(language)-1);
break;
+ case 'O':
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--set-variable", "--variable-name=value");
+ break;
#ifdef HAVE_REPLICATION
case OPT_SLAVE_SKIP_ERRORS:
init_slave_skip_errors(argument);
@@ -8244,6 +8272,9 @@ mysqld_get_one_option(int optid,
print_version();
exit(0);
#endif /*EMBEDDED_LIBRARY*/
+ case OPT_WARNINGS:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--warnings", "--log-warnings");
+ /* Note: fall-through to 'W' */
case 'W':
if (!argument)
global_system_variables.log_warnings++;
@@ -8256,6 +8287,18 @@ mysqld_get_one_option(int optid,
test_flags= argument ? (uint) atoi(argument) : 0;
opt_endinfo=1;
break;
+ case (int) OPT_DEFAULT_COLLATION_OLD:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--default-collation", "--collation-server");
+ break;
+ case (int) OPT_SAFE_SHOW_DB:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--safe-show-database", "GRANT SHOW DATABASES");
+ break;
+ case (int) OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-bin-trust-routine-creators", "--log-bin-trust-function-creators");
+ break;
+ case (int) OPT_ENABLE_LOCK:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--enable-locking", "--external-locking");
+ break;
case (int) OPT_BIG_TABLES:
thd_startup_options|=OPTION_BIG_TABLES;
break;
@@ -8266,6 +8309,7 @@ mysqld_get_one_option(int optid,
opt_myisam_log=1;
break;
case (int) OPT_UPDATE_LOG:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-update", "--log-bin");
opt_update_log=1;
break;
case (int) OPT_BIN_LOG:
@@ -8437,8 +8481,18 @@ mysqld_get_one_option(int optid,
"give threads different priorities.");
break;
case (int) OPT_SKIP_LOCK:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-locking", "--skip-external-locking");
opt_external_locking=0;
break;
+ case (int) OPT_SQL_BIN_UPDATE_SAME:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--sql-bin-update-same", "the binary log");
+ break;
+ case (int) OPT_RECORD_BUFFER_OLD:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "record_buffer", "read_buffer_size");
+ break;
+ case (int) OPT_SYMBOLIC_LINKS:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--use-symbolic-links", "--symbolic-links");
+ break;
case (int) OPT_SKIP_HOST_CACHE:
opt_specialflag|= SPECIAL_NO_HOST_CACHE;
break;
@@ -8464,6 +8518,7 @@ mysqld_get_one_option(int optid,
test_flags|=TEST_NO_STACKTRACE;
break;
case (int) OPT_SKIP_SYMLINKS:
+ WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-symlink", "--skip-symbolic-links");
my_use_symdir=0;
break;
case (int) OPT_BIND_ADDRESS:
@@ -8558,6 +8613,9 @@ mysqld_get_one_option(int optid,
server_id_supplied = 1;
break;
case OPT_DELAY_KEY_WRITE_ALL:
+ WARN_DEPRECATED(NULL, VER_CELOSIA,
+ "--delay-key-write-for-all-tables",
+ "--delay-key-write=ALL");
if (argument != disabled_my_option)
argument= (char*) "ALL";
/* Fall through */
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index 5132f51bef6..719528a7728 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -59,10 +59,14 @@ injector::transaction::~transaction()
my_free(the_memory, MYF(0));
}
+/**
+ @retval 0 transaction committed
+ @retval 1 transaction rolled back
+ */
int injector::transaction::commit()
{
DBUG_ENTER("injector::transaction::commit()");
- m_thd->binlog_flush_pending_rows_event(true);
+ int error= m_thd->binlog_flush_pending_rows_event(true);
/*
Cluster replication does not preserve statement or
transaction boundaries of the master. Instead, a new
@@ -82,9 +86,9 @@ int injector::transaction::commit()
is committed by committing the statement transaction
explicitly.
*/
- ha_autocommit_or_rollback(m_thd, 0);
- end_trans(m_thd, COMMIT);
- DBUG_RETURN(0);
+ error |= ha_autocommit_or_rollback(m_thd, error);
+ end_trans(m_thd, error ? ROLLBACK : COMMIT);
+ DBUG_RETURN(error);
}
int injector::transaction::use_table(server_id_type sid, table tbl)
@@ -110,16 +114,17 @@ int injector::transaction::write_row (server_id_type sid, table tbl,
record_type record)
{
DBUG_ENTER("injector::transaction::write_row(...)");
-
- if (int error= check_state(ROW_STATE))
+
+ int error= check_state(ROW_STATE);
+ if (error)
DBUG_RETURN(error);
server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
- m_thd->binlog_write_row(tbl.get_table(), tbl.is_transactional(),
- cols, colcnt, record);
+ error= m_thd->binlog_write_row(tbl.get_table(), tbl.is_transactional(),
+ cols, colcnt, record);
m_thd->set_server_id(save_id);
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -129,15 +134,16 @@ int injector::transaction::delete_row(server_id_type sid, table tbl,
{
DBUG_ENTER("injector::transaction::delete_row(...)");
- if (int error= check_state(ROW_STATE))
+ int error= check_state(ROW_STATE);
+ if (error)
DBUG_RETURN(error);
server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
- m_thd->binlog_delete_row(tbl.get_table(), tbl.is_transactional(),
- cols, colcnt, record);
+ error= m_thd->binlog_delete_row(tbl.get_table(), tbl.is_transactional(),
+ cols, colcnt, record);
m_thd->set_server_id(save_id);
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -147,15 +153,16 @@ int injector::transaction::update_row(server_id_type sid, table tbl,
{
DBUG_ENTER("injector::transaction::update_row(...)");
- if (int error= check_state(ROW_STATE))
+ int error= check_state(ROW_STATE);
+ if (error)
DBUG_RETURN(error);
server_id_type save_id= m_thd->server_id;
m_thd->set_server_id(sid);
- m_thd->binlog_update_row(tbl.get_table(), tbl.is_transactional(),
- cols, colcnt, before, after);
+ error= m_thd->binlog_update_row(tbl.get_table(), tbl.is_transactional(),
+ cols, colcnt, before, after);
m_thd->set_server_id(save_id);
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 8f3a41fbeef..3a46bbcd6ee 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -231,6 +231,22 @@ unpack_row(Relay_log_info const *rli,
{
DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x",
null_mask, null_bits));
+ /**
+ Calling reset just in case one is unpacking on top a
+ record with data.
+
+ This could probably go into set_null() but doing so,
+ (i) triggers assertion in other parts of the code at
+ the moment; (ii) it would make us reset the field,
+ always when setting null, which right now doesn't seem
+ needed anywhere else except here.
+
+ TODO: maybe in the future we should consider moving
+ the reset to make it part of set_null. But then
+ the assertions triggered need to be
+ addressed/revisited.
+ */
+ f->reset();
f->set_null();
}
else
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index ddb4828877e..26daac1b629 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -177,10 +177,10 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
- if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) ||
+ if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE) ||
rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0,
(max_relay_log_size ? max_relay_log_size :
- max_binlog_size), 1))
+ max_binlog_size), 1, TRUE))
{
pthread_mutex_unlock(&rli->data_lock);
sql_print_error("Failed in open_log() called from init_relay_log_info()");
@@ -1017,7 +1017,7 @@ err:
false - condition not met
*/
-bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos)
+bool Relay_log_info::is_until_satisfied(THD *thd, Log_event *ev)
{
const char *log_name;
ulonglong log_pos;
@@ -1027,8 +1027,12 @@ bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos)
if (until_condition == UNTIL_MASTER_POS)
{
+ if (ev && ev->server_id == (uint32) ::server_id && !replicate_same_server_id)
+ DBUG_RETURN(FALSE);
log_name= group_master_log_name;
- log_pos= master_beg_pos;
+ log_pos= (!ev)? group_master_log_pos :
+ ((thd->options & OPTION_BEGIN || !ev->log_pos) ?
+ group_master_log_pos : ev->log_pos - ev->data_written);
}
else
{ /* until_condition == UNTIL_RELAY_POS */
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 49186091496..2c1f581e156 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -303,7 +303,7 @@ public:
void close_temporary_tables();
/* Check if UNTIL condition is satisfied. See slave.cc for more. */
- bool is_until_satisfied(my_off_t master_beg_pos);
+ bool is_until_satisfied(THD *thd, Log_event *ev);
inline ulonglong until_pos()
{
return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos :
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 1f4ca246ff1..d011e9aade8 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -95,6 +95,7 @@ public:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_GEOMETRY:
{
/*
These types store a single byte.
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 0ec1f04a370..c64f6f3d7a3 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -151,6 +151,7 @@ static void sys_default_general_log_path(THD *thd, enum_var_type type);
static bool sys_update_slow_log_path(THD *thd, set_var * var);
static void sys_default_slow_log_path(THD *thd, enum_var_type type);
static void fix_sys_log_slow_filter(THD *thd, enum_var_type);
+static uchar *get_myisam_mmap_size(THD *thd);
/*
Variable definition list
@@ -184,6 +185,8 @@ static sys_var_long_ptr sys_binlog_cache_size(&vars, "binlog_cache_size",
&binlog_cache_size);
static sys_var_thd_binlog_format sys_binlog_format(&vars, "binlog_format",
&SV::binlog_format);
+static sys_var_thd_bool sys_binlog_direct_non_trans_update(&vars, "binlog_direct_non_transactional_updates",
+ &SV::binlog_direct_non_trans_update);
static sys_var_thd_ulong sys_bulk_insert_buff_size(&vars, "bulk_insert_buffer_size",
&SV::bulk_insert_buff_size);
static sys_var_const_os sys_character_sets_dir(&vars,
@@ -939,6 +942,10 @@ sys_var_str sys_var_slow_log_path(&vars, "slow_query_log_file", sys_check_log_pa
opt_slow_logname);
static sys_var_log_output sys_var_log_output_state(&vars, "log_output", &log_output_options,
&log_output_typelib, 0);
+static sys_var_readonly sys_myisam_mmap_size(&vars, "myisam_mmap_size",
+ OPT_GLOBAL,
+ SHOW_LONGLONG,
+ get_myisam_mmap_size);
bool sys_var::check(THD *thd, set_var *var)
@@ -3275,6 +3282,12 @@ static uchar *get_tmpdir(THD *thd)
return (uchar*)mysql_tmpdir;
}
+static uchar *get_myisam_mmap_size(THD *thd)
+{
+ return (uchar *)&myisam_mmap_size;
+}
+
+
/****************************************************************************
Main handling of variables:
- Initialisation
@@ -4183,7 +4196,7 @@ bool process_key_caches(process_key_cache_t func)
void sys_var_trust_routine_creators::warn_deprecated(THD *thd)
{
- WARN_DEPRECATED(thd, "6.0", "@@log_bin_trust_routine_creators",
+ WARN_DEPRECATED(thd, VER_CELOSIA, "@@log_bin_trust_routine_creators",
"'@@log_bin_trust_function_creators'");
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 68ed876f793..093d345ba38 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5138,11 +5138,11 @@ ER_SP_BADSTATEMENT 0A000
eng "%s is not allowed in stored procedures"
ger "%s ist in gespeicherten Prozeduren nicht erlaubt"
ER_UPDATE_LOG_DEPRECATED_IGNORED 42000
- eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored"
- ger "Das Update-Log ist veraltet und wurde durch das Bin�r-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert"
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6."
+ ger "Das Update-Log ist veraltet und wurde durch das Bin�r-Log ersetzt. SET SQL_LOG_UPDATE wird ignoriert. Diese Option wird in MySQL 5.6 entfernt."
ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000
- eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN"
- ger "Das Update-Log ist veraltet und wurde durch das Bin�r-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN �bersetzt"
+ eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6."
+ ger "Das Update-Log ist veraltet und wurde durch das Bin�r-Log ersetzt. SET SQL_LOG_UPDATE wurde in SET SQL_LOG_BIN �bersetzt. Diese Option wird in MySQL 5.6 entfernt."
ER_QUERY_INTERRUPTED 70100
eng "Query execution was interrupted"
ger "Ausf�hrung der Abfrage wurde unterbrochen"
@@ -5696,8 +5696,8 @@ ER_PARTITION_WRONG_NO_SUBPART_ERROR
eng "Wrong number of subpartitions defined, mismatch with previous setting"
ger "Falsche Anzahl von Unterpartitionen definiert, stimmt nicht mit vorherigen Einstellungen �berein"
swe "Antal subpartitioner definierade och antal subpartitioner �r inte lika"
-ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR
- eng "Constant/Random expression in (sub)partitioning function is not allowed"
+ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
+ eng "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed"
ger "Konstante oder Random-Ausdr�cke in (Unter-)Partitionsfunktionen sind nicht erlaubt"
swe "Konstanta uttryck eller slumpm�ssiga uttryck �r inte till�tna (sub)partitioneringsfunktioner"
ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR
diff --git a/sql/slave.cc b/sql/slave.cc
index e4fd07de44b..3a62785886d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2218,9 +2218,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
hits the UNTIL barrier.
*/
if (rli->until_condition != Relay_log_info::UNTIL_NONE &&
- rli->is_until_satisfied((rli->is_in_group() || !ev->log_pos) ?
- rli->group_master_log_pos :
- ev->log_pos - ev->data_written))
+ rli->is_until_satisfied(thd, ev))
{
char buf[22];
sql_print_information("Slave SQL thread stopped because it reached its"
@@ -2963,7 +2961,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
*/
pthread_mutex_lock(&rli->data_lock);
if (rli->until_condition != Relay_log_info::UNTIL_NONE &&
- rli->is_until_satisfied(rli->group_master_log_pos))
+ rli->is_until_satisfied(thd, NULL))
{
char buf[22];
sql_print_information("Slave SQL thread stopped because it reached its"
diff --git a/sql/sp.cc b/sql/sp.cc
index d3c5dfb96d0..f0508142557 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -896,10 +896,13 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
bool store_failed= FALSE;
+ bool save_binlog_row_based;
+
DBUG_ENTER("sp_create_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length,
sp->m_name.str));
String retstr(64);
+ retstr.set_charset(system_charset_info);
DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE ||
type == TYPE_ENUM_FUNCTION);
@@ -912,6 +915,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
saved_count_cuted_fields= thd->count_cuted_fields;
@@ -1104,9 +1108,10 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
/* restore sql_mode when binloging */
thd->variables.sql_mode= saved_mode;
/* Such a statement can always go directly to binlog, no trans cache */
- thd->binlog_query(THD::MYSQL_QUERY_TYPE,
- log_query.c_ptr(), log_query.length(),
- FALSE, FALSE, 0);
+ if (thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+ log_query.c_ptr(), log_query.length(),
+ FALSE, FALSE, 0))
+ ret= SP_INTERNAL_ERROR;
thd->variables.sql_mode= 0;
}
@@ -1117,6 +1122,8 @@ done:
thd->variables.sql_mode= saved_mode;
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -1141,6 +1148,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
{
TABLE *table;
int ret;
+ bool save_binlog_row_based;
DBUG_ENTER("sp_drop_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, (int) name->m_name.length, name->m_name.str));
@@ -1153,6 +1161,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
if (!(table= open_proc_table_for_update(thd)))
@@ -1165,11 +1174,14 @@ sp_drop_routine(THD *thd, int type, sp_name *name)
if (ret == SP_OK)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ ret= SP_INTERNAL_ERROR;
sp_cache_invalidate();
}
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -1196,6 +1208,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
{
TABLE *table;
int ret;
+ bool save_binlog_row_based;
DBUG_ENTER("sp_update_routine");
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, (int) name->m_name.length, name->m_name.str));
@@ -1207,6 +1220,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
if (!(table= open_proc_table_for_update(thd)))
@@ -1235,11 +1249,14 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
if (ret == SP_OK)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ ret= SP_INTERNAL_ERROR;
sp_cache_invalidate();
}
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(ret);
}
@@ -1403,6 +1420,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
64 -- size of "returns" column of mysql.proc.
*/
String retstr(64);
+ retstr.set_charset(sp->get_creation_ctx()->get_client_cs());
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
if (sp->m_first_free_instance)
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8662f1b799e..25cd1d8a9b4 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1790,6 +1790,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
"Invoked ROUTINE modified a transactional table but MySQL "
"failed to reflect this change in the binary log");
+ err_status= TRUE;
}
reset_dynamic(&thd->user_var_events);
/* Forget those values, in case more function calls are binlogged: */
@@ -2772,8 +2773,15 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
m_lex->mark_as_requiring_prelocking(NULL);
}
thd->rollback_item_tree_changes();
- /* Update the state of the active arena. */
- thd->stmt_arena->state= Query_arena::EXECUTED;
+ /*
+ Update the state of the active arena if no errors on
+ open_tables stage.
+ */
+ if (!res || !thd->is_error() ||
+ (thd->main_da.sql_errno() != ER_CANT_REOPEN_TABLE &&
+ thd->main_da.sql_errno() != ER_NO_SUCH_TABLE &&
+ thd->main_da.sql_errno() != ER_UPDATE_TABLE_USED))
+ thd->stmt_arena->state= Query_arena::EXECUTED;
/*
Merge here with the saved parent's values
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 3145ba2fea4..75e55880e60 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -71,7 +71,7 @@ typedef struct sp_label
typedef struct sp_cond_type
{
enum { number, state, warning, notfound, exception } type;
- char sqlstate[6];
+ char sqlstate[SQLSTATE_LENGTH+1];
uint mysqlerr;
} sp_cond_type_t;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 54910a5ff58..ce91f83ce85 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -310,7 +310,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{
TABLE *table;
READ_RECORD read_record_info;
- my_bool return_val= 1;
+ my_bool return_val= TRUE;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
int password_length;
@@ -623,7 +623,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
init_check_host();
initialized=1;
- return_val=0;
+ return_val= FALSE;
end:
thd->variables.sql_mode= old_sql_mode;
@@ -674,7 +674,7 @@ my_bool acl_reload(THD *thd)
DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
MEM_ROOT old_mem;
bool old_initialized;
- my_bool return_val= 1;
+ my_bool return_val= TRUE;
DBUG_ENTER("acl_reload");
if (thd->locked_tables)
@@ -701,8 +701,13 @@ my_bool acl_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
- sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
- thd->main_da.message());
+ /*
+ Execution might have been interrupted; only print the error message
+ if an error condition has been raised.
+ */
+ if (thd->main_da.is_error())
+ sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
+ thd->main_da.message());
goto end;
}
@@ -1061,7 +1066,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
*mqh= acl_user->user_resource;
if (acl_user->host.hostname)
- strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
else
*sctx->priv_host= 0;
}
@@ -1162,7 +1167,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
sctx->priv_user= acl_user->user ? user : (char *) "";
if (acl_user->host.hostname)
- strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
else
*sctx->priv_host= 0;
}
@@ -1655,8 +1660,8 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
thd->clear_error();
- thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
- FALSE, FALSE, 0);
+ result= thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
+ FALSE, FALSE, 0);
}
end:
close_thread_tables(thd);
@@ -2974,6 +2979,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
TABLE_LIST tables[3];
bool create_new_users=0;
char *db_name, *table_name;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_table_grant");
if (!initialized)
@@ -3069,6 +3075,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
#ifdef HAVE_REPLICATION
@@ -3084,7 +3091,11 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
*/
tables[0].updating= tables[1].updating= tables[2].updating= 1;
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(FALSE);
+ }
}
#endif
@@ -3097,6 +3108,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (simple_open_n_lock_tables(thd,tables))
{ // Should never happen
close_thread_tables(thd); /* purecov: deadcode */
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(TRUE); /* purecov: deadcode */
}
@@ -3213,7 +3226,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (!result) /* success */
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
rw_unlock(&LOCK_grant);
@@ -3223,6 +3236,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* Tables are automatically closed */
thd->lex->restore_backup_query_tables_list(&backup);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result);
}
@@ -3251,6 +3266,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
TABLE_LIST tables[2];
bool create_new_users=0, result=0;
char *db_name, *table_name;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_routine_grant");
if (!initialized)
@@ -3286,6 +3302,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
#ifdef HAVE_REPLICATION
@@ -3301,13 +3318,19 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
*/
tables[0].updating= tables[1].updating= 1;
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(FALSE);
+ }
}
#endif
if (simple_open_n_lock_tables(thd,tables))
{ // Should never happen
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(TRUE);
}
@@ -3379,10 +3402,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
if (write_to_binlog)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
+ result= TRUE;
}
rw_unlock(&LOCK_grant);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
/* Tables are automatically closed */
DBUG_RETURN(result);
@@ -3397,6 +3423,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
char tmp_db[NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_grant");
if (!initialized)
{
@@ -3425,6 +3452,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
#ifdef HAVE_REPLICATION
@@ -3440,13 +3468,19 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
*/
tables[0].updating= tables[1].updating= 1;
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(FALSE);
+ }
}
#endif
if (simple_open_n_lock_tables(thd,tables))
{ // This should never happen
close_thread_tables(thd); /* purecov: deadcode */
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(TRUE); /* purecov: deadcode */
}
@@ -3498,7 +3532,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
if (!result)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
rw_unlock(&LOCK_grant);
@@ -3506,6 +3540,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
if (!result)
my_ok(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result);
}
@@ -3766,11 +3802,11 @@ static my_bool grant_reload_procs_priv(THD *thd)
DBUG_RETURN(TRUE);
}
+ rw_wrlock(&LOCK_grant);
/* Save a copy of the current hash if we need to undo the grant load */
old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash;
- rw_wrlock(&LOCK_grant);
if ((return_val= grant_load_procs_priv(table.table)))
{
/* Error; Reverting to old hash */
@@ -5661,6 +5697,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
bool some_users_created= FALSE;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_create_user");
/*
@@ -5668,11 +5705,16 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
/* CREATE USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result != 1);
+ }
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -5710,10 +5752,12 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
if (some_users_created)
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result);
}
@@ -5740,6 +5784,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
bool some_users_deleted= FALSE;
ulong old_sql_mode= thd->variables.sql_mode;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_drop_user");
/*
@@ -5747,11 +5792,16 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
/* DROP USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result != 1);
+ }
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
@@ -5783,11 +5833,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
if (some_users_deleted)
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
thd->variables.sql_mode= old_sql_mode;
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result);
}
@@ -5814,6 +5866,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
bool some_users_renamed= FALSE;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_rename_user");
/*
@@ -5821,11 +5874,16 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
/* RENAME USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result != 1);
+ }
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -5868,10 +5926,12 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
if (some_users_renamed && mysql_bin_log.is_open())
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result);
}
@@ -5896,6 +5956,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
int result;
ACL_DB *acl_db;
TABLE_LIST tables[GRANT_TABLES];
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_revoke_all");
/*
@@ -5903,10 +5964,15 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
if ((result= open_grant_tables(thd, tables)))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(result != 1);
+ }
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -6050,15 +6116,19 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ int binlog_error=
+ write_bin_log(thd, FALSE, thd->query(), thd->query_length());
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
- if (result)
+ /* error for writing binary log has already been reported */
+ if (result && !binlog_error)
my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
- DBUG_RETURN(result);
+ DBUG_RETURN(result || binlog_error);
}
@@ -6140,6 +6210,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
TABLE_LIST tables[GRANT_TABLES];
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
Silence_routine_definer_errors error_handler;
+ bool save_binlog_row_based;
DBUG_ENTER("sp_revoke_privileges");
if ((result= open_grant_tables(thd, tables)))
@@ -6156,6 +6227,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
row-based replication. The flag will be reset at the end of the
statement.
*/
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
thd->clear_current_stmt_binlog_row_based();
/* Remove procedure access */
@@ -6192,6 +6264,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
close_thread_tables(thd);
thd->pop_internal_handler();
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(error_handler.has_errors());
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8cc0b1574a3..1da17c216f2 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1336,7 +1336,7 @@ void close_thread_tables(THD *thd)
handled either before writing a query log event (inside
binlog_query()) or when preparing a pending event.
*/
- thd->binlog_flush_pending_rows_event(TRUE);
+ (void)thd->binlog_flush_pending_rows_event(TRUE);
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
@@ -1550,7 +1550,11 @@ void close_temporary_tables(THD *thd)
qinfo.db= db.ptr();
qinfo.db_len= db.length();
thd->variables.character_set_client= cs_save;
- mysql_bin_log.write(&qinfo);
+ if (mysql_bin_log.write(&qinfo))
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, MYF(0),
+ "Failed to write the DROP statement for temporary tables to binary log");
+ }
thd->variables.pseudo_thread_id= save_pseudo_thread_id;
}
else
@@ -4049,9 +4053,13 @@ retry:
end = strxmov(strmov(query, "DELETE FROM `"),
share->db.str,"`.`",share->table_name.str,"`", NullS);
int errcode= query_error_code(thd, TRUE);
- thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, (ulong)(end-query),
- FALSE, FALSE, errcode);
+ if (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ query, (ulong)(end-query),
+ FALSE, FALSE, errcode))
+ {
+ my_free(query, MYF(0));
+ goto err;
+ }
my_free(query, MYF(0));
}
else
@@ -5698,7 +5706,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
if (!my_strcasecmp(system_charset_info, field_it.name(), name))
{
// in PS use own arena or data will be freed after prepare
- if (register_tree_change && thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
+ if (register_tree_change &&
+ thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute())
arena= thd->activate_stmt_arena_if_needed(&backup);
/*
create_item() may, or may not create a new Item, depending on
diff --git a/sql/sql_class.h b/sql/sql_class.h
index dc19f3d24ba..841acae0bf8 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -359,6 +359,7 @@ struct system_variables
ulong ndb_index_stat_cache_entries;
ulong ndb_index_stat_update_freq;
ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
+ my_bool binlog_direct_non_trans_update;
/*
In slave thread we need to know in behalf of which
thread the query is being run to replicate temp tables properly
@@ -558,6 +559,8 @@ public:
{ return state == INITIALIZED_FOR_SP; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; }
+ inline bool is_stmt_prepare_or_first_stmt_execute() const
+ { return (int)state <= (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline bool is_stmt_execute() const
{ return state == PREPARED || state == EXECUTED; }
@@ -2636,7 +2639,7 @@ public:
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- void binlog_show_create_table(TABLE **tables, uint count);
+ int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 0de2c2d210a..88023bb8e71 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -710,7 +710,7 @@ static int check_connection(THD *thd)
ulong server_capabilites;
{
/* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
+ char buff[SERVER_VERSION_LENGTH + 1 + SCRAMBLE_LENGTH + 1 + 64];
server_capabilites= CLIENT_BASIC_FLAGS;
if (opt_using_transactions)
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 4b5c0a66e43..110083fda36 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -28,14 +28,7 @@
#include "mysql_priv.h"
-SQL_CRYPT::SQL_CRYPT(const char *password, uint length)
-{
- ulong rand_nr[2];
- hash_password(rand_nr,password, length);
- crypt_init(rand_nr);
-}
-
-void SQL_CRYPT::crypt_init(ulong *rand_nr)
+void SQL_CRYPT::init(ulong *rand_nr)
{
uint i;
my_rnd_init(&rand,rand_nr[0],rand_nr[1]);
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index 50ff1217193..7e16807cad9 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -23,15 +23,15 @@ class SQL_CRYPT :public Sql_alloc
struct my_rnd_struct rand,org_rand;
char decode_buff[256],encode_buff[256];
uint shift;
- void crypt_init(ulong *seed);
public:
- SQL_CRYPT(const char *seed, uint length);
+ SQL_CRYPT() {}
SQL_CRYPT(ulong *seed)
{
- crypt_init(seed);
+ init(seed);
}
~SQL_CRYPT() {}
- void init() { shift=0; rand=org_rand; }
+ void init(ulong *seed);
+ void reinit() { shift=0; rand=org_rand; }
void encode(char *str, uint length);
void decode(char *str, uint length);
};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index adc1aab9976..94be8a5f240 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -178,13 +178,13 @@ uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
Helper function to write a query to binlog used by mysql_rm_db()
*/
-static inline void write_to_binlog(THD *thd, char *query, uint q_len,
- char *db, uint db_len)
+static inline int write_to_binlog(THD *thd, char *query, uint q_len,
+ char *db, uint db_len)
{
Query_log_event qinfo(thd, query, q_len, 0, 0, 0);
qinfo.db= db;
qinfo.db_len= db_len;
- mysql_bin_log.write(&qinfo);
+ return mysql_bin_log.write(&qinfo);
}
@@ -618,7 +618,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_ENTER("mysql_create_db");
/* do not create 'information_schema' db */
- if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
+ if (is_schema_db(db))
{
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
@@ -695,6 +695,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
file. In this case it's best to just continue as if nothing has
happened. (This is a very unlikely senario)
*/
+ thd->clear_error();
}
not_silent:
@@ -746,7 +747,11 @@ not_silent:
qinfo.db_len = strlen(db);
/* These DDL methods and logging protected with LOCK_mysql_create_db */
- mysql_bin_log.write(&qinfo);
+ if (mysql_bin_log.write(&qinfo))
+ {
+ error= -1;
+ goto exit;
+ }
}
my_ok(thd, result);
}
@@ -810,9 +815,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if (mysql_bin_log.is_open())
{
- int errcode= query_error_code(thd, TRUE);
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0,
- /* suppress_use */ TRUE, errcode);
+ /* suppress_use */ TRUE, 0);
/*
Write should use the database being created as the "current
@@ -822,9 +827,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
qinfo.db = db;
qinfo.db_len = strlen(db);
- thd->clear_error();
/* These DDL methods and logging protected with LOCK_mysql_create_db */
- mysql_bin_log.write(&qinfo);
+ if ((error= mysql_bin_log.write(&qinfo)))
+ goto exit;
}
my_ok(thd, result);
@@ -962,9 +967,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
if (mysql_bin_log.is_open())
{
- int errcode= query_error_code(thd, TRUE);
+ thd->clear_error();
Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE, errcode);
+ /* suppress_use */ TRUE, 0);
/*
Write should use the database being created as the "current
database" and not the threads current database, which is the
@@ -973,9 +978,12 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
qinfo.db = db;
qinfo.db_len = strlen(db);
- thd->clear_error();
/* These DDL methods and logging protected with LOCK_mysql_create_db */
- mysql_bin_log.write(&qinfo);
+ if (mysql_bin_log.write(&qinfo))
+ {
+ error= -1;
+ goto exit;
+ }
}
thd->clear_error();
thd->server_status|= SERVER_STATUS_DB_DROPPED;
@@ -1003,7 +1011,11 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (query_pos + tbl_name_len + 1 >= query_end)
{
/* These DDL methods and logging protected with LOCK_mysql_create_db */
- write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
+ if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
+ {
+ error= -1;
+ goto exit;
+ }
query_pos= query_data_start;
}
@@ -1016,7 +1028,11 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (query_pos != query_data_start)
{
/* These DDL methods and logging protected with LOCK_mysql_create_db */
- write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
+ if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len))
+ {
+ error= -1;
+ goto exit;
+ }
}
}
@@ -1554,8 +1570,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
}
}
- if (my_strcasecmp(system_charset_info, new_db_name->str,
- INFORMATION_SCHEMA_NAME.str) == 0)
+ if (is_schema_db(new_db_name->str, new_db_name->length))
{
/* Switch the current database to INFORMATION_SCHEMA. */
@@ -1963,7 +1978,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
Query_log_event qinfo(thd, thd->query(), thd->query_length(),
0, TRUE, errcode);
thd->clear_error();
- mysql_bin_log.write(&qinfo);
+ error|= mysql_bin_log.write(&qinfo);
}
/* Step9: Let's do "use newdb" if we renamed the current database */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index cea9b2857e2..0404e552dfc 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -850,9 +850,10 @@ void multi_delete::abort()
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode);
+ /* possible error of writing binary log is ignored deliberately */
+ (void) thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ transactional_tables, FALSE, errcode);
}
thd->transaction.all.modified_non_trans_table= true;
}
@@ -1176,8 +1177,9 @@ end:
{
/* In RBR, the statement is not binlogged if the table is temporary. */
if (!is_temporary_table || !thd->current_stmt_binlog_row_based)
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- my_ok(thd); // This should return record count
+ error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (!error)
+ my_ok(thd); // This should return record count
}
VOID(pthread_mutex_lock(&LOCK_open));
unlock_table_name(thd, table_list);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index dfef1364a3f..fc53529da37 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -807,12 +807,21 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
restore_record(table,s->default_values); // Get empty record
else
{
+ TABLE_SHARE *share= table->s;
+
/*
Fix delete marker. No need to restore rest of record since it will
be overwritten by fill_record() anyway (and fill_record() does not
use default values in this case).
*/
- table->record[0][0]= table->s->default_values[0];
+ table->record[0][0]= share->default_values[0];
+
+ /* Fix undefined null_bits. */
+ if (share->null_bytes > 1 && share->last_null_bit_pos)
+ {
+ table->record[0][share->null_bytes - 1]=
+ share->default_values[share->null_bytes - 1];
+ }
}
if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
table->triggers,
@@ -2765,10 +2774,11 @@ bool Delayed_insert::handle_inserts(void)
will be binlogged together as one single Table_map event and one
single Rows event.
*/
- thd.binlog_query(THD::ROW_QUERY_TYPE,
- row->query.str, row->query.length,
- FALSE, FALSE, errcode);
-
+ if (thd.binlog_query(THD::ROW_QUERY_TYPE,
+ row->query.str, row->query.length,
+ FALSE, FALSE, errcode))
+ goto err;
+
thd.time_zone_used = backup_time_zone_used;
thd.variables.time_zone = backup_time_zone;
}
@@ -2837,8 +2847,9 @@ bool Delayed_insert::handle_inserts(void)
TODO: Move the logging to last in the sequence of rows.
*/
- if (thd.current_stmt_binlog_row_based)
- thd.binlog_flush_pending_rows_event(TRUE);
+ if (thd.current_stmt_binlog_row_based &&
+ thd.binlog_flush_pending_rows_event(TRUE))
+ goto err;
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{ // This shouldn't happen
@@ -3289,16 +3300,21 @@ bool select_insert::send_eof()
events are in the transaction cache and will be written when
ha_autocommit_or_rollback() is issued below.
*/
- if (mysql_bin_log.is_open())
+ if (mysql_bin_log.is_open() &&
+ (!error || thd->transaction.stmt.modified_non_trans_table))
{
int errcode= 0;
if (!error)
thd->clear_error();
else
errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
- thd->binlog_query(THD::ROW_QUERY_TYPE,
+ if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query(), thd->query_length(),
- trans_table, FALSE, errcode);
+ trans_table, FALSE, errcode))
+ {
+ table->file->ha_release_auto_increment();
+ DBUG_RETURN(1);
+ }
}
table->file->ha_release_auto_increment();
@@ -3367,9 +3383,10 @@ void select_insert::abort() {
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
- thd->query_length(),
- transactional_table, FALSE, errcode);
+ /* error of writing binary log is ignored */
+ (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(),
+ thd->query_length(),
+ transactional_table, FALSE, errcode);
}
if (!thd->current_stmt_binlog_row_based && !can_rollback_data())
thd->transaction.all.modified_non_trans_table= TRUE;
@@ -3633,7 +3650,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
!table->s->tmp_table &&
!ptr->get_create_info()->table_existed)
{
- ptr->binlog_show_create_table(tables, count);
+ if (int error= ptr->binlog_show_create_table(tables, count))
+ return error;
}
return 0;
}
@@ -3740,7 +3758,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_RETURN(0);
}
-void
+int
select_create::binlog_show_create_table(TABLE **tables, uint count)
{
/*
@@ -3779,12 +3797,13 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
if (mysql_bin_log.is_open())
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- thd->binlog_query(THD::STMT_QUERY_TYPE,
- query.ptr(), query.length(),
- /* is_trans */ TRUE,
- /* suppress_use */ FALSE,
- errcode);
+ result= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ query.ptr(), query.length(),
+ /* is_trans */ TRUE,
+ /* suppress_use */ FALSE,
+ errcode);
}
+ return result;
}
void select_create::store_values(List<Item> &values)
@@ -3882,7 +3901,8 @@ void select_create::abort()
select_insert::abort();
thd->transaction.stmt.modified_non_trans_table= FALSE;
reenable_binlog(thd);
- thd->binlog_flush_pending_rows_event(TRUE);
+ /* possible error of writing binary log is ignored deliberately */
+ (void)thd->binlog_flush_pending_rows_event(TRUE);
if (m_plock)
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index d9c3868092c..82cc8f81b4a 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -122,7 +122,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
char name[FN_REFLEN];
File file;
TABLE *table= NULL;
- int error;
+ int error= 0;
String *field_term=ex->field_term,*escaped=ex->escaped;
String *enclosed=ex->enclosed;
bool is_fifo=0;
@@ -504,18 +504,20 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
+ /* since there is already an error, the possible error of
+ writing binary log will be ignored */
if (thd->transaction.stmt.modified_non_trans_table)
- write_execute_load_query_log_event(thd, ex,
- table_list->db,
- table_list->table_name,
- handle_duplicates, ignore,
- transactional_table,
- errcode);
+ (void) write_execute_load_query_log_event(thd, ex,
+ table_list->db,
+ table_list->table_name,
+ handle_duplicates, ignore,
+ transactional_table,
+ errcode);
else
{
Delete_file_log_event d(thd, db, transactional_table);
d.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
- mysql_bin_log.write(&d);
+ (void) mysql_bin_log.write(&d);
}
}
}
@@ -541,7 +543,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
after this point.
*/
if (thd->current_stmt_binlog_row_based)
- thd->binlog_flush_pending_rows_event(true);
+ error= thd->binlog_flush_pending_rows_event(true);
else
{
/*
@@ -553,13 +555,15 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (lf_info.wrote_create_file)
{
int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
- write_execute_load_query_log_event(thd, ex,
- table_list->db, table_list->table_name,
- handle_duplicates, ignore,
- transactional_table,
- errcode);
+ error= write_execute_load_query_log_event(thd, ex,
+ table_list->db, table_list->table_name,
+ handle_duplicates, ignore,
+ transactional_table,
+ errcode);
}
}
+ if (error)
+ goto err;
}
#endif /*!EMBEDDED_LIBRARY*/
@@ -640,7 +644,11 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
if (n++)
pfields.append(", ");
if (item->name)
+ {
+ pfields.append("`");
pfields.append(item->name);
+ pfields.append("`");
+ }
else
item->print(&pfields, QT_ORDINARY);
}
@@ -660,7 +668,9 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
val= lv++;
if (n++)
pfields.append(", ");
+ pfields.append("`");
pfields.append(item->name);
+ pfields.append("`");
pfields.append("=");
val->print(&pfields, QT_ORDINARY);
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9c222837f81..9503e8a5d81 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -626,8 +626,10 @@ void free_items(Item *item)
DBUG_VOID_RETURN;
}
-/* This works because items are allocated with sql_alloc() */
-
+/**
+ This works because items are allocated with sql_alloc().
+ @note The function also handles null pointers (empty list).
+*/
void cleanup_items(Item *item)
{
DBUG_ENTER("cleanup_items");
@@ -1323,8 +1325,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
table_list.alias= table_list.table_name= conv_name.str;
packet= arg_end + 1;
- if (!my_strcasecmp(system_charset_info, table_list.db,
- INFORMATION_SCHEMA_NAME.str))
+ if (is_schema_db(table_list.db, table_list.db_length))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
if (schema_table)
@@ -1386,7 +1387,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
- is_schema_db(db.str)))
+ is_schema_db(db.str, db.length)))
break;
general_log_print(thd, command, "%.*s", db.length, db.str);
bzero(&create_info, sizeof(create_info));
@@ -1405,7 +1406,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_error(ER_WRONG_DB_NAME, MYF(0), db.str ? db.str : "NULL");
break;
}
- if (check_access(thd, DROP_ACL, db.str, 0, 1, 0, is_schema_db(db.str)))
+ if (check_access(thd, DROP_ACL, db.str, 0, 1, 0,
+ is_schema_db(db.str, db.length)))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -2710,6 +2712,8 @@ mysql_execute_command(THD *thd)
{
lex->link_first_table_back(create_table, link_to_local);
create_table->create= TRUE;
+ /* Base table and temporary table are not in the same name space. */
+ create_table->skip_temporary= 1;
}
if (!(res= open_and_lock_tables(thd, lex->query_tables)))
@@ -3041,7 +3045,7 @@ end_with_restore_list:
/*
Presumably, REPAIR and binlog writing doesn't require synchronization
*/
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
@@ -3075,7 +3079,7 @@ end_with_restore_list:
/*
Presumably, ANALYZE and binlog writing doesn't require synchronization
*/
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
@@ -3099,7 +3103,7 @@ end_with_restore_list:
/*
Presumably, OPTIMIZE and binlog writing doesn't require synchronization
*/
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
select_lex->table_list.first= (uchar*) first_table;
lex->query_tables=all_tables;
@@ -3216,7 +3220,7 @@ end_with_restore_list:
if (incident)
{
Incident_log_event ev(thd, incident);
- mysql_bin_log.write(&ev);
+ (void) mysql_bin_log.write(&ev); /* error is ignored */
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
}
DBUG_PRINT("debug", ("Just after generate_incident()"));
@@ -3409,9 +3413,9 @@ end_with_restore_list:
select_lex->where,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
- select_lex->options | thd->options |
+ (select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
- OPTION_SETUP_TABLES_DONE,
+ OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT,
del_result, unit, select_lex);
res|= thd->is_error();
if (res)
@@ -3434,17 +3438,6 @@ end_with_restore_list:
}
else
{
- /*
- If this is a slave thread, we may sometimes execute some
- DROP / * 40005 TEMPORARY * / TABLE
- that come from parts of binlogs (likely if we use RESET SLAVE or CHANGE
- MASTER TO), while the temporary table has already been dropped.
- To not generate such irrelevant "table does not exist errors",
- we silently add IF EXISTS if TEMPORARY was used.
- */
- if (thd->slave_thread)
- lex->drop_if_exists= 1;
-
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->options|= OPTION_KEEP_LOG;
}
@@ -3658,7 +3651,7 @@ end_with_restore_list:
}
#endif
if (check_access(thd,CREATE_ACL,lex->name.str, 0, 1, 0,
- is_schema_db(lex->name.str)))
+ is_schema_db(lex->name.str, lex->name.length)))
break;
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
lex->name.str), &create_info, 0);
@@ -3693,7 +3686,7 @@ end_with_restore_list:
}
#endif
if (check_access(thd,DROP_ACL,lex->name.str,0,1,0,
- is_schema_db(lex->name.str)))
+ is_schema_db(lex->name.str, lex->name.length)))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -3727,9 +3720,12 @@ end_with_restore_list:
my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
break;
}
- if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
- check_access(thd, DROP_ACL, db->str, 0, 1, 0, is_schema_db(db->str)) ||
- check_access(thd, CREATE_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
+ if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
+ is_schema_db(db->str, db->length)) ||
+ check_access(thd, DROP_ACL, db->str, 0, 1, 0,
+ is_schema_db(db->str, db->length)) ||
+ check_access(thd, CREATE_ACL, db->str, 0, 1, 0,
+ is_schema_db(db->str, db->length)))
{
res= 1;
break;
@@ -3772,7 +3768,8 @@ end_with_restore_list:
break;
}
#endif
- if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0, is_schema_db(db->str)))
+ if (check_access(thd, ALTER_ACL, db->str, 0, 1, 0,
+ is_schema_db(db->str, db->length)))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -3928,7 +3925,8 @@ end_with_restore_list:
first_table ? &first_table->grant.privilege : 0,
first_table ? 0 : 1, 0,
first_table ? (bool) first_table->schema_table :
- select_lex->db ? is_schema_db(select_lex->db) : 0))
+ select_lex->db ?
+ is_schema_db(select_lex->db) : 0))
goto error;
if (thd->security_ctx->user) // If not replication
@@ -4051,7 +4049,8 @@ end_with_restore_list:
*/
if (!lex->no_write_to_binlog && write_to_binlog)
{
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length())))
+ break;
}
my_ok(thd);
}
@@ -4271,7 +4270,8 @@ end_with_restore_list:
}
if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
- is_schema_db(lex->sphead->m_db.str)))
+ is_schema_db(lex->sphead->m_db.str,
+ lex->sphead->m_db.length)))
goto create_sp_error;
if (end_active_trans(thd))
@@ -4628,12 +4628,12 @@ create_sp_error:
case SP_KEY_NOT_FOUND:
if (lex->drop_if_exists)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
SP_COM_STRING(lex), lex->spname->m_name.str);
- res= FALSE;
- my_ok(thd);
+ if (!res)
+ my_ok(thd);
break;
}
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
@@ -4926,7 +4926,8 @@ create_sp_error:
res= mysql_xa_recover(thd);
break;
case SQLCOM_ALTER_TABLESPACE:
- if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0))
+ if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0,
+ thd->db ? is_schema_db(thd->db, thd->db_length) : 0))
break;
if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
my_ok(thd);
@@ -6332,8 +6333,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
- if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
- INFORMATION_SCHEMA_NAME.str))
+ if (!ptr->derived && is_schema_db(ptr->db, ptr->db_length))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
@@ -6861,13 +6861,13 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
thd->store_globals();
lex_start(thd);
}
-
+
if (thd)
{
bool reload_acl_failed= acl_reload(thd);
bool reload_grants_failed= grant_reload(thd);
bool reload_servers_failed= servers_reload(thd);
-
+
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
{
result= 1;
@@ -7023,7 +7023,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
*write_to_binlog= tmp_write_to_binlog;
- return result;
+ /*
+ If the query was killed then this function must fail.
+ */
+ return result || (thd ? thd->killed : 0);
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index cb968291ca2..c5c5191d176 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -870,6 +870,8 @@ int check_signed_flag(partition_info *part_info)
part_info Reference to partitioning data structure
is_sub_part Is the table subpartitioned as well
is_field_to_be_setup Flag if we are to set-up field arrays
+ is_create_table_ind Indicator of whether openfrm was called as part of
+ CREATE or ALTER TABLE
RETURN VALUE
TRUE An error occurred, something was wrong with the
@@ -892,8 +894,9 @@ int check_signed_flag(partition_info *part_info)
on the field object.
*/
-bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
- bool is_sub_part, bool is_field_to_be_setup)
+static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
+ bool is_sub_part, bool is_field_to_be_setup,
+ bool is_create_table_ind)
{
partition_info *part_info= table->part_info;
uint dir_length, home_dir_length;
@@ -1005,10 +1008,31 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
thd->where= save_where;
if (unlikely(func_expr->const_item()))
{
- my_error(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
+ my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
clear_field_flag(table);
goto end;
}
+
+ /*
+ We don't allow creating partitions with timezone-dependent expressions as
+ a (sub)partitioning function, but we want to allow such expressions when
+ opening existing tables for easier maintenance. This exception should be
+ deprecated at some point in future so that we always throw an error.
+ */
+ if (func_expr->walk(&Item::is_timezone_dependent_processor,
+ 0, NULL))
+ {
+ if (is_create_table_ind)
+ {
+ my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
+ goto end;
+ }
+ else
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
+ ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
+ }
+
if ((!is_sub_part) && (error= check_signed_flag(part_info)))
goto end;
result= FALSE;
@@ -1616,7 +1640,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
- table, TRUE, TRUE)))
+ table, TRUE, TRUE,
+ is_create_table_ind)))
goto end;
if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
{
@@ -1644,7 +1669,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
else
{
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE)))
+ table, FALSE, TRUE,
+ is_create_table_ind)))
goto end;
if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
{
@@ -1658,7 +1684,8 @@ bool fix_partition_func(THD *thd, TABLE *table,
{
const char *error_str;
if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
- table, FALSE, TRUE)))
+ table, FALSE, TRUE,
+ is_create_table_ind)))
goto end;
if (part_info->part_type == RANGE_PARTITION)
{
@@ -2851,16 +2878,13 @@ int get_partition_id_range(partition_info *part_info,
part_func_value-= 0x8000000000000000ULL;
while (max_part_id > min_part_id)
{
- loc_part_id= (max_part_id + min_part_id + 1) >> 1;
+ loc_part_id= (max_part_id + min_part_id) / 2;
if (range_array[loc_part_id] <= part_func_value)
min_part_id= loc_part_id + 1;
else
- max_part_id= loc_part_id - 1;
+ max_part_id= loc_part_id;
}
loc_part_id= max_part_id;
- if (part_func_value >= range_array[loc_part_id])
- if (loc_part_id != max_partition)
- loc_part_id++;
*part_id= (uint32)loc_part_id;
if (loc_part_id == max_partition &&
part_func_value >= range_array[loc_part_id] &&
@@ -2934,6 +2958,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
bool include_endpoint)
{
longlong *range_array= part_info->range_int_array;
+ longlong part_end_val;
uint max_partition= part_info->no_parts - 1;
uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
/* Get the partitioning function value for the endpoint */
@@ -2967,46 +2992,45 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
}
}
-
if (unsigned_flag)
part_func_value-= 0x8000000000000000ULL;
if (left_endpoint && !include_endpoint)
part_func_value++;
+
+ /*
+ Search for the partition containing part_func_value
+ (including the right endpoint).
+ */
while (max_part_id > min_part_id)
{
- loc_part_id= (max_part_id + min_part_id + 1) >> 1;
- if (range_array[loc_part_id] <= part_func_value)
+ loc_part_id= (max_part_id + min_part_id) / 2;
+ if (range_array[loc_part_id] < part_func_value)
min_part_id= loc_part_id + 1;
else
- max_part_id= loc_part_id - 1;
+ max_part_id= loc_part_id;
}
loc_part_id= max_part_id;
- if (loc_part_id < max_partition &&
- part_func_value >= range_array[loc_part_id+1])
- {
- loc_part_id++;
- }
+
+ /* Adjust for endpoints */
+ part_end_val= range_array[loc_part_id];
if (left_endpoint)
{
- longlong bound= range_array[loc_part_id];
/*
In case of PARTITION p VALUES LESS THAN MAXVALUE
the maximum value is in the current partition.
*/
- if (part_func_value > bound ||
- (part_func_value == bound &&
- (!part_info->defined_max_value || loc_part_id < max_partition)))
+ if (part_func_value == part_end_val &&
+ (loc_part_id < max_partition || !part_info->defined_max_value))
loc_part_id++;
}
else
{
- if (loc_part_id < max_partition)
- {
- if (part_func_value == range_array[loc_part_id])
- loc_part_id += test(include_endpoint);
- else if (part_func_value > range_array[loc_part_id])
- loc_part_id++;
- }
+ /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */
+ if (include_endpoint && loc_part_id < max_partition &&
+ part_func_value == part_end_val)
+ loc_part_id++;
+
+ /* Right endpoint, set end after correct partition */
loc_part_id++;
}
DBUG_RETURN(loc_part_id);
@@ -4089,8 +4113,9 @@ static int fast_end_partition(THD *thd, ulonglong copied,
}
if ((!is_empty) && (!written_bin_log) &&
- (!thd->lex->no_write_to_binlog))
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ (!thd->lex->no_write_to_binlog) &&
+ write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
+ DBUG_RETURN(TRUE);
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted),
@@ -5681,8 +5706,7 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
part_info->first_log_entry= NULL;
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db,
- lpt->table_name, "#", 0);
+ build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
@@ -5738,8 +5762,7 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db,
- lpt->table_name, "#", 0);
+ build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
FALSE))
@@ -5964,7 +5987,7 @@ void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
partition_info *part_info= lpt->part_info;
DBUG_ENTER("handle_alter_part_error");
- if (!part_info->first_log_entry &&
+ if (part_info->first_log_entry &&
execute_ddl_log_entry(current_thd,
part_info->first_log_entry->entry_pos))
{
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 282e24f1853..b9efbf25a00 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -91,9 +91,6 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
bool left_endpoint,
bool include_endpoint);
-bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
- bool is_sub_part, bool is_field_to_be_setup);
-
bool check_part_func_fields(Field **ptr, bool ok_with_charsets);
bool field_is_partition_charset(Field *field);
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 56d181bdda2..7e017588531 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2085,7 +2085,7 @@ static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
&error, &error_len, &not_used);
if (error_len)
{
- strmake(buff, error, min(sizeof(buff), error_len));
+ strmake(buff, error, min(sizeof(buff) - 1, error_len));
strvalue= buff;
goto err;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index ead31436dc7..f7ee60531bc 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1600,6 +1600,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
{
lex->link_first_table_back(create_table, link_to_local);
create_table->create= TRUE;
+ /* Base table and temporary table are not in the same name space. */
+ create_table->skip_temporary= true;
}
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index dac96f2e9c4..e85e730db5b 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -34,6 +34,7 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
{
bool error= 1;
+ bool binlog_error= 0;
TABLE_LIST *ren_table= 0;
int to_table;
char *rename_log_table[2]= {NULL, NULL};
@@ -174,11 +175,11 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
*/
pthread_mutex_unlock(&LOCK_open);
- /* Lets hope this doesn't fail as the result will be messy */
if (!silent && !error)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- my_ok(thd);
+ binlog_error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (!binlog_error)
+ my_ok(thd);
}
if (!error)
@@ -190,7 +191,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
err:
start_waiting_global_read_lock(thd);
- DBUG_RETURN(error);
+ DBUG_RETURN(error || binlog_error);
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index f05147d4146..ae995ea5ed3 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -711,11 +711,14 @@ impossible position";
thd_proc_info(thd, "Finished reading one binlog; switching to next binlog");
switch (mysql_bin_log.find_next_log(&linfo, 1)) {
- case LOG_INFO_EOF:
- loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
- break;
case 0:
break;
+ case LOG_INFO_EOF:
+ if (mysql_bin_log.is_active(log_file_name))
+ {
+ loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
+ break;
+ }
default:
errmsg = "could not find next log";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
@@ -1001,8 +1004,8 @@ int reset_slave(THD *thd, Master_info* mi)
MY_STAT stat_area;
char fname[FN_REFLEN];
int thread_mask= 0, error= 0;
- uint sql_errno=0;
- const char* errmsg=0;
+ uint sql_errno=ER_UNKNOWN_ERROR;
+ const char* errmsg= "Unknown error occured while reseting slave";
DBUG_ENTER("reset_slave");
lock_slave_threads(mi);
@@ -1668,7 +1671,8 @@ err:
replication events along LOAD DATA processing.
@param file pointer to io-cache
- @return 0
+ @retval 0 success
+ @retval 1 failure
*/
int log_loaded_block(IO_CACHE* file)
{
@@ -1695,7 +1699,8 @@ int log_loaded_block(IO_CACHE* file)
Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
min(block_len, max_event_size),
lf_info->log_delayed);
- mysql_bin_log.write(&a);
+ if (mysql_bin_log.write(&a))
+ DBUG_RETURN(1);
}
else
{
@@ -1703,7 +1708,8 @@ int log_loaded_block(IO_CACHE* file)
buffer,
min(block_len, max_event_size),
lf_info->log_delayed);
- mysql_bin_log.write(&b);
+ if (mysql_bin_log.write(&b))
+ DBUG_RETURN(1);
lf_info->wrote_create_file= 1;
DBUG_SYNC_POINT("debug_lock.created_file_event",10);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 8d184617242..94f7d15d281 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -529,7 +529,7 @@ JOIN::prepare(Item ***rref_pointer_array,
thd->lex->allow_sum_func= save_allow_sum_func;
}
- if (!thd->lex->view_prepare_mode)
+ if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE))
{
Item_subselect *subselect;
/* Is it subselect? */
@@ -549,13 +549,26 @@ JOIN::prepare(Item ***rref_pointer_array,
if (order)
{
+ bool real_order= FALSE;
ORDER *ord;
for (ord= order; ord; ord= ord->next)
{
Item *item= *ord->item;
+ /*
+ Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields
+ there. Such fields don't contain any data to sort.
+ */
+ if (!real_order &&
+ (item->type() != Item::FIELD_ITEM ||
+ ((Item_field *) item)->field->maybe_null() ||
+ ((Item_field *) item)->field->sort_length()))
+ real_order= TRUE;
+
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
item->split_sum_func(thd, ref_pointer_array, all_fields);
}
+ if (!real_order)
+ order= NULL;
}
if (having && having->with_sum_func)
@@ -952,6 +965,7 @@ JOIN::optimize()
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
+ const_tables= tables;
/*
Extract all table-independent conditions and replace the WHERE
clause with them. All other conditions were computed by opt_sum_query
@@ -1632,6 +1646,11 @@ JOIN::reinit()
if (join_tab_save)
memcpy(join_tab, join_tab_save, sizeof(JOIN_TAB) * tables);
+ /* need to reset ref access state (see join_read_key) */
+ if (join_tab)
+ for (uint i= 0; i < tables; i++)
+ join_tab[i].ref.key_err= TRUE;
+
if (tmp_join)
restore_tmp();
@@ -3718,20 +3737,20 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
cond_func=(Item_func_match *)cond;
else if (func->arg_count == 2)
{
- Item_func *arg0=(Item_func *)(func->arguments()[0]),
- *arg1=(Item_func *)(func->arguments()[1]);
- if (arg1->const_item() &&
- arg0->type() == Item::FUNC_ITEM &&
- arg0->functype() == Item_func::FT_FUNC &&
+ Item *arg0= func->arguments()[0],
+ *arg1= func->arguments()[1];
+ if (arg1->const_item() && arg1->cols() == 1 &&
+ arg0->type() == Item::FUNC_ITEM &&
+ ((Item_func *) arg0)->functype() == Item_func::FT_FUNC &&
((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
- (functype == Item_func::GT_FUNC && arg1->val_real() >=0)))
- cond_func=(Item_func_match *) arg0;
- else if (arg0->const_item() &&
- arg1->type() == Item::FUNC_ITEM &&
- arg1->functype() == Item_func::FT_FUNC &&
+ (functype == Item_func::GT_FUNC && arg1->val_real() >= 0)))
+ cond_func= (Item_func_match *) arg0;
+ else if (arg0->const_item() && arg0->cols() == 1 &&
+ arg1->type() == Item::FUNC_ITEM &&
+ ((Item_func *) arg1)->functype() == Item_func::FT_FUNC &&
((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
- (functype == Item_func::LT_FUNC && arg0->val_real() >=0)))
- cond_func=(Item_func_match *) arg1;
+ (functype == Item_func::LT_FUNC && arg0->val_real() >= 0)))
+ cond_func= (Item_func_match *) arg1;
}
}
else if (cond->type() == Item::COND_ITEM)
@@ -5946,6 +5965,7 @@ inline void add_cond_and_fix(Item **e1, Item *e2)
{
*e1= res;
res->quick_fix_field();
+ res->update_used_tables();
}
}
else
@@ -7154,6 +7174,7 @@ static void update_depend_map(JOIN *join, ORDER *order)
table_map depend_map;
order->item[0]->update_used_tables();
order->depend_map=depend_map=order->item[0]->used_tables();
+ order->used= 0;
// Not item_sum(), RAND() and no reference to table outside of sub select
if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT))
&& !order->item[0]->with_sum_func)
@@ -7211,7 +7232,19 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
for (order=first_order; order ; order=order->next)
{
table_map order_tables=order->item[0]->used_tables();
- if (order->item[0]->with_sum_func)
+ if (order->item[0]->with_sum_func ||
+ /*
+ If the outer table of an outer join is const (either by itself or
+ after applying WHERE condition), grouping on a field from such a
+ table will be optimized away and filesort without temporary table
+ will be used unless we prevent that now. Filesort is not fit to
+ handle joins and the join condition is not applied. We can't detect
+ the case without an expensive test, however, so we force temporary
+ table for all queries containing more than one table, ROLLUP, and an
+ outer join.
+ */
+ (join->tables > 1 && join->rollup.state == ROLLUP::STATE_INITED &&
+ join->outer_join))
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
@@ -7619,7 +7652,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
already contains a constant and its value is not equal to
the value of const_item.
*/
- item_equal->add(const_item);
+ item_equal->add(const_item, field_item);
}
else
{
@@ -13799,7 +13832,7 @@ check_reverse_order:
select->quick=tmp;
}
}
- else if (tab->type != JT_NEXT &&
+ else if (tab->type != JT_NEXT && tab->type != JT_REF_OR_NULL &&
tab->ref.key >= 0 && tab->ref.key_parts <= used_key_parts)
{
/*
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d8f1769397c..c50303ee812 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -722,6 +722,12 @@ public:
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
table->write_set);
int res= item->save_in_field(to_field, 1);
+ /*
+ Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
+ we need to check for errors executing it and react accordingly
+ */
+ if (!res && table->in_use->is_error())
+ res= 2;
dbug_tmp_restore_column_map(table->write_set, old_map);
null_key= to_field->is_null() || item->null_value;
return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res);
@@ -755,6 +761,12 @@ protected:
if (!err)
err= res;
}
+ /*
+ Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
+ we need to check for errors executing it and react accordingly
+ */
+ if (!err && to_field->table->in_use->is_error())
+ err= 2;
}
null_key= to_field->is_null() || item->null_value;
return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc
index f8a8dea18ff..1655426bb4a 100644
--- a/sql/sql_servers.cc
+++ b/sql/sql_servers.cc
@@ -241,8 +241,14 @@ bool servers_reload(THD *thd)
if (simple_open_n_lock_tables(thd, tables))
{
- sql_print_error("Can't open and lock privilege tables: %s",
- thd->main_da.message());
+ /*
+ Execution might have been interrupted; only print the error message
+ if an error condition has been raised.
+ */
+ if (thd->main_da.is_error())
+ sql_print_error("Can't open and lock privilege tables: %s",
+ thd->main_da.message());
+ return_val= FALSE;
goto end;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index cc3b68c51c8..68d1d4619f4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -828,8 +828,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
DBUG_RETURN(TRUE);
}
#endif
- if (!my_strcasecmp(system_charset_info, dbname,
- INFORMATION_SCHEMA_NAME.str))
+ if (is_schema_db(dbname))
{
dbname= INFORMATION_SCHEMA_NAME.str;
create.default_table_charset= system_charset_info;
@@ -2797,8 +2796,8 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
*/
if (lookup_field_vals->db_value.str)
{
- if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str,
- lookup_field_vals->db_value.str))
+ if (is_schema_db(lookup_field_vals->db_value.str,
+ lookup_field_vals->db_value.length))
{
*with_i_schema= 1;
if (files->push_back(i_s_name_copy))
@@ -3385,11 +3384,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
while ((db_name= it++))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!check_access(thd,SELECT_ACL, db_name->str,
- &thd->col_access, 0, 1, with_i_schema) ||
+ if (!(check_access(thd,SELECT_ACL, db_name->str,
+ &thd->col_access, 0, 1, with_i_schema) ||
+ (!thd->col_access && check_grant_db(thd, db_name->str))) ||
sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
- acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
- !check_grant_db(thd, db_name->str))
+ acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
#endif
{
thd->no_warnings_for_error= 1;
@@ -5250,7 +5249,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
*/
if (thd->lex->sql_command != SQLCOM_SHOW_EVENTS &&
check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1,
- is_schema_db(et.dbname.str)))
+ is_schema_db(et.dbname.str, et.dbname.length)))
DBUG_RETURN(0);
/* ->field[0] is EVENT_CATALOG and is by default NULL */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 1c72f1986ec..6d20ea0d3e5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -647,7 +647,7 @@ static bool read_ddl_log_file_entry(uint entry_no)
Write one entry from ddl log file
SYNOPSIS
write_ddl_log_file_entry()
- entry_no Entry number to read
+ entry_no Entry number to write
RETURN VALUES
TRUE Error
FALSE Success
@@ -748,10 +748,10 @@ static uint read_ddl_log_header()
else
successful_open= TRUE;
}
- entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
- global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
if (successful_open)
{
+ entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
+ global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
DBUG_ASSERT(global_ddl_log.io_size <=
sizeof(global_ddl_log.file_entry_buf));
@@ -832,6 +832,7 @@ static bool init_ddl_log()
goto end;
global_ddl_log.io_size= IO_SIZE;
+ global_ddl_log.name_len= FN_LEN;
create_ddl_log_file_name(file_name);
if ((global_ddl_log.file_id= my_create(file_name,
CREATE_MODE,
@@ -884,6 +885,13 @@ static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
{
DBUG_RETURN(FALSE);
}
+ DBUG_PRINT("ddl_log",
+ ("execute type %c next %u name '%s' from_name '%s' handler '%s'",
+ ddl_log_entry->action_type,
+ ddl_log_entry->next_entry,
+ ddl_log_entry->name,
+ ddl_log_entry->from_name,
+ ddl_log_entry->handler_name));
handler_name.str= (char*)ddl_log_entry->handler_name;
handler_name.length= strlen(ddl_log_entry->handler_name);
init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
@@ -1091,6 +1099,15 @@ bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
DBUG_RETURN(TRUE);
}
error= FALSE;
+ DBUG_PRINT("ddl_log",
+ ("write type %c next %u name '%s' from_name '%s' handler '%s'",
+ (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS],
+ ddl_log_entry->next_entry,
+ (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
+ (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
+ + FN_LEN],
+ (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
+ + (2*FN_LEN)]));
if (write_ddl_log_file_entry((*active_entry)->entry_pos))
{
error= TRUE;
@@ -1731,9 +1748,10 @@ end:
file
*/
-void write_bin_log(THD *thd, bool clear_error,
- char const *query, ulong query_length)
+int write_bin_log(THD *thd, bool clear_error,
+ char const *query, ulong query_length)
{
+ int error= 0;
if (mysql_bin_log.is_open())
{
int errcode= 0;
@@ -1741,9 +1759,10 @@ void write_bin_log(THD *thd, bool clear_error,
thd->clear_error();
else
errcode= query_error_code(thd, TRUE);
- thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, query_length, FALSE, FALSE, errcode);
+ error= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ query, query_length, FALSE, FALSE, errcode);
}
+ return error;
}
@@ -2091,7 +2110,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
tables). In this case, we can write the original query into
the binary log.
*/
- write_bin_log(thd, !error, thd->query(), thd->query_length());
+ error |= write_bin_log(thd, !error, thd->query(), thd->query_length());
}
else if (thd->current_stmt_binlog_row_based &&
tmp_table_deleted)
@@ -2113,7 +2132,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
built_query.chop(); // Chop of the last comma
built_query.append(" /* generated by server */");
- write_bin_log(thd, !error, built_query.ptr(), built_query.length());
+ error|= write_bin_log(thd, !error, built_query.ptr(), built_query.length());
}
/*
@@ -2132,7 +2151,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
built_tmp_query.chop(); // Chop of the last comma
built_tmp_query.append(" /* generated by server */");
- write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length());
+ error|= write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length());
}
}
@@ -2577,7 +2596,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
MY_CS_BINSORT,MYF(0))))
{
- char tmp[64];
+ char tmp[65];
strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
STRING_WITH_LEN("_bin"));
my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
@@ -3541,9 +3560,9 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
RETURN VALUES
NONE
*/
-static inline void write_create_table_bin_log(THD *thd,
- const HA_CREATE_INFO *create_info,
- bool internal_tmp_table)
+static inline int write_create_table_bin_log(THD *thd,
+ const HA_CREATE_INFO *create_info,
+ bool internal_tmp_table)
{
/*
Don't write statement if:
@@ -3556,7 +3575,8 @@ static inline void write_create_table_bin_log(THD *thd,
(!thd->current_stmt_binlog_row_based ||
(thd->current_stmt_binlog_row_based &&
!(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ return write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ return 0;
}
@@ -3823,8 +3843,7 @@ bool mysql_create_table_no_lock(THD *thd,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
- error= 0;
- write_create_table_bin_log(thd, create_info, internal_tmp_table);
+ error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
goto err;
}
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
@@ -3952,8 +3971,7 @@ bool mysql_create_table_no_lock(THD *thd,
thd->thread_specific_used= TRUE;
}
- write_create_table_bin_log(thd, create_info, internal_tmp_table);
- error= FALSE;
+ error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
unlock_and_end:
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -3968,7 +3986,7 @@ warn:
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias);
create_info->table_existed= 1; // Mark that table existed
- write_create_table_bin_log(thd, create_info, internal_tmp_table);
+ error= write_create_table_bin_log(thd, create_info, internal_tmp_table);
goto unlock_and_end;
}
@@ -5444,18 +5462,20 @@ binlog:
create_info, FALSE /* show_database */);
DBUG_ASSERT(result == 0); // store_create_info() always return 0
- write_bin_log(thd, TRUE, query.ptr(), query.length());
+ if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
+ goto err;
}
}
else // Case 1
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ goto err;
}
/*
Case 3 and 4 does nothing under RBR
*/
}
- else
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ goto err;
res= FALSE;
@@ -5543,7 +5563,7 @@ mysql_discard_or_import_tablespace(THD *thd,
error=1;
if (error)
goto err;
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err:
ha_autocommit_or_rollback(thd, error);
@@ -6571,11 +6591,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->clear_error();
Query_log_event qinfo(thd, thd->query(), thd->query_length(),
0, FALSE, 0);
- mysql_bin_log.write(&qinfo);
+ if ((error= mysql_bin_log.write(&qinfo)))
+ goto view_err_unlock;
}
my_ok(thd);
}
+view_err_unlock:
unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
view_err:
@@ -6828,8 +6850,9 @@ view_err:
if (!error)
{
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- my_ok(thd);
+ error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (!error)
+ my_ok(thd);
}
else if (error > 0)
{
@@ -7322,8 +7345,9 @@ view_err:
if (rename_temporary_table(thd, new_table, new_db, new_name))
goto err1;
/* We don't replicate alter table statement on temporary tables */
- if (!thd->current_stmt_binlog_row_based)
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (!thd->current_stmt_binlog_row_based &&
+ write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ DBUG_RETURN(TRUE);
goto end_temporary;
}
@@ -7486,7 +7510,8 @@ view_err:
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->current_stmt_binlog_row_based &&
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ DBUG_RETURN(TRUE);
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
{
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index aec54bda13e..7585fd4fc98 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -67,6 +67,6 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
hton_name(hton)->str,
"TABLESPACE or LOGFILE GROUP");
}
- write_bin_log(thd, FALSE, thd->query(), thd->query_length());
- DBUG_RETURN(FALSE);
+ error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
+ DBUG_RETURN(error);
}
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index eeb9a21b6f5..5de8301fd05 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -168,6 +168,21 @@ TEST_join(JOIN *join)
uint i,ref;
DBUG_ENTER("TEST_join");
+ /*
+ Assemble results of all the calls to full_name() first,
+ in order not to garble the tabular output below.
+ */
+ String ref_key_parts[MAX_TABLES];
+ for (i= 0; i < join->tables; i++)
+ {
+ JOIN_TAB *tab= join->join_tab + i;
+ for (ref= 0; ref < tab->ref.key_parts; ref++)
+ {
+ ref_key_parts[i].append(tab->ref.items[ref]->full_name());
+ ref_key_parts[i].append(" ");
+ }
+ }
+
DBUG_LOCK_FILE;
VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
for (i=0 ; i < join->tables ; i++)
@@ -199,13 +214,8 @@ TEST_join(JOIN *join)
}
if (tab->ref.key_parts)
{
- VOID(fputs(" refs: ",DBUG_FILE));
- for (ref=0 ; ref < tab->ref.key_parts ; ref++)
- {
- Item *item=tab->ref.items[ref];
- fprintf(DBUG_FILE,"%s ", item->full_name());
- }
- VOID(fputc('\n',DBUG_FILE));
+ fprintf(DBUG_FILE,
+ " refs: %s\n", ref_key_parts[i].ptr());
}
}
DBUG_UNLOCK_FILE;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index a251a533622..ba0515d38ad 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -507,7 +507,7 @@ end:
if (!result)
{
- write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length());
+ result= write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length());
}
VOID(pthread_mutex_unlock(&LOCK_open));
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index c6b41b59a3f..d455a66c4f2 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -398,6 +398,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
TABLE *table;
TABLE_LIST tables;
udf_func *u_d;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_create_function");
if (!initialized)
@@ -437,8 +438,8 @@ int mysql_create_function(THD *thd,udf_func *udf)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for CREATE FUNCTION command.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
rw_wrlock(&THR_LOCK_udf);
if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
@@ -506,14 +507,22 @@ int mysql_create_function(THD *thd,udf_func *udf)
rw_unlock(&THR_LOCK_udf);
/* Binlog the create function. */
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
-
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_RETURN(1);
+ }
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(0);
err:
if (new_dl)
dlclose(dl);
rw_unlock(&THR_LOCK_udf);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(1);
}
@@ -525,6 +534,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
udf_func *udf;
char *exact_name_str;
uint exact_name_len;
+ bool save_binlog_row_based;
DBUG_ENTER("mysql_drop_function");
if (!initialized)
@@ -540,8 +550,8 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for DROP FUNCTION command.
*/
- if (thd->current_stmt_binlog_row_based)
- thd->clear_current_stmt_binlog_row_based();
+ save_binlog_row_based= thd->current_stmt_binlog_row_based;
+ thd->clear_current_stmt_binlog_row_based();
rw_wrlock(&THR_LOCK_udf);
if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
@@ -581,11 +591,19 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
rw_unlock(&THR_LOCK_udf);
/* Binlog the drop function. */
- write_bin_log(thd, TRUE, thd->query(), thd->query_length());
-
+ if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
+ {
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_RETURN(1);
+ }
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(0);
err:
rw_unlock(&THR_LOCK_udf);
+ /* Restore the state of binlog format */
+ thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(1);
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1a7e171edf3..61f47bee799 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -335,6 +335,35 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
}
+ /*
+ Disable the usage of fulltext searches in the last union branch.
+ This is a temporary 5.x limitation because of the way the fulltext
+ search functions are handled by the optimizer.
+ This is manifestation of the more general problems of "taking away"
+ parts of a SELECT statement post-fix_fields(). This is generally not
+ doable since various flags are collected in various places (e.g.
+ SELECT_LEX) that carry information about the presence of certain
+ expressions or constructs in the parts of the query.
+ When part of the query is taken away it's not clear how to "divide"
+ the meaning of these accumulated flags and what to carry over to the
+ recipient query (SELECT_LEX).
+ */
+ if (global_parameters->ftfunc_list->elements &&
+ global_parameters->order_list.elements &&
+ global_parameters != fake_select_lex)
+ {
+ ORDER *ord;
+ Item_func::Functype ft= Item_func::FT_FUNC;
+ for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next)
+ if ((*ord->item)->walk (&Item::find_function_processor, FALSE,
+ (uchar *) &ft))
+ {
+ my_error (ER_CANT_USE_OPTION_HERE, MYF(0), "MATCH()");
+ goto err;
+ }
+ }
+
+
create_options= (first_sl->options | thd_arg->options |
TMP_TABLE_ALL_COLUMNS);
/*
@@ -669,7 +698,7 @@ bool st_select_lex_unit::cleanup()
{
ORDER *ord;
for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next)
- (*ord->item)->cleanup();
+ (*ord->item)->walk (&Item::cleanup_processor, 0, 0);
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 00769d2abda..0bef5aa3ae8 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -23,6 +23,7 @@
#include "sql_select.h"
#include "sp_head.h"
#include "sql_trigger.h"
+#include "debug_sync.h"
/* Return 0 if row hasn't changed */
@@ -828,7 +829,7 @@ int mysql_update(THD *thd,
if (error < 0)
{
- char buff[STRING_BUFFER_USUAL_SIZE];
+ char buff[MYSQL_ERRMSG_SIZE];
my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
(ulong) thd->cuted_fields);
thd->row_count_func=
@@ -1143,8 +1144,11 @@ reopen_tables:
items from 'fields' list, so the cleanup above is necessary to.
*/
cleanup_items(thd->free_list);
-
+ cleanup_items(thd->stmt_arena->free_list);
close_tables_for_reopen(thd, &table_list);
+
+ DEBUG_SYNC(thd, "multi_update_reopen_tables");
+
goto reopen_tables;
}
@@ -1864,9 +1868,10 @@ void multi_update::abort()
into repl event.
*/
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
- thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query(), thd->query_length(),
- transactional_tables, FALSE, errcode);
+ /* the error of binary logging is ignored */
+ (void)thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query(), thd->query_length(),
+ transactional_tables, FALSE, errcode);
}
thd->transaction.all.modified_non_trans_table= TRUE;
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index ae3af0640a3..c6d412112c2 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -268,11 +268,11 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
table (i.e. user will not get some privileges by view creation)
*/
if ((check_access(thd, CREATE_VIEW_ACL, view->db, &view->grant.privilege,
- 0, 0, is_schema_db(view->db)) ||
+ 0, 0, is_schema_db(view->db, view->db_length)) ||
check_grant(thd, CREATE_VIEW_ACL, view, 0, 1, 0)) ||
(mode != VIEW_CREATE_NEW &&
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
- 0, 0, is_schema_db(view->db)) ||
+ 0, 0, is_schema_db(view->db, view->db_length)) ||
check_grant(thd, DROP_ACL, view, 0, 1, 0))))
goto err;
@@ -662,8 +662,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
buff.append(views->source.str, views->source.length);
int errcode= query_error_code(thd, TRUE);
- thd->binlog_query(THD::STMT_QUERY_TYPE,
- buff.ptr(), buff.length(), FALSE, FALSE, errcode);
+ if (thd->binlog_query(THD::STMT_QUERY_TYPE,
+ buff.ptr(), buff.length(), FALSE, FALSE, errcode))
+ res= TRUE;
}
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -1652,7 +1653,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
/* if something goes wrong, bin-log with possible error code,
otherwise bin-log with error code cleared.
*/
- write_bin_log(thd, !something_wrong, thd->query(), thd->query_length());
+ if (write_bin_log(thd, !something_wrong, thd->query(), thd->query_length()))
+ something_wrong= 1;
}
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -1771,7 +1773,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item))
{
thd->mark_used_columns= save_mark_used_columns;
- return TRUE;
+ DBUG_RETURN(TRUE);
}
}
thd->mark_used_columns= save_mark_used_columns;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 110f510c9f6..e0f5cd9a562 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -596,6 +596,35 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
DBUG_RETURN(result);
}
+
+static bool add_create_index_prepare (LEX *lex, Table_ident *table)
+{
+ lex->sql_command= SQLCOM_CREATE_INDEX;
+ if (!lex->current_select->add_table_to_list(lex->thd, table, NULL,
+ TL_OPTION_UPDATING))
+ return TRUE;
+ lex->alter_info.reset();
+ lex->alter_info.flags= ALTER_ADD_INDEX;
+ lex->col_list.empty();
+ lex->change= NullS;
+ return FALSE;
+}
+
+
+static bool add_create_index (LEX *lex, Key::Keytype type, const char *name,
+ KEY_CREATE_INFO *info= NULL, bool generated= 0)
+{
+ Key *key;
+ key= new Key(type, name, info ? info : &lex->key_create_info, generated,
+ lex->col_list);
+ if (key == NULL)
+ return TRUE;
+
+ lex->alter_info.key_list.push_back(key);
+ lex->col_list.empty();
+ return FALSE;
+}
+
%}
%union {
int num;
@@ -1335,7 +1364,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
option_type opt_var_type opt_var_ident_type
%type <key_type>
- key_type opt_unique_or_fulltext constraint_key_type
+ normal_key_type opt_unique constraint_key_type fulltext spatial
%type <key_alg>
btree_or_rtree
@@ -1434,7 +1463,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail
install uninstall partition_entry binlog_base64_event
- init_key_options key_options key_opts key_opt key_using_alg
+ init_key_options normal_key_options normal_key_opts all_key_opt
+ spatial_key_options fulltext_key_options normal_key_opt
+ fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts
+ key_using_alg
server_def server_options_list server_option
definer_opt no_definer definer
END_OF_INPUT
@@ -1828,35 +1860,37 @@ create:
$5->table.str);
}
}
- | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON
+ | CREATE opt_unique INDEX_SYM ident key_alg ON table_ident
+ {
+ if (add_create_index_prepare(Lex, $7))
+ MYSQL_YYABORT;
+ }
+ '(' key_list ')' normal_key_options
+ {
+ if (add_create_index(Lex, $2, $4.str))
+ MYSQL_YYABORT;
+ }
+ | CREATE fulltext INDEX_SYM ident init_key_options ON
table_ident
{
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_CREATE_INDEX;
- if (!lex->current_select->add_table_to_list(lex->thd, $7,
- NULL,
- TL_OPTION_UPDATING))
+ if (add_create_index_prepare(Lex, $7))
MYSQL_YYABORT;
- lex->alter_info.reset();
- lex->alter_info.flags= ALTER_ADD_INDEX;
- lex->col_list.empty();
- lex->change=NullS;
}
- '(' key_list ')' key_options
+ '(' key_list ')' fulltext_key_options
{
- LEX *lex=Lex;
- Key *key;
- if ($2 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
- {
- my_parse_error(ER(ER_SYNTAX_ERROR));
+ if (add_create_index(Lex, $2, $4.str))
MYSQL_YYABORT;
- }
- key= new Key($2, $4.str, &lex->key_create_info, 0,
- lex->col_list);
- if (key == NULL)
+ }
+ | CREATE spatial INDEX_SYM ident init_key_options ON
+ table_ident
+ {
+ if (add_create_index_prepare(Lex, $7))
+ MYSQL_YYABORT;
+ }
+ '(' key_list ')' spatial_key_options
+ {
+ if (add_create_index(Lex, $2, $4.str))
MYSQL_YYABORT;
- lex->alter_info.key_list.push_back(key);
- lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
{
@@ -4082,7 +4116,7 @@ part_func_expr:
lex->safe_to_cache_query= 1;
if (not_corr_func)
{
- my_parse_error(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
+ my_parse_error(ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
MYSQL_YYABORT;
}
$$=$1;
@@ -4822,32 +4856,28 @@ column_def:
;
key_def:
- key_type opt_ident key_alg '(' key_list ')' key_options
+ normal_key_type opt_ident key_alg '(' key_list ')' normal_key_options
{
- LEX *lex=Lex;
- if ($1 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
- {
- my_parse_error(ER(ER_SYNTAX_ERROR));
+ if (add_create_index (Lex, $1, $2))
MYSQL_YYABORT;
- }
- Key *key= new Key($1, $2, &lex->key_create_info, 0,
- lex->col_list);
- if (key == NULL)
+ }
+ | fulltext opt_key_or_index opt_ident init_key_options
+ '(' key_list ')' fulltext_key_options
+ {
+ if (add_create_index (Lex, $1, $3))
+ MYSQL_YYABORT;
+ }
+ | spatial opt_key_or_index opt_ident init_key_options
+ '(' key_list ')' spatial_key_options
+ {
+ if (add_create_index (Lex, $1, $3))
MYSQL_YYABORT;
- lex->alter_info.key_list.push_back(key);
- lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint constraint_key_type opt_ident key_alg
- '(' key_list ')' key_options
+ '(' key_list ')' normal_key_options
{
- LEX *lex=Lex;
- const char *key_name= $3 ? $3 : $1;
- Key *key= new Key($2, key_name, &lex->key_create_info, 0,
- lex->col_list);
- if (key == NULL)
+ if (add_create_index (Lex, $2, $3 ? $3 : $1))
MYSQL_YYABORT;
- lex->alter_info.key_list.push_back(key);
- lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
@@ -4863,13 +4893,9 @@ key_def:
if (key == NULL)
MYSQL_YYABORT;
lex->alter_info.key_list.push_back(key);
- key= new Key(Key::MULTIPLE, key_name,
- &default_key_create_info, 1,
- lex->col_list);
- if (key == NULL)
+ if (add_create_index (lex, Key::MULTIPLE, key_name,
+ &default_key_create_info, 1))
MYSQL_YYABORT;
- lex->alter_info.key_list.push_back(key);
- lex->col_list.empty(); /* Alloced by sql_alloc */
/* Only used for ALTER TABLE. Ignored otherwise. */
lex->alter_info.flags|= ALTER_FOREIGN_KEY;
}
@@ -5437,19 +5463,8 @@ delete_option:
| SET DEFAULT { $$= (int) Foreign_key::FK_OPTION_DEFAULT; }
;
-key_type:
+normal_key_type:
key_or_index { $$= Key::MULTIPLE; }
- | FULLTEXT_SYM opt_key_or_index { $$= Key::FULLTEXT; }
- | SPATIAL_SYM opt_key_or_index
- {
-#ifdef HAVE_SPATIAL
- $$= Key::SPATIAL;
-#else
- my_error(ER_FEATURE_DISABLED, MYF(0),
- sym_group_geom.name, sym_group_geom.needed_define);
- MYSQL_YYABORT;
-#endif
- }
;
constraint_key_type:
@@ -5473,11 +5488,17 @@ keys_or_index:
| INDEXES {}
;
-opt_unique_or_fulltext:
+opt_unique:
/* empty */ { $$= Key::MULTIPLE; }
| UNIQUE_SYM { $$= Key::UNIQUE; }
- | FULLTEXT_SYM { $$= Key::FULLTEXT;}
- | SPATIAL_SYM
+ ;
+
+fulltext:
+ FULLTEXT_SYM { $$= Key::FULLTEXT;}
+ ;
+
+spatial:
+ SPATIAL_SYM
{
#ifdef HAVE_SPATIAL
$$= Key::SPATIAL;
@@ -5506,14 +5527,34 @@ key_alg:
| init_key_options key_using_alg
;
-key_options:
+normal_key_options:
+ /* empty */ {}
+ | normal_key_opts
+ ;
+
+fulltext_key_options:
/* empty */ {}
- | key_opts
+ | fulltext_key_opts
+ ;
+
+spatial_key_options:
+ /* empty */ {}
+ | spatial_key_opts
+ ;
+
+normal_key_opts:
+ normal_key_opt
+ | normal_key_opts normal_key_opt
+ ;
+
+spatial_key_opts:
+ spatial_key_opt
+ | spatial_key_opts spatial_key_opt
;
-key_opts:
- key_opt
- | key_opts key_opt
+fulltext_key_opts:
+ fulltext_key_opt
+ | fulltext_key_opts fulltext_key_opt
;
key_using_alg:
@@ -5521,10 +5562,22 @@ key_using_alg:
| TYPE_SYM btree_or_rtree { Lex->key_create_info.algorithm= $2; }
;
-key_opt:
- key_using_alg
- | KEY_BLOCK_SIZE opt_equal ulong_num
+all_key_opt:
+ KEY_BLOCK_SIZE opt_equal ulong_num
{ Lex->key_create_info.block_size= $3; }
+ ;
+
+normal_key_opt:
+ all_key_opt
+ | key_using_alg
+ ;
+
+spatial_key_opt:
+ all_key_opt
+ ;
+
+fulltext_key_opt:
+ all_key_opt
| WITH PARSER_SYM IDENT_sys
{
if (plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN))
@@ -8895,7 +8948,7 @@ interval_time_stamp:
implementation without changing its
resolution.
*/
- WARN_DEPRECATED(yythd, "6.2", "FRAC_SECOND", "MICROSECOND");
+ WARN_DEPRECATED(yythd, VER_CELOSIA, "FRAC_SECOND", "MICROSECOND");
}
;
diff --git a/sql/table.cc b/sql/table.cc
index 8ceda6e7513..088a22b5203 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -212,10 +212,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
DBUG_ASSERT(db != NULL);
DBUG_ASSERT(name != NULL);
- if ((db->length == INFORMATION_SCHEMA_NAME.length) &&
- (my_strcasecmp(system_charset_info,
- INFORMATION_SCHEMA_NAME.str,
- db->str) == 0))
+ if (is_schema_db(db->str, db->length))
{
return TABLE_CATEGORY_INFORMATION;
}