summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc12
-rw-r--r--sql/ha_innodb.h5
-rw-r--r--sql/handler.cc16
-rw-r--r--sql/item.cc38
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_func.cc4
-rw-r--r--sql/item_geofunc.cc27
-rw-r--r--sql/item_strfunc.cc12
-rw-r--r--sql/item_strfunc.h15
-rw-r--r--sql/log.cc15
-rw-r--r--sql/log_event.cc3
-rw-r--r--sql/log_event.h6
-rw-r--r--sql/mysql_priv.h12
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/set_var.cc6
-rw-r--r--sql/slave.cc108
-rw-r--r--sql/slave.h4
-rw-r--r--sql/sp.cc8
-rw-r--r--sql/sp_head.cc30
-rw-r--r--sql/sp_head.h8
-rw-r--r--sql/sp_pcontext.cc22
-rw-r--r--sql/sp_pcontext.h4
-rw-r--r--sql/sql_acl.cc24
-rw-r--r--sql/sql_base.cc80
-rw-r--r--sql/sql_db.cc8
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_handler.cc8
-rw-r--r--sql/sql_insert.cc5
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h16
-rw-r--r--sql/sql_parse.cc46
-rw-r--r--sql/sql_rename.cc3
-rw-r--r--sql/sql_select.cc57
-rw-r--r--sql/sql_table.cc34
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_view.cc6
-rw-r--r--sql/sql_yacc.yy179
38 files changed, 561 insertions, 282 deletions
diff --git a/sql/field.cc b/sql/field.cc
index f8ab4b852ec..99e9d7803e1 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5987,13 +5987,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
@@ -6001,7 +6001,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);
@@ -8587,16 +8587,16 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
else if (tmp_length > PRECISION_FOR_FLOAT)
{
sql_type= FIELD_TYPE_DOUBLE;
- length= DBL_DIG+7; /* -[digits].E+### */
+ length= MAX_DOUBLE_STR_LENGTH;
}
else
- length= FLT_DIG+6; /* -[digits].E+## */
+ length= MAX_FLOAT_STR_LENGTH;
decimals= NOT_FIXED_DEC;
break;
}
if (!fld_length && !fld_decimals)
{
- length= FLT_DIG+6;
+ length= MAX_FLOAT_STR_LENGTH;
decimals= NOT_FIXED_DEC;
}
if (length < decimals &&
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 3db983901b3..e27fb89d014 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -234,6 +234,11 @@ extern ulong srv_thread_sleep_delay;
extern ulong srv_thread_concurrency;
extern ulong srv_commit_concurrency;
extern ulong srv_flush_log_at_trx_commit;
+/* An option to enable the fix for "Bug#43660 SHOW INDEXES/ANALYZE does
+NOT update cardinality for indexes of InnoDB table". By default we are
+running with the fix disabled because MySQL 5.1 is frozen for such
+behavioral changes. */
+extern char srv_use_legacy_cardinality_algorithm;
}
bool innobase_init(void);
diff --git a/sql/handler.cc b/sql/handler.cc
index d069d56caae..63f652fc2b4 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -730,6 +730,16 @@ end:
if (is_real_trans)
start_waiting_global_read_lock(thd);
}
+ else if (all)
+ {
+ /*
+ A COMMIT of an empty transaction. There may be savepoints.
+ Destroy them. If the transaction is not empty
+ savepoints are cleared in ha_commit_one_phase()
+ or ha_rollback_trans().
+ */
+ thd->transaction.cleanup();
+ }
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -825,11 +835,11 @@ int ha_rollback_trans(THD *thd, bool all)
thd->transaction.xid_state.xid.null();
}
if (all)
- {
thd->variables.tx_isolation=thd->session_tx_isolation;
- thd->transaction.cleanup();
- }
}
+ /* Always cleanup. Even if there nht==0. There may be savepoints. */
+ if (all)
+ thd->transaction.cleanup();
#endif /* USING_TRANSACTIONS */
if (all)
thd->transaction_rollback_request= FALSE;
diff --git a/sql/item.cc b/sql/item.cc
index 6ae52d8be59..13f09914ec6 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1282,7 +1282,10 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST");
return TRUE;
}
- set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info);
+ if (is_autogenerated_name)
+ {
+ set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info);
+ }
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
max_length= value_item->max_length;
decimals= value_item->decimals;
@@ -1320,6 +1323,7 @@ public:
else
Item_ident::print(str);
}
+ virtual Ref_Type ref_type() { return AGGREGATE_REF; }
};
@@ -4337,7 +4341,7 @@ Item *Item_field::replace_equal_field(byte *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;
@@ -6966,18 +6970,26 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
{
if (decimals != NOT_FIXED_DEC)
{
- int delta1= max_length_orig - decimals_orig;
- int delta2= item->max_length - item->decimals;
- max_length= max(delta1, delta2) + decimals;
- if (fld_type == MYSQL_TYPE_FLOAT && max_length > FLT_DIG + 2)
- {
- max_length= FLT_DIG + 6;
- decimals= NOT_FIXED_DEC;
- }
- if (fld_type == MYSQL_TYPE_DOUBLE && max_length > DBL_DIG + 2)
+ /*
+ For FLOAT(M,D)/DOUBLE(M,D) do not change precision
+ if both fields have the same M and D
+ */
+ if (item->max_length != max_length_orig ||
+ item->decimals != decimals_orig)
{
- max_length= DBL_DIG + 7;
- decimals= NOT_FIXED_DEC;
+ int delta1= max_length_orig - decimals_orig;
+ int delta2= item->max_length - item->decimals;
+ max_length= max(delta1, delta2) + decimals;
+ if (fld_type == MYSQL_TYPE_FLOAT && max_length > FLT_DIG + 2)
+ {
+ max_length= MAX_FLOAT_STR_LENGTH;
+ decimals= NOT_FIXED_DEC;
+ }
+ else if (fld_type == MYSQL_TYPE_DOUBLE && max_length > DBL_DIG + 2)
+ {
+ max_length= MAX_DOUBLE_STR_LENGTH;
+ decimals= NOT_FIXED_DEC;
+ }
}
}
else
diff --git a/sql/item.h b/sql/item.h
index 852b0fcc1ba..22eb0c08e2d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1899,7 +1899,7 @@ class Item_ref :public Item_ident
protected:
void set_properties();
public:
- enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF };
+ enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF };
Field *result_field; /* Save result here */
Item **ref;
Item_ref(Name_resolution_context *context_arg,
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 17700d0d23d..3cbb278ea48 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3377,6 +3377,10 @@ longlong Item_master_pos_wait::val_int()
}
#ifdef EXTRA_DEBUG
+/**
+ This will release the user lock that the thread currently locked,
+ please see also the comment of DEBUG_SYNC_POINT.
+*/
void debug_sync_point(const char* lock_name, uint lock_timeout)
{
THD* thd=current_thd;
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index d088f68fc0c..71bd1347f6e 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -70,10 +70,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();
@@ -83,8 +90,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;
}
@@ -337,14 +344,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);
@@ -368,12 +377,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);
@@ -391,13 +402,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
@@ -406,7 +417,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 7edc1a62307..4640929b2bf 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -473,17 +473,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,
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 9794a092648..1c5346ab074 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -306,13 +306,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"; }
};
@@ -323,7 +327,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 d979dd101e0..b16303ee232 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -158,7 +158,8 @@ static int binlog_commit(THD *thd, bool all)
*/
if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
+ Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"),
+ TRUE, FALSE, THD::KILLED_NO_VALUE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev));
}
@@ -202,7 +203,8 @@ static int binlog_rollback(THD *thd, bool all)
*/
if (unlikely(thd->transaction.all.modified_non_trans_table))
{
- Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE);
+ Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"),
+ TRUE, FALSE, THD::KILLED_NO_VALUE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
error= binlog_end_trans(thd, trans_log, &qev);
}
@@ -240,7 +242,8 @@ static int binlog_savepoint_set(THD *thd, void *sv)
*(my_off_t *)sv= my_b_tell(trans_log);
/* Write it to the binary log */
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ TRUE, FALSE, THD::KILLED_NO_VALUE);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
}
@@ -257,7 +260,8 @@ static int binlog_savepoint_rollback(THD *thd, void *sv)
*/
if (unlikely(thd->transaction.all.modified_non_trans_table))
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ TRUE, FALSE, THD::KILLED_NO_VALUE);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
}
reinit_io_cache(trans_log, WRITE_CACHE, *(my_off_t *)sv, 0, 0);
@@ -2089,7 +2093,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
transaction is either a BEGIN..COMMIT block or a single
statement in autocommit mode.
*/
- Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE);
+ Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"),
+ TRUE, FALSE, THD::KILLED_NO_VALUE);
/*
Imagine this is rollback due to net timeout, after all
statements of the transaction succeeded. Then we want a
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ac29bd8ea63..3912308cafa 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1358,6 +1358,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
{
time_t end_time;
+ DBUG_EXECUTE_IF("debug_lock_before_query_log_event",
+ DBUG_SYNC_POINT("debug_lock.before_query_log_event", 10););
+
if (killed_status_arg == THD::KILLED_NO_VALUE)
killed_status_arg= thd_arg->killed;
error_code=
diff --git a/sql/log_event.h b/sql/log_event.h
index 6ccbf8e4d5c..45e3d11b48c 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -813,9 +813,13 @@ public:
#ifndef MYSQL_CLIENT
+ /*
+ for argument killed_err_arg, use ` THD::NOT_KILLED ' if the killed
+ status should be ignored, otherwise use `THD::KILLED_NO_VALUE'
+ */
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
bool using_trans, bool suppress_use,
- THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
+ THD::killed_state killed_err_arg);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 261393353f8..9768668f103 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -253,6 +253,11 @@ MY_LOCALE *my_locale_by_number(uint number);
#define PRECISION_FOR_DOUBLE 53
#define PRECISION_FOR_FLOAT 24
+/* -[digits].E+## */
+#define MAX_FLOAT_STR_LENGTH (FLT_DIG + 6)
+/* -[digits].E+### */
+#define MAX_DOUBLE_STR_LENGTH (DBL_DIG + 7)
+
/*
Default time to wait before aborting a new client connection
that does not respond to "initial server greeting" timely
@@ -455,6 +460,13 @@ MY_LOCALE *my_locale_by_number(uint number);
The client tells the server to block with SELECT GET_LOCK()
and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult
concurrency problems
+
+ NOTE: This will release the user lock that the thread currently
+ locked, which can cause problem if users want to use user locks for
+ other purposes. In order to overcome this problem, it's adviced to
+ wrap the call to DBUG_SYNC_POINT() within the DBUG_EXECUTE_IF(), so
+ that it will only be activated if the given keyword is included in
+ the 'debug' option, and will not fiddle user locks otherwise.
*/
#define DBUG_SYNC_POINT(lock_name,lock_timeout) \
debug_sync_point(lock_name,lock_timeout)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 16353e6f0f3..592ae3e755a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -5047,7 +5047,8 @@ enum options_mysqld
OPT_SECURE_FILE_PRIV,
OPT_KEEP_FILES_ON_CREATE,
OPT_INNODB_ADAPTIVE_HASH_INDEX,
- OPT_FEDERATED
+ OPT_FEDERATED,
+ OPT_INNODB_USE_LEGACY_CARDINALITY_ALGORITHM
};
@@ -5354,6 +5355,14 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
(gptr*) &global_system_variables.innodb_table_locks,
(gptr*) &global_system_variables.innodb_table_locks,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ {"innodb_use_legacy_cardinality_algorithm",
+ OPT_INNODB_USE_LEGACY_CARDINALITY_ALGORITHM,
+ "Use legacy algorithm for picking random pages during index cardinality "
+ "estimation. Disable this to use a better algorithm, but note that your "
+ "query plans may change (enabled by default).",
+ (gptr*) &srv_use_legacy_cardinality_algorithm,
+ (gptr*) &srv_use_legacy_cardinality_algorithm,
+ 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
#endif /* End HAVE_INNOBASE_DB */
{"isam", OPT_ISAM, "Obsolete. ISAM storage engine is no longer supported.",
(gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 0, 0, 0,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index dcc7a5a15d1..2cdd306d542 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -450,6 +450,9 @@ sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
&SV::innodb_table_locks);
sys_var_thd_bool sys_innodb_support_xa("innodb_support_xa",
&SV::innodb_support_xa);
+sys_var_bool_ptr sys_innodb_use_legacy_cardinality_algorithm(
+ "innodb_use_legacy_cardinality_algorithm",
+ &srv_use_legacy_cardinality_algorithm);
sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment",
&srv_auto_extend_increment);
sys_var_long_ptr sys_innodb_sync_spin_loops("innodb_sync_spin_loops",
@@ -814,6 +817,7 @@ sys_var *sys_variables[]=
&sys_innodb_max_purge_lag,
&sys_innodb_table_locks,
&sys_innodb_support_xa,
+ &sys_innodb_use_legacy_cardinality_algorithm,
&sys_innodb_autoextend_increment,
&sys_innodb_sync_spin_loops,
&sys_innodb_concurrency_tickets,
@@ -958,6 +962,8 @@ struct show_var_st init_vars[]= {
{sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
{sys_innodb_thread_concurrency.name, (char*) &sys_innodb_thread_concurrency, SHOW_SYS},
{sys_innodb_thread_sleep_delay.name, (char*) &sys_innodb_thread_sleep_delay, SHOW_SYS},
+ {sys_innodb_use_legacy_cardinality_algorithm.name,
+ (char*) &sys_innodb_use_legacy_cardinality_algorithm, SHOW_SYS},
#endif
{sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS},
{sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS},
diff --git a/sql/slave.cc b/sql/slave.cc
index 868b11e137f..f29936c5942 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -78,6 +78,11 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
+static int terminate_slave_thread(THD *thd,
+ pthread_mutex_t *term_lock,
+ pthread_cond_t *term_cond,
+ volatile uint *slave_running,
+ bool skip_lock);
/*
Find out which replications threads are running
@@ -637,55 +642,96 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
return 0; /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
- pthread_mutex_t *sql_cond_lock,*io_cond_lock;
DBUG_ENTER("terminate_slave_threads");
- sql_cond_lock=sql_lock;
- io_cond_lock=io_lock;
-
- if (skip_lock)
- {
- sql_lock = io_lock = 0;
- }
- if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running)
+ 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,
- io_cond_lock,
+ if ((error=terminate_slave_thread(mi->io_thd, io_lock,
&mi->stop_cond,
- &mi->slave_running)) &&
+ &mi->slave_running,
+ skip_lock)) &&
!force_all)
DBUG_RETURN(error);
}
- if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running)
+ if (thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL))
{
DBUG_PRINT("info",("Terminating SQL thread"));
- DBUG_ASSERT(mi->rli.sql_thd != 0) ;
mi->rli.abort_slave=1;
- if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
- sql_cond_lock,
+ if ((error=terminate_slave_thread(mi->rli.sql_thd, sql_lock,
&mi->rli.stop_cond,
- &mi->rli.slave_running)) &&
+ &mi->rli.slave_running,
+ skip_lock)) &&
!force_all)
DBUG_RETURN(error);
}
DBUG_RETURN(0);
}
+/**
+ Wait for a slave thread to terminate.
+
+ This function is called after requesting the thread to terminate
+ (by setting abort_slave member of Relay_log_info or
+ Master_info structure to 1). Termination of the thread is
+ controlled with the the predicate *slave_running.
+
+ Function will acquire term_lock before waiting on the condition
+ unless skip_lock is true in which case the mutex should be owned
+ by the caller of this function and will remain acquired after
+ return from the function.
+
+ term_lock
+ Associated lock to use when waiting for term_cond
+
+ term_cond
+ Condition that is signalled when the thread has terminated
-int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
- pthread_mutex_t *cond_lock,
- pthread_cond_t* term_cond,
- volatile uint *slave_running)
+ slave_running
+ Pointer to predicate to check for slave thread termination
+
+ skip_lock
+ If true the lock will not be acquired before waiting on
+ the condition. In this case, it is assumed that the calling
+ function acquires the lock before calling this function.
+
+
+ returns zero if success, 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.
+*/
+
+int terminate_slave_thread(THD* thd,
+ pthread_mutex_t *term_lock,
+ pthread_cond_t *term_cond,
+ volatile uint *slave_running,
+ bool skip_lock)
{
DBUG_ENTER("terminate_slave_thread");
- if (term_lock)
+ if (!skip_lock)
{
pthread_mutex_lock(term_lock);
- if (!*slave_running)
+ }
+ 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(0);
+ }
+ else
+ {
DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
}
}
@@ -698,6 +744,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
while (*slave_running) // Should always be true
{
+ int error;
DBUG_PRINT("loop", ("killing slave thread"));
pthread_mutex_lock(&thd->LOCK_delete);
@@ -719,9 +766,13 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
*/
struct timespec abstime;
set_timespec(abstime,2);
- pthread_cond_timedwait(term_cond, cond_lock, &abstime);
+ error= pthread_cond_timedwait(term_cond, term_lock, &abstime);
+ DBUG_ASSERT(error == ETIMEDOUT || error == 0);
}
- if (term_lock)
+
+ DBUG_ASSERT(*slave_running == 0);
+
+ if (!skip_lock)
pthread_mutex_unlock(term_lock);
DBUG_RETURN(0);
}
@@ -834,7 +885,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);
}
@@ -1053,8 +1104,7 @@ int 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, (gptr)&e);
- return 0;
+ return insert_dynamic(a, (gptr)&e);
}
@@ -3855,6 +3905,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);
#ifndef DBUG_OFF
if (abort_slave_event_count && !events_till_abort)
@@ -4103,6 +4154,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
*/
const int eta= rli->events_till_abort;
#endif
+ DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
pthread_mutex_unlock(&rli->run_lock); // tell the world we are done
#ifndef DBUG_OFF // TODO: reconsider the code below
diff --git a/sql/slave.h b/sql/slave.h
index da548e145d3..5ae596f1eb5 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -504,10 +504,6 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli);
int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
bool skip_lock = 0);
-int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
- pthread_mutex_t* cond_lock,
- pthread_cond_t* term_cond,
- volatile uint* slave_running);
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname, int thread_mask);
diff --git a/sql/sp.cc b/sql/sp.cc
index 3af51b82521..2450e9564d0 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -646,7 +646,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
/* Such a statement can always go directly to binlog, no trans cache */
Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0,
- FALSE);
+ FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
@@ -680,7 +680,8 @@ db_drop_routine(THD *thd, int type, sp_name *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);
}
}
@@ -725,7 +726,8 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
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);
}
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index dcb865744fd..240948d217c 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1630,7 +1630,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (need_binlog_call && thd->binlog_evt_union.unioned_events)
{
Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
- thd->binlog_evt_union.unioned_events_trans, FALSE);
+ thd->binlog_evt_union.unioned_events_trans,
+ FALSE, THD::KILLED_NO_VALUE);
if (mysql_bin_log.write(&qinfo) &&
thd->binlog_evt_union.unioned_events_trans)
{
@@ -1953,17 +1954,16 @@ sp_head::restore_lex(THD *thd)
DBUG_VOID_RETURN;
}
-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);
}
void
@@ -2038,7 +2038,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;
@@ -2046,15 +2046,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
@@ -2236,7 +2238,7 @@ sp_head::show_create_procedure(THD *thd)
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;
@@ -2247,7 +2249,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, (gptr)&instr);
+ return insert_dynamic(&m_instr, (gptr)&instr);
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 91f465a4e2a..c54dc7401c4 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -226,7 +226,7 @@ public:
int
show_create_function(THD *thd);
- void
+ int
add_instr(sp_instr *instr);
inline uint
@@ -254,7 +254,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
@@ -263,11 +263,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 780243cc79f..265964d3d45 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -263,7 +263,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, (gptr)&p);
+ if (insert_dynamic(&m_vars, (gptr)&p))
+ return NULL;
return p;
}
@@ -308,18 +309,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, (gptr)&p);
- }
+ if (p == NULL)
+ return 1;
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->val= val;
+ return insert_dynamic(&m_conds, (gptr)&p);
}
/*
@@ -382,7 +382,7 @@ sp_pcontext::find_handler(sp_cond_type_t *cond)
return FALSE;
}
-void
+int
sp_pcontext::push_cursor(LEX_STRING *name)
{
LEX_STRING n;
@@ -391,7 +391,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, (gptr)&n);
+ return insert_dynamic(&m_cursors, (gptr)&n);
}
/*
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 5bffda79f98..db8bed349f2 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 b2d0304f007..f61304a1e26 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1506,7 +1506,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();
- Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
+ Query_log_event qinfo(thd, buff, query_length,
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
end:
@@ -3014,7 +3015,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
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);
}
}
@@ -3181,7 +3183,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
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);
}
}
@@ -3294,7 +3297,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
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);
}
}
@@ -5404,7 +5408,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
if (some_users_created && mysql_bin_log.is_open())
{
- 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);
}
@@ -5473,7 +5478,8 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
if (some_users_deleted && mysql_bin_log.is_open())
{
- 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);
}
@@ -5553,7 +5559,8 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
if (some_users_renamed && mysql_bin_log.is_open())
{
- 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);
}
@@ -5731,7 +5738,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (mysql_bin_log.is_open())
{
- 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);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 575bc639398..854e603d21a 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -793,18 +793,9 @@ 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;
+ DBUG_ASSERT(qinfo.error_code == 0);
mysql_bin_log.write(&qinfo);
}
else
@@ -1596,27 +1587,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
- bool check_if_used= thd->prelocked_mode &&
- ((int) table_list->lock_type >=
- (int) TL_WRITE_ALLOW_WRITE);
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->key_length == key_length &&
!memcmp(table->s->table_cache_key, key, key_length))
{
- if (check_if_used && table->query_id &&
- table->query_id != thd->query_id)
- {
- /*
- If we are in stored function or trigger we should ensure that
- we won't change table that is already used by calling statement.
- So if we are opening table for writing, we should check that it
- is not already open by some calling stamement.
- */
- my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
- table->s->table_name);
- DBUG_RETURN(0);
- }
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id && /* skip tables already used */
!(thd->prelocked_mode && table->query_id))
@@ -1640,13 +1615,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
best_distance= distance;
best_table= table;
- if (best_distance == 0 && !check_if_used)
+ if (best_distance == 0)
{
/*
- If we have found perfect match and we don't need to check that
- table is not used by one of calling statements (assuming that
- we are inside of function or trigger) we can finish iterating
- through open tables list.
+ We have found a perfect match and can finish iterating
+ through open tables list. Check for table use conflict
+ between calling statement and SP/trigger is done in
+ lock_tables().
*/
break;
}
@@ -2578,7 +2553,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
{
end = strxmov(strmov(query, "DELETE FROM `"),
db,"`.`",name,"`", NullS);
- Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
+ Query_log_event qinfo(thd, query, (ulong)(end-query),
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
my_free(query, MYF(0));
}
@@ -2944,9 +2920,9 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
lock_type Lock to use for open
NOTE
- This function don't do anything like SP/SF/views/triggers analysis done
- in open_tables(). It is intended for opening of only one concrete table.
- And used only in special contexts.
+ This function doesn't do anything like SP/SF/views/triggers analysis done
+ in open_tables()/lock_tables(). It is intended for opening of only one
+ concrete table. And used only in special contexts.
RETURN VALUES
table Opened table
@@ -3262,8 +3238,36 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() &&
- check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ if (table->placeholder())
+ continue;
+
+ /*
+ In a stored function or trigger we should ensure that we won't change
+ a table that is already used by the calling statement.
+ */
+ if (thd->prelocked_mode &&
+ table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
+ {
+ /*
+ issue an error if the tables are the same (by key comparison),
+ but query_id isn't
+ */
+ if (opentab->query_id &&
+ table->table->query_id != opentab->query_id &&
+ table->table->s->key_length == opentab->s->key_length &&
+ !memcmp(table->table->s->table_cache_key,
+ opentab->s->table_cache_key, opentab->s->key_length))
+ {
+ my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
+ table->table->s->table_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
DBUG_RETURN(-1);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 80fea3ef1b1..be538783458 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -70,7 +70,7 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *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;
@@ -562,7 +562,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
@@ -645,7 +645,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
@@ -770,7 +770,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
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index d5d09c88441..7a48044877b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -730,7 +730,7 @@ void multi_delete::send_error(uint errcode,const char *err)
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_tables, FALSE);
+ transactional_tables, FALSE, THD::KILLED_NO_VALUE);
mysql_bin_log.write(&qinfo);
}
thd->transaction.all.modified_non_trans_table= true;
@@ -958,7 +958,7 @@ end:
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- 0, FALSE);
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); // This should return record count
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index c376f1b3d1d..721b365a7b9 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -190,6 +190,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_insert.cc b/sql/sql_insert.cc
index 9c8aa196908..d9027e3f5b9 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2543,7 +2543,8 @@ bool Delayed_insert::handle_inserts(void)
thd.variables.time_zone = row->time_zone;
}
- Query_log_event qinfo(&thd, row->query, row->query_length, 0, FALSE);
+ Query_log_event qinfo(&thd, row->query, row->query_length,
+ 0, FALSE, THD::KILLED_NO_VALUE);
mysql_bin_log.write(&qinfo);
thd.time_zone_used = backup_time_zone_used;
@@ -3105,7 +3106,7 @@ void select_insert::abort()
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, THD::KILLED_NO_VALUE);
mysql_bin_log.write(&qinfo);
}
if (thd->transaction.stmt.modified_non_trans_table)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d48dacf75d7..436f41dd209 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -204,6 +204,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;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index d91e3907fb3..5c0367632e1 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1184,6 +1184,22 @@ typedef struct st_lex : public Query_tables_list
bool escape_used;
+ /*
+ 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 fcb7047e998..507805ec0c4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2840,6 +2840,10 @@ mysql_execute_command(THD *thd)
if (res)
goto error;
+ if (!thd->locked_tables && lex->protect_against_global_read_lock &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
if (!(res= open_and_lock_tables(thd, all_tables)))
{
if (lex->describe)
@@ -3640,7 +3644,8 @@ end_with_restore_list:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- 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);
}
}
@@ -3675,7 +3680,8 @@ end_with_restore_list:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- 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);
}
}
@@ -3701,7 +3707,8 @@ end_with_restore_list:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- 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);
}
}
@@ -3713,6 +3720,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,
@@ -3739,6 +3749,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
@@ -3906,7 +3925,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:
@@ -4080,6 +4100,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);
@@ -4135,6 +4159,9 @@ end_with_restore_list:
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
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;
@@ -4483,7 +4510,8 @@ end_with_restore_list:
{
if (mysql_bin_log.is_open())
{
- 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);
}
}
@@ -5092,6 +5120,14 @@ create_sp_error:
case SP_KEY_NOT_FOUND:
if (lex->drop_if_exists)
{
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ /* using_trans */ 0,
+ /* suppress use */ FALSE,
+ THD::NOT_KILLED);
+ mysql_bin_log.write(&qinfo);
+ }
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);
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index f6766aec285..cec9e4c39de 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -84,7 +84,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
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);
}
send_ok(thd);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f2f2efc9e77..ced01c2db47 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3383,10 +3383,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
-*/
static uint
max_part_bit(key_part_map bits)
@@ -3396,7 +3392,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;
@@ -3426,24 +3431,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,(gptr) &keyuse));
+ if (insert_dynamic(keyuse_array,(gptr) &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)
{
@@ -3477,13 +3484,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;
@@ -3493,7 +3503,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,(gptr) &keyuse));
+ return insert_dynamic(keyuse_array,(gptr) &keyuse);
}
@@ -3643,7 +3653,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())
@@ -3681,11 +3692,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;
}
/*
@@ -3706,7 +3721,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,(gptr) &key_end));
+ if (insert_dynamic(keyuse,(gptr) &key_end))
+ return TRUE;
use=save_pos=dynamic_element(keyuse,0,KEYUSE*);
prev= &key_end;
@@ -14217,6 +14233,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
Item *pos;
List_iterator_fast<Item> li(all_fields);
Copy_field *copy= NULL;
+ IF_DBUG(Copy_field *copy_start);
res_selected_fields.empty();
res_all_fields.empty();
List_iterator_fast<Item> itr(res_all_fields);
@@ -14229,12 +14246,19 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
goto err2;
param->copy_funcs.empty();
+ IF_DBUG(copy_start= copy);
for (i= 0; (pos= li++); i++)
{
Field *field;
char *tmp;
Item *real_pos= pos->real_item();
- if (real_pos->type() == Item::FIELD_ITEM)
+ /*
+ Aggregate functions can be substituted for fields (by e.g. temp tables).
+ We need to filter those substituted fields out.
+ */
+ if (real_pos->type() == Item::FIELD_ITEM &&
+ !(real_pos != pos &&
+ ((Item_ref *)pos)->ref_type() == Item_ref::AGGREGATE_REF))
{
Item_field *item;
if (!(item= new Item_field(thd, ((Item_field*) real_pos))))
@@ -14282,6 +14306,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
goto err;
if (copy)
{
+ DBUG_ASSERT (param->field_count > (uint) (copy - copy_start));
copy->set(tmp, item->result_field);
item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
#ifdef HAVE_purify
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 79aa0b04335..9952fca6bcb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -333,7 +333,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
if (!error)
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
}
@@ -1814,7 +1815,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!internal_tmp_table && mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
error= FALSE;
@@ -2903,7 +2905,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table,
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
res= FALSE;
@@ -3012,7 +3015,8 @@ mysql_discard_or_import_tablespace(THD *thd,
goto err;
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
err:
@@ -3168,7 +3172,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);
}
send_ok(thd);
@@ -3360,7 +3365,8 @@ view_err:
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
@@ -3872,7 +3878,8 @@ view_err:
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
goto end_temporary;
@@ -4007,7 +4014,8 @@ view_err:
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ FALSE, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
broadcast_refresh();
@@ -4368,6 +4376,16 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
{
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_trigger.cc b/sql/sql_trigger.cc
index 930e3601699..d2ae494d4eb 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -304,7 +304,7 @@ end:
/* Such a statement can always go directly to binlog, no trans cache. */
Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0,
- FALSE);
+ FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 195a2beed88..69f876ace39 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1575,7 +1575,7 @@ void multi_update::send_error(uint errcode,const char *err)
into repl event.
*/
Query_log_event qinfo(thd, thd->query, thd->query_length,
- transactional_tables, FALSE);
+ transactional_tables, FALSE, THD::KILLED_NO_VALUE);
mysql_bin_log.write(&qinfo);
}
thd->transaction.all.modified_non_trans_table= TRUE;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index bef3bc65e51..d1d84e76811 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -655,7 +655,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
else if (views->with_check == VIEW_CHECK_CASCADED)
buff.append(STRING_WITH_LEN(" WITH CASCADED CHECK OPTION"));
- Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
+ Query_log_event qinfo(thd, buff.ptr(), buff.length(),
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
}
@@ -1544,7 +1545,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{
if (!something_wrong)
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);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 04caaa7ad20..61020a3eed0 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -234,9 +234,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);
}
/**
@@ -247,7 +245,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;
@@ -279,9 +277,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);
}
/**
@@ -290,13 +289,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
@@ -312,7 +312,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());
}
/**
@@ -1918,10 +1918,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);
@@ -1940,7 +1939,8 @@ sp_decl:
my_error(ER_SP_DUP_COND, MYF(0), $2.str);
MYSQL_YYABORT;
}
- YYTHD->lex->spcont->push_cond(&$2, $5);
+ if(YYTHD->lex->spcont->push_cond(&$2, $5))
+ MYSQL_YYABORT;
$$.vars= $$.hndlrs= $$.curs= 0;
$$.conds= 1;
}
@@ -1955,10 +1955,10 @@ sp_decl:
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
ctx->current_var_count());
- if (i == NULL)
+ if (i == NULL ||
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->add_instr(i);
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
}
sp_hcond_list sp_proc_stmt
@@ -1973,17 +1973,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);
@@ -2009,10 +2009,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;
}
@@ -2236,10 +2236,11 @@ sp_proc_stmt:
i->m_query.length= lip->ptr - sp->m_tmp_query;
else
i->m_query.length= lip->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);
}
@@ -2264,9 +2265,9 @@ sp_proc_stmt:
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);
@@ -2324,23 +2325,23 @@ sp_proc_stmt:
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, exclusive);
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);
- if (i == NULL)
+ if (i == NULL ||
+ sp->push_backpatch(i, lab) || /* Jumping forward */
+ sp->add_instr(i))
MYSQL_YYABORT;
- sp->push_backpatch(i, lab); /* Jumping forward */
- sp->add_instr(i);
}
}
| ITERATE_SYM label_ident
@@ -2365,22 +2366,22 @@ sp_proc_stmt:
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);
}
}
| OPEN_SYM ident
@@ -2396,9 +2397,9 @@ sp_proc_stmt:
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);
}
| FETCH_SYM sp_opt_fetch_noise ident INTO
{
@@ -2413,9 +2414,9 @@ sp_proc_stmt:
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
{ }
@@ -2432,9 +2433,9 @@ sp_proc_stmt:
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);
}
;
@@ -2501,11 +2502,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
@@ -2514,9 +2515,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));
}
@@ -2602,14 +2603,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;
}
;
@@ -2622,14 +2625,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;
}
;
@@ -2641,9 +2646,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
;
@@ -2757,17 +2762,17 @@ sp_block_content:
{
sp_instr_hpop *hpop= new sp_instr_hpop(sp->instructions(), ctx,
$3.hndlrs);
- if (hpop == NULL)
+ if (hpop == NULL ||
+ sp->add_instr(hpop))
MYSQL_YYABORT;
- sp->add_instr(hpop);
}
if ($3.curs)
{
sp_instr_cpop *cpop= new sp_instr_cpop(sp->instructions(), ctx,
$3.curs);
- if (cpop == NULL)
+ if (cpop == NULL ||
+ sp->add_instr(cpop))
MYSQL_YYABORT;
- sp->add_instr(cpop);
}
lex->spcont= ctx->pop_context();
}
@@ -2781,9 +2786,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);
}
| WHILE_SYM
{
@@ -2797,12 +2802,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)
- MYSQL_YYABORT;
+ if (i == NULL ||
/* Jumping forward */
- sp->push_backpatch(i, lex->spcont->last_label());
- sp->new_cont_backpatch(i);
- sp->add_instr(i);
+ sp->push_backpatch(i, lex->spcont->last_label()) ||
+ sp->new_cont_backpatch(i) ||
+ sp->add_instr(i))
+ MYSQL_YYABORT;
sp->restore_lex(YYTHD);
}
sp_proc_stmts1 END WHILE_SYM
@@ -2811,9 +2816,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
@@ -2829,9 +2834,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;
@@ -4535,6 +4540,7 @@ select_lock_type:
LEX *lex=Lex;
lex->current_select->set_lock_for_tables(TL_WRITE);
lex->safe_to_cache_query=0;
+ lex->protect_against_global_read_lock= TRUE;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
@@ -9742,7 +9748,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);
}
@@ -9824,7 +9831,8 @@ sys_option_value:
lex->trg_table_fields.link_in_list((byte *)trg_fld,
(byte **)&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 */
@@ -9854,11 +9862,12 @@ sys_option_value:
it= spv->dflt;
else
it= new Item_null();
- if (it == NULL)
+ if (it == NULL ||
+ (sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
+ spv->offset, it, spv->type, lex,
+ TRUE)) == NULL ||
+ lex->sphead->add_instr(sp_set))
MYSQL_YYABORT;
- sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
- spv->offset, it, spv->type, lex, TRUE);
- lex->sphead->add_instr(sp_set);
}
}
| option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
@@ -10152,8 +10161,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;
}
;