summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc241
1 files changed, 197 insertions, 44 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 22d6137bfba..b40ee63fac6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -55,6 +55,7 @@
#include <mysys_err.h>
#include <limits.h>
+#include "sp_head.h"
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "transaction.h"
@@ -100,6 +101,23 @@ extern "C" void free_user_var(user_var_entry *entry)
my_free(entry);
}
+/* Functions for last-value-from-sequence hash */
+
+extern "C" uchar *get_sequence_last_key(SEQUENCE_LAST_VALUE *entry,
+ size_t *length,
+ my_bool not_used
+ __attribute__((unused)))
+{
+ *length= entry->length;
+ return (uchar*) entry->key;
+}
+
+extern "C" void free_sequence_last(SEQUENCE_LAST_VALUE *entry)
+{
+ delete entry;
+}
+
+
bool Key_part_spec::operator==(const Key_part_spec& other) const
{
return length == other.length &&
@@ -233,7 +251,7 @@ bool Foreign_key::validate(List<Create_field> &table_fields)
while ((sql_field= it++) &&
my_strcasecmp(system_charset_info,
column->field_name.str,
- sql_field->field_name)) {}
+ sql_field->field_name.str)) {}
if (!sql_field)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
@@ -552,7 +570,7 @@ char *thd_get_error_context_description(THD *thd, char *buffer,
len= my_snprintf(header, sizeof(header),
"MySQL thread id %lu, OS thread handle %lu, query id %lu",
- thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id);
+ (ulong) thd->thread_id, (ulong) thd->real_id, (ulong) thd->query_id);
str.length(0);
str.append(header, len);
@@ -888,6 +906,9 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC);
+ my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
+ (my_hash_get_key) get_sequence_last_key,
+ (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
sp_proc_cache= NULL;
sp_func_cache= NULL;
@@ -927,8 +948,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
}
m_binlog_invoker= INVOKER_NONE;
- memset(&invoker_user, 0, sizeof(invoker_user));
- memset(&invoker_host, 0, sizeof(invoker_host));
+ invoker.init();
prepare_derived_at_open= FALSE;
create_tmp_table_for_derived= FALSE;
save_prep_leaf_list= FALSE;
@@ -1075,9 +1095,10 @@ void THD::raise_note_printf(uint sql_errno, ...)
}
Sql_condition* THD::raise_condition(uint sql_errno,
- const char* sqlstate,
- Sql_condition::enum_warning_level level,
- const char* msg)
+ const char* sqlstate,
+ Sql_condition::enum_warning_level level,
+ const Sql_user_condition_identity &ucid,
+ const char* msg)
{
Diagnostics_area *da= get_stmt_da();
Sql_condition *cond= NULL;
@@ -1136,7 +1157,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (!da->is_error())
{
set_row_count_func(-1);
- da->set_error_status(sql_errno, msg, sqlstate, cond);
+ da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
}
}
@@ -1150,7 +1171,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
sql_errno == ER_OUTOFMEMORY)))
{
- cond= da->push_warning(this, sql_errno, sqlstate, level, msg);
+ cond= da->push_warning(this, sql_errno, sqlstate, level, ucid, msg);
}
DBUG_RETURN(cond);
}
@@ -1180,11 +1201,11 @@ char *thd_strmake(MYSQL_THD thd, const char *str, size_t size)
}
extern "C"
-LEX_STRING *thd_make_lex_string(THD *thd, LEX_STRING *lex_str,
+LEX_CSTRING *thd_make_lex_string(THD *thd, LEX_CSTRING *lex_str,
const char *str, size_t size,
int allocate_lex_string)
{
- return allocate_lex_string ? thd->make_lex_string(str, size)
+ return allocate_lex_string ? thd->make_clex_string(str, size)
: thd->make_lex_string(lex_str, str, size);
}
@@ -1233,6 +1254,17 @@ extern "C" my_thread_id next_thread_id_noinline()
}
#endif
+
+const Type_handler *THD::type_handler_for_date() const
+{
+ if (!(variables.sql_mode & MODE_ORACLE))
+ return &type_handler_newdate;
+ if (opt_mysql56_temporal_format)
+ return &type_handler_datetime2;
+ return &type_handler_datetime;
+}
+
+
/*
Init common variables that has to be reset on start and on change_user
*/
@@ -1250,7 +1282,7 @@ void THD::init(void)
variables.pseudo_thread_id= thread_id;
variables.default_master_connection.str= default_master_connection_buff;
- ::strmake(variables.default_master_connection.str,
+ ::strmake(default_master_connection_buff,
global_system_variables.default_master_connection.str,
variables.default_master_connection.length);
@@ -1335,7 +1367,17 @@ void THD::init(void)
DBUG_VOID_RETURN;
}
-
+
+bool THD::restore_from_local_lex_to_old_lex(LEX *oldlex)
+{
+ DBUG_ASSERT(lex->sphead);
+ if (lex->sphead->merge_lex(this, oldlex, lex))
+ return true;
+ lex= oldlex;
+ return false;
+}
+
+
/* Updates some status variables to be used by update_global_user_stats */
void THD::update_stats(void)
@@ -1429,6 +1471,9 @@ void THD::change_user(void)
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, 0);
+ my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
+ (my_hash_get_key) get_sequence_last_key,
+ (my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
}
@@ -1485,6 +1530,7 @@ void THD::cleanup(void)
#endif /* defined(ENABLED_DEBUG_SYNC) */
my_hash_free(&user_vars);
+ my_hash_free(&sequences);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
auto_inc_intervals_forced.empty();
@@ -2343,6 +2389,26 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs)
}
+Item_string *THD::make_string_literal(const char *str, size_t length,
+ uint repertoire)
+{
+ if (!charset_is_collation_connection &&
+ (repertoire != MY_REPERTOIRE_ASCII ||
+ !my_charset_is_ascii_based(variables.collation_connection)))
+ {
+ LEX_STRING to;
+ if (convert_string(&to, variables.collation_connection,
+ str, length, variables.character_set_client))
+ return NULL;
+ str= to.str;
+ length= to.length;
+ }
+ return new (mem_root) Item_string(this, str, length,
+ variables.collation_connection,
+ DERIVATION_COERCIBLE, repertoire);
+}
+
+
/*
Update some cache variables when character set changes
*/
@@ -2696,7 +2762,7 @@ static String default_field_term("\t",default_charset_info);
static String default_enclosed_and_line_start("", default_charset_info);
static String default_xml_row_term("<row>", default_charset_info);
-sql_exchange::sql_exchange(char *name, bool flag,
+sql_exchange::sql_exchange(const char *name, bool flag,
enum enum_filetype filetype_arg)
:file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
{
@@ -3091,7 +3157,7 @@ int select_export::send_data(List<Item> &items)
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"string", printable_buff,
- item->name, static_cast<long>(row_count));
+ item->name.str, static_cast<long>(row_count));
}
else if (copier.source_end_pos() < res->ptr() + res->length())
{
@@ -3374,7 +3440,7 @@ int select_max_min_finder_subselect::send_data(List<Item> &items)
{
if (!cache)
{
- cache= Item_cache::get_cache(thd, val_item);
+ cache= val_item->get_cache(thd);
switch (val_item->result_type()) {
case REAL_RESULT:
op= &select_max_min_finder_subselect::cmp_real;
@@ -3496,15 +3562,29 @@ int select_exists_subselect::send_data(List<Item> &items)
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
+ my_var_sp *mvsp;
unit= u;
-
- if (var_list.elements != list.elements)
+ m_var_sp_row= NULL;
+
+ if (var_list.elements == 1 &&
+ (mvsp= var_list.head()->get_my_var_sp()) &&
+ mvsp->type_handler() == &type_handler_row)
{
- my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
- ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
- return 1;
- }
- return 0;
+ // SELECT INTO row_type_sp_variable
+ if (thd->spcont->get_item(mvsp->offset)->cols() != list.elements)
+ goto error;
+ m_var_sp_row= mvsp;
+ return 0;
+ }
+
+ // SELECT INTO variable list
+ if (var_list.elements == list.elements)
+ return 0;
+
+error:
+ my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
+ ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
+ return 1;
}
@@ -3830,7 +3910,7 @@ Statement_map::~Statement_map()
bool my_var_user::set(THD *thd, Item *item)
{
- Item_func_set_user_var *suv= new (thd->mem_root) Item_func_set_user_var(thd, name, item);
+ Item_func_set_user_var *suv= new (thd->mem_root) Item_func_set_user_var(thd, &name, item);
suv->save_item_result(item);
return suv->fix_fields(thd, 0) || suv->update();
}
@@ -3840,12 +3920,30 @@ bool my_var_sp::set(THD *thd, Item *item)
return thd->spcont->set_variable(thd, offset, &item);
}
-int select_dumpvar::send_data(List<Item> &items)
+bool my_var_sp_row_field::set(THD *thd, Item *item)
{
+ return thd->spcont->set_variable_row_field(thd, offset, m_field_offset, &item);
+}
+
+
+bool select_dumpvar::send_data_to_var_list(List<Item> &items)
+{
+ DBUG_ENTER("select_dumpvar::send_data_to_var_list");
List_iterator_fast<my_var> var_li(var_list);
List_iterator<Item> it(items);
Item *item;
my_var *mv;
+ while ((mv= var_li++) && (item= it++))
+ {
+ if (mv->set(thd, item))
+ DBUG_RETURN(true);
+ }
+ DBUG_RETURN(false);
+}
+
+
+int select_dumpvar::send_data(List<Item> &items)
+{
DBUG_ENTER("select_dumpvar::send_data");
if (unit->offset_limit_cnt)
@@ -3858,11 +3956,11 @@ int select_dumpvar::send_data(List<Item> &items)
my_message(ER_TOO_MANY_ROWS, ER_THD(thd, ER_TOO_MANY_ROWS), MYF(0));
DBUG_RETURN(1);
}
- while ((mv= var_li++) && (item= it++))
- {
- if (mv->set(thd, item))
- DBUG_RETURN(1);
- }
+ if (m_var_sp_row ?
+ thd->spcont->set_variable_row(thd, m_var_sp_row->offset, items) :
+ send_data_to_var_list(items))
+ DBUG_RETURN(1);
+
DBUG_RETURN(thd->is_error());
}
@@ -3892,7 +3990,8 @@ create_result_table(THD *thd_arg, List<Item> *column_types,
bool is_union_distinct, ulonglong options,
const char *table_alias, bool bit_fields_as_long,
bool create_table,
- bool keep_row_order)
+ bool keep_row_order,
+ uint hidden)
{
DBUG_ASSERT(table == 0);
tmp_table_param.field_count= column_types->elements;
@@ -3927,12 +4026,12 @@ void select_materialize_with_stats::reset()
void select_materialize_with_stats::cleanup()
{
reset();
- select_union::cleanup();
+ select_unit::cleanup();
}
/**
- Override select_union::send_data to analyze each row for NULLs and to
+ Override select_unit::send_data to analyze each row for NULLs and to
update null_statistics before sending data to the client.
@return TRUE if fatal error when sending data to the client
@@ -3947,7 +4046,7 @@ int select_materialize_with_stats::send_data(List<Item> &items)
uint nulls_in_row= 0;
int res;
- if ((res= select_union::send_data(items)))
+ if ((res= select_unit::send_data(items)))
return res;
if (table->null_catch_flags & REJECT_ROW_DUE_TO_NULL_FIELDS)
{
@@ -4059,7 +4158,7 @@ void Security_context::destroy()
}
if (user != delayed_user)
{
- my_free(user);
+ my_free((char*) user);
user= NULL;
}
@@ -4069,7 +4168,7 @@ void Security_context::destroy()
external_user= NULL;
}
- my_free(ip);
+ my_free((char*) ip);
ip= NULL;
}
@@ -4085,7 +4184,7 @@ void Security_context::skip_grants()
bool Security_context::set_user(char *user_arg)
{
- my_free(user);
+ my_free((char*) user);
user= my_strdup(user_arg, MYF(0));
return user == 0;
}
@@ -4143,9 +4242,9 @@ bool Security_context::set_user(char *user_arg)
bool
Security_context::
change_security_context(THD *thd,
- LEX_STRING *definer_user,
- LEX_STRING *definer_host,
- LEX_STRING *db,
+ LEX_CSTRING *definer_user,
+ LEX_CSTRING *definer_host,
+ LEX_CSTRING *db,
Security_context **backup)
{
bool needs_change;
@@ -5324,8 +5423,8 @@ void THD::get_definer(LEX_USER *definer, bool role)
if (slave_thread && has_invoker())
#endif
{
- definer->user = invoker_user;
- definer->host= invoker_host;
+ definer->user= invoker.user;
+ definer->host= invoker.host;
definer->reset_auth();
}
else
@@ -5707,7 +5806,7 @@ int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
int THD::decide_logging_format(TABLE_LIST *tables)
{
DBUG_ENTER("THD::decide_logging_format");
- DBUG_PRINT("info", ("Query: %s", query()));
+ DBUG_PRINT("info", ("Query: %.*s", (uint) query_length(), query()));
DBUG_PRINT("info", ("variables.binlog_format: %lu",
variables.binlog_format));
DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
@@ -5874,7 +5973,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (prev_write_table && prev_write_table->file->ht !=
table->table->file->ht)
multi_write_engine= TRUE;
- if (table->table->s->non_determinstic_insert)
+ if (table->table->s->non_determinstic_insert &&
+ !(sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE))
has_write_tables_with_unsafe_statements= true;
trans= table->table->file->has_transactions();
@@ -7394,4 +7494,57 @@ bool Discrete_intervals_list::append(Discrete_interval *new_interval)
DBUG_RETURN(0);
}
+
+void AUTHID::copy(MEM_ROOT *mem_root, const LEX_CSTRING *user_name,
+ const LEX_CSTRING *host_name)
+{
+ user.str= strmake_root(mem_root, user_name->str, user_name->length);
+ user.length= user_name->length;
+
+ host.str= strmake_root(mem_root, host_name->str, host_name->length);
+ host.length= host_name->length;
+}
+
+
+/*
+ Set from a string in 'user@host' format.
+ This method resebmles parse_user(),
+ but does not need temporary buffers.
+*/
+void AUTHID::parse(const char *str, size_t length)
+{
+ const char *p= strrchr(str, '@');
+ if (!p)
+ {
+ user.str= str;
+ user.length= length;
+ host= null_clex_str;
+ }
+ else
+ {
+ user.str= str;
+ user.length= (size_t) (p - str);
+ host.str= p + 1;
+ host.length= (size_t) (length - user.length - 1);
+ if (user.length && !host.length)
+ host= host_not_specified; // 'user@' -> 'user@%'
+ }
+ if (user.length > USERNAME_LENGTH)
+ user.length= USERNAME_LENGTH;
+ if (host.length > HOSTNAME_LENGTH)
+ host.length= HOSTNAME_LENGTH;
+}
+
+
+void Database_qualified_name::copy(MEM_ROOT *mem_root,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name)
+{
+ m_db.length= db.length;
+ m_db.str= strmake_root(mem_root, db.str, db.length);
+ m_name.length= name.length;
+ m_name.str= strmake_root(mem_root, name.str, name.length);
+}
+
+
#endif /* !defined(MYSQL_CLIENT) */