diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.cc | 19 | ||||
-rw-r--r-- | sql/item.cc | 7 | ||||
-rw-r--r-- | sql/item.h | 48 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 93 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 2 | ||||
-rw-r--r-- | sql/item_subselect.cc | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 4 | ||||
-rw-r--r-- | sql/privilege.h | 2 | ||||
-rw-r--r-- | sql/sql_acl.cc | 14 | ||||
-rw-r--r-- | sql/sql_class.cc | 16 | ||||
-rw-r--r-- | sql/sql_class.h | 8 | ||||
-rw-r--r-- | sql/sql_explain.cc | 15 | ||||
-rw-r--r-- | sql/sql_insert.cc | 35 | ||||
-rw-r--r-- | sql/sql_lex.cc | 6 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 92 | ||||
-rw-r--r-- | sql/sql_select.h | 6 | ||||
-rw-r--r-- | sql/sql_show.cc | 22 | ||||
-rw-r--r-- | sql/sql_time.cc | 45 | ||||
-rw-r--r-- | sql/sql_tvc.cc | 13 | ||||
-rw-r--r-- | sql/sql_view.cc | 24 | ||||
-rw-r--r-- | sql/sql_view.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 | ||||
-rw-r--r-- | sql/table.cc | 12 |
25 files changed, 371 insertions, 145 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index f1a6bb3746b..577d6ef9e26 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4932,32 +4932,17 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); - const ulong v= table->s->mysql_version; - - if ((v >= MYSQL_VERSION_ID) && + if ((table->s->mysql_version >= MYSQL_VERSION_ID) && (check_opt->sql_flags & TT_FOR_UPGRADE)) return 0; - if (v < MYSQL_VERSION_ID) + if (table->s->mysql_version < MYSQL_VERSION_ID) { if (unlikely((error= check_old_types()))) return error; error= ha_check_for_upgrade(check_opt); if (unlikely(error && (error != HA_ADMIN_NEEDS_CHECK))) return error; - if (table->s->table_category == TABLE_CATEGORY_USER && - (v < 100142 || - (v >= 100200 && v < 100228) || - (v >= 100300 && v < 100319) || - (v >= 100400 && v < 100409))) - { - for (const KEY *key= table->key_info, - *end= table->key_info + table->s->keys; key < end; key++) - { - if (key->flags & HA_BINARY_PACK_KEY && key->flags & HA_VAR_LENGTH_KEY) - return HA_ADMIN_NEEDS_UPGRADE; - } - } if (unlikely(!error && (check_opt->sql_flags & TT_FOR_UPGRADE))) return 0; } diff --git a/sql/item.cc b/sql/item.cc index 991825663c2..385016d51b0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3597,11 +3597,6 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref, /* just pull to the upper context */ ctx->outer_context= context->outer_context->outer_context; } - else - { - /* No upper context (merging Derived/VIEW where context chain ends) */ - ctx->outer_context= NULL; - } ctx->table_list= context->first_name_resolution_table; ctx->select_lex= new_parent; if (context->select_lex == NULL) @@ -9898,6 +9893,8 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it) Item *item= thd->sp_fix_func_item_for_assignment(field, it); if (!item) return true; + if (field->vers_sys_field()) + return false; // NOTE: field->table->copy_blobs should be false here, but let's // remember the value at runtime to avoid subtle bugs. diff --git a/sql/item.h b/sql/item.h index b3fc475fcdc..5122d361dbb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -214,7 +214,7 @@ struct Name_resolution_context: Sql_alloc The name resolution context to search in when an Item cannot be resolved in this context (the context of an outer select) */ - Name_resolution_context *outer_context; + Name_resolution_context *outer_context= nullptr; /* List of tables used to resolve the items of this context. Usually these @@ -224,7 +224,7 @@ struct Name_resolution_context: Sql_alloc statements we have to change this member dynamically to ensure correct name resolution of different parts of the statement. */ - TABLE_LIST *table_list; + TABLE_LIST *table_list= nullptr; /* In most cases the two table references below replace 'table_list' above for the purpose of name resolution. The first and last name resolution @@ -232,62 +232,65 @@ struct Name_resolution_context: Sql_alloc join tree in a FROM clause. This is needed for NATURAL JOIN, JOIN ... USING and JOIN ... ON. */ - TABLE_LIST *first_name_resolution_table; + TABLE_LIST *first_name_resolution_table= nullptr; /* Last table to search in the list of leaf table references that begins with first_name_resolution_table. */ - TABLE_LIST *last_name_resolution_table; + TABLE_LIST *last_name_resolution_table= nullptr; /* Cache first_name_resolution_table in setup_natural_join_row_types */ - TABLE_LIST *natural_join_first_table; + TABLE_LIST *natural_join_first_table= nullptr; /* SELECT_LEX item belong to, in case of merged VIEW it can differ from SELECT_LEX where item was created, so we can't use table_list/field_list from there */ - st_select_lex *select_lex; + st_select_lex *select_lex= nullptr; /* Processor of errors caused during Item name resolving, now used only to hide underlying tables in errors about views (i.e. it substitute some errors for views) */ - void (*error_processor)(THD *, void *); - void *error_processor_data; + void (*error_processor)(THD *, void *)= &dummy_error_processor; + void *error_processor_data= nullptr; /* When TRUE items are resolved in this context both against the SELECT list and this->table_list. If FALSE, items are resolved only against this->table_list. */ - bool resolve_in_select_list; + bool resolve_in_select_list= false; /* Bitmap of tables that should be ignored when doing name resolution. Normally it is {0}. Non-zero values are used by table functions. */ - ignored_tables_list_t ignored_tables; + ignored_tables_list_t ignored_tables= nullptr; /* Security context of this name resolution context. It's used for views and is non-zero only if the view is defined with SQL SECURITY DEFINER. */ - Security_context *security_ctx; + Security_context *security_ctx= nullptr; - Name_resolution_context() - :outer_context(0), table_list(0), select_lex(0), - error_processor_data(0), - ignored_tables(NULL), - security_ctx(0) - {} + Name_resolution_context() = default; + + /** + Name resolution context with resolution in only one table + */ + Name_resolution_context(TABLE_LIST *table) : + first_name_resolution_table(table), last_name_resolution_table(table) + {} void init() { resolve_in_select_list= FALSE; error_processor= &dummy_error_processor; - first_name_resolution_table= NULL; - last_name_resolution_table= NULL; + ignored_tables= nullptr; + first_name_resolution_table= nullptr; + last_name_resolution_table= nullptr; } void resolve_in_table_list_only(TABLE_LIST *tables) @@ -2119,6 +2122,11 @@ public: } virtual Item* transform(THD *thd, Item_transformer transformer, uchar *arg); + virtual Item* top_level_transform(THD *thd, Item_transformer transformer, + uchar *arg) + { + return transform(thd, transformer, arg); + } /* This function performs a generic "compilation" of the Item tree. @@ -2488,6 +2496,8 @@ public: { return this; } virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) { return this; } + virtual Item *in_predicate_to_equality_transformer(THD *thd, uchar *arg) + { return this; } virtual Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) { return this; } virtual Item *multiple_equality_transformer(THD *thd, uchar *arg) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c202a32c3be..8b31362a9d9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -35,6 +35,7 @@ #define PCRE2_STATIC 1 /* Important on Windows */ #include "pcre2.h" /* pcre2 header file */ +#include "my_json_writer.h" /* Compare row signature of two expressions @@ -417,9 +418,18 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp) if (args[0]->cmp_type() == STRING_RESULT && args[1]->cmp_type() == STRING_RESULT) { + Query_arena *arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); + DTCollation tmp; - if (agg_arg_charsets_for_comparison(tmp, args, 2)) - return true; + bool ret= agg_arg_charsets_for_comparison(tmp, args, 2); + + if (arena) + thd->restore_active_arena(arena, &backup); + + if (ret) + return ret; + cmp->m_compare_collation= tmp.collation; } // Convert constants when compared to int/year field @@ -4345,6 +4355,56 @@ Item_func_in::fix_fields(THD *thd, Item **ref) } +Item *Item_func_in::in_predicate_to_equality_transformer(THD *thd, uchar *arg) +{ + if (!array || have_null || !all_items_are_consts(args + 1, arg_count - 1)) + return this; /* Transformation is not applicable */ + + /* + If all elements in the array of constant values are equal and there are + no NULLs in the list then clause + - "a IN (e1,..,en)" can be converted to "a = e1" + - "a NOT IN (e1,..,en)" can be converted to "a != e1". + This means an object of Item_func_in can be replaced with an object of + Item_func_eq for IN (e1,..,en) clause or Item_func_ne for + NOT IN (e1,...,en). + */ + + /* + Since the array is sorted it's enough to compare the first and the last + elements to tell whether all elements are equal + */ + if (array->compare_elems(0, array->used_count - 1)) + { + /* Not all elements are equal, transformation is not possible */ + return this; + } + + Json_writer_object trace_wrapper(thd); + trace_wrapper.add("transformation", "in_predicate_to_equality") + .add("before", this); + + Item *new_item= nullptr; + if (negated) + new_item= new (thd->mem_root) Item_func_ne(thd, args[0], args[1]); + else + new_item= new (thd->mem_root) Item_func_eq(thd, args[0], args[1]); + if (new_item) + { + new_item->set_name(thd, name); + if (new_item->fix_fields(thd, &new_item)) + { + /* + If there are any problems during fixing fields, there is no need to + return an error, just discard the transformation + */ + new_item= this; + } + } + trace_wrapper.add("after", new_item); + return new_item; +} + bool Item_func_in::eval_not_null_tables(void *opt_arg) { @@ -5167,6 +5227,35 @@ Item *Item_cond::transform(THD *thd, Item_transformer transformer, uchar *arg) /** + Transform an Item_cond object with a transformer callback function. + + This is like transform() but doesn't use change_item_tree(), + because top-level expression is stored in prep_where/prep_on anyway and + is restored from there, there is no need to use change_item_tree(). + + Furthermore, it can be actually harmful to use it, if build_equal_items() + had replaced Item_eq with Item_equal and deleted list_node with a pointer + to Item_eq. In this case rollback_item_tree_changes() would modify the + deleted list_node. +*/ +Item *Item_cond::top_level_transform(THD *thd, Item_transformer transformer, uchar *arg) +{ + DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); + + List_iterator<Item> li(list); + Item *item; + while ((item= li++)) + { + Item *new_item= item->top_level_transform(thd, transformer, arg); + if (!new_item) + return 0; + *li.ref()= new_item; + } + return Item_func::transform(thd, transformer, arg); +} + + +/** Compile Item_cond object with a processor and a transformer callback functions. diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index fe55f524f89..2d4b73cc6d8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -2620,6 +2620,7 @@ public: bool to_be_transformed_into_in_subq(THD *thd); bool create_value_list_for_tvc(THD *thd, List< List<Item> > *values); Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) override; + Item *in_predicate_to_equality_transformer(THD *thd, uchar *arg) override; uint32 max_length_of_left_expr(); }; @@ -3179,6 +3180,7 @@ public: void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, bool walk_subquery, void *arg) override; Item *transform(THD *thd, Item_transformer transformer, uchar *arg) override; + Item *top_level_transform(THD *thd, Item_transformer transformer, uchar *arg) override; void traverse_cond(Cond_traverser, void *arg, traverse_order order) override; void neg_arguments(THD *thd); Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index ae57462df8e..f509e00b8f6 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2021, MariaDB + Copyright (c) 2010, 2022, 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 @@ -5288,12 +5288,9 @@ bool subselect_hash_sj_engine::make_semi_join_conds() tmp_table_ref->init_one_table(&empty_clex_str, &table_name, NULL, TL_READ); tmp_table_ref->table= tmp_table; - context= new Name_resolution_context; - context->init(); - context->first_name_resolution_table= - context->last_name_resolution_table= tmp_table_ref; + context= new Name_resolution_context(tmp_table_ref); semi_join_conds_context= context; - + for (uint i= 0; i < item_in->left_expr->cols(); i++) { /* New equi-join condition for the current column. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 31aac7301d2..5d3c4facd81 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6271,7 +6271,7 @@ void handle_connections_sockets() } #endif // HAVE_POLL - for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++) + for (uint retry=0; retry < MAX_ACCEPT_RETRY && !abort_loop; retry++) { size_socket length= sizeof(struct sockaddr_storage); MYSQL_SOCKET new_sock; @@ -8017,7 +8017,7 @@ mysqld_get_one_option(const struct my_option *opt, const char *argument, global_system_variables.log_warnings= atoi(argument); break; case 'T': - test_flags= argument ? (uint) atoi(argument) : 0; + test_flags= argument ? ((uint) atoi(argument) & ~TEST_BLOCKING) : 0; opt_endinfo=1; break; case OPT_THREAD_CONCURRENCY: diff --git a/sql/privilege.h b/sql/privilege.h index c1233102522..82173912e2a 100644 --- a/sql/privilege.h +++ b/sql/privilege.h @@ -293,7 +293,7 @@ constexpr privilege_t SHOW_CREATE_TABLE_ACLS= existing temporary tables (CREATE_ACL is necessary for ALTER ... RENAME). */ constexpr privilege_t TMP_TABLE_ACLS= - COL_DML_ACLS | ALL_TABLE_DDL_ACLS; + COL_DML_ACLS | ALL_TABLE_DDL_ACLS | REFERENCES_ACL; constexpr privilege_t PRIV_LOCK_TABLES= SELECT_ACL | LOCK_TABLES_ACL; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 95ca8b233ce..90776566458 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4102,7 +4102,7 @@ bool change_password(THD *thd, LEX_USER *user) if (update_user_table_password(thd, tables.user_table(), *acl_user)) goto end; - acl_cache->clear(1); // Clear locked hostname cache + hostname_cache_refresh(); // Clear locked hostname cache mysql_mutex_unlock(&acl_cache->lock); result= acl_cache_is_locked= 0; if (mysql_bin_log.is_open()) @@ -4259,7 +4259,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, goto end; } - acl_cache->clear(1); mysql_mutex_unlock(&acl_cache->lock); result= 0; if (mysql_bin_log.is_open()) @@ -7742,7 +7741,10 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) a role */ if (role_as_user) + { propagate_role_grants(role_as_user, PRIVS_TO_MERGE::ALL); + acl_cache->clear(1); + } } mysql_mutex_unlock(&acl_cache->lock); @@ -14147,11 +14149,11 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) if (global_system_variables.log_warnings) sql_print_information("X509 issuer mismatch: should be '%s' " "but is '%s'", acl_user->x509_issuer, ptr); - free(ptr); + OPENSSL_free(ptr); X509_free(cert); return 1; } - free(ptr); + OPENSSL_free(ptr); } /* X509 subject is specified, we check it .. */ if (acl_user->x509_subject[0]) @@ -14164,11 +14166,11 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) if (global_system_variables.log_warnings) sql_print_information("X509 subject mismatch: should be '%s' but is '%s'", acl_user->x509_subject, ptr); - free(ptr); + OPENSSL_free(ptr); X509_free(cert); return 1; } - free(ptr); + OPENSSL_free(ptr); } X509_free(cert); return 0; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ee79115e65b..0913b3834f8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5111,12 +5111,22 @@ void reset_thd(MYSQL_THD thd) before writing response to client, to provide durability guarantees, in other words, server can't send OK packet before modified data is durable in redo log. -*/ -extern "C" void thd_increment_pending_ops(MYSQL_THD thd) + + NOTE: system THD (those that are not associated with client + connection) do not allows async operations yet. + + @param thd a THD + @return thd + @retval nullptr if this is system THD */ +extern "C" MYSQL_THD thd_increment_pending_ops(MYSQL_THD thd) { + if (!thd || thd->system_thread != NON_SYSTEM_THREAD) + return nullptr; thd->async_state.inc_pending_ops(); + return thd; } + /** This function can be used by plugin/engine to indicate end of async operation (such as end of group commit @@ -5127,6 +5137,8 @@ extern "C" void thd_increment_pending_ops(MYSQL_THD thd) extern "C" void thd_decrement_pending_ops(MYSQL_THD thd) { DBUG_ASSERT(thd); + DBUG_ASSERT(thd->system_thread == NON_SYSTEM_THREAD); + thd_async_state::enum_async_state state; if (thd->async_state.dec_pending_ops(&state) == 0) { diff --git a/sql/sql_class.h b/sql/sql_class.h index bd8c1faf412..2daa5705bfc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2590,9 +2590,6 @@ struct thd_async_state } }; -extern "C" void thd_increment_pending_ops(MYSQL_THD); -extern "C" void thd_decrement_pending_ops(MYSQL_THD); - /** @class THD @@ -6116,7 +6113,7 @@ class select_insert :public select_result_interceptor { int prepare(List<Item> &list, SELECT_LEX_UNIT *u); virtual int prepare2(JOIN *join); virtual int send_data(List<Item> &items); - virtual void store_values(List<Item> &values); + virtual bool store_values(List<Item> &values, bool ignore_errors); virtual bool can_rollback_data() { return 0; } bool prepare_eof(); bool send_ok_packet(); @@ -6161,7 +6158,8 @@ public: } int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - void store_values(List<Item> &values); + int binlog_show_create_table(TABLE **tables, uint count); + bool store_values(List<Item> &values, bool ignore_errors); bool send_eof(); virtual void abort_result_set(); virtual bool can_rollback_data() { return 1; } diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index 3cee9bbb2c5..87095917f71 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -664,7 +664,11 @@ int Explain_node::print_explain_for_children(Explain_query *query, for (int i= 0; i < (int) children.elements(); i++) { Explain_node *node= query->get_node(children.at(i)); - if (node->print_explain(query, output, explain_flags, is_analyze)) + /* + Note: node may not be present because for certain kinds of subqueries, + the optimizer is not able to see that they were eliminated. + */ + if (node && node->print_explain(query, output, explain_flags, is_analyze)) return 1; } return 0; @@ -708,8 +712,15 @@ void Explain_node::print_explain_json_for_children(Explain_query *query, for (int i= 0; i < (int) children.elements(); i++) { Explain_node *node= query->get_node(children.at(i)); - /* Derived tables are printed inside Explain_table_access objects */ + /* + Note: node may not be present because for certain kinds of subqueries, + the optimizer is not able to see that they were eliminated. + */ + if (!node) + continue; + + /* Derived tables are printed inside Explain_table_access objects */ if (!is_connection_printable_in_json(node->connection_type)) continue; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0d4eabd2d06..7d05e2bae79 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -95,8 +95,8 @@ pthread_handler_t handle_delayed_insert(void *arg); static void unlink_blobs(TABLE *table); #endif static bool check_view_insertability(THD *thd, TABLE_LIST *view); -static int binlog_show_create_table(THD *thd, TABLE *table, - Table_specification_st *create_info); +static int binlog_show_create_table_(THD *thd, TABLE *table, + Table_specification_st *create_info); /* Check that insert/update fields are from the same single table of a view. @@ -4147,9 +4147,7 @@ int select_insert::send_data(List<Item> &values) bool error=0; thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields - store_values(values); - if (table->default_field && - unlikely(table->update_default_fields(info.ignore))) + if (store_values(values, info.ignore)) DBUG_RETURN(1); thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; if (unlikely(thd->is_error())) @@ -4207,18 +4205,19 @@ int select_insert::send_data(List<Item> &values) } -void select_insert::store_values(List<Item> &values) +bool select_insert::store_values(List<Item> &values, bool ignore_errors) { DBUG_ENTER("select_insert::store_values"); + bool error; if (fields->elements) - fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1, - TRG_EVENT_INSERT); + error= fill_record_n_invoke_before_triggers(thd, table, *fields, values, + ignore_errors, TRG_EVENT_INSERT); else - fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(), - values, 1, TRG_EVENT_INSERT); + error= fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(), + values, ignore_errors, TRG_EVENT_INSERT); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } bool select_insert::prepare_eof() @@ -4753,7 +4752,7 @@ select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u) TABLE const *const table = *tables; if (thd->is_current_stmt_binlog_format_row() && !table->s->tmp_table) - return binlog_show_create_table(thd, *tables, ptr->create_info); + return binlog_show_create_table_(thd, *tables, ptr->create_info); return 0; } select_create *ptr; @@ -4874,8 +4873,8 @@ select_create::prepare(List<Item> &_values, SELECT_LEX_UNIT *u) } -static int binlog_show_create_table(THD *thd, TABLE *table, - Table_specification_st *create_info) +static int binlog_show_create_table_(THD *thd, TABLE *table, + Table_specification_st *create_info) { /* Note 1: In RBR mode, we generate a CREATE TABLE statement for the @@ -4968,7 +4967,7 @@ bool binlog_create_table(THD *thd, TABLE *table, bool replace) HA_CREATE_USED_DEFAULT_CHARSET); /* Ensure we write all engine options to binary log */ create_info.used_fields|= HA_CREATE_PRINT_ALL_OPTIONS; - result= binlog_show_create_table(thd, table, &create_info) != 0; + result= binlog_show_create_table_(thd, table, &create_info) != 0; thd->variables.option_bits= save_option_bits; return result; } @@ -5010,10 +5009,10 @@ bool binlog_drop_table(THD *thd, TABLE *table) } -void select_create::store_values(List<Item> &values) +bool select_create::store_values(List<Item> &values, bool ignore_errors) { - fill_record_n_invoke_before_triggers(thd, table, field, values, 1, - TRG_EVENT_INSERT); + return fill_record_n_invoke_before_triggers(thd, table, field, values, + ignore_errors, TRG_EVENT_INSERT); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b98d4a62c55..57f7cfac595 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2951,6 +2951,7 @@ void st_select_lex::init_query() min_max_opt_list.empty(); limit_params.clear(); join= 0; + cur_pos_in_select_list= UNDEF_POS; having= prep_having= where= prep_where= 0; cond_pushed_into_where= cond_pushed_into_having= 0; attach_to_conds.empty(); @@ -10872,9 +10873,8 @@ st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd, Item *cond) */ if (cond->get_extraction_flag() == MARKER_FULL_EXTRACTION) { - Item *result= cond->transform(thd, - &Item::multiple_equality_transformer, - (uchar *)this); + Item *result= cond->top_level_transform(thd, + &Item::multiple_equality_transformer, (uchar *)this); if (!result) return true; if (result->type() == Item::COND_ITEM && diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 784194e1dd7..3d0809f8785 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7041,13 +7041,13 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) @brief Check if the requested privileges exists in either User-, Host- or Db-tables. @param thd Thread context - @param want_access Privileges requested + @param requirements Privileges requested @param tables List of tables to be compared against - @param no_errors Don't report error to the client (using my_error() call). @param any_combination_of_privileges_will_do TRUE if any privileges on any column combination is enough. @param number Only the first 'number' tables in the linked list are relevant. + @param no_errors Don't report error to the client (using my_error() call). The suppled table list contains cached privileges. This functions calls the help functions check_access and check_grant to verify the first three steps @@ -7074,7 +7074,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) bool check_table_access(THD *thd, privilege_t requirements, TABLE_LIST *tables, - bool any_combination_of_privileges_will_do, + bool any_combination_of_privileges_will_do, uint number, bool no_errors) { TABLE_LIST *org_tables= tables; @@ -9022,7 +9022,6 @@ push_new_name_resolution_context(THD *thd, Name_resolution_context *on_context; if (!(on_context= new (thd->mem_root) Name_resolution_context)) return TRUE; - on_context->init(); on_context->first_name_resolution_table= left_op->first_leaf_for_name_resolution(); on_context->last_name_resolution_table= diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c82744ae48e..65d515d312f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -5630,6 +5630,7 @@ public: MEM_ROOT *alloc; THD *new_thd; Security_context empty_ctx; + ulonglong client_capabilities; my_bool do_log_bin; @@ -6257,6 +6258,7 @@ loc_advanced_command(MYSQL *mysql, enum enum_server_command command, { Ed_connection con(p->thd); Security_context *ctx_orig= p->thd->security_ctx; + ulonglong cap_orig= p->thd->client_capabilities; MYSQL_LEX_STRING sql_text; my_bool log_bin_orig; p->set_binlog_vars(&log_bin_orig); @@ -6265,7 +6267,9 @@ loc_advanced_command(MYSQL *mysql, enum enum_server_command command, sql_text.str= (char *) arg; sql_text.length= arg_length; p->thd->security_ctx= &p->empty_ctx; + p->thd->client_capabilities= p->client_capabilities; result= con.execute_direct(p, sql_text); + p->thd->client_capabilities= cap_orig; p->thd->security_ctx= ctx_orig; p->restore_binlog_vars(log_bin_orig); } @@ -6391,6 +6395,7 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql) THD *thd_orig= current_thd; THD *new_thd; Protocol_local *p; + ulonglong client_flag; DBUG_ENTER("mysql_real_connect_local"); /* Test whether we're already connected */ @@ -6402,6 +6407,9 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql) mysql->methods= &local_methods; mysql->user= NULL; + client_flag= mysql->options.client_flag; + client_flag|= CLIENT_MULTI_RESULTS;; + client_flag&= ~(CLIENT_COMPRESS | CLIENT_PLUGIN_AUTH); mysql->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME, MYSQL_ERRMSG_SIZE, MYF(0)); @@ -6425,6 +6433,7 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql) new_thd->variables.wsrep_on= 0; new_thd->variables.sql_log_bin= 0; new_thd->set_binlog_bit(); + new_thd->client_capabilities= client_flag; /* TOSO: decide if we should turn the auditing off @@ -6446,6 +6455,7 @@ extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql) { p->empty_ctx.init(); p->empty_ctx.skip_grants(); + p->client_capabilities= client_flag; } mysql->thd= p; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9bd6aa4d5d3..794bcca00da 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2216,6 +2216,9 @@ JOIN::optimize_inner() ignore_on_expr= true; break; } + + transform_in_predicates_into_equalities(thd); + conds= optimize_cond(this, conds, join_list, ignore_on_expr, &cond_value, &cond_equal, OPT_LINK_EQUAL_FIELDS); @@ -30463,6 +30466,95 @@ static bool process_direct_rownum_comparison(THD *thd, SELECT_LEX_UNIT *unit, DBUG_RETURN(false); } +/** + @brief + Transform IN predicates having equal constant elements to equalities + + @param thd The context of the statement + + @details + If all elements in an IN predicate are constant and equal to each other + then clause + - "a IN (e1,..,en)" can be transformed to "a = e1" + - "a NOT IN (e1,..,en)" can be transformed to "a != e1". + This means an object of Item_func_in can be replaced with an object of + Item_func_eq for IN (e1,..,en) clause or Item_func_ne for + NOT IN (e1,...,en). + Such a replacement allows the optimizer to choose a better execution plan. + + This methods applies such transformation for each IN predicate of the WHERE + condition and ON expressions of this join where possible + + @retval + false success + true failure +*/ +bool JOIN::transform_in_predicates_into_equalities(THD *thd) +{ + DBUG_ENTER("JOIN::transform_in_predicates_into_equalities"); + DBUG_RETURN(transform_all_conds_and_on_exprs( + thd, &Item::in_predicate_to_equality_transformer)); +} + + +/** + @brief + Transform all items in WHERE and ON expressions using a given transformer + + @param thd The context of the statement + transformer Pointer to the transformation function + + @details + For each item of the WHERE condition and ON expressions of the SELECT + for this join the method performs the intransformation using the given + transformation function + + @retval + false success + true failure +*/ +bool JOIN::transform_all_conds_and_on_exprs(THD *thd, + Item_transformer transformer) +{ + if (conds) + { + conds= conds->top_level_transform(thd, transformer, (uchar *) 0); + if (!conds) + return true; + } + if (join_list) + { + if (transform_all_conds_and_on_exprs_in_join_list(thd, join_list, + transformer)) + return true; + } + return false; +} + + +bool JOIN::transform_all_conds_and_on_exprs_in_join_list( + THD *thd, List<TABLE_LIST> *join_list, Item_transformer transformer) +{ + TABLE_LIST *table; + List_iterator<TABLE_LIST> li(*join_list); + + while ((table= li++)) + { + if (table->nested_join) + { + if (transform_all_conds_and_on_exprs_in_join_list( + thd, &table->nested_join->join_list, transformer)) + return true; + } + if (table->on_expr) + { + table->on_expr= table->on_expr->top_level_transform(thd, transformer, 0); + if (!table->on_expr) + return true; + } + } + return false; +} /** diff --git a/sql/sql_select.h b/sql/sql_select.h index 3a28c431df5..5aa775f4a2d 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1792,6 +1792,12 @@ private: bool make_aggr_tables_info(); bool add_fields_for_current_rowid(JOIN_TAB *cur, List<Item> *fields); void init_join_cache_and_keyread(); + bool transform_in_predicates_into_equalities(THD *thd); + bool transform_all_conds_and_on_exprs(THD *thd, + Item_transformer transformer); + bool transform_all_conds_and_on_exprs_in_join_list(THD *thd, + List<TABLE_LIST> *join_list, + Item_transformer transformer); }; enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS}; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 173cac3a3b7..a2a1c76411c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6057,6 +6057,15 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, show_table->use_all_columns(); // Required for default restore_record(show_table, s->default_values); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + check_access(thd, SELECT_ACL, db_name->str, + &tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table)); + if (is_temporary_table(tables)) + { + tables->grant.privilege|= TMP_TABLE_ACLS; + } +#endif + for (; (field= *ptr) ; ptr++) { if(field->invisible > INVISIBLE_USER) @@ -6076,14 +6085,13 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, restore_record(table, s->default_values); #ifndef NO_EMBEDDED_ACCESS_CHECKS - ulonglong col_access; - check_access(thd,SELECT_ACL, db_name->str, - &tables->grant.privilege, 0, 0, MY_TEST(tables->schema_table)); - col_access= get_column_grant(thd, &tables->grant, - db_name->str, table_name->str, - field->field_name.str) & COL_ACLS; - if (!tables->schema_table && !col_access) + ulonglong col_access= + get_column_grant(thd, &tables->grant, db_name->str, table_name->str, + field->field_name.str) & COL_ACLS; + + if (!col_access && !tables->schema_table) continue; + char *end= tmp; for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) { diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 8bb96dfa776..12e4460ed25 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -68,62 +68,71 @@ int append_interval(String *str, interval_type int_type, const INTERVAL &interva size_t len; switch (int_type) { case INTERVAL_YEAR: - len= my_snprintf(buf,sizeof(buf),"%u", interval.year); + len= my_snprintf(buf,sizeof(buf),"%lu", interval.year); break; case INTERVAL_QUARTER: case INTERVAL_MONTH: - len= my_snprintf(buf,sizeof(buf),"%u", interval.month); + len= my_snprintf(buf,sizeof(buf),"%lu", interval.month); int_type=INTERVAL_MONTH; break; case INTERVAL_WEEK: case INTERVAL_DAY: - len= my_snprintf(buf,sizeof(buf),"%u", interval.day); + len= my_snprintf(buf,sizeof(buf),"%lu", interval.day); int_type=INTERVAL_DAY; break; case INTERVAL_HOUR: - len= my_snprintf(buf,sizeof(buf),"%u", interval.hour); + len= my_snprintf(buf,sizeof(buf),"%lu", interval.hour); break; case INTERVAL_MINUTE: - len= my_snprintf(buf,sizeof(buf),"%u", interval.minute); + len= my_snprintf(buf,sizeof(buf),"%llu", interval.minute); break; case INTERVAL_SECOND: - len= my_snprintf(buf,sizeof(buf),"%u", interval.second); + len= my_snprintf(buf,sizeof(buf),"%llu", interval.second); break; case INTERVAL_MICROSECOND: - len= my_snprintf(buf,sizeof(buf),"%u", interval.second_part); + len= my_snprintf(buf,sizeof(buf),"%llu", interval.second_part); break; case INTERVAL_YEAR_MONTH: - len= my_snprintf(buf,sizeof(buf),"%u-%02u", interval.day, interval.month); + len= my_snprintf(buf,sizeof(buf),"'%lu-%02lu'", + interval.year, interval.month); break; case INTERVAL_DAY_HOUR: - len= my_snprintf(buf,sizeof(buf),"%u %u", interval.day, interval.hour); + len= my_snprintf(buf,sizeof(buf),"'%lu %lu'", interval.day, interval.hour); break; case INTERVAL_DAY_MINUTE: - len= my_snprintf(buf,sizeof(buf),"%u %u:%02u", interval.day, interval.hour, interval.minute); + len= my_snprintf(buf,sizeof(buf),"'%lu %lu:%02llu'", + interval.day, interval.hour, interval.minute); break; case INTERVAL_DAY_SECOND: - len= my_snprintf(buf,sizeof(buf),"%u %u:%02u:%02u", interval.day, interval.hour, interval.minute, interval.second); + len= my_snprintf(buf,sizeof(buf),"'%lu %lu:%02llu:%02llu'", + interval.day, interval.hour, interval.minute, interval.second); break; case INTERVAL_HOUR_MINUTE: - len= my_snprintf(buf,sizeof(buf),"%u:%02u", interval.hour, interval.minute); + len= my_snprintf(buf,sizeof(buf),"'%lu:%02llu'", interval.hour, interval.minute); break; case INTERVAL_HOUR_SECOND: - len= my_snprintf(buf,sizeof(buf),"%u:%02u:%02u", interval.hour, interval.minute, interval.second); + len= my_snprintf(buf,sizeof(buf),"'%lu:%02llu:%02llu'", + interval.hour, interval.minute, interval.second); break; case INTERVAL_MINUTE_SECOND: - len= my_snprintf(buf,sizeof(buf),"%u:%02u", interval.minute, interval.second); + len= my_snprintf(buf,sizeof(buf),"'%llu:%02llu'", interval.minute, interval.second); break; case INTERVAL_DAY_MICROSECOND: - len= my_snprintf(buf,sizeof(buf),"%u %u:%02u:%02u.%06u", interval.day, interval.hour, interval.minute, interval.second, interval.second_part); + len= my_snprintf(buf,sizeof(buf),"'%lu %lu:%02llu:%02llu.%06llu'", + interval.day, interval.hour, interval.minute, + interval.second, interval.second_part); break; case INTERVAL_HOUR_MICROSECOND: - len= my_snprintf(buf,sizeof(buf),"%u:%02u:%02u.%06u", interval.hour, interval.minute, interval.second, interval.second_part); + len= my_snprintf(buf,sizeof(buf),"'%lu:%02llu:%02llu.%06llu'", + interval.hour, interval.minute, interval.second, + interval.second_part); break; case INTERVAL_MINUTE_MICROSECOND: - len= my_snprintf(buf,sizeof(buf),"%u:%02u.%06u", interval.minute, interval.second, interval.second_part); + len= my_snprintf(buf,sizeof(buf),"'%llu:%02llu.%06llu'", + interval.minute, interval.second, interval.second_part); break; case INTERVAL_SECOND_MICROSECOND: - len= my_snprintf(buf,sizeof(buf),"%u.%06u", interval.second, interval.second_part); + len= my_snprintf(buf,sizeof(buf),"%llu.%06llu", interval.second, interval.second_part); break; default: DBUG_ASSERT(0); diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index a045d0e3908..6e6d446ce16 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -1173,12 +1173,10 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd) { select_lex->parsing_place= IN_WHERE; conds= - conds->transform(thd, - &Item::in_predicate_to_in_subs_transformer, - (uchar*) 0); + conds->top_level_transform(thd, + &Item::in_predicate_to_in_subs_transformer, 0); if (!conds) DBUG_RETURN(true); - select_lex->prep_where= conds ? conds->copy_andor_structure(thd) : 0; select_lex->where= conds; } @@ -1193,13 +1191,10 @@ bool JOIN::transform_in_predicates_into_in_subq(THD *thd) if (table->on_expr) { table->on_expr= - table->on_expr->transform(thd, - &Item::in_predicate_to_in_subs_transformer, - (uchar*) 0); + table->on_expr->top_level_transform(thd, + &Item::in_predicate_to_in_subs_transformer, 0); if (!table->on_expr) DBUG_RETURN(true); - table->prep_on_expr= table->on_expr ? - table->on_expr->copy_andor_structure(thd) : 0; } } } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 7a52b822b9d..a2b744fc8be 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1245,19 +1245,26 @@ err: bool mariadb_view_version_get(TABLE_SHARE *share) { DBUG_ASSERT(share->is_view); + DBUG_ASSERT(share->tabledef_version.length == 0); if (!(share->tabledef_version.str= (uchar*) alloc_root(&share->mem_root, MICROSECOND_TIMESTAMP_BUFFER_SIZE))) return TRUE; - share->tabledef_version.length= 0; // safety if the drfinition file is brocken DBUG_ASSERT(share->view_def != NULL); if (share->view_def->parse((uchar *) &share->tabledef_version, NULL, view_timestamp_parameters, 1, &file_parser_dummy_hook)) + { + // safety if the definition file is brocken + share->tabledef_version.length= 0; + my_error(ER_TABLE_CORRUPT, MYF(0), + share->db.str, share->table_name.str); return TRUE; + } DBUG_ASSERT(share->tabledef_version.length == MICROSECOND_TIMESTAMP_BUFFER_SIZE-1); + return FALSE; } @@ -1322,10 +1329,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, mysql_handle_single_derived(thd->lex, table, DT_REINIT); DEBUG_SYNC(thd, "after_cached_view_opened"); - if (!share->tabledef_version.length) - { - mariadb_view_version_get(share); - } + DBUG_ASSERT(share->tabledef_version.length); DBUG_RETURN(0); } @@ -1379,15 +1383,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, required_view_parameters, &file_parser_dummy_hook))) goto end; - if (!share->tabledef_version.length) - { - share->tabledef_version.str= (const uchar *) - memdup_root(&share->mem_root, - (const void *) - table->hr_timestamp.str, - (share->tabledef_version.length= - table->hr_timestamp.length)); - } + DBUG_ASSERT(share->tabledef_version.length); if (!table->tabledef_version.length) { table->set_view_def_version(&table->hr_timestamp); diff --git a/sql/sql_view.h b/sql/sql_view.h index 536b5f1b784..1b880e43eb1 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -66,4 +66,6 @@ extern const LEX_CSTRING view_type; void make_valid_column_names(List<Item> &item_list); +bool mariadb_view_version_get(TABLE_SHARE *share); + #endif /* SQL_VIEW_INCLUDED */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0f651865a89..1c13fc1a1e1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5116,11 +5116,12 @@ server_part_option: opt_versioning_rotation: /* empty */ {} - | INTERVAL_SYM expr interval opt_versioning_interval_start + | { Lex->clause_that_disallows_subselect= "INTERVAL"; } + INTERVAL_SYM expr interval opt_versioning_interval_start { partition_info *part_info= Lex->part_info; const char *table_name= Lex->create_last_non_select_table->table_name.str; - if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4, table_name))) + if (unlikely(part_info->vers_set_interval(thd, $3, $4, $5, table_name))) MYSQL_YYABORT; } | LIMIT ulonglong_num diff --git a/sql/table.cc b/sql/table.cc index b25779c3de8..6c20a1f8bbd 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -673,7 +673,11 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) if (!share->view_def) share->error= OPEN_FRM_ERROR_ALREADY_ISSUED; else + { share->error= OPEN_FRM_OK; + if (mariadb_view_version_get(share)) + share->error= OPEN_FRM_ERROR_ALREADY_ISSUED; + } } else share->error= OPEN_FRM_NOT_A_TABLE; @@ -8891,7 +8895,7 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) Counting_error_handler count_errors; Suppress_warnings_error_handler warning_handler; in_use->push_internal_handler(&count_errors); - bool abort_on_warning; + bool abort_on_warning= ignore_warnings; if (ignore_warnings) { abort_on_warning= in_use->abort_on_warning; @@ -9716,7 +9720,8 @@ bool TABLE_LIST::change_refs_to_fields() Item **materialized_items= (Item **)thd->calloc(sizeof(void *) * table->s->fields); - if (!materialized_items) + Name_resolution_context *ctx= new Name_resolution_context(this); + if (!materialized_items || !ctx) return TRUE; while ((ref= (Item_direct_ref*)li++)) @@ -9732,7 +9737,8 @@ bool TABLE_LIST::change_refs_to_fields() DBUG_ASSERT(!field_it.end_of_fields()); if (!materialized_items[idx]) { - materialized_items[idx]= new (thd->mem_root) Item_field(thd, table->field[idx]); + materialized_items[idx]= + new (thd->mem_root) Item_field(thd, ctx, table->field[idx]); if (!materialized_items[idx]) return TRUE; } |