From 01c49e66b559d311725ff4c0d86592c3c9eaa58d Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 2 Feb 2017 12:09:49 +0100 Subject: MDEV-11966: Impossible to execute prepared ANALYZE SELECT Prepare os ANALYZE now respond as EXPLAIN. --- sql/sql_prepare.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fd2592d8f5a..455d6b3cb86 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1527,7 +1527,7 @@ static int mysql_test_select(Prepared_statement *stmt, */ if (unit->prepare(thd, 0, 0)) goto error; - if (!lex->describe && !stmt->is_sql_prepare()) + if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ List fields(lex->select_lex.item_list); -- cgit v1.2.1 From 83123412f00d9b69f1c5ea39b160d1d27be701a9 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 18 Apr 2018 19:34:12 +0200 Subject: MDEV-11975: SQLCOM_PREPARE of EXPLAIN & ANALYZE statement do not return correct metadata info Added metadate info after prepare EXPLAIN/ANALYZE. --- sql/sql_class.cc | 29 +++++++++++++++++++++-------- sql/sql_class.h | 2 ++ sql/sql_prepare.cc | 24 ++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0971d4fdaaa..628dcee0570 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2405,18 +2405,31 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) } -int THD::send_explain_fields(select_result *result, uint8 explain_flags, bool is_analyze) +void THD::prepare_explain_fields(select_result *result, + List *field_list, + uint8 explain_flags, + bool is_analyze) { - List field_list; if (lex->explain_json) - make_explain_json_field_list(field_list, is_analyze); + make_explain_json_field_list(*field_list, is_analyze); else - make_explain_field_list(field_list, explain_flags, is_analyze); + make_explain_field_list(*field_list, explain_flags, is_analyze); + + result->prepare(*field_list, NULL); +} - result->prepare(field_list, NULL); - return (result->send_result_set_metadata(field_list, - Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF)); + +int THD::send_explain_fields(select_result *result, + uint8 explain_flags, + bool is_analyze) +{ + List field_list; + int rc; + prepare_explain_fields(result, &field_list, explain_flags, is_analyze); + rc= result->send_result_set_metadata(field_list, + Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF); + return(rc); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 8dde68b7fba..e93bd00eec0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3331,6 +3331,8 @@ public: void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); + void prepare_explain_fields(select_result *result, List *field_list, + uint8 explain_flags, bool is_analyze); int send_explain_fields(select_result *result, uint8 explain_flags, bool is_analyze); void make_explain_field_list(List &field_list, uint8 explain_flags, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 455d6b3cb86..89b7e490cb9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2475,8 +2475,28 @@ static bool check_prepared_statement(Prepared_statement *stmt) break; } if (res == 0) - DBUG_RETURN(stmt->is_sql_prepare() ? - FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush())); + { + if (!stmt->is_sql_prepare()) + { + if (lex->describe || lex->analyze_stmt) + { + if (!lex->result && + !(lex->result= new (stmt->mem_root) select_send(thd))) + DBUG_RETURN(TRUE); + List field_list; + thd->prepare_explain_fields(lex->result, &field_list, + lex->describe, lex->analyze_stmt); + res= send_prep_stmt(stmt, lex->result->field_count(field_list)) || + lex->result->send_result_set_metadata(field_list, + Protocol::SEND_EOF); + } + else + res= send_prep_stmt(stmt, 0); + if (!res) + thd->protocol->flush(); + } + DBUG_RETURN(FALSE); + } error: DBUG_RETURN(TRUE); } -- cgit v1.2.1 From bc8ae50e7c1dd56ceb7fc39e05f87a104d3ce632 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 7 Mar 2019 11:30:06 +0100 Subject: Fix of prepared CREATE VIEW with global ORDER/GROUP --- sql/sql_union.cc | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 56d6cecadf6..72926a26e13 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -661,16 +661,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, allocation in setup_ref_array(). */ fake_select_lex->n_child_sum_items+= global_parameters()->n_sum_items; - - saved_error= fake_select_lex->join-> - prepare(&fake_select_lex->ref_pointer_array, - fake_select_lex->table_list.first, - 0, 0, - global_parameters()->order_list.elements, // og_num - global_parameters()->order_list.first, // order - false, NULL, NULL, NULL, - fake_select_lex, this); - fake_select_lex->table_list.empty(); } } else @@ -681,6 +671,27 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, */ table->reset_item_list(&item_list); } + if (fake_select_lex != NULL && + (thd->stmt_arena->is_stmt_prepare() || + (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW))) + { + if (!fake_select_lex->join && + !(fake_select_lex->join= + new JOIN(thd, item_list, thd->variables.option_bits, result))) + { + fake_select_lex->table_list.empty(); + DBUG_RETURN(TRUE); + } + saved_error= fake_select_lex->join-> + prepare(&fake_select_lex->ref_pointer_array, + fake_select_lex->table_list.first, + 0, 0, + global_parameters()->order_list.elements, // og_num + global_parameters()->order_list.first, // order + false, NULL, NULL, NULL, + fake_select_lex, this); + fake_select_lex->table_list.empty(); + } } thd_arg->lex->current_select= lex_select_save; -- cgit v1.2.1 From dda2e940fb035d41852e95a1c2f513ab1534b041 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 11 Mar 2019 16:45:38 +0100 Subject: pass the slow logging information in thd->query_plan_flags This solves the following issues: * unlike lex->m_sql_cmd and lex->sql_command, thd->query_plan_flags is not reset in Prepared_statement::execute, it survives till the log_slow_statement(), so slow logging behaves correctly in --ps * using thd->query_plan_flags for both slow_log_filter and log_slow_admin_statements means the definition of "admin" statements for the slow log is the same no matter how it is filtered out. --- sql/log_slow.h | 1 + sql/sql_admin.h | 8 +++---- sql/sql_alter.h | 2 +- sql/sql_class.h | 5 ++++ sql/sql_cmd.h | 15 ------------ sql/sql_lex.cc | 13 ----------- sql/sql_parse.cc | 69 +++++++++++++++++++++++--------------------------------- 7 files changed, 39 insertions(+), 74 deletions(-) (limited to 'sql') diff --git a/sql/log_slow.h b/sql/log_slow.h index 3b6dbd1b2ac..5092e8332ed 100644 --- a/sql/log_slow.h +++ b/sql/log_slow.h @@ -34,4 +34,5 @@ #define QPLAN_FILESORT_PRIORITY_QUEUE (1U << 9) /* ... */ +#define QPLAN_STATUS (1U << 31) /* not in the slow_log_filter */ #define QPLAN_MAX (1U << 31) /* reserved as placeholder */ diff --git a/sql/sql_admin.h b/sql/sql_admin.h index ce7308434c5..96594fad0cb 100644 --- a/sql/sql_admin.h +++ b/sql/sql_admin.h @@ -28,7 +28,7 @@ int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache, /** Sql_cmd_analyze_table represents the ANALYZE TABLE statement. */ -class Sql_cmd_analyze_table : public Sql_cmd_admin +class Sql_cmd_analyze_table : public Sql_cmd { public: /** @@ -53,7 +53,7 @@ public: /** Sql_cmd_check_table represents the CHECK TABLE statement. */ -class Sql_cmd_check_table : public Sql_cmd_admin +class Sql_cmd_check_table : public Sql_cmd { public: /** @@ -77,7 +77,7 @@ public: /** Sql_cmd_optimize_table represents the OPTIMIZE TABLE statement. */ -class Sql_cmd_optimize_table : public Sql_cmd_admin +class Sql_cmd_optimize_table : public Sql_cmd { public: /** @@ -102,7 +102,7 @@ public: /** Sql_cmd_repair_table represents the REPAIR TABLE statement. */ -class Sql_cmd_repair_table : public Sql_cmd_admin +class Sql_cmd_repair_table : public Sql_cmd { public: /** diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 74dd8b0e5d8..a4505f1d6c1 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -363,7 +363,7 @@ private: statements. @todo move Alter_info and other ALTER generic structures from Lex here. */ -class Sql_cmd_common_alter_table : public Sql_cmd_admin +class Sql_cmd_common_alter_table : public Sql_cmd { protected: /** diff --git a/sql/sql_class.h b/sql/sql_class.h index e93bd00eec0..db9a3742fc0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5458,6 +5458,11 @@ public: */ #define CF_UPDATES_DATA (1U << 18) +/** + Not logged into slow log as "admin commands" +*/ +#define CF_ADMIN_COMMAND (1U << 19) + /* Bits in server_command_flags */ /** diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 9cb2a728f41..904578134b4 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -145,8 +145,6 @@ public: */ virtual bool execute(THD *thd) = 0; - virtual bool log_slow_enabled_statement(const THD *thd) const; - protected: Sql_cmd() {} @@ -163,17 +161,4 @@ protected: } }; - -class Sql_cmd_admin: public Sql_cmd -{ -public: - Sql_cmd_admin() - {} - ~Sql_cmd_admin() - {} - bool log_slow_enabled_statement(const THD *thd) const; -}; - - - #endif // SQL_CMD_INCLUDED diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7c330151545..df868d0321f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4720,19 +4720,6 @@ bool LEX::is_partition_management() const } -bool Sql_cmd::log_slow_enabled_statement(const THD *thd) const -{ - return global_system_variables.sql_log_slow && thd->variables.sql_log_slow; -} - - -bool Sql_cmd_admin::log_slow_enabled_statement(const THD *thd) const -{ - return opt_log_slow_admin_statements && - Sql_cmd::log_slow_enabled_statement(thd); -} - - #ifdef MYSQL_SERVER uint binlog_unsafe_map[256]; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8da2a257df7..c9651e1038b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -309,10 +309,11 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_CAN_GENERATE_ROW_EVENTS; - sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; + sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | - CF_INSERTS_DATA; + CF_INSERTS_DATA | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; @@ -324,7 +325,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; + sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; @@ -492,10 +494,14 @@ void init_update_queries(void) The following admin table operations are allowed on log tables. */ - sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; - sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; - sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; - sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; + sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; + sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; + sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; + sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | + CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_CHECKSUM]= CF_REPORT_PROGRESS; sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS; @@ -1304,10 +1310,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, m_key); thd->set_command(command); - /* - Commands which always take a long time are logged into - the slow log only if opt_log_slow_admin_statements is set. - */ thd->enable_slow_log= true; thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ @@ -1718,7 +1720,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, status_var_increment(thd->status_var.com_other); - thd->enable_slow_log&= opt_log_slow_admin_statements; thd->query_plan_flags|= QPLAN_ADMIN; if (check_global_access(thd, REPL_SLAVE_ACL)) break; @@ -2018,31 +2019,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } -static bool log_slow_enabled_statement(const THD *thd) -{ - /* - TODO-10.4: Add classes Sql_cmd_create_index and Sql_cmd_drop_index - for symmetry with other admin commands, so these statements can be - handled by this command: - */ - if (thd->lex->m_sql_cmd) - return thd->lex->m_sql_cmd->log_slow_enabled_statement(thd); - - /* - Currently CREATE INDEX or DROP INDEX cause a full table rebuild - and thus classify as slow administrative statements just like - ALTER TABLE. - */ - if ((thd->lex->sql_command == SQLCOM_CREATE_INDEX || - thd->lex->sql_command == SQLCOM_DROP_INDEX) && - !opt_log_slow_admin_statements) - return true; - - return global_system_variables.sql_log_slow && - thd->variables.sql_log_slow; -} - - /* @note This function must call delete_explain_query(). @@ -2075,12 +2051,20 @@ void log_slow_statement(THD *thd) ((thd->server_status & (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && opt_log_queries_not_using_indexes && - !(sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND))) && + !(thd->query_plan_flags & QPLAN_STATUS))) && thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; - if (!log_slow_enabled_statement(thd)) + /* + until opt_log_slow_admin_statements is removed, it + duplicates slow_log_filter=admin + */ + if ((thd->query_plan_flags & QPLAN_ADMIN) && + !opt_log_slow_admin_statements) + goto end; + + if (!global_system_variables.sql_log_slow || !thd->variables.sql_log_slow) goto end; /* @@ -2953,6 +2937,11 @@ mysql_execute_command(THD *thd) goto error; } + if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) + thd->query_plan_flags|= QPLAN_STATUS; + if (sql_command_flags[lex->sql_command] & CF_ADMIN_COMMAND) + thd->query_plan_flags|= QPLAN_ADMIN; + /* Start timeouts */ thd->set_query_timer(); @@ -3574,7 +3563,6 @@ end_with_restore_list: if (check_one_table_access(thd, INDEX_ACL, all_tables)) goto error; /* purecov: inspected */ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL) - thd->query_plan_flags|= QPLAN_ADMIN; bzero((char*) &create_info, sizeof(create_info)); create_info.db_type= 0; @@ -5732,7 +5720,6 @@ end_with_restore_list: case SQLCOM_REPAIR: case SQLCOM_TRUNCATE: case SQLCOM_ALTER_TABLE: - thd->query_plan_flags|= QPLAN_ADMIN; DBUG_ASSERT(first_table == all_tables && first_table != 0); /* fall through */ case SQLCOM_SIGNAL: -- cgit v1.2.1 From 22f1cf9292f859f2f59208f267917481b29d4739 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 11 Nov 2018 14:20:37 +0100 Subject: cleanup: misc --- sql/protocol.h | 60 ++++++++++++++++---------------------------------------- sql/sql_class.h | 12 ++++++------ sql/sql_parse.cc | 10 ++++------ sql/sql_priv.h | 6 ------ sql/sql_show.cc | 7 ++++--- sql/sql_view.cc | 11 ++--------- 6 files changed, 33 insertions(+), 73 deletions(-) (limited to 'sql') diff --git a/sql/protocol.h b/sql/protocol.h index ea33c6bbb45..93b8fcbe8ef 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -230,60 +230,34 @@ class Protocol_discard : public Protocol_text { public: Protocol_discard(THD *thd_arg) : Protocol_text(thd_arg) {} - /* The real writing is done only in write() */ - virtual bool write() { return 0; } virtual bool send_result_set_metadata(List *list, uint flags) { // Don't pas Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF flags return Protocol_text::send_result_set_metadata(list, 0); } - // send_error is intentionally not overloaded. - virtual bool send_eof(uint server_status, uint statement_warn_count) - { - return 0; - } - - void prepare_for_resend() - { -#ifndef DBUG_OFF - field_pos= 0; -#endif - } + bool write() { return 0; } + bool send_eof(uint, uint) { return 0; } + void prepare_for_resend() { IF_DBUG(field_pos= 0,); } /* Provide dummy overrides for any storage methods so that we avoid allocating and copying of data */ - virtual bool store_null() - { return false; } - virtual bool store_tiny(longlong from) - { return false; } - virtual bool store_short(longlong from) - { return false; } - virtual bool store_long(longlong from) - { return false; } - virtual bool store_longlong(longlong from, bool unsigned_flag) - { return false; } - virtual bool store_decimal(const my_decimal *) - { return false; } - virtual bool store(const char *from, size_t length, CHARSET_INFO *cs) - { return false; } - virtual bool store(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs) - { return false; } - virtual bool store(MYSQL_TIME *time, int decimals) - { return false; } - virtual bool store_date(MYSQL_TIME *time) - { return false; } - virtual bool store_time(MYSQL_TIME *time, int decimals) - { return false; } - virtual bool store(float nr, uint32 decimals, String *buffer) - { return false; } - virtual bool store(double from, uint32 decimals, String *buffer) - { return false; } - virtual bool store(Field *field) - { return false; } + bool store_null() { return false; } + bool store_tiny(longlong) { return false; } + bool store_short(longlong) { return false; } + bool store_long(longlong) { return false; } + bool store_longlong(longlong, bool) { return false; } + bool store_decimal(const my_decimal *) { return false; } + bool store(const char *, size_t, CHARSET_INFO *) { return false; } + bool store(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) { return false; } + bool store(MYSQL_TIME *, int) { return false; } + bool store_date(MYSQL_TIME *) { return false; } + bool store_time(MYSQL_TIME *, int) { return false; } + bool store(float, uint32, String *) { return false; } + bool store(double, uint32, String *) { return false; } + bool store(Field *) { return false; } }; diff --git a/sql/sql_class.h b/sql/sql_class.h index db9a3742fc0..a52367be108 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4262,6 +4262,7 @@ public: virtual ~select_result_sink() {}; }; +class select_result_interceptor; /* Interface for sending tabular data, together with some other stuff: @@ -4350,11 +4351,10 @@ public: /* This returns - - FALSE if the class sends output row to the client - - TRUE if the output is set elsewhere (a file, @variable, or table). - Currently all intercepting classes derive from select_result_interceptor. + - NULL if the class sends output row to the client + - this if the output is set elsewhere (a file, @variable, or table). */ - virtual bool is_result_interceptor()=0; + virtual select_result_interceptor *result_interceptor()=0; }; @@ -4422,7 +4422,7 @@ public: } /* Remove gcc warning */ uint field_count(List &fields) const { return 0; } bool send_result_set_metadata(List &fields, uint flag) { return FALSE; } - bool is_result_interceptor() { return true; } + select_result_interceptor *result_interceptor() { return this; } /* Instruct the object to not call my_ok(). Client output will be handled @@ -4450,7 +4450,7 @@ public: virtual bool check_simple_select() const { return FALSE; } void abort_result_set(); virtual void cleanup(); - bool is_result_interceptor() { return false; } + select_result_interceptor *result_interceptor() { return NULL; } }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c9651e1038b..150d13f1360 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3004,12 +3004,10 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_PROFILE: case SQLCOM_SELECT: { -#ifdef WITH_WSREP if (lex->sql_command == SQLCOM_SELECT) - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ) + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ); else - WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW) -#endif /* WITH_WSREP */ + WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); thd->status_var.last_query_cost= 0.0; @@ -5959,8 +5957,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) Protocol *save_protocol= NULL; if (lex->analyze_stmt) { - if (result && result->is_result_interceptor()) - ((select_result_interceptor*)result)->disable_my_ok_calls(); + if (result && result->result_interceptor()) + result->result_interceptor()->disable_my_ok_calls(); else { DBUG_ASSERT(thd->protocol); diff --git a/sql/sql_priv.h b/sql/sql_priv.h index e30060c8d3e..f54c66e1d99 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -175,12 +175,6 @@ */ #define OPTION_MASTER_SQL_ERROR (1ULL << 35) -/* - Dont report errors for individual rows, - But just report error on commit (or read ofcourse) - Note! Reserved for use in MySQL Cluster -*/ -#define OPTION_ALLOW_BATCH (1ULL << 36) // THD, intern (slave) #define OPTION_SKIP_REPLICATION (1ULL << 37) // THD, user #define OPTION_RPL_SKIP_PARALLEL (1ULL << 38) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 46030f96043..e0a4fb4ea95 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1142,13 +1142,14 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, List *field_list, String *buffer) { bool error= TRUE; + LEX *lex= thd->lex; MEM_ROOT *mem_root= thd->mem_root; DBUG_ENTER("mysqld_show_create_get_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); /* We want to preserve the tree for views. */ - thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; { /* @@ -1163,14 +1164,14 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, bool open_error= open_tables(thd, &table_list, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL) || - mysql_handle_derived(thd->lex, DT_PREPARE); + mysql_handle_derived(lex, DT_PREPARE); thd->pop_internal_handler(); if (open_error && (thd->killed || thd->is_error())) goto exit; } /* TODO: add environment variables show when it become possible */ - if (thd->lex->only_view && !table_list->view) + if (lex->only_view && !table_list->view) { my_error(ER_WRONG_OBJECT, MYF(0), table_list->db, table_list->table_name, "VIEW"); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 9a9309a133b..df9fdab6635 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -891,15 +891,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, View definition query is stored in the client character set. */ - char view_query_buff[4096]; - String view_query(view_query_buff, - sizeof (view_query_buff), - thd->charset()); - - char is_query_buff[4096]; - String is_query(is_query_buff, - sizeof (is_query_buff), - system_charset_info); + StringBuffer<4096> view_query(thd->charset()); + StringBuffer<4096> is_query(system_charset_info); char md5[MD5_BUFF_LENGTH]; bool can_be_merged; -- cgit v1.2.1 From a62e9a83c04738009918ae63da41c9bea7ab941e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 10 Mar 2019 23:59:50 +0100 Subject: MDEV-15945 --ps-protocol does not test some queries Make mysqltest to use --ps-protocol more use prepared statements for everything that server supports with the exception of CALL (for now). Fix discovered test failures and bugs. tests: * PROCESSLIST shows Execute state, not Query * SHOW STATUS increments status variables more than in text protocol * multi-statements should be avoided (see tests with a wrong delimiter) * performance_schema events have different names in --ps-protocol * --enable_prepare_warnings mysqltest.cc: * make sure run_query_stmt() doesn't crash if there's no active connection (in wait_until_connected_again.inc) * prepare all statements that server supports protocol.h * Protocol_discard::send_result_set_metadata() should not send anything to the client. sql_acl.cc: * extract the functionality of getting the user for SHOW GRANTS from check_show_access(), so that mysql_test_show_grants() could generate the correct column names in the prepare step sql_class.cc: * result->prepare() can fail, don't ignore its return value * use correct number of decimals for EXPLAIN columns sql_parse.cc: * discard profiling for SHOW PROFILE. In text protocol it's done in prepare_schema_table(), but in --ps it is called on prepare only, so nothing was discarding profiling during execute. * move the permission checking code for SHOW CREATE VIEW to mysqld_show_create_get_fields(), so that it would be called during prepare step too. * only set sel_result when it was created here and needs to be destroyed in the same block. Avoid destroying lex->result. * use the correct number of tables in check_show_access(). Saying "as many as possible" doesn't work when first_not_own_table isn't set yet. sql_prepare.cc: * use correct user name for SHOW GRANTS columns * don't ignore verbose flag for SHOW SLAVE STATUS * support preparing REVOKE ALL and ROLLBACK TO SAVEPOINT * don't ignore errors from thd->prepare_explain_fields() * use select_send result for sending ANALYZE and EXPLAIN, but don't overwrite lex->result, because it might be needed to issue execute-time errors (select_dumpvar - too many rows) sql_show.cc: * check grants for SHOW CREATE VIEW here, not in mysql_execute_command sql_view.cc: * use the correct function to check privileges. Old code was doing check_access() for thd->security_ctx, which is invoker's sctx, not definer's sctx. Hide various view related errors from the invoker. sql_yacc.yy: * initialize lex->select_lex for LOAD, otherwise it'll contain garbage data that happen to fail tests with views in --ps (but not otherwise). --- sql/protocol.h | 7 +---- sql/sql_acl.cc | 92 +++++++++++++++++++++++++++++------------------------- sql/sql_acl.h | 2 ++ sql/sql_class.cc | 19 +++++------ sql/sql_class.h | 4 +-- sql/sql_parse.cc | 58 ++++++---------------------------- sql/sql_prepare.cc | 31 ++++++++++++------ sql/sql_show.cc | 42 +++++++++++++++++++++++++ sql/sql_view.cc | 9 +++--- sql/sql_yacc.yy | 1 + 10 files changed, 140 insertions(+), 125 deletions(-) (limited to 'sql') diff --git a/sql/protocol.h b/sql/protocol.h index 93b8fcbe8ef..2edad5663e8 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -230,13 +230,8 @@ class Protocol_discard : public Protocol_text { public: Protocol_discard(THD *thd_arg) : Protocol_text(thd_arg) {} - virtual bool send_result_set_metadata(List *list, uint flags) - { - // Don't pas Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF flags - return Protocol_text::send_result_set_metadata(list, 0); - } - bool write() { return 0; } + bool send_result_set_metadata(List *, uint) { return 0; } bool send_eof(uint, uint) { return 0; } void prepare_for_resend() { IF_DBUG(field_pos= 0,); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6052284428e..9110834b449 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7776,6 +7776,51 @@ void mysql_show_grants_get_fields(THD *thd, List *fields, fields->push_back(field, thd->mem_root); } +bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username, + const char **hostname, const char **rolename) +{ + if (lex_user->user.str == current_user.str) + { + *username= thd->security_ctx->priv_user; + *hostname= thd->security_ctx->priv_host; + return 0; + } + if (lex_user->user.str == current_role.str) + { + *rolename= thd->security_ctx->priv_role; + return 0; + } + if (lex_user->user.str == current_user_and_current_role.str) + { + *username= thd->security_ctx->priv_user; + *hostname= thd->security_ctx->priv_host; + *rolename= thd->security_ctx->priv_role; + return 0; + } + + Security_context *sctx= thd->security_ctx; + bool do_check_access; + + if (!(lex_user= get_current_user(thd, lex_user))) + return 1; + + if (lex_user->is_role()) + { + *rolename= lex_user->user.str; + do_check_access= strcmp(*rolename, sctx->priv_role); + } + else + { + *username= lex_user->user.str; + *hostname= lex_user->host.str; + do_check_access= strcmp(*username, sctx->priv_user) || + strcmp(*hostname, sctx->priv_host); + } + + if (do_check_access && check_access(thd, SELECT_ACL, "mysql", 0, 0, 1, 0)) + return 1; + return 0; +} /* SHOW GRANTS; Send grants for a user to the client @@ -7791,9 +7836,9 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) ACL_ROLE *acl_role= NULL; char buff[1024]; Protocol *protocol= thd->protocol; - char *username= NULL; - char *hostname= NULL; - char *rolename= NULL; + const char *username= NULL; + const char *hostname= NULL; + const char *rolename= NULL; DBUG_ENTER("mysql_show_grants"); if (!initialized) @@ -7802,46 +7847,9 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) DBUG_RETURN(TRUE); } - if (lex_user->user.str == current_user.str) - { - username= thd->security_ctx->priv_user; - hostname= thd->security_ctx->priv_host; - } - else if (lex_user->user.str == current_role.str) - { - rolename= thd->security_ctx->priv_role; - } - else if (lex_user->user.str == current_user_and_current_role.str) - { - username= thd->security_ctx->priv_user; - hostname= thd->security_ctx->priv_host; - rolename= thd->security_ctx->priv_role; - } - else - { - Security_context *sctx= thd->security_ctx; - bool do_check_access; - - lex_user= get_current_user(thd, lex_user); - if (!lex_user) - DBUG_RETURN(TRUE); - - if (lex_user->is_role()) - { - rolename= lex_user->user.str; - do_check_access= strcmp(rolename, sctx->priv_role); - } - else - { - username= lex_user->user.str; - hostname= lex_user->host.str; - do_check_access= strcmp(username, sctx->priv_user) || - strcmp(hostname, sctx->priv_host); - } + if (get_show_user(thd, lex_user, &username, &hostname, &rolename)) + DBUG_RETURN(TRUE); - if (do_check_access && check_access(thd, SELECT_ACL, "mysql", 0, 0, 1, 0)) - DBUG_RETURN(TRUE); - } DBUG_ASSERT(rolename || username); List field_list; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index c2ad9a649e5..fc3fcdc534a 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -241,6 +241,8 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table); ulong get_column_grant(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *field_name); +bool get_show_user(THD *thd, LEX_USER *lex_user, const char **username, + const char **hostname, const char **rolename); void mysql_show_grants_get_fields(THD *thd, List *fields, const char *name); bool mysql_show_grants(THD *thd, LEX_USER *user); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 628dcee0570..02e76520cb4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2405,17 +2405,15 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) } -void THD::prepare_explain_fields(select_result *result, - List *field_list, - uint8 explain_flags, - bool is_analyze) +int THD::prepare_explain_fields(select_result *result, List *field_list, + uint8 explain_flags, bool is_analyze) { if (lex->explain_json) make_explain_json_field_list(*field_list, is_analyze); else make_explain_field_list(*field_list, explain_flags, is_analyze); - result->prepare(*field_list, NULL); + return result->prepare(*field_list, NULL); } @@ -2425,11 +2423,10 @@ int THD::send_explain_fields(select_result *result, { List field_list; int rc; - prepare_explain_fields(result, &field_list, explain_flags, is_analyze); - rc= result->send_result_set_metadata(field_list, - Protocol::SEND_NUM_ROWS | - Protocol::SEND_EOF); - return(rc); + rc= prepare_explain_fields(result, &field_list, explain_flags, is_analyze) || + result->send_result_set_metadata(field_list, Protocol::SEND_NUM_ROWS | + Protocol::SEND_EOF); + return rc; } @@ -2504,7 +2501,7 @@ void THD::make_explain_field_list(List &field_list, uint8 explain_flags, if (is_analyze) { field_list.push_back(item= new (mem_root) - Item_float(this, "r_rows", 0.1234, 10, 4), + Item_float(this, "r_rows", 0.1234, 2, 4), mem_root); item->maybe_null=1; } diff --git a/sql/sql_class.h b/sql/sql_class.h index a52367be108..de52cec0f38 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3331,8 +3331,8 @@ public: void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); - void prepare_explain_fields(select_result *result, List *field_list, - uint8 explain_flags, bool is_analyze); + int prepare_explain_fields(select_result *result, List *field_list, + uint8 explain_flags, bool is_analyze); int send_explain_fields(select_result *result, uint8 explain_flags, bool is_analyze); void make_explain_field_list(List &field_list, uint8 explain_flags, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 150d13f1360..04ea7dad8bb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3007,7 +3007,11 @@ mysql_execute_command(THD *thd) if (lex->sql_command == SQLCOM_SELECT) WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ); else + { WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); + if (lex->sql_command == SQLCOM_SHOW_PROFILE) + thd->profiling.discard_current_query(); + } thd->status_var.last_query_cost= 0.0; @@ -3723,49 +3727,6 @@ end_with_restore_list: DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s", lex->only_view, first_table->db, first_table->table_name)); - if (lex->only_view) - { - if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE)) - { - DBUG_PRINT("debug", ("check_table_access failed")); - my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), - "SHOW", thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, first_table->alias); - goto error; - } - DBUG_PRINT("debug", ("check_table_access succeeded")); - - /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ - first_table->open_type= OT_BASE_ONLY; - - } - else - { - /* - Temporary tables should be opened for SHOW CREATE TABLE, but not - for SHOW CREATE VIEW. - */ - if (open_temporary_tables(thd, all_tables)) - goto error; - - /* - The fact that check_some_access() returned FALSE does not mean that - access is granted. We need to check if first_table->grant.privilege - contains any table-specific privilege. - */ - DBUG_PRINT("debug", ("first_table->grant.privilege: %lx", - first_table->grant.privilege)); - if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, first_table) || - (first_table->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0) - { - my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), - "SHOW", thd->security_ctx->priv_user, - thd->security_ctx->host_or_ip, first_table->alias); - goto error; - } - } - - /* Access is granted. Execute the command. */ res= mysqld_show_create(thd, first_table); break; #endif @@ -4116,7 +4077,7 @@ end_with_restore_list: case SQLCOM_DELETE: { WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); - select_result *sel_result=lex->result; + select_result *sel_result= NULL; DBUG_ASSERT(first_table == all_tables && first_table != 0); if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) @@ -4147,16 +4108,15 @@ end_with_restore_list: } else { - if (!(sel_result= lex->result) && - !(sel_result= new (thd->mem_root) select_send(thd))) - return 1; + if (!lex->result && !(sel_result= new (thd->mem_root) select_send(thd))) + goto error; } } res = mysql_delete(thd, all_tables, select_lex->where, &select_lex->order_list, unit->select_limit_cnt, select_lex->options, - sel_result); + lex->result ? lex->result : sel_result); if (replaced_protocol) { @@ -6517,7 +6477,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) Check_grant will grant access if there is any column privileges on all of the tables thanks to the fourth parameter (bool show_table). */ - if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE)) + if (check_grant(thd, SELECT_ACL, dst_table, TRUE, 1, FALSE)) return TRUE; /* Access denied */ close_thread_tables(thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 89b7e490cb9..9de2f7f34a5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1883,9 +1883,20 @@ static int mysql_test_show_grants(Prepared_statement *stmt) DBUG_ENTER("mysql_test_show_grants"); THD *thd= stmt->thd; List fields; + char buff[1024]; + const char *username= NULL, *hostname= NULL, *rolename= NULL; - mysql_show_grants_get_fields(thd, &fields, "Grants for"); - + if (get_show_user(thd, thd->lex->grant_user, &username, &hostname, &rolename)) + DBUG_RETURN(1); + + if (username) + strxmov(buff,"Grants for ",username,"@",hostname, NullS); + else if (rolename) + strxmov(buff,"Grants for ",rolename, NullS); + else + DBUG_RETURN(1); + + mysql_show_grants_get_fields(thd, &fields, buff); DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields)); } #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ @@ -1909,7 +1920,7 @@ static int mysql_test_show_slave_status(Prepared_statement *stmt) THD *thd= stmt->thd; List fields; - show_master_info_get_fields(thd, &fields, 0, 0); + show_master_info_get_fields(thd, &fields, thd->lex->verbose, 0); DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields)); } @@ -2424,6 +2435,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_CREATE_INDEX: case SQLCOM_DROP_INDEX: case SQLCOM_ROLLBACK: + case SQLCOM_ROLLBACK_TO_SAVEPOINT: case SQLCOM_TRUNCATE: case SQLCOM_DROP_VIEW: case SQLCOM_REPAIR: @@ -2452,6 +2464,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_GRANT: case SQLCOM_GRANT_ROLE: case SQLCOM_REVOKE: + case SQLCOM_REVOKE_ALL: case SQLCOM_REVOKE_ROLE: case SQLCOM_KILL: case SQLCOM_COMPOUND: @@ -2480,14 +2493,12 @@ static bool check_prepared_statement(Prepared_statement *stmt) { if (lex->describe || lex->analyze_stmt) { - if (!lex->result && - !(lex->result= new (stmt->mem_root) select_send(thd))) - DBUG_RETURN(TRUE); + select_send result(thd); List field_list; - thd->prepare_explain_fields(lex->result, &field_list, - lex->describe, lex->analyze_stmt); - res= send_prep_stmt(stmt, lex->result->field_count(field_list)) || - lex->result->send_result_set_metadata(field_list, + res= thd->prepare_explain_fields(&result, &field_list, + lex->describe, lex->analyze_stmt) || + send_prep_stmt(stmt, result.field_count(field_list)) || + result.send_result_set_metadata(field_list, Protocol::SEND_EOF); } else diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e0a4fb4ea95..e1c599102c6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1148,6 +1148,48 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list, DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); + if (lex->only_view) + { + if (check_table_access(thd, SELECT_ACL, table_list, FALSE, 1, FALSE)) + { + DBUG_PRINT("debug", ("check_table_access failed")); + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "SHOW", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, table_list->alias); + goto exit; + } + DBUG_PRINT("debug", ("check_table_access succeeded")); + + /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ + table_list->open_type= OT_BASE_ONLY; + } + else + { + /* + Temporary tables should be opened for SHOW CREATE TABLE, but not + for SHOW CREATE VIEW. + */ + if (open_temporary_tables(thd, table_list)) + goto exit; + + /* + The fact that check_some_access() returned FALSE does not mean that + access is granted. We need to check if table_list->grant.privilege + contains any table-specific privilege. + */ + DBUG_PRINT("debug", ("table_list->grant.privilege: %lx", + table_list->grant.privilege)); + if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, table_list) || + (table_list->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0) + { + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + "SHOW", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, table_list->alias); + goto exit; + } + } + /* Access is granted. Execute the command. */ + /* We want to preserve the tree for views. */ lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index df9fdab6635..8fa03f23ca1 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -330,12 +330,11 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, { if (!tbl->table_in_first_from_clause) { - if (check_access(thd, SELECT_ACL, tbl->db, - &tbl->grant.privilege, - &tbl->grant.m_internal, - 0, 0) || - check_grant(thd, SELECT_ACL, tbl, FALSE, 1, FALSE)) + if (check_single_table_access(thd, SELECT_ACL, tbl, FALSE)) + { + tbl->hide_view_error(thd); goto err; + } } } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f98a7b7e474..c3a34f23ac9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12994,6 +12994,7 @@ load: LOAD data_or_xml { LEX *lex= thd->lex; + mysql_init_select(lex); if (lex->sphead) { -- cgit v1.2.1 From a4e5888248811e625ad703ee4feb717f37b0e38a Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Mon, 11 Mar 2019 18:59:25 +0530 Subject: MDEV-18431: Select max + row_number giving incorrect result The issue here was when we had a subquery and a window function in an expression in the select list then subquery was getting computed after window function computation. This resulted in incorrect results because the subquery was correlated and the fields in the subquery was pointing to the base table instead of the temporary table. The approach to fix this was to have an additional field in the temporary table for the subquery and to execute the subquery before window function execution. After execution the values for the subquery were stored in the temporary table and then when we needed to calcuate the expression, all we do is read the values from the temporary table for the subquery. --- sql/item.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 46420fd2c78..6c9496c9393 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1996,7 +1996,6 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, } if (unlikely((!(used_tables() & ~PARAM_TABLE_BIT) || - type() == SUBSELECT_ITEM || (type() == REF_ITEM && ((Item_ref*)this)->ref_type() != Item_ref::VIEW_REF)))) return; -- cgit v1.2.1 From 90ce95de4b6f44735487c700f2b14d5ca1c4a315 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 12 Mar 2019 18:46:37 +0400 Subject: Tests for MDEV-18892 Regression in slow log and admin statements The patch for MDEV-15945 fixed MDEV-18892. Adding tests only. --- sql/sql_parse.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 04ea7dad8bb..099d3cd4bf1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2047,6 +2047,9 @@ void log_slow_statement(THD *thd) if (!thd->enable_slow_log) goto end; // E.g. SP statement + DBUG_EXECUTE_IF("simulate_slow_query", + thd->server_status|= SERVER_QUERY_WAS_SLOW;); + if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || ((thd->server_status & (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && -- cgit v1.2.1 From 20928e2e960454ff7f9dee0094a464b1a6fdb195 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 13 Mar 2019 06:02:08 +0400 Subject: MDEV-14984 - regression in connect performance Removed redundant plugin_thdvar_cleanup() from end_connection(): called by THD::free_connection(), which always follows end_connection(). Saves at least one lock(LOCK_plugin) and one rdlock(LOCK_system_variables_hash). Benchmarked on a 2socket/20core/40threads Broadwell system using sysbench connect brencmark @40 threads (with select 1 disabled). 10.2 shows moderate improvement: 136219.93 -> 137766.31 CPS. 10.3 is improvement is somewhat better: 93018.29 -> 101379.77 CPS. Also backported MyRocks memory leak fix from 10.4, which turned out to be unrelated. --- sql/sql_connect.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 278677b8b2d..d7b388e310f 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1122,7 +1122,6 @@ void end_connection(THD *thd) } thd->wsrep_client_thread= 0; #endif - plugin_thdvar_cleanup(thd); if (thd->user_connect) { -- cgit v1.2.1 From d0ebb155fe68924848b92cbc0e6f5e9958acdab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 12 Mar 2019 15:44:10 +0200 Subject: MDEV-18577: Indexes problem on import dump SQL Problem was that we skipped background persistent statistics calculation on applier nodes if thread is marked as high priority (a.k.a BF). However, on applier nodes all DDL which is replicate will be executed as high priority i.e BF. Fixed by allowing background persistent statistics calculation on applier nodes even when thread is marked as BF. This could lead BF lock waits but for queries on that node needs that statistics. --- sql/sql_plugin_services.ic | 3 ++- sql/wsrep_dummy.cc | 3 +++ sql/wsrep_thd.cc | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 7fb5524016a..3d6cf0a0723 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -181,7 +181,8 @@ static struct wsrep_service_st wsrep_handler = { wsrep_trx_is_aborting, wsrep_trx_order_before, wsrep_unlock_rollback, - wsrep_set_data_home_dir + wsrep_set_data_home_dir, + wsrep_thd_is_applier }; static struct thd_specifics_service_st thd_specifics_handler= diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 795e2d19252..7297dbfe0fd 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -141,3 +141,6 @@ void wsrep_unlock_rollback() void wsrep_set_data_home_dir(const char *) { } + +my_bool wsrep_thd_is_applier(MYSQL_THD thd) +{ return false; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index a3d1961ade2..dab9f91b381 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -698,3 +698,13 @@ void wsrep_thd_auto_increment_variables(THD* thd, *increment= thd->variables.auto_increment_increment; } } + +my_bool wsrep_thd_is_applier(MYSQL_THD thd) +{ + my_bool is_applier= false; + + if (thd && thd->wsrep_applier) + is_applier= true; + + return (is_applier); +} -- cgit v1.2.1 From 691c3069531c066b7a71ddb17e9adaed886344c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 13 Mar 2019 11:38:09 +0200 Subject: MDEV-14033: wsrep_on=off + binlog = mixed on MariaDB 10.2.9 If wsrep provider (i.e. galera library) is defined but wsrep_on=OFF we should not force row binlog row format. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 813f0988b74..917a993ee0a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -9494,7 +9494,7 @@ static int get_options(int *argc_ptr, char ***argv_ptr) else global_system_variables.option_bits&= ~OPTION_BIG_SELECTS; - if (!opt_bootstrap && WSREP_PROVIDER_EXISTS && + if (!opt_bootstrap && WSREP_PROVIDER_EXISTS && WSREP_ON && global_system_variables.binlog_format != BINLOG_FORMAT_ROW) { -- cgit v1.2.1 From d7a38eaf1a3b3138a77156a64fba7f90a5dc6257 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 13 Mar 2019 15:38:33 +0400 Subject: MDEV-18907 Slow log: RENAME TABLE is not "admin", while ALTER TABLE..RENAME is --- sql/sql_parse.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 099d3cd4bf1..b6591c4d8c3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -324,7 +324,8 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | + CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | CF_ADMIN_COMMAND; sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | -- cgit v1.2.1 From cb66cdc6f80a32b9ea363f8d59ccb665730a4464 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 14 Mar 2019 10:05:38 +0400 Subject: MDEV-14926 AddressSanitizer: heap-use-after-free in make_date_time on weird combination of functions --- sql/item_timefunc.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 83949f2502e..c10b6442ce8 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -455,7 +455,7 @@ err: Create a formated date/time value in a string. */ -static bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, +static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time, timestamp_type type, MY_LOCALE *locale, String *str) { char intbuff[15]; @@ -469,7 +469,7 @@ static bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, if (l_time->neg) str->append('-'); - end= (ptr= format->format.str) + format->format.length; + end= (ptr= format.str) + format.length; for (; ptr != end ; ptr++) { if (*ptr != '%' || ptr+1 == end) @@ -1949,6 +1949,7 @@ uint Item_func_date_format::format_length(const String *format) String *Item_func_date_format::val_str(String *str) { + StringBuffer<64> format_buffer; String *format; MYSQL_TIME l_time; uint size; @@ -1958,7 +1959,7 @@ String *Item_func_date_format::val_str(String *str) if (get_arg0_date(&l_time, is_time_flag)) return 0; - if (!(format = args[1]->val_str(str)) || !format->length()) + if (!(format= args[1]->val_str(&format_buffer)) || !format->length()) goto null_date; if (fixed_length) @@ -1969,18 +1970,13 @@ String *Item_func_date_format::val_str(String *str) if (size < MAX_DATE_STRING_REP_LENGTH) size= MAX_DATE_STRING_REP_LENGTH; - if (format == str) - str= &value; // Save result here + DBUG_ASSERT(format != str); if (str->alloc(size)) goto null_date; - DATE_TIME_FORMAT date_time_format; - date_time_format.format.str= (char*) format->ptr(); - date_time_format.format.length= format->length(); - /* Create the result string */ str->set_charset(collation.collation); - if (!make_date_time(&date_time_format, &l_time, + if (!make_date_time(format->lex_cstring(), &l_time, is_time_format ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATE, locale, str)) -- cgit v1.2.1 From ddfa722a03ab3649783f8798df02d94a8a8ef6e3 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 14 Mar 2019 14:40:33 +0400 Subject: MDEV-18626 ASAN stack-buffer-overflow in int10_to_str / make_date_time upon DATE_FORMAT --- sql/item_timefunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index c10b6442ce8..e8440803295 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -577,7 +577,7 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time, str->append_with_prefill(intbuff, length, 2, '0'); break; case 'j': - if (type == MYSQL_TIMESTAMP_TIME) + if (type == MYSQL_TIMESTAMP_TIME || !l_time->month || !l_time->year) return 1; length= (uint) (int10_to_str(calc_daynr(l_time->year,l_time->month, l_time->day) - -- cgit v1.2.1 From 3d2d060b626a94a19480db55feecc3020440b5c3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 12 Mar 2019 16:27:19 +0100 Subject: fix gcc 8 compiler warnings There were two newly enabled warnings: 1. cast for a function pointers. Affected sql_analyse.h, mi_write.c and ma_write.cc, mf_iocache-t.cc, mysqlbinlog.cc, encryption.cc, etc 2. memcpy/memset of nontrivial structures. Fixed as: * the warning disabled for InnoDB * TABLE, TABLE_SHARE, and TABLE_LIST got a new method reset() which does the bzero(), which is safe for these classes, but any other bzero() will still cause a warning * Table_scope_and_contents_source_st uses `TABLE_LIST *` (trivial) instead of `SQL_I_List` (not trivial) so it's safe to bzero now. * added casts in debug_sync.cc and sql_select.cc (for JOIN) * move assignment method for MDL_request instead of memcpy() * PARTIAL_INDEX_INTERSECT_INFO::init() instead of bzero() * remove constructor from READ_RECORD() to make it trivial * replace some memcpy() with c++ copy assignments --- sql/debug_sync.cc | 6 +++--- sql/encryption.cc | 15 +++++++++++---- sql/handler.h | 2 +- sql/mdl.h | 10 ++++++++++ sql/opt_range.cc | 16 ++++++++++++---- sql/partition_info.cc | 11 +++++------ sql/records.h | 2 -- sql/sql_acl.cc | 4 +++- sql/sql_alter.cc | 10 +++++----- sql/sql_analyse.cc | 4 ++-- sql/sql_analyse.h | 5 ++--- sql/sql_handler.cc | 7 ++----- sql/sql_insert.cc | 6 ++---- sql/sql_parse.cc | 5 ++--- sql/sql_select.cc | 12 ++++++------ sql/sql_select.h | 1 - sql/sql_show.cc | 2 +- sql/sql_trigger.cc | 4 ++-- sql/sql_view.cc | 5 +++-- sql/sql_yacc.yy | 4 ++-- sql/table.h | 15 ++++++++------- sql/tztime.cc | 11 +++-------- 22 files changed, 85 insertions(+), 72 deletions(-) (limited to 'sql') diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index f6291ca7acc..3dfbcdbcf81 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -584,7 +584,7 @@ static void debug_sync_remove_action(st_debug_sync_control *ds_control, memmove(save_action, action, sizeof(st_debug_sync_action)); /* Move actions down. */ - memmove(ds_control->ds_action + dsp_idx, + memmove((void*)(ds_control->ds_action + dsp_idx), ds_control->ds_action + dsp_idx + 1, (ds_control->ds_active - dsp_idx) * sizeof(st_debug_sync_action)); @@ -595,8 +595,8 @@ static void debug_sync_remove_action(st_debug_sync_control *ds_control, produced by the shift. Again do not use an assignment operator to avoid string allocation/copy. */ - memmove(ds_control->ds_action + ds_control->ds_active, save_action, - sizeof(st_debug_sync_action)); + memmove((void*)(ds_control->ds_action + ds_control->ds_active), + save_action, sizeof(st_debug_sync_action)); } DBUG_VOID_RETURN; diff --git a/sql/encryption.cc b/sql/encryption.cc index 52eab262570..e5b54633066 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -25,6 +25,10 @@ struct encryption_service_st encryption_handler; extern "C" { +uint no_get_key(uint, uint, uchar*, uint*) +{ + return ENCRYPTION_KEY_VERSION_INVALID; +} uint no_key(uint) { return ENCRYPTION_KEY_VERSION_INVALID; @@ -47,6 +51,11 @@ static unsigned int get_length(unsigned int slen, unsigned int key_id, return my_aes_get_size(MY_AES_CBC, slen); } +uint ctx_size(unsigned int, unsigned int) +{ + return MY_AES_CTX_SIZE; +} + } /* extern "C" */ int initialize_encryption_plugin(st_plugin_int *plugin) @@ -72,8 +81,7 @@ int initialize_encryption_plugin(st_plugin_int *plugin) if (handle->crypt_ctx_size) encryption_handler.encryption_ctx_size_func= handle->crypt_ctx_size; else - encryption_handler.encryption_ctx_size_func= - (uint (*)(unsigned int, unsigned int))my_aes_ctx_size; + encryption_handler.encryption_ctx_size_func= ctx_size; encryption_handler.encryption_ctx_init_func= handle->crypt_ctx_init ? handle->crypt_ctx_init : ctx_init; @@ -102,8 +110,7 @@ int finalize_encryption_plugin(st_plugin_int *plugin) if (used) { - encryption_handler.encryption_key_get_func= - (uint (*)(uint, uint, uchar*, uint*))no_key; + encryption_handler.encryption_key_get_func= no_get_key; encryption_handler.encryption_key_get_latest_version_func= no_key; encryption_handler.encryption_ctx_size_func= zero_size; } diff --git a/sql/handler.h b/sql/handler.h index 792cce281f6..af492e75da6 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1687,7 +1687,6 @@ struct Table_scope_and_contents_source_st uint options; /* OR of HA_CREATE_ options */ uint merge_insert_method; uint extra_size; /* length of extra data segment */ - SQL_I_List merge_list; handlerton *db_type; /** Row type of the table definition. @@ -1716,6 +1715,7 @@ struct Table_scope_and_contents_source_st TABLE_LIST *pos_in_locked_tables; MDL_ticket *mdl_ticket; bool table_was_deleted; + TABLE_LIST *merge_list; void init() { diff --git a/sql/mdl.h b/sql/mdl.h index 7961f1f24b2..15a1976876b 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -475,6 +475,16 @@ public: DBUG_ASSERT(ticket == NULL); type= type_arg; } + void move_from(MDL_request &from) + { + type= from.type; + duration= from.duration; + ticket= from.ticket; + next_in_list= from.next_in_list; + prev_in_list= from.prev_in_list; + key.mdl_key_init(&from.key); + from.ticket= NULL; // that's what "move" means + } /* This is to work around the ugliness of TABLE_LIST diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 46b10b559b2..2f76f918e34 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1340,8 +1340,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() - Use rowids from unique to run a disk-ordered sweep */ -QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, - TABLE *table) +QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, TABLE *table) :unique(NULL), pk_quick_select(NULL), thd(thd_param) { DBUG_ENTER("QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT"); @@ -5111,6 +5110,16 @@ typedef struct st_partial_index_intersect_info key_map filtered_scans; /* scans to be filtered by cpk conditions */ MY_BITMAP *intersect_fields; /* bitmap of fields used in intersection */ + + void init() + { + common_info= NULL; + intersect_fields= NULL; + records_sent_to_unique= records= length= in_memory= use_cpk_filter= 0; + cost= index_read_cost= in_memory_cost= 0.0; + filtered_scans.init(); + filtered_scans.clear_all(); + } } PARTIAL_INDEX_INTERSECT_INFO; @@ -5247,8 +5256,7 @@ bool prepare_search_best_index_intersect(PARAM *param, if (!n_index_scans) return 1; - bzero(init, sizeof(*init)); - init->filtered_scans.init(); + init->init(); init->common_info= common; init->cost= cutoff_cost; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index c633ea708d0..892b7e8bd05 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -47,7 +47,7 @@ partition_info *partition_info::get_clone(THD *thd) mem_alloc_error(sizeof(partition_info)); DBUG_RETURN(NULL); } - memcpy(clone, this, sizeof(partition_info)); + *clone= *this; memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions)); memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions)); clone->bitmaps_are_initialized= FALSE; @@ -63,7 +63,7 @@ partition_info *partition_info::get_clone(THD *thd) mem_alloc_error(sizeof(partition_element)); DBUG_RETURN(NULL); } - memcpy(part_clone, part, sizeof(partition_element)); + *part_clone= *part; part_clone->subpartitions.empty(); while ((subpart= (subpart_it++))) { @@ -73,7 +73,7 @@ partition_info *partition_info::get_clone(THD *thd) mem_alloc_error(sizeof(partition_element)); DBUG_RETURN(NULL); } - memcpy(subpart_clone, subpart, sizeof(partition_element)); + *subpart_clone= *subpart; part_clone->subpartitions.push_back(subpart_clone, mem_root); } clone->partitions.push_back(part_clone, mem_root); @@ -1897,12 +1897,11 @@ void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag) TABLE_LIST table_list; THD *thd= current_thd; - bzero(&table_list, sizeof(table_list)); + table_list.reset(); table_list.db= table_arg->s->db.str; table_list.table_name= table_arg->s->table_name.str; - if (check_single_table_access(thd, - SELECT_ACL, &table_list, TRUE)) + if (check_single_table_access(thd, SELECT_ACL, &table_list, TRUE)) { my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE, ER_THD(thd, ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), errflag); diff --git a/sql/records.h b/sql/records.h index a3f0b5eb084..b55fbc22f55 100644 --- a/sql/records.h +++ b/sql/records.h @@ -69,8 +69,6 @@ struct READ_RECORD */ Copy_field *copy_field; Copy_field *copy_field_end; -public: - READ_RECORD() {} }; bool init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9110834b449..ff18c1d4c10 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8538,11 +8538,13 @@ static int open_grant_tables(THD *thd, TABLE_LIST *tables, } int prev= -1; - bzero(tables, sizeof(TABLE_LIST) * TABLES_MAX); for (int cur=TABLES_MAX-1, mask= 1 << cur; mask; cur--, mask >>= 1) { if ((tables_to_open & mask) == 0) + { + tables[cur].table= NULL; continue; + } tables[cur].init_one_table(C_STRING_WITH_LEN("mysql"), acl_table_names[cur].str, acl_table_names[cur].length, diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 243cf4c790f..ddac271146e 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -233,7 +233,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) DBUG_RETURN(TRUE); /* purecov: inspected */ /* If it is a merge table, check privileges for merge children. */ - if (create_info.merge_list.first) + if (create_info.merge_list) { /* The user must have (SELECT_ACL | UPDATE_ACL | DELETE_ACL) on the @@ -271,7 +271,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) */ if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - create_info.merge_list.first, FALSE, UINT_MAX, FALSE)) + create_info.merge_list, FALSE, UINT_MAX, FALSE)) DBUG_RETURN(TRUE); } @@ -282,9 +282,9 @@ bool Sql_cmd_alter_table::execute(THD *thd) { // Rename of table TABLE_LIST tmp_table; - memset(&tmp_table, 0, sizeof(tmp_table)); - tmp_table.table_name= lex->name.str; - tmp_table.db= select_lex->db; + tmp_table.init_one_table(select_lex->db, strlen(select_lex->db), + lex->name.str, lex->name.length, + lex->name.str, TL_IGNORE); tmp_table.grant.privilege= priv; if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE, UINT_MAX, FALSE)) diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 1f801a33dcd..45f4f87f172 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -298,9 +298,9 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num) } // get_ev_num_info -void free_string(String *s) +void free_string(void* str, TREE_FREE, void*) { - s->free(); + ((String*)str)->free(); } diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 820877f2a69..738737f0edc 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -68,7 +68,7 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)), int compare_decimal2(int* len, const char *s, const char *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); -void free_string(String*); +void free_string(void* str, TREE_FREE, void*); class analyse; class field_info :public Sql_alloc @@ -121,8 +121,7 @@ public: must_be_blob(0), was_zero_fill(0), was_maybe_zerofill(0), can_be_still_num(1) { init_tree(&tree, 0, 0, sizeof(String), (qsort_cmp2) sortcmp2, - (tree_element_free) free_string, NULL, - MYF(MY_THREAD_SPECIFIC)); }; + free_string, NULL, MYF(MY_THREAD_SPECIFIC)); }; void add(); void get_opt_type(String*, ha_rows); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 5a022ba72cf..bc6119b9a9c 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -359,8 +359,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) sql_handler->reset(); } sql_handler->table= table; - memcpy(&sql_handler->mdl_request, &tables->mdl_request, - sizeof(tables->mdl_request)); if (!(sql_handler->lock= get_lock_data(thd, &sql_handler->table, 1, GET_LOCK_STORE_LOCKS))) @@ -374,6 +372,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) if (error) goto err; + sql_handler->mdl_request.move_from(tables->mdl_request); + /* Always read all columns */ table->read_set= &table->s->all_set; if (table->vcol_set) @@ -403,9 +403,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen) */ table->open_by_handler= 1; - /* Safety, cleanup the pointer to satisfy MDL assertions. */ - tables->mdl_request.ticket= NULL; - if (! reopen) my_ok(thd); DBUG_PRINT("exit",("OK")); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 6455818993d..1745c6b4aaa 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4319,14 +4319,12 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) DBUG_ASSERT(thd->is_current_stmt_binlog_format_row()); DBUG_ASSERT(tables && *tables && count > 0); - char buf[2048]; - String query(buf, sizeof(buf), system_charset_info); + StringBuffer<2048> query(system_charset_info); int result; TABLE_LIST tmp_table_list; - memset(&tmp_table_list, 0, sizeof(tmp_table_list)); + tmp_table_list.reset(); tmp_table_list.table = *tables; - query.length(0); // Have to zero it since constructor doesn't result= show_create_table(thd, &tmp_table_list, &query, create_info, WITH_DB_NAME); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b6591c4d8c3..6b289a9fee9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8948,7 +8948,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, goto err; /* If it is a merge table, check privileges for merge children. */ - if (lex->create_info.merge_list.first) + if (lex->create_info.merge_list) { /* The user must have (SELECT_ACL | UPDATE_ACL | DELETE_ACL) on the @@ -8986,8 +8986,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, */ if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - lex->create_info.merge_list.first, - FALSE, UINT_MAX, FALSE)) + lex->create_info.merge_list, FALSE, UINT_MAX, FALSE)) goto err; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 155e261ac34..280de2b2ef1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2329,7 +2329,7 @@ void JOIN::restore_tmp() { DBUG_PRINT("info", ("restore_tmp this %p tmp_join %p", this, tmp_join)); DBUG_ASSERT(tmp_join != this); - memcpy(tmp_join, this, (size_t) sizeof(JOIN)); + memcpy((void*)tmp_join, this, (size_t) sizeof(JOIN)); } @@ -3610,7 +3610,7 @@ make_join_statistics(JOIN *join, List &tables_list, DBUG_RETURN(1); /* The following should be optimized to only clear critical things */ - bzero(stat, sizeof(JOIN_TAB)* table_count); + bzero((void*)stat, sizeof(JOIN_TAB)* table_count); /* Initialize POSITION objects */ for (i=0 ; i <= table_count ; i++) (void) new ((char*) (join->positions + i)) POSITION; @@ -8758,7 +8758,7 @@ get_best_combination(JOIN *join) 1. Put into main join order a JOIN_TAB that represents a lookup or scan in the temptable. */ - bzero(j, sizeof(JOIN_TAB)); + bzero((void*)j, sizeof(JOIN_TAB)); j->join= join; j->table= NULL; //temporary way to tell SJM tables from others. j->ref.key = -1; @@ -9360,7 +9360,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) row_limit= unit->select_limit_cnt; do_send_rows= row_limit ? 1 : 0; - bzero(join_tab, sizeof(JOIN_TAB)); + bzero((void*)join_tab, sizeof(JOIN_TAB)); join_tab->table=temp_table; join_tab->set_select_cond(NULL, __LINE__); join_tab->type= JT_ALL; /* Map through all records */ @@ -17275,11 +17275,11 @@ TABLE *create_virtual_tmp_table(THD *thd, List &field_list) NullS)) return 0; - bzero(table, sizeof(*table)); - bzero(share, sizeof(*share)); + table->reset(); table->field= field; table->s= share; table->temp_pool_slot= MY_BIT_NONE; + share->reset(); share->blob_field= blob_field; share->fields= field_count; setup_tmp_table_column_bitmaps(table, bitmaps); diff --git a/sql/sql_select.h b/sql/sql_select.h index 8c55528e120..266fe7a7066 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -199,7 +199,6 @@ class SJ_TMP_TABLE; class JOIN_TAB_RANGE; typedef struct st_join_table { - st_join_table() {} /* Remove gcc warning */ TABLE *table; KEYUSE *keyuse; /**< pointer to first used key */ KEY *hj_key; /**< descriptor of the used best hash join key diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e1c599102c6..73f0f564c4c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6266,7 +6266,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, { TABLE_LIST table_list; uint view_access; - memset(&table_list, 0, sizeof(table_list)); + table_list.reset(); table_list.db= tables->db; table_list.table_name= tables->table_name; table_list.grant.privilege= thd->col_access; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 14e1e84739b..f6dd48131bf 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1818,7 +1818,7 @@ bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name) bool result= 0; DBUG_ENTER("drop_all_triggers"); - bzero(&table, sizeof(table)); + table.reset(); init_sql_alloc(&table.mem_root, 8192, 0, MYF(0)); if (Table_triggers_list::check_n_load(thd, db, name, &table, 1)) @@ -2038,7 +2038,7 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db, LEX_STRING *err_trigname; DBUG_ENTER("change_table_name"); - bzero(&table, sizeof(table)); + table.reset(); init_sql_alloc(&table.mem_root, 8192, 0, MYF(0)); /* diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8fa03f23ca1..4d7c3de9337 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -214,7 +214,8 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) LEX *lex= thd->lex; TABLE_LIST decoy; - memcpy (&decoy, view, sizeof (TABLE_LIST)); + decoy= *view; + decoy.mdl_request.key.mdl_key_init(&view->mdl_request.key); if (tdc_open_view(thd, &decoy, decoy.alias, OPEN_VIEW_NO_PARSE)) return TRUE; @@ -2133,7 +2134,7 @@ mysql_rename_view(THD *thd, view definition parsing or use temporary 'view_def' object for it. */ - bzero(&view_def, sizeof(view_def)); + view_def.reset(); view_def.timestamp.str= view_def.timestamp_buffer; view_def.view_suid= TRUE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c3a34f23ac9..5111f0690ab 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5671,7 +5671,7 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; + lex->create_info.merge_list= lex->select_lex.table_list.first; lex->select_lex.table_list= lex->save_list; /* When excluding union list from the global list we assume that @@ -5680,7 +5680,7 @@ create_table_option: */ TABLE_LIST *last_non_sel_table= lex->create_last_non_select_table; DBUG_ASSERT(last_non_sel_table->next_global == - lex->create_info.merge_list.first); + lex->create_info.merge_list); last_non_sel_table->next_global= 0; Lex->query_tables_last= &last_non_sel_table->next_global; diff --git a/sql/table.h b/sql/table.h index de10a966d1b..afe3220c943 100644 --- a/sql/table.h +++ b/sql/table.h @@ -789,6 +789,8 @@ struct TABLE_SHARE /** Instrumentation for this table share. */ PSI_table_share *m_psi; + inline void reset() { bzero((void*)this, sizeof(*this)); } + /* Set share's table cache key and update its db and table name appropriately. @@ -1337,6 +1339,7 @@ public: bool histograms_are_read; MDL_ticket *mdl_ticket; + inline void reset() { bzero((void*)this, sizeof(*this)); } void init(THD *thd, TABLE_LIST *tl); bool fill_item_list(List *item_list) const; void reset_item_list(List *item_list) const; @@ -1763,6 +1766,7 @@ struct TABLE_LIST Prepare TABLE_LIST that consists of one table instance to use in open_and_lock_tables */ + inline void reset() { bzero((void*)this, sizeof(*this)); } inline void init_one_table(const char *db_name_arg, size_t db_length_arg, const char *table_name_arg, @@ -1778,7 +1782,7 @@ struct TABLE_LIST else mdl_type= MDL_SHARED_READ; - bzero((char*) this, sizeof(*this)); + reset(); db= (char*) db_name_arg; db_length= db_length_arg; table_name= (char*) table_name_arg; @@ -2272,8 +2276,7 @@ struct TABLE_LIST @sa check_and_update_table_version() */ - inline - bool is_table_ref_id_equal(TABLE_SHARE *s) const + inline bool is_table_ref_id_equal(TABLE_SHARE *s) const { return (m_table_ref_type == s->get_table_ref_type() && m_table_ref_version == s->get_table_ref_version()); @@ -2285,12 +2288,10 @@ struct TABLE_LIST @sa check_and_update_table_version() */ - inline - void set_table_ref_id(TABLE_SHARE *s) + inline void set_table_ref_id(TABLE_SHARE *s) { set_table_ref_id(s->get_table_ref_type(), s->get_table_ref_version()); } - inline - void set_table_ref_id(enum_table_ref_type table_ref_type_arg, + inline void set_table_ref_id(enum_table_ref_type table_ref_type_arg, ulong table_ref_version_arg) { m_table_ref_type= table_ref_type_arg; diff --git a/sql/tztime.cc b/sql/tztime.cc index 279d5990460..60a3ceafe0a 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1537,16 +1537,11 @@ my_offset_tzs_get_key(Time_zone_offset *entry, static void tz_init_table_list(TABLE_LIST *tz_tabs) { - bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT); - for (int i= 0; i < MY_TZ_TABLES_COUNT; i++) { - tz_tabs[i].alias= tz_tabs[i].table_name= tz_tables_names[i].str; - tz_tabs[i].table_name_length= tz_tables_names[i].length; - tz_tabs[i].db= tz_tables_db_name.str; - tz_tabs[i].db_length= tz_tables_db_name.length; - tz_tabs[i].lock_type= TL_READ; - + tz_tabs[i].init_one_table(tz_tables_db_name.str, tz_tables_db_name.length, + tz_tables_names[i].str, tz_tables_names[i].length, + NULL, TL_READ); if (i != MY_TZ_TABLES_COUNT - 1) tz_tabs[i].next_global= tz_tabs[i].next_local= &tz_tabs[i+1]; if (i != 0) -- cgit v1.2.1 From 78c2499282aa16b96441e293a957483bf14cfca0 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 15 Mar 2019 11:36:41 +0400 Subject: MDEV-16958 Assertion `field_length < 5' failed in Field_year::val_str or data corruption upon SELECT with UNION and aggregate functions --- sql/item.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index d8f27bdb30e..3bfbdb75c40 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9476,7 +9476,10 @@ bool Item_type_holder::join_types(THD *thd, Item *item) break; } default: - max_length= MY_MAX(max_length, display_length(item)); + if (fld_type == MYSQL_TYPE_YEAR) + max_length= MY_MAX(max_length, item->max_length); + else + max_length= MY_MAX(max_length, display_length(item)); }; maybe_null|= item->maybe_null; get_full_info(item); -- cgit v1.2.1 From f1134d567695990dc7d62b6c25e4b9aa8de439e0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 Mar 2019 15:03:26 +0100 Subject: post-merge: gcc 8 warnings note: Inherit String from Sql_alloc, to get operators new and new[] in sync in rocksdb gcc was complaining that non-lvalue was cast to const. --- sql/item_jsonfunc.cc | 4 ++-- sql/opt_range.cc | 1 - sql/sql_acl.cc | 4 ++-- sql/sql_select.cc | 8 ++++---- sql/sql_select.h | 4 ++-- sql/sql_string.h | 13 ++----------- 6 files changed, 12 insertions(+), 22 deletions(-) (limited to 'sql') diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 78eb58506ff..e236010c459 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -680,11 +680,11 @@ static int alloc_tmp_paths(THD *thd, uint n_paths, *paths= (json_path_with_flags *) alloc_root(root, sizeof(json_path_with_flags) * n_paths); - *tmp_paths= (String *) alloc_root(root, sizeof(String) * n_paths); + + *tmp_paths= new (root) String[n_paths]; if (*paths == 0 || *tmp_paths == 0) return 1; - bzero(*tmp_paths, sizeof(String) * n_paths); for (uint c_path=0; c_path < n_paths; c_path++) (*tmp_paths)[c_path].set_charset(&my_charset_utf8_general_ci); } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index da5e9707595..d7bbdeb82a4 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1348,7 +1348,6 @@ QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT(THD *thd_param, TABLE *table) DBUG_ENTER("QUICK_INDEX_SORT_SELECT::QUICK_INDEX_SORT_SELECT"); index= MAX_KEY; head= table; - bzero(&read_record, sizeof(read_record)); init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0, MYF(MY_THREAD_SPECIFIC)); DBUG_VOID_RETURN; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1d1cca0568e..ae6030115fa 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -772,7 +772,7 @@ enum enum_acl_tables ROLES_MAPPING_TABLE, TABLES_MAX // <== always the last }; -// bits for open_grant_tables + static const int Table_user= 1 << USER_TABLE; static const int Table_db= 1 << DB_TABLE; static const int Table_tables_priv= 1 << TABLES_PRIV_TABLE; @@ -853,7 +853,7 @@ class Grant_table_base Grant_table_base() : start_privilege_column(0), num_privilege_cols(0) { - bzero(&tl, sizeof(tl)); + tl.reset(); }; /* Initialization sequence common for all grant tables. This should be called diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 69aa8a97a87..1dfd6520e17 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2447,7 +2447,7 @@ bool JOIN::make_aggr_tables_info() aggr_tables++; curr_tab= join_tab + exec_join_tab_cnt(); - bzero(curr_tab, sizeof(JOIN_TAB)); + bzero((void*)curr_tab, sizeof(JOIN_TAB)); curr_tab->ref.key= -1; curr_tab->join= this; @@ -2535,7 +2535,7 @@ bool JOIN::make_aggr_tables_info() { aggr_tables++; curr_tab= join_tab + exec_join_tab_cnt(); - bzero(curr_tab, sizeof(JOIN_TAB)); + bzero((void*)curr_tab, sizeof(JOIN_TAB)); curr_tab->ref.key= -1; if (only_const_tables()) first_select= sub_select_postjoin_aggr; @@ -2663,7 +2663,7 @@ bool JOIN::make_aggr_tables_info() curr_tab++; aggr_tables++; - bzero(curr_tab, sizeof(JOIN_TAB)); + bzero((void*)curr_tab, sizeof(JOIN_TAB)); curr_tab->ref.key= -1; /* group data to new table */ @@ -17448,7 +17448,7 @@ bool Virtual_tmp_table::init(uint field_count) &bitmaps, bitmap_buffer_size(field_count) * 6, NullS)) return true; - bzero(s, sizeof(*s)); + s->reset(); s->blob_field= blob_field; setup_tmp_table_column_bitmaps(this, bitmaps, field_count); m_alloced_field_count= field_count; diff --git a/sql/sql_select.h b/sql/sql_select.h index 09e8f5a3e10..5eea5937ea6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2046,9 +2046,9 @@ public: static void *operator new(size_t size, THD *thd) throw(); static void operator delete(void *ptr, size_t size) {TRASH_FREE(ptr, size);} - Virtual_tmp_table(THD *thd) + Virtual_tmp_table(THD *thd) : m_alloced_field_count(0) { - bzero(this, sizeof(*this)); + reset(); temp_pool_slot= MY_BIT_NONE; in_use= thd; } diff --git a/sql/sql_string.h b/sql/sql_string.h index ea810f15f80..0065b1424ce 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -27,6 +27,7 @@ #include "m_ctype.h" /* my_charset_bin */ #include "my_sys.h" /* alloc_root, my_free, my_realloc */ #include "m_string.h" /* TRASH */ +#include "sql_list.h" class String; typedef struct st_io_cache IO_CACHE; @@ -129,7 +130,7 @@ uint convert_to_printable(char *to, size_t to_len, const char *from, size_t from_len, CHARSET_INFO *from_cs, size_t nbytes= 0); -class String +class String : public Sql_alloc { char *Ptr; uint32 str_length,Alloced_length, extra_alloc; @@ -179,16 +180,6 @@ public: alloced= thread_specific= 0; str_charset=str.str_charset; } - static void *operator new(size_t size, MEM_ROOT *mem_root) throw () - { return (void*) alloc_root(mem_root, (uint) size); } - static void operator delete(void *ptr_arg, size_t size) - { - (void) ptr_arg; - (void) size; - TRASH_FREE(ptr_arg, size); - } - static void operator delete(void *, MEM_ROOT *) - { /* never called */ } ~String() { free(); } /* Mark variable thread specific it it's not allocated already */ -- cgit v1.2.1 From 1f020299f816263e347c852eb2a494b5ef1cbf0d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 Mar 2019 15:06:17 +0100 Subject: post-merge: --ps-protocol fixes Includes: MDEV-17302 Add support for ALTER USER command in prepared statement and MDEV-17673 main.cte_recursive fails in bb-10.4-ps branch in --ps Set correct SELECT_LEX linkage for recursive CTEs. Do not delegate this job to TABLE_LIST::set_as_with_table, because it is only run on prepare, while With_element::move_anchors_ahead is run both on prepare and execute (fix by Igor) --- sql/sql_cte.cc | 1 + sql/sql_parse.cc | 7 +++++-- sql/sql_prepare.cc | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 5d4c2b20872..bcba4d03492 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -689,6 +689,7 @@ void With_element::move_anchors_ahead() } } first_recursive= new_pos; + spec->first_select()->linkage= DERIVED_TABLE_TYPE; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d2dde1277a1..a0107347fde 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2479,8 +2479,11 @@ void log_slow_statement(THD *thd) if (!thd->enable_slow_log) goto end; // E.g. SP statement - DBUG_EXECUTE_IF("simulate_slow_query", - thd->server_status|= SERVER_QUERY_WAS_SLOW;); + DBUG_EXECUTE_IF("simulate_slow_query", { + if (thd->get_command() == COM_QUERY || + thd->get_command() == COM_STMT_EXECUTE) + thd->server_status|= SERVER_QUERY_WAS_SLOW; + }); if (((thd->server_status & SERVER_QUERY_WAS_SLOW) || ((thd->server_status & diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index f99dc237cd0..fa9fc6fb9f8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2530,6 +2530,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_ALTER_DB_UPGRADE: case SQLCOM_CHECKSUM: case SQLCOM_CREATE_USER: + case SQLCOM_ALTER_USER: case SQLCOM_RENAME_USER: case SQLCOM_DROP_USER: case SQLCOM_CREATE_ROLE: -- cgit v1.2.1 From 5e044f78c0a9a8cd40dedff0e4bc857c0bd76b95 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Sat, 16 Mar 2019 15:08:17 -0700 Subject: MDEV-18945 Assertion `fixed == 1' failed in Item_cond_and::val_int In the function make_cond_for_table_from_pred a call of ix_fields() missed checking of the return code. As a result an extracted constant condition could be not well formed and this caused an assertion failure. --- sql/sql_select.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1dfd6520e17..6253c39b777 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20614,7 +20614,8 @@ make_cond_for_table_from_pred(THD *thd, Item *root_cond, Item *cond, the new parent Item. This should not be expensive because all children of Item_cond_and should be fixed by now. */ - new_cond->fix_fields(thd, 0); + if (new_cond->fix_fields(thd, 0)) + return (COND*) 0; new_cond->used_tables_cache= ((Item_cond_and*) cond)->used_tables_cache & tables; -- cgit v1.2.1 From f38c3521725ff9847819eb92af46cbb302650770 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 16 Mar 2019 16:03:54 +0100 Subject: post-merge: gcc 8 warnings --- sql/datadict.cc | 2 +- sql/ha_partition.cc | 2 +- sql/handler.cc | 1 - sql/mysqld.h | 3 --- sql/sql_partition_admin.cc | 4 ++-- sql/sql_show.cc | 2 +- 6 files changed, 5 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/datadict.cc b/sql/datadict.cc index 410dbff8778..231e7ea22ca 100644 --- a/sql/datadict.cc +++ b/sql/datadict.cc @@ -196,7 +196,7 @@ bool dd_recreate_table(THD *thd, const char *db, const char *table_name, char path_buf[FN_REFLEN + 1]; DBUG_ENTER("dd_recreate_table"); - memset(&create_info, 0, sizeof(create_info)); + create_info.init(); if (path) create_info.options|= HA_LEX_CREATE_TMP_TABLE; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 051a0e15af9..98a3259a39b 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2194,7 +2194,7 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info) uint num_parts= (num_subparts ? m_file_tot_parts / num_subparts : m_file_tot_parts); HA_CREATE_INFO dummy_info; - memset(&dummy_info, 0, sizeof(dummy_info)); + dummy_info.init(); /* Since update_create_info() can be called from mysql_prepare_alter_table() diff --git a/sql/handler.cc b/sql/handler.cc index 53c58e64782..e01392d236c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6976,7 +6976,6 @@ static Create_field *vers_init_sys_field(THD *thd, const char *field_name, int f if (!f) return NULL; - memset(f, 0, sizeof(*f)); f->field_name.str= field_name; f->field_name.length= strlen(field_name); f->charset= system_charset_info; diff --git a/sql/mysqld.h b/sql/mysqld.h index d5cabd790b2..9cb0a0fda39 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -196,9 +196,6 @@ struct vers_asof_timestamp_t { ulong type; MYSQL_TIME ltime; - vers_asof_timestamp_t() : - type(SYSTEM_TIME_UNSPECIFIED) - {} }; enum vers_alter_history_enum diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index cba4949ccd3..a530f2886b4 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -192,8 +192,8 @@ static bool compare_table_with_partition(THD *thd, TABLE *table, DBUG_ENTER("compare_table_with_partition"); bool metadata_equal= false; - memset(&part_create_info, 0, sizeof(HA_CREATE_INFO)); - memset(&table_create_info, 0, sizeof(HA_CREATE_INFO)); + part_create_info.init(); + table_create_info.init(); update_create_info_from_table(&table_create_info, table); /* get the current auto_increment value */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0003d546ed3..e5dbfeed149 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5518,7 +5518,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (file) { HA_CREATE_INFO create_info; - memset(&create_info, 0, sizeof(create_info)); + create_info.init(); file->update_create_info(&create_info); append_directory(thd, &str, "DATA", create_info.data_file_name); append_directory(thd, &str, "INDEX", create_info.index_file_name); -- cgit v1.2.1 From 4f410473ed3609636c5912a3578034cd326ad125 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 17 Mar 2019 00:14:14 +0100 Subject: post-merge: --ps-protocol fixes --- sql/sql_tvc.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index a5085fdfc58..a05673f2a6c 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -230,30 +230,30 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl, if (fix_fields_for_tvc(thd, li)) DBUG_RETURN(true); - if (!(holders= new (thd->mem_root) - Type_holder[cnt]) || - join_type_handlers_for_tvc(thd, li, holders, - cnt) || + if (!(holders= new (thd->stmt_arena->mem_root) Type_holder[cnt]) || + join_type_handlers_for_tvc(thd, li, holders, cnt) || get_type_attributes_for_tvc(thd, li, holders, lists_of_values.elements, cnt)) DBUG_RETURN(true); List_iterator_fast it(*first_elem); Item *item; + Query_arena *arena, backup; + arena=thd->activate_stmt_arena_if_needed(&backup); sl->item_list.empty(); for (uint pos= 0; (item= it++); pos++) { /* Error's in 'new' will be detected after loop */ Item_type_holder *new_holder= new (thd->mem_root) - Item_type_holder(thd, - item, - holders[pos].type_handler(), + Item_type_holder(thd, item, holders[pos].type_handler(), &holders[pos]/*Type_all_attributes*/, holders[pos].get_maybe_null()); new_holder->fix_fields(thd, 0); sl->item_list.push_back(new_holder); } + if (arena) + thd->restore_active_arena(arena, &backup); if (unlikely(thd->is_fatal_error)) DBUG_RETURN(true); // out of memory -- cgit v1.2.1 From 26432e49d37a37d09b862bb49a021e44bdf4789c Mon Sep 17 00:00:00 2001 From: sysprg Date: Mon, 18 Mar 2019 06:39:51 +0100 Subject: MDEV-17262: mysql crashed on galera while node rejoined cluster (#895) This patch contains a fix for the MDEV-17262/17243 issues and new mtr test. These issues (MDEV-17262/17243) have two reasons: 1) After an intermediate commit, a transaction loses its status of "transaction that registered in the MySQL for 2pc coordinator" (in the InnoDB) due to the fact that since version 10.2 the write_row() function (which located in the ha_innodb.cc) does not call trx_register_for_2pc(m_prebuilt->trx) during the processing of split transactions. It is necessary to restore this call inside the write_row() when an intermediate commit was made (for a split transaction). Similarly, we need to set the flag of the started transaction (m_prebuilt->sql_stat_start) after intermediate commit. The table->file->extra(HA_EXTRA_FAKE_START_STMT) called from the wsrep_load_data_split() function (which located in sql_load.cc) will also do this, but it will be too late. As a result, the call to the wsrep_append_keys() function from the InnoDB engine may be lost or function may be called with invalid transaction identifier. 2) If a transaction with the LOAD DATA statement is divided into logical mini-transactions (of the 10K rows) and binlog is rotated, then in rare cases due to the wsrep handler re-registration at the boundary of the split, the last portion of data may be lost. Since splitting of the LOAD DATA into mini-transactions is technical, I believe that we should not allow these mini-transactions to fall into separate binlogs. Therefore, it is necessary to prohibit the rotation of binlog in the middle of processing LOAD DATA statement. https://jira.mariadb.org/browse/MDEV-17262 and https://jira.mariadb.org/browse/MDEV-17243 --- sql/log.cc | 51 ++++++++++++++++++++++++++++++++++++++++++ sql/sql_class.cc | 2 ++ sql/sql_class.h | 8 +++++++ sql/sql_load.cc | 55 +++++++++++++++++++++++++++++----------------- sql/sql_plugin_services.ic | 2 ++ sql/wsrep_dummy.cc | 6 +++++ sql/wsrep_hton.cc | 1 + sql/wsrep_thd.cc | 10 +++++++++ 8 files changed, 115 insertions(+), 20 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 4d62c9783cd..df928e89390 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -6413,8 +6413,25 @@ err: update_binlog_end_pos(offset); signal_update(); + /* + If a transaction with the LOAD DATA statement is divided + into logical mini-transactions (of the 10K rows) and binlog + is rotated, then the last portion of data may be lost due to + wsrep handler re-registration at the boundary of the split. + Since splitting of the LOAD DATA into mini-transactions is + logical, we should not allow these mini-transactions to fall + into separate binlogs. Therefore, it is necessary to prohibit + the rotation of binlog in the middle of processing LOAD DATA: + */ +#ifdef WITH_WSREP + if (!thd->wsrep_split_flag) + { +#endif /* WITH_WSREP */ if ((error= rotate(false, &check_purge))) check_purge= false; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } } } @@ -7139,8 +7156,25 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd) !(error= flush_and_sync(0))) { signal_update(); + /* + If a transaction with the LOAD DATA statement is divided + into logical mini-transactions (of the 10K rows) and binlog + is rotated, then the last portion of data may be lost due to + wsrep handler re-registration at the boundary of the split. + Since splitting of the LOAD DATA into mini-transactions is + logical, we should not allow these mini-transactions to fall + into separate binlogs. Therefore, it is necessary to prohibit + the rotation of binlog in the middle of processing LOAD DATA: + */ +#ifdef WITH_WSREP + if (!thd->wsrep_split_flag) + { +#endif /* WITH_WSREP */ if ((error= rotate(false, &check_purge))) check_purge= false; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ } offset= my_b_tell(&log_file); @@ -7906,6 +7940,20 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) mark_xids_active(binlog_id, xid_count); } + /* + If a transaction with the LOAD DATA statement is divided + into logical mini-transactions (of the 10K rows) and binlog + is rotated, then the last portion of data may be lost due to + wsrep handler re-registration at the boundary of the split. + Since splitting of the LOAD DATA into mini-transactions is + logical, we should not allow these mini-transactions to fall + into separate binlogs. Therefore, it is necessary to prohibit + the rotation of binlog in the middle of processing LOAD DATA: + */ +#ifdef WITH_WSREP + if (!leader->thd->wsrep_split_flag) + { +#endif /* WITH_WSREP */ if (rotate(false, &check_purge)) { /* @@ -7925,6 +7973,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno); check_purge= false; } +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ /* In case of binlog rotate, update the correct current binlog offset. */ commit_offset= my_b_write_tell(&log_file); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d6aa6456710..512f7fdfd56 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -784,6 +784,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) wsrep_affected_rows = 0; wsrep_replicate_GTID = false; wsrep_skip_wsrep_GTID = false; + wsrep_split_flag = false; #endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1218,6 +1219,7 @@ void THD::init(void) wsrep_affected_rows = 0; wsrep_replicate_GTID = false; wsrep_skip_wsrep_GTID = false; + wsrep_split_flag = false; #endif /* WITH_WSREP */ if (variables.sql_log_bin) diff --git a/sql/sql_class.h b/sql/sql_class.h index d701d4cb46c..cb182f55bf1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4431,6 +4431,14 @@ public: ulong wsrep_affected_rows; bool wsrep_replicate_GTID; bool wsrep_skip_wsrep_GTID; + /* This flag is set when innodb do an intermediate commit to + processing the LOAD DATA INFILE statement by splitting it into 10K + rows chunks. If flag is set, then binlog rotation is not performed + while intermediate transaction try to commit, because in this case + rotation causes unregistration of innodb handler. Later innodb handler + registered again, but replication of last chunk of rows is skipped + by the innodb engine: */ + bool wsrep_split_flag; #endif /* WITH_WSREP */ /* Handling of timeouts for commands */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 8c2f17dac3f..8e0bdcb32b8 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -41,6 +41,7 @@ #include "sql_trigger.h" #include "sql_derived.h" #include "sql_show.h" +#include "debug_sync.h" extern "C" int _my_b_net_read(IO_CACHE *info, uchar *Buffer, size_t Count); @@ -119,21 +120,43 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table, if (hton->db_type != DB_TYPE_INNODB) DBUG_RETURN(false); WSREP_DEBUG("intermediate transaction commit in LOAD DATA"); + wsrep_set_load_multi_commit(thd, true); if (wsrep_run_wsrep_commit(thd, true) != WSREP_TRX_OK) DBUG_RETURN(true); if (binlog_hton->commit(binlog_hton, thd, true)) DBUG_RETURN(true); wsrep_post_commit(thd, true); hton->commit(hton, thd, true); + wsrep_set_load_multi_commit(thd, false); + DEBUG_SYNC(thd, "intermediate_transaction_commit"); table->file->extra(HA_EXTRA_FAKE_START_STMT); } DBUG_RETURN(false); } -# define WSREP_LOAD_DATA_SPLIT(thd,table,info) \ - if (wsrep_load_data_split(thd,table,info)) DBUG_RETURN(1) +/* + If the commit fails, then an early return from + the function occurs there and therefore we need + to reset the table->auto_increment_field_not_null + flag, which is usually reset after calling + the write_record(): +*/ +#define WSREP_LOAD_DATA_SPLIT(thd,table,info) \ + if (wsrep_load_data_split(thd,table,info)) \ + { \ + table->auto_increment_field_not_null= FALSE; \ + DBUG_RETURN(1); \ + } #else /* WITH_WSREP */ #define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */ #endif /* WITH_WSREP */ +#define WRITE_RECORD(thd,table,info) \ + do { \ + int err_= write_record(thd, table, &info); \ + table->auto_increment_field_not_null= FALSE; \ + if (err_) \ + DBUG_RETURN(1); \ + } while (0) + class READ_INFO: public Load_data_param { File file; @@ -911,7 +934,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, List_iterator_fast it(fields_vars); Item *item; TABLE *table= table_list->table; - bool err, progress_reports; + bool progress_reports; ulonglong counter, time_to_report_progress; DBUG_ENTER("read_fixed_length"); @@ -1003,11 +1026,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } WSREP_LOAD_DATA_SPLIT(thd, table, info); - err= write_record(thd, table, &info); - table->auto_increment_field_not_null= FALSE; - if (err) - DBUG_RETURN(1); - + WRITE_RECORD(thd, table, info); + /* We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. @@ -1040,7 +1060,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, Item *item; TABLE *table= table_list->table; uint enclosed_length; - bool err, progress_reports; + bool progress_reports; ulonglong counter, time_to_report_progress; DBUG_ENTER("read_sep_field"); @@ -1124,7 +1144,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { Load_data_outvar *dst= item->get_load_data_outvar_or_error(); DBUG_ASSERT(dst); - if (dst->load_data_set_no_data(thd, &read_info)) + if (unlikely(dst->load_data_set_no_data(thd, &read_info))) DBUG_RETURN(1); } } @@ -1146,10 +1166,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } WSREP_LOAD_DATA_SPLIT(thd, table, info); - err= write_record(thd, table, &info); - table->auto_increment_field_not_null= FALSE; - if (err) - DBUG_RETURN(1); + WRITE_RECORD(thd, table, info); + /* We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. @@ -1267,13 +1285,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, case VIEW_CHECK_ERROR: DBUG_RETURN(-1); } - + WSREP_LOAD_DATA_SPLIT(thd, table, info); - err= write_record(thd, table, &info); - table->auto_increment_field_not_null= false; - if (err) - DBUG_RETURN(1); - + WRITE_RECORD(thd, table, info); + /* We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 3d6cf0a0723..e7de45b5ee2 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -178,6 +178,8 @@ static struct wsrep_service_st wsrep_handler = { wsrep_thd_trx_seqno, wsrep_thd_ws_handle, wsrep_thd_auto_increment_variables, + wsrep_set_load_multi_commit, + wsrep_is_load_multi_commit, wsrep_trx_is_aborting, wsrep_trx_order_before, wsrep_unlock_rollback, diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 7297dbfe0fd..aff75cf7790 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -133,6 +133,12 @@ void wsrep_thd_auto_increment_variables(THD *thd, *increment= thd->variables.auto_increment_increment; } +void wsrep_set_load_multi_commit(THD *thd, bool split) +{ } + +bool wsrep_is_load_multi_commit(THD *thd) +{ return false; } + int wsrep_trx_is_aborting(THD *) { return 0; } diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index e3da6a79f26..3603e05fd5f 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -45,6 +45,7 @@ void wsrep_cleanup_transaction(THD *thd) thd->wsrep_exec_mode= LOCAL_STATE; thd->wsrep_affected_rows= 0; thd->wsrep_skip_wsrep_GTID= false; + thd->wsrep_split_flag= false; return; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index dab9f91b381..00afbec290e 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -708,3 +708,13 @@ my_bool wsrep_thd_is_applier(MYSQL_THD thd) return (is_applier); } + +void wsrep_set_load_multi_commit(THD *thd, bool split) +{ + thd->wsrep_split_flag= split; +} + +bool wsrep_is_load_multi_commit(THD *thd) +{ + return thd->wsrep_split_flag; +} -- cgit v1.2.1 From 1d728a98d8c4626098db9876de101d8cf704c993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 18 Mar 2019 12:29:54 +0200 Subject: Fixup MDEV-17262: Remove a unused variable --- sql/sql_load.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 8e0bdcb32b8..9006bf2b1d4 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1211,7 +1211,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, for ( ; ; it.rewind()) { - bool err; if (thd->killed) { thd->send_kill_message(); -- cgit v1.2.1