diff options
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r-- | sql/sql_class.cc | 241 |
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) */ |