Commit a295acf5 authored by Otto Kekäläinen's avatar Otto Kekäläinen
Browse files

Imported Upstream version 5.5.47

parent a90934f3
......@@ -22,6 +22,10 @@ extern ST_SCHEMA_TABLE schema_tables[];
namespace feedback {
#ifndef DBUG_OFF
ulong debug_startup_interval, debug_first_interval, debug_interval;
#endif
char server_uid_buf[SERVER_UID_SIZE+1]; ///< server uid will be written here
/* backing store for system variables */
......@@ -249,6 +253,18 @@ static int init(void *p)
prepare_linux_info();
#ifndef DBUG_OFF
if (startup_interval != debug_startup_interval ||
first_interval != debug_first_interval ||
interval != debug_interval)
{
startup_interval= debug_startup_interval;
first_interval= debug_first_interval;
interval= debug_interval;
user_info= const_cast<char*>("mysql-test");
}
#endif
url_count= 0;
if (*url)
{
......@@ -347,12 +363,29 @@ static MYSQL_SYSVAR_ULONG(send_retry_wait, send_retry_wait, PLUGIN_VAR_RQCMDARG,
"Wait this many seconds before retrying a failed send.",
NULL, NULL, 60, 1, 60*60*24, 1);
#ifndef DBUG_OFF
static MYSQL_SYSVAR_ULONG(debug_startup_interval, debug_startup_interval,
PLUGIN_VAR_RQCMDARG, "for debugging only",
NULL, NULL, startup_interval, 1, INT_MAX32, 1);
static MYSQL_SYSVAR_ULONG(debug_first_interval, debug_first_interval,
PLUGIN_VAR_RQCMDARG, "for debugging only",
NULL, NULL, first_interval, 1, INT_MAX32, 1);
static MYSQL_SYSVAR_ULONG(debug_interval, debug_interval,
PLUGIN_VAR_RQCMDARG, "for debugging only",
NULL, NULL, interval, 1, INT_MAX32, 1);
#endif
static struct st_mysql_sys_var* settings[] = {
MYSQL_SYSVAR(server_uid),
MYSQL_SYSVAR(user_info),
MYSQL_SYSVAR(url),
MYSQL_SYSVAR(send_timeout),
MYSQL_SYSVAR(send_retry_wait),
#ifndef DBUG_OFF
MYSQL_SYSVAR(debug_startup_interval),
MYSQL_SYSVAR(debug_first_interval),
MYSQL_SYSVAR(debug_interval),
#endif
NULL
};
......
......@@ -58,6 +58,10 @@ class Url {
extern Url **urls;
extern uint url_count;
extern ulong startup_interval;
extern ulong first_interval;
extern ulong interval;
/* these are used to communicate with the background thread */
extern mysql_mutex_t sleep_mutex;
extern mysql_cond_t sleep_condition;
......
......@@ -25,9 +25,9 @@ static my_thread_id thd_thread_id; ///< its thread_id
static size_t needed_size= 20480;
static const time_t startup_interval= 60*5; ///< in seconds (5 minutes)
static const time_t first_interval= 60*60*24; ///< in seconds (one day)
static const time_t interval= 60*60*24*7; ///< in seconds (one week)
ulong startup_interval= 60*5; ///< in seconds (5 minutes)
ulong first_interval= 60*60*24; ///< in seconds (one day)
ulong interval= 60*60*24*7; ///< in seconds (one week)
/**
reads the rows from a table and puts them, concatenated, in a String
......@@ -124,6 +124,7 @@ static int prepare_for_fill(TABLE_LIST *tables)
if (!tables->table)
return 1;
tables->select_lex= thd->lex->current_select;
tables->table->pos_in_table_list= tables;
return 0;
......@@ -253,6 +254,7 @@ static void send_report(const char *when)
{
if (tables.table)
free_tmp_table(thd, tables.table);
thd->cleanup_after_query();
/*
clean up, free the thd.
reset all thread local status variables to minimize
......
......@@ -425,7 +425,8 @@ char *should;
(sub.rm_so != -1 && sub.rm_eo == -1) ||
(sub.rm_so != -1 && sub.rm_so < 0) ||
(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
snprintf(grump, sizeof(grump),
"start %ld end %ld", (long)sub.rm_so,
(long)sub.rm_eo);
return(grump);
}
......@@ -438,7 +439,8 @@ char *should;
/* check for in range */
if ((int) sub.rm_eo > (int) strlen(str)) {
sprintf(grump, "start %ld end %ld, past end of string",
snprintf(grump, sizeof(grump),
"start %ld end %ld, past end of string",
(long)sub.rm_so, (long)sub.rm_eo);
return(grump);
}
......@@ -449,13 +451,15 @@ char *should;
/* check for not supposed to match */
if (should == NULL) {
sprintf(grump, "matched `%.*s'", len, p);
snprintf(grump, sizeof(grump),
"matched `%.*s'", len, p);
return(grump);
}
/* check for wrong match */
if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
sprintf(grump, "matched `%.*s' instead", len, p);
snprintf(grump, sizeof(grump),
"matched `%.*s' instead", len, p);
return(grump);
}
if (shlen > 0)
......@@ -468,7 +472,8 @@ char *should;
if (shlen == 0)
shlen = 1; /* force check for end-of-string */
if (strncmp(p, at, shlen) != 0) {
sprintf(grump, "matched null at `%.20s'", p);
snprintf(grump, sizeof(grump),
"matched null at `%.20s'", p);
return(grump);
}
return(NULL);
......@@ -501,7 +506,7 @@ char *name;
static char efbuf[100];
my_regex_t re;
sprintf(efbuf, "REG_%s", name);
snprintf(efbuf, sizeof(efbuf), "REG_%s", name);
assert(strlen(efbuf) < sizeof(efbuf));
re.re_endp = efbuf;
(void) my_regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
......
......@@ -486,6 +486,7 @@ sub get_mysqladmin_options
# Return a list of option files which can be opened. Similar, but not
# identical, to behavior of my_search_option_files()
# TODO implement and use my_print_defaults --list-groups instead
sub list_defaults_files
{
my %opt;
......@@ -497,9 +498,7 @@ sub list_defaults_files
return ($opt{file}) if exists $opt{file};
my %seen; # Don't list the same file more than once
return grep { defined $_ and not $seen{$_}++ and -f $_ and -r $_ }
('/etc/my.cnf',
return ('/etc/my.cnf',
'/etc/mysql/my.cnf',
'@sysconfdir@/my.cnf',
($ENV{MYSQL_HOME} ? "$ENV{MYSQL_HOME}/my.cnf" : undef),
......@@ -539,11 +538,12 @@ sub find_groups
}
}
my %seen;
my @defaults_files = list_defaults_files();
#warn "@{[sort keys %gids]} -> @defaults_files\n";
foreach my $file (@defaults_files)
while (@defaults_files)
{
next unless open CONF, "< $file";
my $file = shift @defaults_files;
next unless defined $file and not $seen{$file}++ and open CONF, '<', $file;
while (<CONF>)
{
......@@ -556,6 +556,14 @@ sub find_groups
push @groups, "$1$2";
}
}
elsif (/^\s*!include\s+(\S.*?)\s*$/)
{
push @defaults_files, $1;
}
elsif (/^\s*!includedir\s+(\S.*?)\s*$/)
{
push @defaults_files, <$1/*.cnf>;
}
}
close CONF;
......
......@@ -1885,8 +1885,11 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const c
{
SSL *ssl;
X509 *server_cert;
char *cp1, *cp2;
char *buf;
X509_NAME *x509sn;
int cn_pos;
X509_NAME_ENTRY *cn_entry;
ASN1_STRING *cn_asn1;
const char *cn_str;
DBUG_ENTER("ssl_verify_server_cert");
DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
......@@ -1920,34 +1923,32 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const c
are what we expect.
*/
buf= X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
X509_free (server_cert);
x509sn= X509_get_subject_name(server_cert);
if (!buf)
{
*errptr= "Out of memory";
DBUG_RETURN(1);
}
if ((cn_pos= X509_NAME_get_index_by_NID(x509sn, NID_commonName, -1)) < 0)
goto err;
DBUG_PRINT("info", ("hostname in cert: %s", buf));
cp1= strstr(buf, "/CN=");
if (cp1)
{
cp1+= 4; /* Skip the "/CN=" that we found */
/* Search for next / which might be the delimiter for email */
cp2= strchr(cp1, '/');
if (cp2)
*cp2= '\0';
DBUG_PRINT("info", ("Server hostname in cert: %s", cp1));
if (!strcmp(cp1, server_hostname))
{
free(buf);
/* Success */
DBUG_RETURN(0);
}
}
if (!(cn_entry= X509_NAME_get_entry(x509sn, cn_pos)))
goto err;
if (!(cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry)))
goto err;
cn_str = (char *)ASN1_STRING_data(cn_asn1);
/* Make sure there is no embedded \0 in the CN */
if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn_str))
goto err;
if (strcmp(cn_str, server_hostname))
goto err;
X509_free (server_cert);
DBUG_RETURN(0);
err:
X509_free(server_cert);
*errptr= "SSL certificate validation failure";
free(buf);
DBUG_RETURN(1);
}
......
......@@ -349,7 +349,7 @@ class Field
DBUG_ENTER("Field::pack_length_from_metadata");
DBUG_RETURN(field_metadata);
}
virtual uint row_pack_length() { return 0; }
virtual uint row_pack_length() const { return 0; }
virtual int save_field_metadata(uchar *first_byte)
{ return do_save_field_metadata(first_byte); }
......@@ -757,7 +757,7 @@ class Field_num :public Field {
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
uint is_equal(Create_field *new_field);
uint row_pack_length() { return pack_length(); }
uint row_pack_length() const { return pack_length(); }
uint32 pack_length_from_metadata(uint field_metadata) {
uint32 length= pack_length();
DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u",
......@@ -940,7 +940,7 @@ class Field_new_decimal :public Field_num {
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
uint pack_length_from_metadata(uint field_metadata);
uint row_pack_length() { return pack_length(); }
uint row_pack_length() const { return pack_length(); }
bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
uint16 mflags, int *order_var);
uint is_equal(Create_field *new_field);
......@@ -1189,7 +1189,7 @@ class Field_float :public Field_real {
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(float); }
uint row_pack_length() { return pack_length(); }
uint row_pack_length() const { return pack_length(); }
void sql_type(String &str) const;
private:
int do_save_field_metadata(uchar *first_byte);
......@@ -1229,7 +1229,7 @@ class Field_double :public Field_real {
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(double); }
uint row_pack_length() { return pack_length(); }
uint row_pack_length() const { return pack_length(); }
void sql_type(String &str) const;
private:
int do_save_field_metadata(uchar *first_byte);
......@@ -1718,7 +1718,7 @@ class Field_string :public Field_longstr {
}
bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
uint16 mflags, int *order_var);
uint row_pack_length() { return field_length; }
uint row_pack_length() const { return field_length; }
int pack_cmp(const uchar *a,const uchar *b,uint key_length,
bool insert_or_update);
int pack_cmp(const uchar *b,uint key_length,bool insert_or_update);
......@@ -1768,7 +1768,7 @@ class Field_varstring :public Field_longstr {
enum_field_types type() const { return MYSQL_TYPE_VARCHAR; }
bool match_collation_to_optimize_range() const { return TRUE; }
enum ha_base_keytype key_type() const;
uint row_pack_length() { return field_length; }
uint row_pack_length() const { return field_length; }
bool zero_pack() const { return 0; }
int reset(void) { bzero(ptr,field_length+length_bytes); return 0; }
uint32 pack_length() const { return (uint32) field_length+length_bytes; }
......@@ -1893,7 +1893,7 @@ class Field_blob :public Field_longstr {
*/
uint32 pack_length_no_ptr() const
{ return (uint32) (packlength); }
uint row_pack_length() { return pack_length_no_ptr(); }
uint row_pack_length() const { return pack_length_no_ptr(); }
uint32 sort_length() const;
virtual uint32 max_data_length() const
{
......@@ -2055,7 +2055,7 @@ class Field_enum :public Field_str {
enum_field_types real_type() const { return MYSQL_TYPE_ENUM; }
uint pack_length_from_metadata(uint field_metadata)
{ return (field_metadata & 0x00ff); }
uint row_pack_length() { return pack_length(); }
uint row_pack_length() const { return pack_length(); }
virtual bool zero_pack() const { return 0; }
bool optimize_range(uint idx, uint part) { return 0; }
bool eq_def(Field *field);
......@@ -2176,7 +2176,7 @@ class Field_bit :public Field {
uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
uint32 pack_length_in_rec() const { return bytes_in_rec; }
uint pack_length_from_metadata(uint field_metadata);
uint row_pack_length()
uint row_pack_length() const
{ return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
bool compatible_field_size(uint metadata, Relay_log_info *rli,
uint16 mflags, int *order_var);
......
......@@ -1891,6 +1891,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
*/
Item_aggregate_ref *item_ref;
uint el= fields.elements;
DBUG_ASSERT(fields.elements <=
thd->lex->current_select->ref_pointer_array_size);
/*
If this is an item_ref, get the original item
This is a safety measure if this is called for things that is
......@@ -4887,8 +4889,24 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
As this is an outer field it should be added to the list of
non aggregated fields of the outer select.
*/
marker= select->cur_pos_in_select_list;
select->join->non_agg_fields.push_back(this);
if (select->join)
{
marker= select->cur_pos_in_select_list;
select->join->non_agg_fields.push_back(this);
}
else
{
/*
join is absent if it is upper SELECT_LEX of non-select
command
*/
DBUG_ASSERT(select->master_unit()->outer_select() == NULL &&
(thd->lex->sql_command != SQLCOM_SELECT &&
thd->lex->sql_command != SQLCOM_UPDATE_MULTI &&
thd->lex->sql_command != SQLCOM_DELETE_MULTI &&
thd->lex->sql_command != SQLCOM_INSERT_SELECT &&
thd->lex->sql_command != SQLCOM_REPLACE_SELECT));
}
}
if (*from_field != view_ref_found)
{
......@@ -6719,6 +6737,7 @@ Item *Item_field::update_value_transformer(uchar *select_arg)
{
List<Item> *all_fields= &select->join->all_fields;
Item **ref_pointer_array= select->ref_pointer_array;
DBUG_ASSERT(all_fields->elements <= select->ref_pointer_array_size);
int el= all_fields->elements;
Item_ref *ref;
......
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2009, 2013, Monty Program Ab.
Copyright (c) 2009, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
#ifndef ITEM_CMPFUNC_INCLUDED
#define ITEM_CMPFUNC_INCLUDED
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2011, Monty Program Ab.
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2009, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2009, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
......@@ -719,7 +719,7 @@ void Item_func::count_real_length()
bool Item_func::count_string_result_length(enum_field_types field_type,
Item **items, uint nitems)
{
if (agg_arg_charsets(collation, items, nitems, MY_COLL_ALLOW_CONV, 1))
if (agg_arg_charsets_for_string_result(collation, items, nitems, 1))
return true;
if (is_temporal_type(field_type))
count_datetime_length(items, nitems);
......@@ -6280,9 +6280,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
table= 0;
for (uint i=1 ; i < arg_count ; i++)
{
item=args[i];
if (item->type() == Item::REF_ITEM)
args[i]= item= *((Item_ref *)item)->ref;
item= args[i]= args[i]->real_item();
/*
When running in PS mode, some Item_field's can already be replaced
to Item_func_conv_charset during PREPARE time. This is possible
......@@ -6295,7 +6293,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
if (!thd->stmt_arena->is_stmt_execute() &&
item->type() != Item::FIELD_ITEM)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST");
my_error(ER_WRONG_ARGUMENTS, MYF(0), "MATCH");
return TRUE;
}
/*
......
/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2012, Monty Program Ab
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -1748,6 +1748,27 @@ Item_in_subselect::single_value_transformer(JOIN *join)
runtime created Ref item which is deleted at the end
of the statement. Thus one of 'substitution' arguments
can be broken in case of PS.
@todo
Why do we use real_item()/substitutional_item() instead of the plain
left_expr?
Because left_expr might be a rollbackable item, and we fail to properly
rollback all copies of left_expr at end of execution, so we want to
avoid creating copies of left_expr as much as possible, so we use
real_item() instead.
Doing a proper rollback is difficult: the change was registered for the
original item which was the left argument of IN. Then this item was
copied to left_expr, which is copied below to substitution->args[0]. To
do a proper rollback, we would have to restore the content
of both copies as well as the original item. There might be more copies,
if AND items have been constructed.
The same applies to the right expression.
However, using real_item()/substitutional_item() brings its own
problems: for example, we lose information that the item is an outer
reference; the item can thus wrongly be considered for a Keyuse (causing
bug#17766653).
When WL#6570 removes the "rolling back" system, all
real_item()/substitutional_item() in this file should be removed.
*/
substitution= func->create(left_expr, where_item);
have_to_be_excluded= 1;
......@@ -2034,6 +2055,9 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
}
else
{
/*
Grep for "WL#6570" to see the relevant comment about real_item.
*/
Item *item= (Item*) select_lex->item_list.head()->real_item();
if (select_lex->table_list.elements)
......
......@@ -6296,11 +6296,13 @@ int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
int ret= 0;
DBUG_ENTER("wait_for_update_bin_log");
thd_wait_begin(thd, THD_WAIT_BINLOG);
if (!timeout)
mysql_cond_wait(&update_cond, &LOCK_log);
else
ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
const_cast<struct timespec *>(timeout));
thd_wait_end(thd);
DBUG_RETURN(ret);
}
......
......@@ -1813,14 +1813,9 @@ void clean_up(bool print_message)
item_user_lock_free();
lex_free(); /* Free some memory */
item_create_cleanup();
if (!opt_noacl)
{
#ifdef HAVE_DLOPEN
udf_free();
#endif
}
table_def_start_shutdown();
plugin_shutdown();
udf_free();
ha_end();
if (tc_log)
tc_log->close();
......@@ -5005,12 +5000,7 @@ int mysqld_main(int argc, char **argv)
if (!opt_bootstrap)
servers_init(0);
if (!opt_noacl)
{
#ifdef HAVE_DLOPEN
udf_init();
#endif
}
udf_init();
init_status_vars();
if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
......
/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2006, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -336,6 +337,7 @@ extern mysql_mutex_t
LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count;
#ifdef HAVE_OPENSSL
extern char* des_key_file;
extern mysql_mutex_t LOCK_des_key_file;
#endif
extern mysql_mutex_t LOCK_server_started;
......
......@@ -7326,6 +7326,8 @@ acl_check_proxy_grant_access(THD *thd, const char *host, const char *user,
DBUG_RETURN(FALSE);
}
mysql_mutex_lock(&acl_cache->lock);
/* check for matching WITH PROXY rights */
for (uint i=0; i < acl_proxy_users.elements; i++)
{
......@@ -7338,10 +7340,12 @@ acl_check_proxy_grant_access(THD *thd, const char *host, const char *user,
proxy->get_with_grant())
{
DBUG_PRINT("info", ("found"));
mysql_mutex_unlock(&acl_cache->lock);
DBUG_RETURN(FALSE);
}
}
mysql_mutex_unlock(&acl_cache->lock);
my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
thd->security_ctx->user,
thd->security_ctx->host_or_ip);
......
......@@ -1999,7 +1999,7 @@ class Delayed_insert :public ilink {
*/
MDL_request grl_protection;
Delayed_insert()
Delayed_insert(SELECT_LEX *current_select)
:locks_in_memory(0), table(0),tables_in_use(0),stacked_inserts(0),
status(0), handler_thread_initialized(FALSE), group_count(0)
{
......@@ -2009,7 +2009,7 @@ class Delayed_insert :public ilink {
strmake_buf(thd.security_ctx->priv_user, thd.security_ctx->user);
thd.current_tablenr=0;
thd.command=COM_DELAYED_INSERT;
thd.lex->current_select= 0; // for my_message_sql
thd.lex->current_select= current_select;
thd.lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
/*
Prevent changes to global.lock_wait_timeout from affecting
......@@ -2186,7 +2186,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
*/
if (! (di= find_handler(thd, table_list)))
{
if (!(di= new Delayed_insert()))
if (!(di= new Delayed_insert(thd->lex->current_select)))
goto end_create;
mysql_mutex_lock(&LOCK_thread_count);
thread_count++;
......@@ -2817,6 +2817,16 @@ pthread_handler_t handle_delayed_insert(void *arg)
if (di->open_and_lock_table())
goto err;
/*
INSERT DELAYED generally expects thd->lex->current_select to be NULL,
since this is not an attribute of the current thread. This can lead to
problems if the thread that spawned the current one disconnects.
current_select will then point to freed memory. But current_select is
required to resolve the partition function. So, after fulfilling that
requirement, we set the current_select to 0.
*/
thd->lex->current_select= NULL;
/* Tell client that the thread is initialized */
mysql_cond_signal(&di->cond_client);
......
......@@ -545,6 +545,16 @@ void lex_end(LEX *lex)
DBUG_ENTER("lex_end");
DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex));
lex_end_stage1(lex);
lex_end_stage2(lex);
DBUG_VOID_RETURN;
}
void lex_end_stage1(LEX *lex)
{
DBUG_ENTER("lex_end_stage1");
/* release used plugins */
if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
{
......@@ -556,6 +566,19 @@ void lex_end(LEX *lex)
delete lex->sphead;
lex->sphead= NULL;
DBUG_VOID_RETURN;
}
/*
MASTER INFO parameters (or state) is normally cleared towards the end
of a statement. But in case of PS, the state needs to be preserved during
its lifetime and should only be cleared on PS close or deallocation.
*/
void lex_end_stage2(LEX *lex)
{
DBUG_ENTER("lex_end_stage2");
/* Reset LEX_MASTER_INFO */
lex->mi.reset();
DBUG_VOID_RETURN;
......
......@@ -2940,6 +2940,8 @@ extern void lex_init(void);
extern void lex_free(void);
extern void lex_start(THD *thd);
extern void lex_end(LEX *lex);
extern void lex_end_stage1(LEX *lex);
extern void lex_end_stage2(LEX *lex);
void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex);
int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex);
extern int MYSQLlex(union YYSTYPE *yylval, THD *thd);
......
/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
Copyright (c) 2008, 2013, Monty Program Ab
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -1408,7 +1408,8 @@ static int mysql_test_update(Prepared_statement *stmt,
(SELECT_ACL & ~table_list->table->grant.privilege);
table_list->register_want_access(SELECT_ACL);
#endif
if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0) ||
check_unique_table(thd, table_list))
goto error;
/* TODO: here we should send types of placeholders to the client. */
DBUG_RETURN(0);
......@@ -3416,7 +3417,8 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
thd->mdl_context.release_transactional_locks();
}
lex_end(lex);
/* Preserve CHANGE MASTER attributes */
lex_end_stage1(lex);
cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
thd->stmt_arena= old_stmt_arena;
......@@ -3779,8 +3781,8 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy)
swap_variables(LEX_STRING, name, copy->name);
/* Ditto */
swap_variables(char *, db, copy->db);
swap_variables(size_t, db_length, copy->db_length);
DBUG_ASSERT(db_length == copy->db_length);
DBUG_ASSERT(param_count == copy->param_count);
DBUG_ASSERT(thd == copy->thd);
last_error[0]= '\0';
......@@ -3997,6 +3999,10 @@ void Prepared_statement::deallocate()
{
/* We account deallocate in the same manner as mysqld_stmt_close */
status_var_increment(thd->status_var.com_stmt_close);
/* It should now be safe to reset CHANGE MASTER parameters */
lex_end_stage2(lex);
/* Statement map calls delete stmt on erase */
thd->stmt_map.erase(this);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment