summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJoerg Bruehe <joerg@mysql.com>2009-05-08 21:04:07 +0200
committerJoerg Bruehe <joerg@mysql.com>2009-05-08 21:04:07 +0200
commitd2fe2a71dafc7d2fcdfb29970f37c5dbd6681df9 (patch)
treebc4bd9206c7d8ee035e07b31775ceb949164ba93 /sql
parent1b4cfc363231c8ef58410d65ffe2a3e60be35453 (diff)
parentc715ff413a0a7ed5059c4001a166ad163a48cb57 (diff)
downloadmariadb-git-d2fe2a71dafc7d2fcdfb29970f37c5dbd6681df9.tar.gz
Merge main 5.1 into 5.1-build
165 changesets with 23 conflicts: Text conflict in mysql-test/r/lock_multi.result Text conflict in mysql-test/t/lock_multi.test Text conflict in mysql-test/t/mysqldump.test Text conflict in sql/item_strfunc.cc Text conflict in sql/log.cc Text conflict in sql/log_event.cc Text conflict in sql/parse_file.cc Text conflict in sql/slave.cc Text conflict in sql/sp.cc Text conflict in sql/sp_head.cc Text conflict in sql/sql_acl.cc Text conflict in sql/sql_base.cc Text conflict in sql/sql_class.cc Text conflict in sql/sql_crypt.cc Text conflict in sql/sql_db.cc Text conflict in sql/sql_lex.cc Text conflict in sql/sql_parse.cc Text conflict in sql/sql_select.cc Text conflict in sql/sql_table.cc Text conflict in sql/sql_view.cc Text conflict in storage/innobase/handler/ha_innodb.cc Text conflict in storage/myisam/mi_packrec.c Text conflict in tests/mysql_client_test.c Updates to Innobase, taken from main 5.1: bzr: ERROR: Some change isn't sane: File mysql-test/r/innodb-semi-consistent.result is owned by Innobase and should not be updated. File mysql-test/t/innodb-semi-consistent.test is owned by Innobase and should not be updated. File storage/innobase/handler/ha_innodb.cc is owned by Innobase and should not be updated. File storage/innobase/ibuf/ibuf0ibuf.c is owned by Innobase and should not be updated. File storage/innobase/include/row0mysql.h is owned by Innobase and should not be updated. File storage/innobase/include/srv0srv.h is owned by Innobase and should not be updated. File storage/innobase/include/trx0trx.h is owned by Innobase and should not be updated. File storage/innobase/include/trx0trx.ic is owned by Innobase and should not be updated. File storage/innobase/lock/lock0lock.c is owned by Innobase and should not be updated. File storage/innobase/page/page0cur.c is owned by Innobase and should not be updated. File storage/innobase/row/row0mysql.c is owned by Innobase and should not be updated. File storage/innobase/row/row0sel.c is owned by Innobase and should not be updated. File storage/innobase/srv/srv0srv.c is owned by Innobase and should not be updated. File storage/innobase/trx/trx0trx.c is owned by Innobase and should not be updated. (Set env var 'ALLOW_UPDATE_INNOBASE_OWNED' to override.)
Diffstat (limited to 'sql')
-rw-r--r--sql/events.cc12
-rw-r--r--sql/field.cc6
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_geofunc.cc27
-rw-r--r--sql/item_strfunc.cc20
-rw-r--r--sql/item_strfunc.h15
-rw-r--r--sql/log.cc5
-rw-r--r--sql/log_event.cc190
-rw-r--r--sql/parse_file.cc5
-rw-r--r--sql/parse_file.h2
-rw-r--r--sql/rpl_filter.cc3
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/slave.cc91
-rw-r--r--sql/sp.cc3
-rw-r--r--sql/sp_head.cc28
-rw-r--r--sql/sp_head.h8
-rw-r--r--sql/sp_pcontext.cc23
-rw-r--r--sql/sp_pcontext.h4
-rw-r--r--sql/sql_acl.cc3
-rw-r--r--sql/sql_base.cc26
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_crypt.cc4
-rw-r--r--sql/sql_crypt.h2
-rw-r--r--sql/sql_db.cc11
-rw-r--r--sql/sql_handler.cc8
-rw-r--r--sql/sql_lex.cc92
-rw-r--r--sql/sql_lex.h30
-rw-r--r--sql/sql_parse.cc33
-rw-r--r--sql/sql_rename.cc11
-rw-r--r--sql/sql_repl.cc3
-rw-r--r--sql/sql_select.cc50
-rw-r--r--sql/sql_table.cc15
-rw-r--r--sql/sql_test.cc28
-rw-r--r--sql/sql_view.cc12
-rw-r--r--sql/sql_view.h3
-rw-r--r--sql/sql_yacc.yy176
37 files changed, 637 insertions, 324 deletions
diff --git a/sql/events.cc b/sql/events.cc
index 4203ca06d7f..ea935e67bd3 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -412,6 +412,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)))
{
Event_queue_element *new_element;
+ bool dropped= 0;
if (!(new_element= new Event_queue_element()))
ret= TRUE; // OOM
@@ -419,8 +420,9 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
parse_data->name,
new_element)))
{
- db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
- TRUE);
+ if (!db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
+ TRUE))
+ dropped= 1;
delete new_element;
}
else
@@ -429,6 +431,12 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
bool created;
if (event_queue)
event_queue->create_event(thd, new_element, &created);
+ }
+ /*
+ binlog the create event unless it's been successfully dropped
+ */
+ if (!dropped)
+ {
/* Binlog the create event. */
DBUG_ASSERT(thd->query && thd->query_length);
write_bin_log(thd, TRUE, thd->query, thd->query_length);
diff --git a/sql/field.cc b/sql/field.cc
index a06021bee3d..d11b509075b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6448,13 +6448,13 @@ int Field_str::store(double nr)
calculate the maximum number of significant digits if the 'f'-format
would be used (+1 for decimal point if the number has a fractional part).
*/
- digits= max(0, (int) max_length - fractional);
+ digits= max(1, (int) max_length - fractional);
/*
If the exponent is negative, decrease digits by the number of leading zeros
after the decimal point that do not count as significant digits.
*/
if (exp < 0)
- digits= max(0, (int) digits + exp);
+ digits= max(1, (int) digits + exp);
/*
'e'-format is used only if the exponent is less than -4 or greater than or
equal to the precision. In this case we need to adjust the number of
@@ -6462,7 +6462,7 @@ int Field_str::store(double nr)
We also have to reserve one additional character if abs(exp) >= 100.
*/
if (exp >= (int) digits || exp < -4)
- digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100)));
+ digits= max(1, (int) (max_length - 5 - (exp >= 100 || exp <= -100)));
/* Limit precision to DBL_DIG to avoid garbage past significant digits */
set_if_smaller(digits, DBL_DIG);
diff --git a/sql/item.cc b/sql/item.cc
index 180ce4f4702..d1418b9a137 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4468,7 +4468,7 @@ Item *Item_field::replace_equal_field(uchar *arg)
return const_item;
}
Item_field *subst= item_equal->get_first();
- if (subst && !field->eq(subst->field))
+ if (subst && field->table != subst->field->table && !field->eq(subst->field))
return subst;
}
return this;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8fc9fadb6bd..876aee719a3 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2716,7 +2716,7 @@ longlong Item_func_find_in_set::val_int()
int diff;
if ((diff=buffer->length() - find->length()) >= 0)
{
- my_wc_t wc;
+ my_wc_t wc= 0;
CHARSET_INFO *cs= cmp_collation.collation;
const char *str_begin= buffer->ptr();
const char *str_end= buffer->ptr();
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index ac1b7738a27..24a92c78e9c 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -78,10 +78,17 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
String arg_val;
- String *wkb= args[0]->val_str(&arg_val);
+ String *wkb;
Geometry_buffer buffer;
uint32 srid= 0;
+ if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY)
+ {
+ return args[0]->val_str(str);
+ }
+
+ wkb= args[0]->val_str(&arg_val);
+
if ((arg_count == 2) && !args[1]->null_value)
srid= (uint32)args[1]->val_int();
@@ -91,8 +98,8 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
str->length(0);
str->q_append(srid);
if ((null_value=
- (args[0]->null_value ||
- !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
+ (args[0]->null_value ||
+ !Geometry::create_from_wkb(&buffer, wkb->ptr(), wkb->length(), str))))
return 0;
return str;
}
@@ -345,14 +352,16 @@ String *Item_func_point::val_str(String *str)
DBUG_ASSERT(fixed == 1);
double x= args[0]->val_real();
double y= args[1]->val_real();
+ uint32 srid= 0;
if ((null_value= (args[0]->null_value ||
args[1]->null_value ||
- str->realloc(1 + 4 + SIZEOF_STORED_DOUBLE*2))))
+ str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE*2))))
return 0;
str->set_charset(&my_charset_bin);
str->length(0);
+ str->q_append(srid);
str->q_append((char)Geometry::wkb_ndr);
str->q_append((uint32)Geometry::wkb_point);
str->q_append(x);
@@ -376,12 +385,14 @@ String *Item_func_spatial_collection::val_str(String *str)
DBUG_ASSERT(fixed == 1);
String arg_value;
uint i;
+ uint32 srid= 0;
str->set_charset(&my_charset_bin);
str->length(0);
- if (str->reserve(1 + 4 + 4, 512))
+ if (str->reserve(4/*SRID*/ + 1 + 4 + 4, 512))
goto err;
+ str->q_append(srid);
str->q_append((char) Geometry::wkb_ndr);
str->q_append((uint32) coll_type);
str->q_append((uint32) arg_count);
@@ -399,13 +410,13 @@ String *Item_func_spatial_collection::val_str(String *str)
In the case of GeometryCollection we don't need any checkings
for item types, so just copy them into target collection
*/
- if (str->append(res->ptr(), len, (uint32) 512))
+ if (str->append(res->ptr() + 4/*SRID*/, len - 4/*SRID*/, (uint32) 512))
goto err;
}
else
{
enum Geometry::wkbType wkb_type;
- const char *data= res->ptr() + 1;
+ const char *data= res->ptr() + 4/*SRID*/ + 1;
/*
In the case of named collection we must check that items
@@ -414,7 +425,7 @@ String *Item_func_spatial_collection::val_str(String *str)
wkb_type= (Geometry::wkbType) uint4korr(data);
data+= 4;
- len-= 5;
+ len-= 5 + 4/*SRID*/;
if (wkb_type != item_type)
goto err;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 649910e1162..267036e4a3d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -504,17 +504,21 @@ String *Item_func_des_encrypt::val_str(String *str)
string marking change of string length.
*/
- tail= (8-(res_length) % 8); // 1..8 marking extra length
+ tail= 8 - (res_length % 8); // 1..8 marking extra length
res_length+=tail;
+ tmp_arg.realloc(res_length);
+ tmp_arg.length(0);
+ tmp_arg.append(res->ptr(), res->length());
code= ER_OUT_OF_RESOURCES;
- if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1))
+ if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1))
goto error;
- (*res)[res_length-1]=tail; // save extra length
+ tmp_arg[res_length-1]=tail; // save extra length
+ tmp_value.realloc(res_length+1);
tmp_value.length(res_length+1);
tmp_value[0]=(char) (128 | key_number);
// Real encryption
bzero((char*) &ivec,sizeof(ivec));
- DES_ede3_cbc_encrypt((const uchar*) (res->ptr()),
+ DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()),
(uchar*) (tmp_value.ptr()+1),
res_length,
&keyschedule.ks1,
@@ -1689,10 +1693,10 @@ String *Item_func_encrypt::val_str(String *str)
String *salt_str=args[1]->val_str(&tmp_value);
if ((null_value= (args[1]->null_value || salt_str->length() < 2)))
return 0;
- salt_ptr= salt_str->c_ptr();
+ salt_ptr= salt_str->c_ptr_safe();
}
pthread_mutex_lock(&LOCK_crypt);
- char *tmp= crypt(res->c_ptr(),salt_ptr);
+ char *tmp= crypt(res->c_ptr_safe(),salt_ptr);
if (!tmp)
{
pthread_mutex_unlock(&LOCK_crypt);
@@ -1738,7 +1742,7 @@ String *Item_func_encode::val_str(String *str)
null_value=0;
res=copy_if_not_alloced(str,res,res->length());
- SQL_CRYPT sql_crypt(password->ptr());
+ 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);
@@ -1767,7 +1771,7 @@ String *Item_func_decode::val_str(String *str)
null_value=0;
res=copy_if_not_alloced(str,res,res->length());
- SQL_CRYPT sql_crypt(password->ptr());
+ SQL_CRYPT sql_crypt(password->ptr(), password->length());
sql_crypt.init();
sql_crypt.decode((char*) res->ptr(),res->length());
return res;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 81baf9a4c5f..5265f608344 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -293,13 +293,17 @@ public:
class Item_func_des_encrypt :public Item_str_func
{
- String tmp_value;
+ String tmp_value,tmp_arg;
public:
Item_func_des_encrypt(Item *a) :Item_str_func(a) {}
Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
String *val_str(String *);
void fix_length_and_dec()
- { maybe_null=1; max_length = args[0]->max_length+8; }
+ {
+ maybe_null=1;
+ /* 9 = MAX ((8- (arg_len % 8)) + 1) */
+ max_length = args[0]->max_length + 9;
+ }
const char *func_name() const { return "des_encrypt"; }
};
@@ -310,7 +314,12 @@ public:
Item_func_des_decrypt(Item *a) :Item_str_func(a) {}
Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {}
String *val_str(String *);
- void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
+ void fix_length_and_dec()
+ {
+ maybe_null=1;
+ /* 9 = MAX ((8- (arg_len % 8)) + 1) */
+ max_length = args[0]->max_length - 9;
+ }
const char *func_name() const { return "des_decrypt"; }
};
diff --git a/sql/log.cc b/sql/log.cc
index 44296daa939..ed2eff6625d 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -845,6 +845,7 @@ void LOGGER::cleanup_base()
{
table_log_handler->cleanup();
delete table_log_handler;
+ table_log_handler= NULL;
}
if (file_log_handler)
file_log_handler->cleanup();
@@ -855,7 +856,11 @@ void LOGGER::cleanup_end()
{
DBUG_ASSERT(inited == 1);
if (file_log_handler)
+ {
delete file_log_handler;
+ file_log_handler=NULL;
+ }
+ inited= 0;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 89094da3e94..1a8cb8ee4fa 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -277,6 +277,47 @@ static void clear_all_errors(THD *thd, Relay_log_info *rli)
rli->clear_error();
}
+inline int idempotent_error_code(int err_code)
+{
+ int ret= 0;
+
+ switch (err_code)
+ {
+ case 0:
+ ret= 1;
+ break;
+ /*
+ The following list of "idempotent" errors
+ means that an error from the list might happen
+ because of idempotent (more than once)
+ applying of a binlog file.
+ Notice, that binlog has a ddl operation its
+ second applying may cause
+
+ case HA_ERR_TABLE_DEF_CHANGED:
+ case HA_ERR_CANNOT_ADD_FOREIGN:
+
+ which are not included into to the list.
+
+ Note that HA_ERR_RECORD_DELETED is not in the list since
+ do_exec_row() should not return that error code.
+ */
+ case HA_ERR_RECORD_CHANGED:
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_END_OF_FILE:
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ case HA_ERR_FOREIGN_DUPLICATE_KEY:
+ case HA_ERR_NO_REFERENCED_ROW:
+ case HA_ERR_ROW_IS_REFERENCED:
+ ret= 1;
+ break;
+ default:
+ ret= 0;
+ break;
+ }
+ return (ret);
+}
/**
Ignore error code specified on command line.
@@ -301,14 +342,37 @@ inline int ignored_error_code(int err_code)
return ((err_code == ER_SLAVE_IGNORED_TABLE) ||
(use_slave_mask && bitmap_is_set(&slave_error_mask, err_code)));
}
-#endif
+/*
+ This function converts an engine's error to a server error.
+
+ If the thread does not have an error already reported, it tries to
+ define it by calling the engine's method print_error. However, if a
+ mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
+ warning message.
+*/
+int convert_handler_error(int error, THD* thd, TABLE *table)
+{
+ uint actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
+ 0);
+
+ if (actual_error == 0)
+ {
+ table->file->print_error(error, MYF(0));
+ actual_error= (thd->is_error() ? thd->main_da.sql_errno() :
+ ER_UNKNOWN_ERROR);
+ if (actual_error == ER_UNKNOWN_ERROR)
+ if (global_system_variables.log_warnings)
+ sql_print_warning("Unknown error detected %d in handler", error);
+ }
+
+ return (actual_error);
+}
/*
pretty_print_str()
*/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
static char *pretty_print_str(char *packet, const char *str, int len)
{
const char *end= str + len;
@@ -2292,7 +2356,16 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
(thd_arg->is_error() ? thd_arg->main_da.sql_errno() : 0) :
((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 :
thd_arg->killed_errno());
-
+
+ /* thd_arg->main_da.sql_errno() might be ER_SERVER_SHUTDOWN or
+ ER_QUERY_INTERRUPTED, So here we need to make sure that
+ error_code is not set to these errors when specified NOT_KILLED
+ by the caller
+ */
+ if ((killed_status_arg == THD::NOT_KILLED) &&
+ (error_code == ER_SERVER_SHUTDOWN || error_code == ER_QUERY_INTERRUPTED))
+ error_code= 0;
+
time(&end_time);
exec_time = (ulong) (end_time - thd_arg->start_time);
/**
@@ -7121,7 +7194,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
*/
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
-
+ /*
+ The current statement is just about to begin and
+ has not yet modified anything. Note, all.modified is reset
+ by mysql_reset_thd_for_next_command.
+ */
+ thd->transaction.stmt.modified_non_trans_table= FALSE;
/*
Check if the slave is set to use SBR. If so, it should switch
to using RBR until the end of the "statement", i.e., next
@@ -7158,7 +7236,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
/*
Error reporting borrowed from Query_log_event with many excessive
- simplifications (we don't honour --slave-skip-errors)
+ simplifications.
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skiped.
*/
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on opening tables",
@@ -7184,6 +7264,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
if (ptr->m_tabledef.compatible_with(rli, ptr->table))
{
+ /*
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skiped.
+ */
mysql_unlock_tables(thd, thd->lock);
thd->lock= 0;
thd->is_slave_error= 1;
@@ -7224,6 +7308,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
if (table)
{
+ bool transactional_table= table->file->has_transactions();
/*
table == NULL means that this table should not be replicated
(this was set up by Table_map_log_event::do_apply_event()
@@ -7291,48 +7376,27 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
table->in_use = old_thd;
- switch (error)
- {
- case 0:
- break;
- /*
- The following list of "idempotent" errors
- means that an error from the list might happen
- because of idempotent (more than once)
- applying of a binlog file.
- Notice, that binlog has a ddl operation its
- second applying may cause
-
- case HA_ERR_TABLE_DEF_CHANGED:
- case HA_ERR_CANNOT_ADD_FOREIGN:
-
- which are not included into to the list.
-
- Note that HA_ERR_RECORD_DELETED is not in the list since
- do_exec_row() should not return that error code.
- */
- case HA_ERR_RECORD_CHANGED:
- case HA_ERR_KEY_NOT_FOUND:
- case HA_ERR_END_OF_FILE:
- case HA_ERR_FOUND_DUPP_KEY:
- case HA_ERR_FOUND_DUPP_UNIQUE:
- case HA_ERR_FOREIGN_DUPLICATE_KEY:
- case HA_ERR_NO_REFERENCED_ROW:
- case HA_ERR_ROW_IS_REFERENCED:
- if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
+ if (error)
+ {
+ int actual_error= convert_handler_error(error, thd, table);
+ bool idempotent_error= (idempotent_error_code(error) &&
+ ((bit_is_set(slave_exec_mode,
+ SLAVE_EXEC_MODE_IDEMPOTENT)) == 1));
+ bool ignored_error= (idempotent_error == 0 ?
+ ignored_error_code(actual_error) : 0);
+
+ if (idempotent_error || ignored_error)
{
if (global_system_variables.log_warnings)
slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
get_type_str(),
RPL_LOG_NAME, (ulong) log_pos);
+ clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
error= 0;
+ if (idempotent_error == 0)
+ break;
}
- break;
-
- default:
- thd->is_slave_error= 1;
- break;
}
/*
@@ -7346,7 +7410,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
(ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end));
if (!m_curr_row_end && !error)
- unpack_current_row(rli);
+ error= unpack_current_row(rli);
// at this moment m_curr_row_end should be set
DBUG_ASSERT(error || m_curr_row_end != NULL);
@@ -7355,11 +7419,26 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
m_curr_row= m_curr_row_end;
+ if (error == 0 && !transactional_table)
+ thd->transaction.all.modified_non_trans_table=
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
} // row processing loop
DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
- error= do_after_row_operations(rli, error);
+
+ if ((error= do_after_row_operations(rli, error)) &&
+ ignored_error_code(convert_handler_error(error, thd, table)))
+ {
+
+ if (global_system_variables.log_warnings)
+ slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, (ulong) log_pos);
+ clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
+ error= 0;
+ }
+
if (!cache_stmt)
{
DBUG_PRINT("info", ("Marked that we need to keep log"));
@@ -7375,36 +7454,21 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
if (error)
- { /* error has occured during the transaction */
- slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
- get_type_str(), RPL_LOG_NAME, (ulong) log_pos);
- }
- if (error)
{
- /*
- If one day we honour --skip-slave-errors in row-based replication, and
- the error should be skipped, then we would clear mappings, rollback,
- close tables, but the slave SQL thread would not stop and then may
- assume the mapping is still available, the tables are still open...
- So then we should clear mappings/rollback/close here only if this is a
- STMT_END_F.
- For now we code, knowing that error is not skippable and so slave SQL
- thread is certainly going to stop.
- rollback at the caller along with sbr.
- */
+ slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, (ulong) log_pos);
thd->reset_current_stmt_binlog_row_based();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
thd->is_slave_error= 1;
- DBUG_RETURN(error);
}
-
/*
This code would ideally be placed in do_update_pos() instead, but
since we have no access to table there, we do the setting of
last_event_start_time here instead.
*/
- if (table && (table->s->primary_key == MAX_KEY) &&
- !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
+ else if (table && (table->s->primary_key == MAX_KEY) &&
+ !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
{
/*
------------ Temporary fix until WL#2975 is implemented ---------
@@ -7425,7 +7489,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
Log_event::enum_skip_reason
@@ -9187,7 +9251,7 @@ Incident_log_event::Incident_log_event(const char *buf, uint event_len,
// If the incident is not recognized, this binlog event is
// invalid. If we set incident_number to INCIDENT_NONE, the
// invalidity will be detected by is_valid().
- incident_number= INCIDENT_NONE;
+ m_incident= INCIDENT_NONE;
DBUG_VOID_RETURN;
}
m_incident= static_cast<Incident>(incident_number);
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 07ea434e8e0..f2dbeba1bbf 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -302,6 +302,7 @@ err_w_file:
@thd thread handler
@param schema name of given schema
@param old_name original file name
+ @param new_db new schema
@param new_name new file name
@retval
@@ -311,14 +312,14 @@ err_w_file:
*/
my_bool rename_in_schema_file(THD *thd,
const char *schema, const char *old_name,
- const char *new_name)
+ const char *new_db, const char *new_name)
{
char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN];
build_table_filename(old_path, sizeof(old_path) - 1,
schema, old_name, reg_ext, 0);
build_table_filename(new_path, sizeof(new_path) - 1,
- schema, new_name, reg_ext, 0);
+ new_db, new_name, reg_ext, 0);
if (my_rename(old_path, new_path, MYF(MY_WME)))
return 1;
diff --git a/sql/parse_file.h b/sql/parse_file.h
index cfac69cc471..84647e45927 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -83,7 +83,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
uchar* base, File_option *parameters);
my_bool rename_in_schema_file(THD *thd,
const char *schema, const char *old_name,
- const char *new_name);
+ const char *new_db, const char *new_name);
class File_parser: public Sql_alloc
{
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index fb609e12dcb..3004a3905e5 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -340,8 +340,7 @@ Rpl_filter::add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
e->tbl_name= e->db + (dot - table_spec) + 1;
e->key_len= len;
memcpy(e->db, table_spec, len);
- insert_dynamic(a, (uchar*)&e);
- return 0;
+ return insert_dynamic(a, (uchar*)&e);
}
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index aa1521acab6..f9b66990e93 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5614,7 +5614,7 @@ ER_SP_WRONG_NAME 42000
eng "Incorrect routine name '%-.192s'"
ger "Ungültiger Routinenname '%-.192s'"
ER_TABLE_NEEDS_UPGRADE
- eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" to fix it!"
+ eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" or dump/reload to fix it!"
ger "Tabellenaktualisierung erforderlich. Bitte zum Reparieren \"REPAIR TABLE `%-.32s`\" eingeben!"
ER_SP_NO_AGGREGATE 42000
eng "AGGREGATE is not supported for stored functions"
diff --git a/sql/slave.cc b/sql/slave.cc
index 8c29cb8a72f..81c18c5e04b 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -128,6 +128,7 @@ static bool wait_for_relay_log_space(Relay_log_info* rli);
static inline bool io_slave_killed(THD* thd,Master_info* mi);
static inline bool sql_slave_killed(THD* thd,Relay_log_info* rli);
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
+static void print_slave_skip_errors(void);
static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi);
static int safe_reconnect(THD* thd, MYSQL* mysql, Master_info* mi,
bool suppress_warnings);
@@ -142,8 +143,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi);
static Log_event* next_event(Relay_log_info* rli);
static int queue_event(Master_info* mi,const char* buf,ulong event_len);
static int terminate_slave_thread(THD *thd,
- pthread_mutex_t* term_lock,
- pthread_cond_t* term_cond,
+ pthread_mutex_t *term_lock,
+ pthread_cond_t *term_cond,
volatile uint *slave_running,
bool skip_lock);
static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info);
@@ -232,6 +233,15 @@ int init_slave()
active_mi= new Master_info;
/*
+ If --slave-skip-errors=... was not used, the string value for the
+ system variable has not been set up yet. Do it now.
+ */
+ if (!use_slave_mask)
+ {
+ print_slave_skip_errors();
+ }
+
+ /*
If master_host is not specified, try to read it from the master_info file.
If master_host is specified, create the master_info file if it doesn't
exists.
@@ -311,7 +321,7 @@ static void print_slave_skip_errors(void)
char *bend= buff + sizeof(slave_skip_error_names);
int errnum;
- for (errnum= 1; errnum < MAX_SLAVE_ERROR; errnum++)
+ for (errnum= 0; errnum < MAX_SLAVE_ERROR; errnum++)
{
if (bitmap_is_set(&slave_error_mask, errnum))
{
@@ -361,6 +371,7 @@ void init_slave_skip_errors(const char* arg)
if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
{
bitmap_set_all(&slave_error_mask);
+ print_slave_skip_errors();
DBUG_VOID_RETURN;
}
for (p= arg ; *p; )
@@ -388,22 +399,22 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
- if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)))
+ if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL))
{
DBUG_PRINT("info",("Terminating IO thread"));
mi->abort_slave=1;
- if ((error=terminate_slave_thread(mi->io_thd,io_lock,
+ if ((error=terminate_slave_thread(mi->io_thd, io_lock,
&mi->stop_cond,
&mi->slave_running,
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
}
- if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)))
+ if (thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL))
{
DBUG_PRINT("info",("Terminating SQL thread"));
mi->rli.abort_slave=1;
- if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
+ if ((error=terminate_slave_thread(mi->rli.sql_thd, sql_lock,
&mi->rli.stop_cond,
&mi->rli.slave_running,
skip_lock)) &&
@@ -441,29 +452,44 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
the condition. In this case, it is assumed that the calling
function acquires the lock before calling this function.
- @retval 0 All OK
+ @retval 0 All OK ER_SLAVE_NOT_RUNNING otherwise.
+
+ @note If the executing thread has to acquire term_lock (skip_lock
+ is false), the negative running status does not represent
+ any issue therefore no error is reported.
+
*/
static int
terminate_slave_thread(THD *thd,
- pthread_mutex_t* term_lock,
- pthread_cond_t* term_cond,
+ pthread_mutex_t *term_lock,
+ pthread_cond_t *term_cond,
volatile uint *slave_running,
bool skip_lock)
{
- int error;
-
DBUG_ENTER("terminate_slave_thread");
-
if (!skip_lock)
+ {
pthread_mutex_lock(term_lock);
-
- safe_mutex_assert_owner(term_lock);
-
+ }
+ else
+ {
+ safe_mutex_assert_owner(term_lock);
+ }
if (!*slave_running)
{
if (!skip_lock)
+ {
+ /*
+ if run_lock (term_lock) is acquired locally then either
+ slave_running status is fine
+ */
pthread_mutex_unlock(term_lock);
- DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
+ }
}
DBUG_ASSERT(thd != 0);
THD_CHECK_SENTRY(thd);
@@ -475,6 +501,7 @@ terminate_slave_thread(THD *thd,
while (*slave_running) // Should always be true
{
+ int error;
DBUG_PRINT("loop", ("killing slave thread"));
pthread_mutex_lock(&thd->LOCK_delete);
@@ -616,7 +643,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
&mi->rli.slave_running, &mi->rli.slave_run_id,
mi, 0);
if (error)
- terminate_slave_threads(mi, thread_mask & SLAVE_IO, 0);
+ terminate_slave_threads(mi, thread_mask & SLAVE_IO, !need_slave_mutex);
}
DBUG_RETURN(error);
}
@@ -687,6 +714,9 @@ static bool sql_slave_killed(THD* thd, Relay_log_info* rli)
DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
if (abort_loop || thd->killed || rli->abort_slave)
{
+ if (rli->abort_slave && rli->is_in_group() &&
+ thd->transaction.all.modified_non_trans_table)
+ DBUG_RETURN(0);
/*
If we are in an unsafe situation (stopping could corrupt replication),
we give one minute to the slave SQL thread of grace before really
@@ -2626,6 +2656,7 @@ err:
delete the mi structure leading to a crash! (see BUG#25306 for details)
*/
pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
+ DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
pthread_mutex_unlock(&mi->run_lock);
my_thread_end();
pthread_exit(0);
@@ -2713,7 +2744,8 @@ pthread_handler_t handle_slave_sql(void *arg)
*/
pthread_cond_broadcast(&rli->start_cond);
pthread_mutex_unlock(&rli->run_lock);
- sql_print_error("Failed during slave thread initialization");
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ "Failed during slave thread initialization");
goto err;
}
thd->init_for_queries();
@@ -2757,9 +2789,9 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->group_relay_log_pos,
1 /*need data lock*/, &errmsg,
1 /*look for a description_event*/))
- {
- sql_print_error("Error initializing relay log position: %s",
- errmsg);
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ "Error initializing relay log position: %s", errmsg);
goto err;
}
THD_CHECK_SENTRY(thd);
@@ -2812,8 +2844,8 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
execute_init_command(thd, &sys_init_slave, &LOCK_sys_init_slave);
if (thd->is_slave_error)
{
- sql_print_error("\
-Slave SQL thread aborted. Can't execute init_slave query");
+ rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
+ "Slave SQL thread aborted. Can't execute init_slave query");
goto err;
}
}
@@ -2863,10 +2895,20 @@ Slave SQL thread aborted. Can't execute init_slave query");
thd->main_da.sql_errno(), last_errno));
if (last_errno == 0)
{
+ /*
+ This function is reporting an error which was not reported
+ while executing exec_relay_log_event().
+ */
rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg);
}
else if (last_errno != thd->main_da.sql_errno())
{
+ /*
+ * An error was reported while executing exec_relay_log_event()
+ * however the error code differs from what is in the thread.
+ * This function prints out more information to help finding
+ * what caused the problem.
+ */
sql_print_error("Slave (additional info): %s Error_code: %d",
errmsg, thd->main_da.sql_errno());
}
@@ -2964,6 +3006,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
delete the mi structure leading to a crash! (see BUG#25306 for details)
*/
pthread_cond_broadcast(&rli->stop_cond);
+ DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
pthread_mutex_unlock(&rli->run_lock); // tell the world we are done
my_thread_end();
diff --git a/sql/sp.cc b/sql/sp.cc
index b2c7c389136..8c8149d0afc 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -940,7 +940,8 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
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);
+ log_query.c_ptr(), log_query.length(),
+ FALSE, FALSE, THD::NOT_KILLED);
thd->variables.sql_mode= 0;
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index fcf51aac1b5..1dba8a45926 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -207,6 +207,7 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_TABLES:
+ case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_WARNS:
case SQLCOM_REPAIR:
@@ -2132,17 +2133,16 @@ sp_head::restore_lex(THD *thd)
/**
Put the instruction on the backpatch list, associated with the label.
*/
-void
+int
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
{
bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
- if (bp)
- {
- bp->lab= lab;
- bp->instr= i;
- (void)m_backpatch.push_front(bp);
- }
+ if (!bp)
+ return 1;
+ bp->lab= lab;
+ bp->instr= i;
+ return m_backpatch.push_front(bp);
}
/**
@@ -2217,7 +2217,7 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
}
-void
+int
sp_head::new_cont_backpatch(sp_instr_opt_meta *i)
{
m_cont_level+= 1;
@@ -2225,15 +2225,17 @@ sp_head::new_cont_backpatch(sp_instr_opt_meta *i)
{
/* Use the cont. destination slot to store the level */
i->m_cont_dest= m_cont_level;
- (void)m_cont_backpatch.push_front(i);
+ if (m_cont_backpatch.push_front(i))
+ return 1;
}
+ return 0;
}
-void
+int
sp_head::add_cont_backpatch(sp_instr_opt_meta *i)
{
i->m_cont_dest= m_cont_level;
- (void)m_cont_backpatch.push_front(i);
+ return m_cont_backpatch.push_front(i);
}
void
@@ -2469,7 +2471,7 @@ sp_head::show_create_routine(THD *thd, int type)
@param instr Instruction
*/
-void sp_head::add_instr(sp_instr *instr)
+int sp_head::add_instr(sp_instr *instr)
{
instr->free_list= m_thd->free_list;
m_thd->free_list= 0;
@@ -2480,7 +2482,7 @@ void sp_head::add_instr(sp_instr *instr)
entire stored procedure, as their life span is equal.
*/
instr->mem_root= &main_mem_root;
- insert_dynamic(&m_instr, (uchar*)&instr);
+ return insert_dynamic(&m_instr, (uchar*)&instr);
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index c17b67f962a..dd11f8693ac 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -308,7 +308,7 @@ public:
bool
show_create_routine(THD *thd, int type);
- void
+ int
add_instr(sp_instr *instr);
inline uint
@@ -344,7 +344,7 @@ public:
restore_lex(THD *thd);
/// Put the instruction on the backpatch list, associated with the label.
- void
+ int
push_backpatch(sp_instr *, struct sp_label *);
/// Update all instruction with this label in the backpatch list to
@@ -353,11 +353,11 @@ public:
backpatch(struct sp_label *);
/// Start a new cont. backpatch level. If 'i' is NULL, the level is just incr.
- void
+ int
new_cont_backpatch(sp_instr_opt_meta *i);
/// Add an instruction to the current level
- void
+ int
add_cont_backpatch(sp_instr_opt_meta *i);
/// Backpatch (and pop) the current level to the current position.
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 414ea12cd7a..302faf3f681 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -265,8 +265,8 @@ sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type,
p->mode= mode;
p->offset= current_var_count();
p->dflt= NULL;
- insert_dynamic(&m_vars, (uchar*)&p);
-
+ if (insert_dynamic(&m_vars, (uchar*)&p))
+ return NULL;
return p;
}
@@ -310,18 +310,17 @@ sp_pcontext::find_label(char *name)
return NULL;
}
-void
+int
sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
{
sp_cond_t *p= (sp_cond_t *)sql_alloc(sizeof(sp_cond_t));
- if (p)
- {
- p->name.str= name->str;
- p->name.length= name->length;
- p->val= val;
- insert_dynamic(&m_conds, (uchar*)&p);
- }
+ if (p == NULL)
+ return 1;
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->val= val;
+ return insert_dynamic(&m_conds, (uchar *)&p);
}
/*
@@ -384,7 +383,7 @@ sp_pcontext::find_handler(sp_cond_type_t *cond)
return FALSE;
}
-void
+int
sp_pcontext::push_cursor(LEX_STRING *name)
{
LEX_STRING n;
@@ -393,7 +392,7 @@ sp_pcontext::push_cursor(LEX_STRING *name)
m_max_cursor_index+= 1;
n.str= name->str;
n.length= name->length;
- insert_dynamic(&m_cursors, (uchar*)&n);
+ return insert_dynamic(&m_cursors, (uchar *)&n);
}
/*
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index aefc501b3b0..3145ba2fea4 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -323,7 +323,7 @@ public:
// Conditions
//
- void
+ int
push_cond(LEX_STRING *name, sp_cond_type_t *val);
inline void
@@ -365,7 +365,7 @@ public:
// Cursors
//
- void
+ int
push_cursor(LEX_STRING *name);
my_bool
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index bd940608a07..b1dbb7031ce 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1647,7 +1647,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);
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
}
end:
close_thread_tables(thd);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 4f08aa0c07f..0dc29f7e3c2 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1541,19 +1541,8 @@ void close_temporary_tables(THD *thd)
thd->variables.character_set_client= system_charset_info;
Query_log_event qinfo(thd, s_query.ptr(),
s_query.length() - 1 /* to remove trailing ',' */,
- 0, FALSE);
+ 0, FALSE, THD::NOT_KILLED);
thd->variables.character_set_client= cs_save;
- /*
- Imagine the thread had created a temp table, then was doing a
- SELECT, and the SELECT was killed. Then it's not clever to
- mark the statement above as "killed", because it's not really
- a statement updating data, and there are 99.99% chances it
- will succeed on slave. If a real update (one updating a
- persistent table) was killed on the master, then this real
- update will be logged with error_code=killed, rightfully
- causing the slave to stop.
- */
- qinfo.error_code= 0;
mysql_bin_log.write(&qinfo);
thd->variables.pseudo_thread_id= save_pseudo_thread_id;
}
@@ -3855,6 +3844,16 @@ retry:
if (share->is_view)
{
/*
+ If parent_l of the table_list is non null then a merge table
+ has this view as child table, which is not supported.
+ */
+ if (table_list->parent_l)
+ {
+ my_error(ER_WRONG_MRG_TABLE, MYF(0));
+ goto err;
+ }
+
+ /*
This table is a view. Validate its metadata version: in particular,
that it was a view when the statement was prepared.
*/
@@ -4017,7 +4016,8 @@ retry:
end = strxmov(strmov(query, "DELETE FROM `"),
share->db.str,"`.`",share->table_name.str,"`", NullS);
thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, (ulong)(end-query), FALSE, FALSE);
+ query, (ulong)(end-query),
+ FALSE, FALSE, THD::NOT_KILLED);
my_free(query, MYF(0));
}
else
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 7f15508caa1..b73822f5a48 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3676,7 +3676,11 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
if (sql_log_bin_toplevel && lex->is_stmt_unsafe() &&
variables.binlog_format == BINLOG_FORMAT_STMT)
{
- push_warning(this, MYSQL_ERROR::WARN_LEVEL_WARN,
+ /*
+ A warning can be elevated a error when STRICT sql mode.
+ But we don't want to elevate binlog warning to error here.
+ */
+ push_warning(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_BINLOG_UNSAFE_STATEMENT,
ER(ER_BINLOG_UNSAFE_STATEMENT));
if (!(binlog_flags & BINLOG_FLAG_UNSAFE_STMT_PRINTED))
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index aa21d429d90..c4f93cc2a33 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -28,10 +28,10 @@
#include "mysql_priv.h"
-SQL_CRYPT::SQL_CRYPT(const char *password)
+SQL_CRYPT::SQL_CRYPT(const char *password, uint length)
{
ulong rand_nr[2];
- hash_password(rand_nr,password, (uint) strlen(password));
+ hash_password(rand_nr,password, length);
crypt_init(rand_nr);
}
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index f3db9adde25..a5a6bee8a58 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -25,7 +25,7 @@ class SQL_CRYPT :public Sql_alloc
uint shift;
void crypt_init(ulong *seed);
public:
- SQL_CRYPT(const char *seed);
+ SQL_CRYPT(const char *seed, uint length);
SQL_CRYPT(ulong *seed)
{
crypt_init(seed);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 72ae664bba1..5a266c3fac9 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -181,7 +181,7 @@ uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
static inline void 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);
+ Query_log_event qinfo(thd, query, q_len, 0, 0, THD::NOT_KILLED);
qinfo.error_code= 0;
qinfo.db= db;
qinfo.db_len= db_len;
@@ -724,7 +724,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE);
+ /* suppress_use */ TRUE, THD::NOT_KILLED);
/*
Write should use the database being created as the "current
@@ -812,7 +812,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
- /* suppress_use */ TRUE);
+ /* suppress_use */ TRUE, THD::NOT_KILLED);
/*
Write should use the database being created as the "current
@@ -959,7 +959,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE);
+ /* suppress_use */ TRUE, THD::NOT_KILLED);
/*
Write should use the database being created as the "current
database" and not the threads current database, which is the
@@ -1958,7 +1958,8 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
/* Step8: logging */
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, TRUE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ 0, TRUE, THD::NOT_KILLED);
thd->clear_error();
mysql_bin_log.write(&qinfo);
}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 9c8bba6208c..16810e29343 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -199,6 +199,14 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
tables->db, tables->table_name, tables->alias,
(int) reopen));
+ if (tables->schema_table)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "HANDLER OPEN",
+ INFORMATION_SCHEMA_NAME.str);
+ DBUG_PRINT("exit",("ERROR"));
+ DBUG_RETURN(TRUE);
+ }
+
if (! hash_inited(&thd->handler_tables_hash))
{
/*
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e6eb9a8a44e..b96ac91679b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -348,6 +348,7 @@ void lex_start(THD *thd)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
+ lex->protect_against_global_read_lock= FALSE;
/*
ok, there must be a better solution for this, long-term
I tried "bzero" in the sql_yacc.yy code, but that for
@@ -712,6 +713,53 @@ static inline uint int_token(const char *str,uint length)
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
}
+
+/**
+ Given a stream that is advanced to the first contained character in
+ an open comment, consume the comment. Optionally, if we are allowed,
+ recurse so that we understand comments within this current comment.
+
+ At this level, we do not support version-condition comments. We might
+ have been called with having just passed one in the stream, though. In
+ that case, we probably want to tolerate mundane comments inside. Thus,
+ the case for recursion.
+
+ @retval Whether EOF reached before comment is closed.
+*/
+bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
+{
+ reg1 uchar c;
+ while (! lip->eof())
+ {
+ c= lip->yyGet();
+
+ if (remaining_recursions_permitted > 0)
+ {
+ if ((c == '/') && (lip->yyPeek() == '*'))
+ {
+ lip->yySkip(); /* Eat asterisk */
+ consume_comment(lip, remaining_recursions_permitted-1);
+ continue;
+ }
+ }
+
+ if (c == '*')
+ {
+ if (lip->yyPeek() == '/')
+ {
+ lip->yySkip(); /* Eat slash */
+ return FALSE;
+ }
+ }
+
+ if (c == '\n')
+ lip->yylineno++;
+ }
+
+ return TRUE;
+}
+
+
/*
MYSQLlex remember the following states from the following MYSQLlex()
@@ -1204,6 +1252,8 @@ int MYSQLlex(void *arg, void *yythd)
/* Reject '/' '*', since we might need to turn off the echo */
lip->yyUnget();
+ lip->save_in_comment_state();
+
if (lip->yyPeekn(2) == '!')
{
lip->in_comment= DISCARD_COMMENT;
@@ -1246,11 +1296,17 @@ int MYSQLlex(void *arg, void *yythd)
/* Expand the content of the special comment as real code */
lip->set_echo(TRUE);
state=MY_LEX_START;
- break;
+ break; /* Do not treat contents as a comment. */
+ }
+ else
+ {
+ comment_closed= ! consume_comment(lip, 1);
+ /* version allowed to have one level of comment inside. */
}
}
else
{
+ /* Not a version comment. */
state=MY_LEX_START;
lip->set_echo(TRUE);
break;
@@ -1261,38 +1317,30 @@ int MYSQLlex(void *arg, void *yythd)
lip->in_comment= PRESERVE_COMMENT;
lip->yySkip(); // Accept /
lip->yySkip(); // Accept *
+ comment_closed= ! consume_comment(lip, 0);
+ /* regular comments can have zero comments inside. */
}
/*
Discard:
- regular '/' '*' comments,
- special comments '/' '*' '!' for a future version,
by scanning until we find a closing '*' '/' marker.
- Note: There is no such thing as nesting comments,
- the first '*' '/' sequence seen will mark the end.
+
+ Nesting regular comments isn't allowed. The first
+ '*' '/' returns the parser to the previous state.
+
+ /#!VERSI oned containing /# regular #/ is allowed #/
+
+ Inside one versioned comment, another versioned comment
+ is treated as a regular discardable comment. It gets
+ no special parsing.
*/
- comment_closed= FALSE;
- while (! lip->eof())
- {
- c= lip->yyGet();
- if (c == '*')
- {
- if (lip->yyPeek() == '/')
- {
- lip->yySkip();
- comment_closed= TRUE;
- state = MY_LEX_START;
- break;
- }
- }
- else if (c == '\n')
- lip->yylineno++;
- }
+
/* Unbalanced comments with a missing '*' '/' are a syntax error */
if (! comment_closed)
return (ABORT_SYM);
state = MY_LEX_START; // Try again
- lip->in_comment= NO_COMMENT;
- lip->set_echo(TRUE);
+ lip->restore_in_comment_state();
break;
case MY_LEX_END_LONG_COMMENT:
if ((lip->in_comment != NO_COMMENT) && lip->yyPeek() == '/')
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f34a1c7c36f..62106a2500b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1160,6 +1160,18 @@ public:
m_echo= echo;
}
+ void save_in_comment_state()
+ {
+ m_echo_saved= m_echo;
+ in_comment_saved= in_comment;
+ }
+
+ void restore_in_comment_state()
+ {
+ m_echo= m_echo_saved;
+ in_comment= in_comment_saved;
+ }
+
/**
Skip binary from the input stream.
@param n number of bytes to accept.
@@ -1417,6 +1429,7 @@ private:
/** Echo the parsed stream to the pre-processed buffer. */
bool m_echo;
+ bool m_echo_saved;
/** Pre-processed buffer. */
char *m_cpp_buf;
@@ -1479,6 +1492,7 @@ public:
/** State of the lexical analyser for comments. */
enum_comment_state in_comment;
+ enum_comment_state in_comment_saved;
/**
Starting position of the TEXT_STRING or IDENT in the pre-processed
@@ -1745,6 +1759,22 @@ typedef struct st_lex : public Query_tables_list
bool escape_used;
bool is_lex_started; /* If lex_start() did run. For debugging. */
+ /*
+ Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE.
+
+ Protect from a impending GRL as otherwise the thread might deadlock
+ if it starts waiting for the GRL in mysql_lock_tables.
+
+ The protection is needed because there is a race between setting
+ the global read lock and waiting for all open tables to be closed.
+ The problem is a circular wait where a thread holding "old" open
+ tables will wait for the global read lock to be released while the
+ thread holding the global read lock will wait for all "old" open
+ tables to be closed -- the flush part of flush tables with read
+ lock.
+ */
+ bool protect_against_global_read_lock;
+
st_lex();
virtual ~st_lex()
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2974dff9ea9..6dbe4a4fd8d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2200,8 +2200,15 @@ mysql_execute_command(THD *thd)
res= check_access(thd,
lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
any_db, 0, 0, 0, 0);
- if (!res)
- res= execute_sqlcom_select(thd, all_tables);
+
+ if (res)
+ break;
+
+ if (!thd->locked_tables && lex->protect_against_global_read_lock &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ break;
+
+ res= execute_sqlcom_select(thd, all_tables);
break;
case SQLCOM_PREPARE:
{
@@ -3006,6 +3013,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
break;
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
res= (up_result= mysql_update(thd, all_tables,
@@ -3032,6 +3042,15 @@ end_with_restore_list:
else
res= 0;
+ /*
+ Protection might have already been risen if its a fall through
+ from the SQLCOM_UPDATE case above.
+ */
+ if (!thd->locked_tables &&
+ lex->sql_command == SQLCOM_UPDATE_MULTI &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
res= mysql_multi_update_prepare(thd);
#ifdef HAVE_REPLICATION
@@ -3229,7 +3248,8 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
-
+ if (!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
res= mysql_truncate(thd, first_table, 0);
break;
case SQLCOM_DELETE:
@@ -3402,6 +3422,10 @@ end_with_restore_list:
if (check_one_table_access(thd, privilege, all_tables))
goto error;
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
lex->update_list, lex->value_list, lex->duplicates,
lex->ignore, (bool) lex->local_file);
@@ -3472,6 +3496,9 @@ end_with_restore_list:
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
UINT_MAX, FALSE))
goto error;
+ if (lex->protect_against_global_read_lock &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index fc87356e452..d4331b12cd4 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -301,12 +301,17 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
}
break;
case FRMTYPE_VIEW:
- /* change of schema is not allowed */
- if (strcmp(ren_table->db, new_db))
+ /*
+ change of schema is not allowed
+ except of ALTER ...UPGRADE DATA DIRECTORY NAME command
+ because a view has valid internal db&table names in this case.
+ */
+ if (thd->lex->sql_command != SQLCOM_ALTER_DB_UPGRADE &&
+ strcmp(ren_table->db, new_db))
my_error(ER_FORBID_SCHEMA_CHANGE, MYF(0), ren_table->db,
new_db);
else
- rc= mysql_rename_view(thd, new_alias, ren_table);
+ rc= mysql_rename_view(thd, new_db, new_alias, ren_table);
break;
default:
DBUG_ASSERT(0); // should never happen
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 6285a2dfb55..06c6c022780 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1026,7 +1026,10 @@ int reset_slave(THD *thd, Master_info* mi)
if ((error= purge_relay_logs(&mi->rli, thd,
1 /* just reset */,
&errmsg)))
+ {
+ sql_errno= ER_RELAY_LOG_FAIL;
goto err;
+ }
/*
Clear master's log coordinates and reset host/user/etc to the values
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0a3238b0185..901e058d934 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3476,14 +3476,6 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
}
}
-/**
- Add all keys with uses 'field' for some keypart.
-
- If field->and_level != and_level then only mark key_part as const_part.
-
- @todo
- ft-keys in non-ft queries. SerG
-*/
static uint
max_part_bit(key_part_map bits)
@@ -3493,7 +3485,16 @@ max_part_bit(key_part_map bits)
return found;
}
-static void
+/*
+ Add all keys with uses 'field' for some keypart
+ If field->and_level != and_level then only mark key_part as const_part
+
+ RETURN
+ 0 - OK
+ 1 - Out of memory.
+*/
+
+static bool
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
Field *field=key_field->field;
@@ -3523,24 +3524,26 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL;
keyuse.null_rejecting= key_field->null_rejecting;
keyuse.cond_guard= key_field->cond_guard;
- VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
+ if (insert_dynamic(keyuse_array,(uchar*) &keyuse))
+ return TRUE;
}
}
}
}
+ return FALSE;
}
#define FT_KEYPART (MAX_REF_PARTS+10)
-static void
+static bool
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
JOIN_TAB *stat,COND *cond,table_map usable_tables)
{
Item_func_match *cond_func=NULL;
if (!cond)
- return;
+ return FALSE;
if (cond->type() == Item::FUNC_ITEM)
{
@@ -3574,13 +3577,16 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
{
Item *item;
while ((item=li++))
- add_ft_keys(keyuse_array,stat,item,usable_tables);
+ {
+ if (add_ft_keys(keyuse_array,stat,item,usable_tables))
+ return TRUE;
+ }
}
}
if (!cond_func || cond_func->key == NO_SUCH_KEY ||
!(usable_tables & cond_func->table->map))
- return;
+ return FALSE;
KEYUSE keyuse;
keyuse.table= cond_func->table;
@@ -3590,7 +3596,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
keyuse.used_tables=cond_func->key_item()->used_tables();
keyuse.optimize= 0;
keyuse.keypart_map= 0;
- VOID(insert_dynamic(keyuse_array,(uchar*) &keyuse));
+ return insert_dynamic(keyuse_array,(uchar*) &keyuse);
}
@@ -3744,7 +3750,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
sargables);
for (; field != end ; field++)
{
- add_key_part(keyuse,field);
+ if (add_key_part(keyuse,field))
+ return TRUE;
/* Mark that we can optimize LEFT JOIN */
if (field->val->type() == Item::NULL_ITEM &&
!field->field->real_maybe_null())
@@ -3782,11 +3789,15 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* fill keyuse with found key parts */
for ( ; field != end ; field++)
- add_key_part(keyuse,field);
+ {
+ if (add_key_part(keyuse,field))
+ return TRUE;
+ }
if (select_lex->ftfunc_list->elements)
{
- add_ft_keys(keyuse,join_tab,cond,normal_tables);
+ if (add_ft_keys(keyuse,join_tab,cond,normal_tables))
+ return TRUE;
}
/*
@@ -3807,7 +3818,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
(qsort_cmp) sort_keyuse);
bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */
- VOID(insert_dynamic(keyuse,(uchar*) &key_end));
+ if (insert_dynamic(keyuse,(uchar*) &key_end))
+ return TRUE;
use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
prev= &key_end;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 842ece1dec4..29d43155778 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1463,7 +1463,7 @@ void write_bin_log(THD *thd, bool clear_error,
if (clear_error)
thd->clear_error();
thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, query_length, FALSE, FALSE);
+ query, query_length, FALSE, FALSE, THD::NOT_KILLED);
}
}
@@ -6165,7 +6165,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
my_ok(thd);
@@ -7488,6 +7489,16 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
{
for (;;)
{
+ if (thd->killed)
+ {
+ /*
+ we've been killed; let handler clean up, and remove the
+ partial current row from the recordset (embedded lib)
+ */
+ t->file->ha_rnd_end();
+ thd->protocol->remove_last_row();
+ goto err;
+ }
ha_checksum row_crc= 0;
int error= t->file->rnd_next(t->record[0]);
if (unlikely(error))
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 78932396efe..eeb9a21b6f5 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -33,18 +33,20 @@
static const char *lock_descriptions[] =
{
- "No lock",
- "Low priority read lock",
- "Shared Read lock",
- "High priority read lock",
- "Read lock without concurrent inserts",
- "Write lock that allows other writers",
- "Write lock, but allow reading",
- "Concurrent insert lock",
- "Lock Used by delayed insert",
- "Low priority write lock",
- "High priority write lock",
- "Highest priority write lock"
+ /* TL_UNLOCK */ "No lock",
+ /* TL_READ_DEFAULT */ NULL,
+ /* TL_READ */ "Low priority read lock",
+ /* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock",
+ /* TL_READ_HIGH_PRIORITY */ "High priority read lock",
+ /* TL_READ_NO_INSERT */ "Read lock without concurrent inserts",
+ /* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers",
+ /* TL_WRITE_ALLOW_READ */ "Write lock, but allow reading",
+ /* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock",
+ /* TL_WRITE_DELAYED */ "Lock used by delayed insert",
+ /* TL_WRITE_DEFAULT */ NULL,
+ /* TL_WRITE_LOW_PRIORITY */ "Low priority write lock",
+ /* TL_WRITE */ "High priority write lock",
+ /* TL_WRITE_ONLY */ "Highest priority write lock"
};
@@ -75,6 +77,8 @@ void print_cached_tables(void)
uint idx,count,unused;
TABLE *start_link,*lnk;
+ compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
+
/* purecov: begin tested */
VOID(pthread_mutex_lock(&LOCK_open));
puts("DB Table Version Thread Open Lock");
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 65157ae4255..4f207f78688 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -662,7 +662,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
buff.append(views->source.str, views->source.length);
thd->binlog_query(THD::STMT_QUERY_TYPE,
- buff.ptr(), buff.length(), FALSE, FALSE);
+ buff.ptr(), buff.length(), FALSE, FALSE, THD::NOT_KILLED);
}
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -1912,6 +1912,7 @@ int view_checksum(THD *thd, TABLE_LIST *view)
Parameters:
thd thread handler
+ new_db new name of database
new_name new name of view
view view
@@ -1921,6 +1922,7 @@ int view_checksum(THD *thd, TABLE_LIST *view)
*/
bool
mysql_rename_view(THD *thd,
+ const char *new_db,
const char *new_name,
TABLE_LIST *view)
{
@@ -1959,16 +1961,16 @@ mysql_rename_view(THD *thd,
goto err;
/* rename view and it's backups */
- if (rename_in_schema_file(thd, view->db, view->table_name, new_name))
+ if (rename_in_schema_file(thd, view->db, view->table_name, new_db, new_name))
goto err;
dir.str= dir_buff;
dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1,
- view->db, "", "", 0);
+ new_db, "", "", 0);
pathstr.str= path_buff;
pathstr.length= build_table_filename(path_buff, sizeof(path_buff) - 1,
- view->db, new_name, reg_ext, 0);
+ new_db, new_name, reg_ext, 0);
file.str= pathstr.str + dir.length;
file.length= pathstr.length - dir.length;
@@ -1977,7 +1979,7 @@ mysql_rename_view(THD *thd,
(uchar*)&view_def, view_parameters))
{
/* restore renamed view in case of error */
- rename_in_schema_file(thd, view->db, new_name, view->table_name);
+ rename_in_schema_file(thd, new_db, new_name, view->db, view->table_name);
goto err;
}
} else
diff --git a/sql/sql_view.h b/sql/sql_view.h
index b8138663489..e08c2168e14 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -37,7 +37,8 @@ int view_checksum(THD *thd, TABLE_LIST *view);
extern TYPELIB updatable_views_with_limit_typelib;
bool check_duplicate_names(List<Item>& item_list, bool gen_unique_view_names);
-bool mysql_rename_view(THD *thd, const char *new_name, TABLE_LIST *view);
+bool mysql_rename_view(THD *thd, const char *new_db, const char *new_name,
+ TABLE_LIST *view);
#define VIEW_ANY_ACL (SELECT_ACL | UPDATE_ACL | INSERT_ACL | DELETE_ACL)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e56ff7c6ad7..0b158ff7574 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -280,9 +280,7 @@ int case_stmt_action_expr(LEX *lex, Item* expr)
parsing_ctx, case_expr_id, expr, lex);
sp->add_cont_backpatch(i);
- sp->add_instr(i);
-
- return 0;
+ return sp->add_instr(i);
}
/**
@@ -293,7 +291,7 @@ int case_stmt_action_expr(LEX *lex, Item* expr)
@param simple true for simple cases, false for searched cases
*/
-void case_stmt_action_when(LEX *lex, Item *when, bool simple)
+int case_stmt_action_when(LEX *lex, Item *when, bool simple)
{
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
@@ -325,9 +323,10 @@ void case_stmt_action_when(LEX *lex, Item *when, bool simple)
(jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
*/
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- sp->add_cont_backpatch(i);
- sp->add_instr(i);
+ return !test(i) ||
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+ sp->add_cont_backpatch(i) ||
+ sp->add_instr(i);
}
/**
@@ -336,13 +335,14 @@ void case_stmt_action_when(LEX *lex, Item *when, bool simple)
@param lex the parser lex context
*/
-void case_stmt_action_then(LEX *lex)
+int case_stmt_action_then(LEX *lex)
{
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
- sp->add_instr(i);
+ if (!test(i) || sp->add_instr(i))
+ return 1;
/*
BACKPATCH: Resolving forward jump from
@@ -358,7 +358,7 @@ void case_stmt_action_then(LEX *lex)
(jump from instruction 4 to 12, 7 to 12 ... in the example)
*/
- sp->push_backpatch(i, ctx->last_label());
+ return sp->push_backpatch(i, ctx->last_label());
}
/**
@@ -2322,10 +2322,9 @@ sp_decl:
var_type,
lex,
(i == num_vars - 1));
- if (is == NULL)
+ if (is == NULL ||
+ lex->sphead->add_instr(is))
MYSQL_YYABORT;
-
- lex->sphead->add_instr(is);
}
pctx->declare_var_boundary(0);
@@ -2339,12 +2338,13 @@ sp_decl:
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
- if (spc->find_cond(&$2, TRUE))
- {
- my_error(ER_SP_DUP_COND, MYF(0), $2.str);
+ if (spc->find_cond(&$2, TRUE))
+ {
+ my_error(ER_SP_DUP_COND, MYF(0), $2.str);
+ MYSQL_YYABORT;
+ }
+ if(YYTHD->lex->spcont->push_cond(&$2, $5))
MYSQL_YYABORT;
- }
- YYTHD->lex->spcont->push_cond(&$2, $5);
$$.vars= $$.hndlrs= $$.curs= 0;
$$.conds= 1;
}
@@ -2358,11 +2358,11 @@ sp_decl:
sp_pcontext *ctx= lex->spcont;
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
- ctx->current_var_count());
- if (i == NULL)
+ ctx->current_var_count());
+ if (i == NULL ||
+ sp->add_instr(i) ||
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0)))
MYSQL_YYABORT;
- sp->add_instr(i);
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
}
sp_hcond_list sp_proc_stmt
{
@@ -2376,17 +2376,17 @@ sp_decl:
{
i= new sp_instr_hreturn(sp->instructions(), ctx,
ctx->current_var_count());
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
else
{ /* EXIT or UNDO handler, just jump to the end of the block */
i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i) ||
+ sp->push_backpatch(i, lex->spcont->last_label())) /* Block end */
MYSQL_YYABORT;
- sp->add_instr(i);
- sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
}
lex->sphead->backpatch(hlab);
@@ -2412,10 +2412,10 @@ sp_decl:
}
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
ctx->current_cursor_count());
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i) ||
+ ctx->push_cursor(&$2))
MYSQL_YYABORT;
- sp->add_instr(i);
- ctx->push_cursor(&$2);
$$.vars= $$.conds= $$.hndlrs= 0;
$$.curs= 1;
}
@@ -2652,10 +2652,11 @@ sp_proc_stmt_statement:
i->m_query.length= lip->get_ptr() - sp->m_tmp_query;
else
i->m_query.length= lip->get_tok_end() - sp->m_tmp_query;
- i->m_query.str= strmake_root(thd->mem_root,
- sp->m_tmp_query,
- i->m_query.length);
- sp->add_instr(i);
+ if (!(i->m_query.str= strmake_root(thd->mem_root,
+ sp->m_tmp_query,
+ i->m_query.length)) ||
+ sp->add_instr(i))
+ MYSQL_YYABORT;
}
sp->restore_lex(thd);
}
@@ -2680,9 +2681,9 @@ sp_proc_stmt_return:
i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
sp->m_return_field_def.sql_type, lex);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
sp->m_flags|= sp_head::HAS_RETURN;
}
sp->restore_lex(YYTHD);
@@ -2779,22 +2780,22 @@ sp_proc_stmt_iterate:
if (n)
{
sp_instr_hpop *hpop= new sp_instr_hpop(ip++, ctx, n);
- if (hpop == NULL)
+ if (hpop == NULL ||
+ sp->add_instr(hpop))
MYSQL_YYABORT;
- sp->add_instr(hpop);
}
n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */
if (n)
{
sp_instr_cpop *cpop= new sp_instr_cpop(ip++, ctx, n);
- if (cpop == NULL)
+ if (cpop == NULL ||
+ sp->add_instr(cpop))
MYSQL_YYABORT;
- sp->add_instr(cpop);
}
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
}
;
@@ -2813,9 +2814,9 @@ sp_proc_stmt_open:
MYSQL_YYABORT;
}
i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
;
@@ -2833,9 +2834,9 @@ sp_proc_stmt_fetch:
MYSQL_YYABORT;
}
i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
sp_fetch_list
{}
@@ -2855,9 +2856,9 @@ sp_proc_stmt_close:
MYSQL_YYABORT;
}
i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
;
@@ -2920,12 +2921,11 @@ sp_if:
uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
$2, lex);
- if (i == NULL)
+ if (i == NULL ||
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0)) ||
+ sp->add_cont_backpatch(i) ||
+ sp->add_instr(i))
MYSQL_YYABORT;
-
- sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- sp->add_cont_backpatch(i);
- sp->add_instr(i);
sp->restore_lex(YYTHD);
}
sp_proc_stmts1
@@ -2934,10 +2934,9 @@ sp_if:
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
-
- sp->add_instr(i);
sp->backpatch(ctx->pop_label());
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
}
@@ -3021,14 +3020,16 @@ simple_when_clause:
/* Simple case: <caseval> = <whenval> */
LEX *lex= Lex;
- case_stmt_action_when(lex, $3, true);
+ if (case_stmt_action_when(lex, $3, true))
+ MYSQL_YYABORT;
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
THEN_SYM
sp_proc_stmts1
{
LEX *lex= Lex;
- case_stmt_action_then(lex);
+ if (case_stmt_action_then(lex))
+ MYSQL_YYABORT;
}
;
@@ -3040,14 +3041,16 @@ searched_when_clause:
expr
{
LEX *lex= Lex;
- case_stmt_action_when(lex, $3, false);
+ if (case_stmt_action_when(lex, $3, false))
+ MYSQL_YYABORT;
lex->sphead->restore_lex(YYTHD); /* For expr $3 */
}
THEN_SYM
sp_proc_stmts1
{
LEX *lex= Lex;
- case_stmt_action_then(lex);
+ if (case_stmt_action_then(lex))
+ MYSQL_YYABORT;
}
;
@@ -3059,9 +3062,9 @@ else_clause_opt:
uint ip= sp->instructions();
sp_instr_error *i= new sp_instr_error(ip, lex->spcont,
ER_SP_CASE_NOT_FOUND);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
| ELSE sp_proc_stmts1
;
@@ -3175,16 +3178,16 @@ sp_block_content:
if ($3.hndlrs)
{
i= new sp_instr_hpop(sp->instructions(), ctx, $3.hndlrs);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
if ($3.curs)
{
i= new sp_instr_cpop(sp->instructions(), ctx, $3.curs);
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
}
lex->spcont= ctx->pop_context();
}
@@ -3198,10 +3201,10 @@ sp_unlabeled_control:
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
- if (i == NULL)
+ if (i == NULL ||
+ lex->sphead->add_instr(i))
MYSQL_YYABORT;
- lex->sphead->add_instr(i);
- }
+ }
| WHILE_SYM
{ Lex->sphead->reset_lex(YYTHD); }
expr DO_SYM
@@ -3211,12 +3214,12 @@ sp_unlabeled_control:
uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
$3, lex);
- if (i == NULL)
+ if (i == NULL ||
+ /* Jumping forward */
+ sp->push_backpatch(i, lex->spcont->last_label()) ||
+ sp->new_cont_backpatch(i) ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- /* Jumping forward */
- sp->push_backpatch(i, lex->spcont->last_label());
- sp->new_cont_backpatch(i);
- sp->add_instr(i);
sp->restore_lex(YYTHD);
}
sp_proc_stmts1 END WHILE_SYM
@@ -3225,9 +3228,9 @@ sp_unlabeled_control:
uint ip= lex->sphead->instructions();
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
- if (i == NULL)
+ if (i == NULL ||
+ lex->sphead->add_instr(i))
MYSQL_YYABORT;
- lex->sphead->add_instr(i);
lex->sphead->do_cont_backpatch();
}
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
@@ -3240,9 +3243,9 @@ sp_unlabeled_control:
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
$5, lab->ip,
lex);
- if (i == NULL)
+ if (i == NULL ||
+ lex->sphead->add_instr(i))
MYSQL_YYABORT;
- lex->sphead->add_instr(i);
lex->sphead->restore_lex(YYTHD);
/* We can shortcut the cont_backpatch here */
i->m_cont_dest= ip+1;
@@ -6538,6 +6541,7 @@ select_lock_type:
lex->current_select->set_lock_for_tables(TL_WRITE);
lex->current_select->lock_option= TL_WRITE;
lex->safe_to_cache_query=0;
+ lex->protect_against_global_read_lock= TRUE;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
@@ -11750,7 +11754,8 @@ option_type_value:
qbuff.length);
qbuff.length+= 4;
i->m_query= qbuff;
- sp->add_instr(i);
+ if (sp->add_instr(i))
+ MYSQL_YYABORT;
}
lex->sphead->restore_lex(thd);
}
@@ -11842,7 +11847,8 @@ sys_option_value:
(uchar **) &trg_fld->
next_trg_field);
- lex->sphead->add_instr(sp_fld);
+ if (lex->sphead->add_instr(sp_fld))
+ MYSQL_YYABORT;
}
else if ($2.var)
{ /* System variable */
@@ -11881,9 +11887,9 @@ sys_option_value:
}
sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
spv->offset, it, spv->type, lex, TRUE);
- if (sp_set == NULL)
+ if (sp_set == NULL ||
+ lex->sphead->add_instr(sp_set))
MYSQL_YYABORT;
- lex->sphead->add_instr(sp_set);
}
}
| option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
@@ -12182,8 +12188,12 @@ table_lock_list:
table_lock:
table_ident opt_table_alias lock_option
{
- if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
+ thr_lock_type lock_type= (thr_lock_type) $3;
+ if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type))
MYSQL_YYABORT;
+ /* If table is to be write locked, protect from a impending GRL. */
+ if (lock_type >= TL_WRITE_ALLOW_WRITE)
+ Lex->protect_against_global_read_lock= TRUE;
}
;