diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-03-06 09:00:52 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-03-06 09:00:52 +0200 |
commit | 2a791c53ad93c8bc1441dd227000234bd49c4990 (patch) | |
tree | 4c52ad715c99bd3c6681771d7cb77d451a34e216 /sql | |
parent | b5c72a843abee033e9ea6028e1a109f03afc4455 (diff) | |
parent | 723ffdb32ee785cbc511abc457eb70d41c2fcce3 (diff) | |
download | mariadb-git-2a791c53ad93c8bc1441dd227000234bd49c4990.tar.gz |
Merge 10.3 into 10.4
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 45 | ||||
-rw-r--r-- | sql/ha_partition.cc | 44 | ||||
-rw-r--r-- | sql/handler.cc | 54 | ||||
-rw-r--r-- | sql/mysqld.cc | 18 | ||||
-rw-r--r-- | sql/opt_split.cc | 13 | ||||
-rw-r--r-- | sql/sql_acl.cc | 12 | ||||
-rw-r--r-- | sql/sql_admin.cc | 4 | ||||
-rw-r--r-- | sql/sql_admin.h | 8 | ||||
-rw-r--r-- | sql/sql_alter.h | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 10 | ||||
-rw-r--r-- | sql/sql_cmd.h | 13 | ||||
-rw-r--r-- | sql/sql_delete.cc | 8 | ||||
-rw-r--r-- | sql/sql_derived.cc | 31 | ||||
-rw-r--r-- | sql/sql_derived.h | 1 | ||||
-rw-r--r-- | sql/sql_insert.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.cc | 36 | ||||
-rw-r--r-- | sql/sql_lex.h | 32 | ||||
-rw-r--r-- | sql/sql_load.cc | 10 | ||||
-rw-r--r-- | sql/sql_parse.cc | 58 | ||||
-rw-r--r-- | sql/sql_plugin_services.ic | 1 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 22 | ||||
-rw-r--r-- | sql/sql_select.cc | 7 | ||||
-rw-r--r-- | sql/sql_select.h | 3 | ||||
-rw-r--r-- | sql/sql_table.cc | 3 | ||||
-rw-r--r-- | sql/sql_union.cc | 5 | ||||
-rw-r--r-- | sql/sys_vars.cc | 93 | ||||
-rw-r--r-- | sql/wsrep_dummy.cc | 8 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 18 |
28 files changed, 443 insertions, 121 deletions
diff --git a/sql/field.h b/sql/field.h index aad96adcd40..475b6907346 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1577,6 +1577,17 @@ public: /* Hash value */ virtual void hash(ulong *nr, ulong *nr2); + /** + Get the upper limit of the MySQL integral and floating-point type. + + @return maximum allowed value for the field + */ + virtual ulonglong get_max_int_value() const + { + DBUG_ASSERT(false); + return 0ULL; + } + /** Checks whether a string field is part of write_set. @@ -2232,6 +2243,10 @@ public: *to= *from; return from + 1; } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFULL : 0x7FULL; + } }; @@ -2276,6 +2291,10 @@ public: virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) { return unpack_int16(to, from, from_end); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFULL : 0x7FFFULL; + } }; class Field_medium :public Field_int @@ -2311,6 +2330,10 @@ public: { return Field::pack(to, from, max_length); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFULL : 0x7FFFFFULL; + } }; @@ -2360,6 +2383,10 @@ public: { return unpack_int32(to, from, from_end); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFFFULL : 0x7FFFFFFFULL; + } }; @@ -2414,6 +2441,10 @@ public: } void set_max(); bool is_max(); + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFULL; + } }; @@ -2496,6 +2527,13 @@ public: uint32 pack_length() const { return sizeof(float); } uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; + virtual ulonglong get_max_int_value() const + { + /* + We use the maximum as per IEEE754-2008 standard, 2^24 + */ + return 0x1000000ULL; + } private: int save_field_metadata(uchar *first_byte); }; @@ -2554,6 +2592,13 @@ public: uint32 pack_length() const { return sizeof(double); } uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; + virtual ulonglong get_max_int_value() const + { + /* + We use the maximum as per IEEE754-2008 standard, 2^53 + */ + return 0x20000000000000ULL; + } private: int save_field_metadata(uchar *first_byte); }; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index c13b26cdb86..aea1796e776 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -10547,31 +10547,37 @@ void ha_partition::release_auto_increment() m_file[i]->ha_release_auto_increment(); } } - else if (next_insert_id) + else { - ulonglong next_auto_inc_val; lock_auto_increment(); - next_auto_inc_val= part_share->next_auto_inc_val; - /* - If the current auto_increment values is lower than the reserved - value, and the reserved value was reserved by this thread, - we can lower the reserved value. - */ - if (next_insert_id < next_auto_inc_val && - auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val) + if (next_insert_id) { - THD *thd= ha_thd(); + ulonglong next_auto_inc_val= part_share->next_auto_inc_val; /* - Check that we do not lower the value because of a failed insert - with SET INSERT_ID, i.e. forced/non generated values. + If the current auto_increment values is lower than the reserved + value, and the reserved value was reserved by this thread, + we can lower the reserved value. */ - if (thd->auto_inc_intervals_forced.maximum() < next_insert_id) - part_share->next_auto_inc_val= next_insert_id; + if (next_insert_id < next_auto_inc_val && + auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val) + { + THD *thd= ha_thd(); + /* + Check that we do not lower the value because of a failed insert + with SET INSERT_ID, i.e. forced/non generated values. + */ + if (thd->auto_inc_intervals_forced.maximum() < next_insert_id) + part_share->next_auto_inc_val= next_insert_id; + } + DBUG_PRINT("info", ("part_share->next_auto_inc_val: %lu", + (ulong) part_share->next_auto_inc_val)); } - DBUG_PRINT("info", ("part_share->next_auto_inc_val: %lu", - (ulong) part_share->next_auto_inc_val)); - - /* Unlock the multi row statement lock taken in get_auto_increment */ + /* + Unlock the multi-row statement lock taken in get_auto_increment. + These actions must be performed even if the next_insert_id field + contains zero, otherwise if the update_auto_increment fails then + an unnecessary lock will remain: + */ if (auto_increment_safe_stmt_log_lock) { auto_increment_safe_stmt_log_lock= FALSE; diff --git a/sql/handler.cc b/sql/handler.cc index 58731fdcda7..0746f8a81fc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3265,11 +3265,17 @@ compute_next_insert_id(ulonglong nr,struct system_variables *variables) nr= nr + 1; // optimization of the formula below else { - nr= (((nr+ variables->auto_increment_increment - - variables->auto_increment_offset)) / - (ulonglong) variables->auto_increment_increment); - nr= (nr* (ulonglong) variables->auto_increment_increment + - variables->auto_increment_offset); + /* + Calculating the number of complete auto_increment_increment extents: + */ + nr= (nr + variables->auto_increment_increment - + variables->auto_increment_offset) / + (ulonglong) variables->auto_increment_increment; + /* + Adding an offset to the auto_increment_increment extent boundary: + */ + nr= nr * (ulonglong) variables->auto_increment_increment + + variables->auto_increment_offset; } if (unlikely(nr <= save_nr)) @@ -3323,8 +3329,14 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) } if (variables->auto_increment_increment == 1) return nr; // optimization of the formula below - nr= (((nr - variables->auto_increment_offset)) / - (ulonglong) variables->auto_increment_increment); + /* + Calculating the number of complete auto_increment_increment extents: + */ + nr= (nr - variables->auto_increment_offset) / + (ulonglong) variables->auto_increment_increment; + /* + Adding an offset to the auto_increment_increment extent boundary: + */ return (nr * (ulonglong) variables->auto_increment_increment + variables->auto_increment_offset); } @@ -3566,10 +3578,32 @@ int handler::update_auto_increment() if (unlikely(tmp)) // Out of range value in store { /* - It's better to return an error here than getting a confusing - 'duplicate key error' later. + First, test if the query was aborted due to strict mode constraints + or new field value greater than maximum integer value: */ - result= HA_ERR_AUTOINC_ERANGE; + if (thd->killed == KILL_BAD_DATA || + nr > table->next_number_field->get_max_int_value()) + { + /* + It's better to return an error here than getting a confusing + 'duplicate key error' later. + */ + result= HA_ERR_AUTOINC_ERANGE; + } + else + { + /* + Field refused this value (overflow) and truncated it, use the result + of the truncation (which is going to be inserted); however we try to + decrease it to honour auto_increment_* variables. + That will shift the left bound of the reserved interval, we don't + bother shifting the right bound (anyway any other value from this + interval will cause a duplicate key). + */ + nr= prev_insert_id(table->next_number_field->val_int(), variables); + if (unlikely(table->next_number_field->store((longlong)nr, TRUE))) + nr= table->next_number_field->val_int(); + } } if (append) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 24993a045ac..4bb0e0cad88 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB Corporation. + Copyright (c) 2008, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3985,6 +3985,8 @@ static int init_common_variables() if (IS_SYSVAR_AUTOSIZE(&server_version_ptr)) set_server_version(server_version, sizeof(server_version)); + mysql_real_data_home_len= uint(strlen(mysql_real_data_home)); + if (!opt_abort) { if (IS_SYSVAR_AUTOSIZE(&server_version_ptr)) @@ -4378,6 +4380,20 @@ static int init_common_variables() global_system_variables.in_subquery_conversion_threshold= IN_SUBQUERY_CONVERSION_THRESHOLD; +#ifdef WITH_WSREP + /* + We need to initialize auxiliary variables, that will be + further keep the original values of auto-increment options + as they set by the user. These variables used to restore + user-defined values of the auto-increment options after + setting of the wsrep_auto_increment_control to 'OFF'. + */ + global_system_variables.saved_auto_increment_increment= + global_system_variables.auto_increment_increment; + global_system_variables.saved_auto_increment_offset= + global_system_variables.auto_increment_offset; +#endif /* WITH_WSREP */ + return 0; } diff --git a/sql/opt_split.cc b/sql/opt_split.cc index fc3f08464f4..cfac0c93544 100644 --- a/sql/opt_split.cc +++ b/sql/opt_split.cc @@ -1078,6 +1078,7 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables) @param spl_plan info on the splitting plan chosen for the splittable table T remaining_tables the table T is joined just before these tables + is_const_table the table T is a constant table @details If in the final query plan the optimizer has chosen a splitting plan @@ -1091,12 +1092,13 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables) */ bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan, - table_map remaining_tables) + table_map remaining_tables, + bool is_const_table) { SplM_opt_info *spl_opt_info= table->spl_opt_info; DBUG_ASSERT(table->spl_opt_info != 0); JOIN *md_join= spl_opt_info->join; - if (spl_plan) + if (spl_plan && !is_const_table) { memcpy((char *) md_join->best_positions, (char *) spl_plan->best_positions, @@ -1113,7 +1115,7 @@ bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan, remaining_tables, true); } - else + else if (md_join->save_qep) { md_join->restore_query_plan(md_join->save_qep); } @@ -1143,10 +1145,11 @@ bool JOIN::fix_all_splittings_in_plan() { POSITION *cur_pos= &best_positions[tablenr]; JOIN_TAB *tab= cur_pos->table; - if (tablenr >= const_tables && tab->table->is_splittable()) + if (tab->table->is_splittable()) { SplM_plan_info *spl_plan= cur_pos->spl_plan; - if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables)) + if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables, + tablenr < const_tables )) return true; } prev_tables|= tab->table->map; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b441356df26..6fef2927938 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -10521,6 +10521,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) LEX_USER *user_name; List_iterator <LEX_USER> user_list(list); bool binlog= false; + bool some_users_dropped= false; DBUG_ENTER("mysql_create_user"); DBUG_PRINT("entry", ("Handle as %s", handle_as_role ? "role" : "user")); @@ -10580,6 +10581,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) result= true; continue; } + else + some_users_dropped= true; // Proceed with the creation } else if (thd->lex->create_info.if_not_exists()) @@ -10648,12 +10651,21 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) } } + if (result && some_users_dropped && !handle_as_role) + { + /* Rebuild in-memory structs, since 'acl_users' has been modified */ + rebuild_check_host(); + rebuild_role_grants(); + } + mysql_mutex_unlock(&acl_cache->lock); if (result) + { my_error(ER_CANNOT_USER, MYF(0), (handle_as_role) ? "CREATE ROLE" : "CREATE USER", wrong_users.c_ptr_safe()); + } if (binlog) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index b39103e382a..795d4c2611b 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2015, Oracle and/or its affiliates. - Copyright (c) 2011, 2018, MariaDB + Copyright (c) 2011, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1402,8 +1402,6 @@ bool Sql_cmd_repair_table::execute(THD *thd) if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table, FALSE, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ - thd->enable_slow_log&= !MY_TEST(thd->variables.log_slow_disabled_statements & - LOG_SLOW_DISABLE_ADMIN); WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair", TL_WRITE, 1, diff --git a/sql/sql_admin.h b/sql/sql_admin.h index e7f4086540a..dea835c2de9 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 +class Sql_cmd_analyze_table : public Sql_cmd_admin { public: /** @@ -53,7 +53,7 @@ public: /** Sql_cmd_check_table represents the CHECK TABLE statement. */ -class Sql_cmd_check_table : public Sql_cmd +class Sql_cmd_check_table : public Sql_cmd_admin { public: /** @@ -77,7 +77,7 @@ public: /** Sql_cmd_optimize_table represents the OPTIMIZE TABLE statement. */ -class Sql_cmd_optimize_table : public Sql_cmd +class Sql_cmd_optimize_table : public Sql_cmd_admin { public: /** @@ -102,7 +102,7 @@ public: /** Sql_cmd_repair_table represents the REPAIR TABLE statement. */ -class Sql_cmd_repair_table : public Sql_cmd +class Sql_cmd_repair_table : public Sql_cmd_admin { public: /** diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 14242015bd2..e2e7abe2a1c 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -333,7 +333,7 @@ private: statements. @todo move Alter_info and other ALTER generic structures from Lex here. */ -class Sql_cmd_common_alter_table : public Sql_cmd +class Sql_cmd_common_alter_table : public Sql_cmd_admin { protected: /** diff --git a/sql/sql_class.h b/sql/sql_class.h index bac5807677c..56ebe7f805f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -599,6 +599,16 @@ typedef struct system_variables ha_rows max_join_size; ha_rows expensive_subquery_limit; ulong auto_increment_increment, auto_increment_offset; +#ifdef WITH_WSREP + /* + Stored values of the auto_increment_increment and auto_increment_offset + that are will be restored when wsrep_auto_increment_control will be set + to 'OFF', because the setting it to 'ON' leads to overwriting of the + original values (which are set by the user) by calculated ones (which + are based on the cluster size): + */ + ulong saved_auto_increment_increment, saved_auto_increment_offset; +#endif /* WITH_WSREP */ uint eq_range_index_dive_limit; ulong column_compression_zlib_strategy; ulong lock_wait_timeout; diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h index 973e159c0cb..cbd7513e29f 100644 --- a/sql/sql_cmd.h +++ b/sql/sql_cmd.h @@ -161,6 +161,8 @@ public: */ virtual bool execute(THD *thd) = 0; + virtual bool log_slow_enabled_statement(const THD *thd) const; + protected: Sql_cmd() {} @@ -178,6 +180,17 @@ protected: }; +class Sql_cmd_admin: public Sql_cmd +{ +public: + Sql_cmd_admin() + {} + ~Sql_cmd_admin() + {} + bool log_slow_enabled_statement(const THD *thd) const; +}; + + /** Sql_cmd_call represents the CALL statement. */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index abfcf0865fe..d02d35a7dd8 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #include "records.h" // init_read_record, #include "filesort.h" #include "uniques.h" -#include "sql_derived.h" // mysql_handle_list_of_derived +#include "sql_derived.h" // mysql_handle_derived // end_read_record #include "sql_partition.h" // make_used_partitions_str @@ -393,9 +393,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(true); } - if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT)) + if (thd->lex->handle_list_of_derived(table_list, DT_MERGE_FOR_INSERT)) DBUG_RETURN(TRUE); - if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) + if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) DBUG_RETURN(TRUE); if (!table_list->single_table_updatable()) diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 9919c30af6d..bce70e63603 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -96,6 +96,7 @@ mysql_handle_derived(LEX *lex, uint phases) sl= sl->next_select_in_list()) { TABLE_LIST *cursor= sl->get_table_list(); + sl->changed_elements|= TOUCHED_SEL_DERIVED; /* DT_MERGE_FOR_INSERT is not needed for views/derived tables inside subqueries. Views and derived tables of subqueries should be @@ -208,36 +209,6 @@ mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases) /** - Run specified phases for derived tables/views in the given list - - @param lex LEX for this thread - @param table_list list of derived tables/view to handle - @param phase_map phases to process tables/views through - - @details - This function runs phases specified by the 'phases_map' on derived - tables/views found in the 'dt_list' with help of the - TABLE_LIST::handle_derived function. - 'lex' is passed as an argument to the TABLE_LIST::handle_derived. - - @return FALSE ok - @return TRUE error -*/ - -bool -mysql_handle_list_of_derived(LEX *lex, TABLE_LIST *table_list, uint phases) -{ - for (TABLE_LIST *tl= table_list; tl; tl= tl->next_local) - { - if (tl->is_view_or_derived() && - tl->handle_derived(lex, phases)) - return TRUE; - } - return FALSE; -} - - -/** Merge a derived table/view into the embedding select @param thd thread handle diff --git a/sql/sql_derived.h b/sql/sql_derived.h index f098cf39083..621a6e9ec24 100644 --- a/sql/sql_derived.h +++ b/sql/sql_derived.h @@ -22,7 +22,6 @@ struct LEX; bool mysql_handle_derived(LEX *lex, uint phases); bool mysql_handle_single_derived(LEX *lex, TABLE_LIST *derived, uint phases); -bool mysql_handle_list_of_derived(LEX *lex, TABLE_LIST *dt_list, uint phases); bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived); /** diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 90170f5a132..b18553ee586 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1497,7 +1497,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(TRUE); if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) DBUG_RETURN(TRUE); - if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) + if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) DBUG_RETURN(TRUE); /* For subqueries in VALUES() we should not see the table in which we are @@ -1590,7 +1590,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(TRUE); } select_lex->fix_prepare_information(thd, &fake_conds, &fake_conds); - select_lex->first_execution= 0; } /* Only call prepare_for_posistion() if we are not performing a DELAYED @@ -1956,7 +1955,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) } else error= 0; // error was HA_ERR_RECORD_IS_THE_SAME - thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row); /* Since we pretend that we have done insert we should call its after triggers. @@ -2012,7 +2010,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info) if (table->file->insert_id_for_cur_row == 0) table->file->insert_id_for_cur_row= insert_id_for_cur_row; - thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row); /* Restore column maps if they where replaced during an duplicate key problem. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index fb9eb5c1ea6..792a196c5a8 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2014, Oracle and/or its affiliates. - Copyright (c) 2009, 2018, MariaDB Corporation + Copyright (c) 2009, 2019, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2377,7 +2377,7 @@ void st_select_lex::init_query() hidden_bit_fields= 0; subquery_in_having= explicit_limit= 0; is_item_list_lookup= 0; - first_execution= 1; + changed_elements= 0; first_natural_join_processing= 1; first_cond_optimization= 1; parsing_place= NO_MATTER; @@ -2973,8 +2973,6 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN(" union ")); if (union_all) str->append(STRING_WITH_LEN("all ")); - else if (union_distinct == sl) - union_all= TRUE; break; case INTERSECT_TYPE: str->append(STRING_WITH_LEN(" intersect ")); @@ -2983,6 +2981,8 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type) str->append(STRING_WITH_LEN(" except ")); break; } + if (sl == union_distinct) + union_all= TRUE; } if (sl->braces) str->append('('); @@ -3950,10 +3950,11 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds, Item **having_conds) { DBUG_ENTER("st_select_lex::fix_prepare_information"); - if (!thd->stmt_arena->is_conventional() && first_execution) + if (!thd->stmt_arena->is_conventional() && + !(changed_elements & TOUCHED_SEL_COND)) { Query_arena_stmt on_stmt_arena(thd); - first_execution= 0; + changed_elements|= TOUCHED_SEL_COND; if (group_list.first) { if (!group_list_ptrs) @@ -4204,14 +4205,7 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) bool st_select_lex::handle_derived(LEX *lex, uint phases) { - for (TABLE_LIST *cursor= (TABLE_LIST*) table_list.first; - cursor; - cursor= cursor->next_local) - { - if (cursor->is_view_or_derived() && cursor->handle_derived(lex, phases)) - return TRUE; - } - return FALSE; + return lex->handle_list_of_derived(table_list.first, phases); } @@ -5222,6 +5216,20 @@ 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 !MY_TEST(thd->variables.log_slow_disabled_statements & + LOG_SLOW_DISABLE_ADMIN) && + Sql_cmd::log_slow_enabled_statement(thd); +} + + /** Exclude last added SELECT_LEX (current) in the UNIT and return pointer in it (previous become currect) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4f60f89ff36..ca72770e13b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1029,6 +1029,10 @@ Field_pair *get_corresponding_field_pair(Item *item, Field_pair *find_matching_field_pair(Item *item, List<Field_pair> pair_list); +#define TOUCHED_SEL_COND 1/* WHERE/HAVING/ON should be reinited before use */ +#define TOUCHED_SEL_DERIVED (1<<1)/* derived should be reinited before use */ + + /* SELECT_LEX - store information of parsed SELECT statment */ @@ -1234,7 +1238,8 @@ public: subquery. Prepared statements work OK in that regard, as in case of an error during prepare the PS is not created. */ - bool first_execution; + uint8 changed_elements; // see TOUCHED_SEL_* + /* TODO: add foloowing first_* to bitmap above */ bool first_natural_join_processing; bool first_cond_optimization; /* do not wrap view fields with Item_ref */ @@ -4310,6 +4315,31 @@ public: bool tmp_table() const { return create_info.tmp_table(); } bool if_exists() const { return create_info.if_exists(); } + /* + Run specified phases for derived tables/views in the given list + + @param table_list - list of derived tables/view to handle + @param phase - phases to process tables/views through + + @details + This method runs phases specified by the 'phases' on derived + tables/views found in the 'table_list' with help of the + TABLE_LIST::handle_derived function. + 'this' is passed as an argument to the TABLE_LIST::handle_derived. + + @return false - ok + @return true - error + */ + bool handle_list_of_derived(TABLE_LIST *table_list, uint phases) + { + for (TABLE_LIST *tl= table_list; tl; tl= tl->next_local) + { + if (tl->is_view_or_derived() && tl->handle_derived(this, phases)) + return true; + } + return false; + } + SELECT_LEX *exclude_last_select(); SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude); void check_automatic_up(enum sub_select_type type); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index da5356ffb4b..0228bf62708 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -387,8 +387,9 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); - if (mysql_handle_single_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) || - mysql_handle_single_derived(thd->lex, table_list, DT_PREPARE)) + if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (thd->lex->handle_list_of_derived(table_list, DT_PREPARE)) DBUG_RETURN(TRUE); if (setup_tables_and_check_access(thd, &thd->lex->first_select_lex()->context, @@ -407,6 +408,11 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias.str, "LOAD"); DBUG_RETURN(TRUE); } + if (table_list->is_multitable()) + { + my_error(ER_WRONG_USAGE, MYF(0), "Multi-table VIEW", "LOAD"); + DBUG_RETURN(TRUE); + } if (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fecd889381c..10417601345 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1575,7 +1575,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->variables.log_slow_disabled_statements defines which statements are logged to slow log */ - thd->enable_slow_log= thd->variables.sql_log_slow; + thd->enable_slow_log= true; thd->query_plan_flags= QPLAN_INIT; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->reset_kill_query(); @@ -2478,6 +2478,32 @@ dispatch_end: } +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) && + MY_TEST(thd->variables.log_slow_disabled_statements & + LOG_SLOW_DISABLE_ADMIN)) + return true; + + return global_system_variables.sql_log_slow && + thd->variables.sql_log_slow; +} + + /* Log query to slow queries, if it passes filtering @@ -2496,8 +2522,17 @@ void log_slow_statement(THD *thd) */ if (unlikely(thd->in_sub_stmt)) goto end; // Don't set time for sub stmt - if (!thd->enable_slow_log || !global_system_variables.sql_log_slow) - goto end; + /* + Skip both long_query_count increment and logging if the current + statement forces slow log suppression (e.g. an SP statement). + + Note, we don't check for global_system_variables.sql_log_slow here. + According to the manual, the "Slow_queries" status variable does not require + sql_log_slow to be ON. So even if sql_log_slow is OFF, we still need to + continue and increment long_query_count (and skip only logging, see below): + */ + if (!thd->enable_slow_log) + goto end; // E.g. SP statement if ((thd->server_status & (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && @@ -2510,15 +2545,14 @@ void log_slow_statement(THD *thd) thd->server_status|= SERVER_QUERY_WAS_SLOW; } - /* Follow the slow log filter configuration. */ - if (thd->variables.log_slow_filter && - !(thd->variables.log_slow_filter & thd->query_plan_flags)) - goto end; - if ((thd->server_status & SERVER_QUERY_WAS_SLOW) && thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) { thd->status_var.long_query_count++; + + if (!log_slow_enabled_statement(thd)) + goto end; + /* If rate limiting of slow log writes is enabled, decide whether to log this query to the log or not. @@ -2527,6 +2561,14 @@ void log_slow_statement(THD *thd) (global_query_id % thd->variables.log_slow_rate_limit) != 0) goto end; + /* + Follow the slow log filter configuration: + skip logging if the current statement matches the filter. + */ + if (thd->variables.log_slow_filter && + !(thd->variables.log_slow_filter & thd->query_plan_flags)) + goto end; + THD_STAGE_INFO(thd, stage_logging_slow_query); slow_log_print(thd, thd->query(), thd->query_length(), thd->utime_after_query); diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 8893ea361e3..adb20c0eb92 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -155,6 +155,7 @@ static struct wsrep_service_st wsrep_handler = { wsrep_thd_retry_counter, wsrep_thd_ignore_table, wsrep_thd_trx_seqno, + wsrep_thd_auto_increment_variables, wsrep_thd_is_aborting, wsrep_set_data_home_dir, wsrep_thd_is_BF, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index cbabdd4221b..3967b4d57a9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB + Copyright (c) 2008, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2946,7 +2946,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) } for (; sl; sl= sl->next_select_in_list()) { - if (!sl->first_execution) + if (sl->changed_elements & TOUCHED_SEL_COND) { /* remove option which was put by mysql_explain_union() */ sl->options&= ~SELECT_DESCRIBE; @@ -2993,8 +2993,13 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) order->next= sl->group_list_ptrs->at(ix+1); } } + } + { // no harm to do it (item_ptr set on parsing) + ORDER *order; for (order= sl->group_list.first; order; order= order->next) + { order->item= &order->item_ptr; + } /* Fix ORDER list */ for (order= sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; @@ -3008,15 +3013,16 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) for (order= win_spec->order_list->first; order; order= order->next) order->item= &order->item_ptr; } - - { + } + if (sl->changed_elements & TOUCHED_SEL_DERIVED) + { #ifdef DBUG_ASSERT_EXISTS - bool res= + bool res= #endif - sl->handle_derived(lex, DT_REINIT); - DBUG_ASSERT(res == 0); - } + sl->handle_derived(lex, DT_REINIT); + DBUG_ASSERT(res == 0); } + { SELECT_LEX_UNIT *unit= sl->master_unit(); unit->unclean(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 211898f46d0..cbf136b9b8b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016 Oracle and/or its affiliates. - Copyright (c) 2009, 2018 MariaDB Corporation + Copyright (c) 2009, 2019 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1270,7 +1270,7 @@ JOIN::prepare(TABLE_LIST *tables_init, select_lex->check_unrestricted_recursive( thd->variables.only_standard_compliant_cte)) DBUG_RETURN(-1); - if (select_lex->first_execution) + if (!(select_lex->changed_elements & TOUCHED_SEL_COND)) select_lex->check_subqueries_with_recursive_references(); int res= check_and_do_in_subquery_rewrites(this); @@ -7062,6 +7062,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key) next=tmp; } join->best_ref[idx]=table; + join->positions[idx].spl_plan= 0; } @@ -24536,7 +24537,9 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, real_pos->type() == Item::COND_ITEM) && !real_pos->with_sum_func()) { // Save for send fields + LEX_CSTRING real_name= pos->name; pos= real_pos; + pos->name= real_name; /* TODO: In most cases this result will be sent to the user. This should be changed to use copy_int or copy_real depending diff --git a/sql/sql_select.h b/sql/sql_select.h index 3bb2710d3a1..dcf95f04702 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -676,7 +676,8 @@ typedef struct st_join_table { void add_keyuses_for_splitting(); SplM_plan_info *choose_best_splitting(double record_count, table_map remaining_tables); - bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables); + bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables, + bool is_const_table); } JOIN_TAB; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cdf418a7cab..b2212fe0ab0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -10508,11 +10508,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, to->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) { char warn_buff[MYSQL_ERRMSG_SIZE]; + bool save_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= false; my_snprintf(warn_buff, sizeof(warn_buff), "ORDER BY ignored as there is a user-defined clustered index" " in the table '%-.192s'", from->s->table_name.str); push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, warn_buff); + thd->abort_on_warning= save_abort_on_warning; } else { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index ca8a5e7a8b3..a1d86959218 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -611,8 +611,9 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, called at the first execution of the statement, while first_execution shows whether this is called at the first execution of the union that may form just a subselect. - */ - if (!fake_select_lex->first_execution && first_execution) + */ + if ((fake_select_lex->changed_elements & TOUCHED_SEL_COND) && + first_execution) { for (ORDER *order= global_parameters()->order_list.first; order; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5e88c4e7544..5626fc5bdaf 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -350,6 +350,25 @@ static Sys_var_long Sys_pfs_connect_attrs_size( #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +#ifdef WITH_WSREP + +/* + We need to keep the original values set by the user, as they will + be lost if wsrep_auto_increment_control set to 'ON': +*/ +static bool update_auto_increment_increment (sys_var *self, THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.saved_auto_increment_increment= + global_system_variables.auto_increment_increment; + else + thd->variables.saved_auto_increment_increment= + thd->variables.auto_increment_increment; + return false; +} + +#endif /* WITH_WSREP */ + static Sys_var_double Sys_analyze_sample_percentage( "analyze_sample_percentage", "Percentage of rows from the table ANALYZE TABLE will sample " @@ -365,7 +384,31 @@ static Sys_var_ulong Sys_auto_increment_increment( SESSION_VAR(auto_increment_increment), CMD_LINE(OPT_ARG), VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1), +#ifdef WITH_WSREP + NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_auto_increment_increment)); +#else NO_MUTEX_GUARD, IN_BINLOG); +#endif /* WITH_WSREP */ + +#ifdef WITH_WSREP + +/* + We need to keep the original values set by the user, as they will + be lost if wsrep_auto_increment_control set to 'ON': +*/ +static bool update_auto_increment_offset (sys_var *self, THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.saved_auto_increment_offset= + global_system_variables.auto_increment_offset; + else + thd->variables.saved_auto_increment_offset= + thd->variables.auto_increment_offset; + return false; +} + +#endif /* WITH_WSREP */ static Sys_var_ulong Sys_auto_increment_offset( "auto_increment_offset", @@ -374,7 +417,12 @@ static Sys_var_ulong Sys_auto_increment_offset( SESSION_VAR(auto_increment_offset), CMD_LINE(OPT_ARG), VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1), +#ifdef WITH_WSREP + NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_auto_increment_offset)); +#else NO_MUTEX_GUARD, IN_BINLOG); +#endif /* WITH_WSREP */ static Sys_var_mybool Sys_automatic_sp_privileges( "automatic_sp_privileges", @@ -5414,11 +5462,54 @@ static Sys_var_ulong Sys_wsrep_retry_autocommit( SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1)); +static bool update_wsrep_auto_increment_control (sys_var *self, THD *thd, enum_var_type type) +{ + if (wsrep_auto_increment_control) + { + /* + The variables that control auto increment shall be calculated + automaticaly based on the size of the cluster. This usually done + within the wsrep_view_handler_cb callback. However, if the user + manually sets the value of wsrep_auto_increment_control to 'ON', + then we should to re-calculate these variables again (because + these values may be required before wsrep_view_handler_cb will + be re-invoked, which is rarely invoked if the cluster stays in + the stable state): + */ + global_system_variables.auto_increment_increment= + wsrep_cluster_size ? wsrep_cluster_size : 1; + global_system_variables.auto_increment_offset= + wsrep_local_index >= 0 ? wsrep_local_index + 1 : 1; + thd->variables.auto_increment_increment= + global_system_variables.auto_increment_increment; + thd->variables.auto_increment_offset= + global_system_variables.auto_increment_offset; + } + else + { + /* + We must restore the last values of the variables that + are explicitly specified by the user: + */ + global_system_variables.auto_increment_increment= + global_system_variables.saved_auto_increment_increment; + global_system_variables.auto_increment_offset= + global_system_variables.saved_auto_increment_offset; + thd->variables.auto_increment_increment= + thd->variables.saved_auto_increment_increment; + thd->variables.auto_increment_offset= + thd->variables.saved_auto_increment_offset; + } + return false; +} + static Sys_var_mybool Sys_wsrep_auto_increment_control( "wsrep_auto_increment_control", "To automatically control the " "assignment of autoincrement variables", GLOBAL_VAR(wsrep_auto_increment_control), - CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + CMD_LINE(OPT_ARG), DEFAULT(TRUE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_wsrep_auto_increment_control)); static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( "wsrep_drupal_282555_workaround", "Enable a workaround to handle the " diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 916788483ab..f021054bf4c 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -101,6 +101,14 @@ const char* wsrep_thd_client_state_str(const THD*) const char* wsrep_thd_client_mode_str(const THD*) { return 0; } +void wsrep_thd_auto_increment_variables(THD *thd, + unsigned long long *offset, + unsigned long long *increment) +{ + *offset= thd->variables.auto_increment_offset; + *increment= thd->variables.auto_increment_increment; +} + const char* wsrep_thd_transaction_state_str(const THD*) { return 0; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 556163ad03d..b849bc256cb 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -397,3 +397,21 @@ bool wsrep_bf_abort(const THD* bf_thd, THD* victim_thd) return ret; } +/* + Get auto increment variables for THD. Use global settings for + applier threads. + */ +void wsrep_thd_auto_increment_variables(THD* thd, + unsigned long long* offset, + unsigned long long* increment) +{ + if (wsrep_thd_is_applying(thd) && + thd->wsrep_trx().state() != wsrep::transaction::s_replaying) + { + *offset= global_system_variables.auto_increment_offset; + *increment= global_system_variables.auto_increment_increment; + return; + } + *offset= thd->variables.auto_increment_offset; + *increment= thd->variables.auto_increment_increment; +} |