1 /* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "sql/dd/impl/upgrade/server.h"
24 #include "sql/dd/upgrade/server.h"
25 
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <vector>
33 
34 #include "lex_string.h"
35 #include "my_dbug.h"
36 #include "mysql/components/services/log_builtins.h"
37 #include "scripts/mysql_fix_privilege_tables_sql.h"
38 #include "scripts/sql_commands_system_tables_data_fix.h"
39 #include "sql/dd/cache/dictionary_client.h"  // dd::cache::Dictionary_client
40 #include "sql/dd/dd_schema.h"                // dd::Schema_MDL_locker
41 #include "sql/dd/dd_table.h"  // dd::warn_on_deprecated_prefix_key_partition
42 #include "sql/dd/dd_tablespace.h"                 // dd::fill_table_and_parts...
43 #include "sql/dd/dd_trigger.h"                    // dd::create_trigger
44 #include "sql/dd/impl/bootstrap/bootstrap_ctx.h"  // dd::DD_bootstrap_ctx
45 #include "sql/dd/impl/bootstrap/bootstrapper.h"
46 #include "sql/dd/impl/tables/dd_properties.h"  // dd::tables::DD_properties
47 #include "sql/dd/impl/utils.h"                 // dd::end_transaction
48 #include "sql/dd/types/routine.h"              // dd::Table
49 #include "sql/dd/types/table.h"                // dd::Table
50 #include "sql/dd/types/tablespace.h"
51 #include "sql/dd_sp.h"      // prepare_sp_chistics_from_dd_routine
52 #include "sql/sd_notify.h"  // sysd::notify
53 #include "sql/sp.h"         // Stored_routine_creation_ctx
54 #include "sql/sp_head.h"    // sp_head
55 #include "sql/sql_base.h"
56 #include "sql/sql_prepare.h"
57 #include "sql/strfunc.h"
58 #include "sql/table_trigger_dispatcher.h"  // Table_trigger_dispatcher
59 #include "sql/thd_raii.h"
60 #include "sql/trigger.h"  // Trigger
61 #include "sql/trigger_def.h"
62 
63 typedef ulonglong sql_mode_t;
64 extern const char *mysql_sys_schema[];
65 extern const char *fill_help_tables[];
66 
67 const char *upgrade_modes[] = {"NONE", "MINIMAL", "AUTO", "FORCE", NullS};
68 TYPELIB upgrade_mode_typelib = {array_elements(upgrade_modes) - 1, "",
69                                 upgrade_modes, nullptr};
70 
71 namespace dd {
72 namespace upgrade {
73 
74 /***************************************************************************
75  * Bootstrap_error_handler implementation
76  ***************************************************************************/
77 
my_message_bootstrap(uint error,const char * str,myf MyFlags)78 void Bootstrap_error_handler::my_message_bootstrap(uint error, const char *str,
79                                                    myf MyFlags) {
80   set_abort_on_error(error);
81   my_message_sql(error, str, MyFlags);
82   if (m_log_error)
83     LogEvent()
84         .type(LOG_TYPE_ERROR)
85         .subsys(LOG_SUBSYSTEM_TAG)
86         .prio(ERROR_LEVEL)
87         .errcode(ER_ERROR_INFO_FROM_DA)
88         .verbatim(str);
89 }
90 
set_abort_on_error(uint error)91 void Bootstrap_error_handler::set_abort_on_error(uint error) {
92   switch (error) {
93     case ER_WRONG_COLUMN_NAME: {
94       abort_on_error = true;
95       m_log_error = true;
96       break;
97     }
98     default:
99       break;
100   }
101 }
102 
Bootstrap_error_handler()103 Bootstrap_error_handler::Bootstrap_error_handler() {
104   m_old_error_handler_hook = error_handler_hook;
105   error_handler_hook = my_message_bootstrap;
106 }
107 
set_log_error(bool log_error)108 void Bootstrap_error_handler::set_log_error(bool log_error) {
109   m_log_error = log_error;
110 }
111 
~Bootstrap_error_handler()112 Bootstrap_error_handler::~Bootstrap_error_handler() {
113   error_handler_hook = m_old_error_handler_hook;
114 }
115 
116 bool Bootstrap_error_handler::m_log_error = true;
117 bool Bootstrap_error_handler::abort_on_error = false;
118 
119 /***************************************************************************
120  * Routine_event_context_guard implementation
121  ***************************************************************************/
122 
Routine_event_context_guard(THD * thd)123 Routine_event_context_guard::Routine_event_context_guard(THD *thd)
124     : m_thd(thd) {
125   m_thd = thd;
126   m_sql_mode = m_thd->variables.sql_mode;
127   m_client_cs = m_thd->variables.character_set_client;
128   m_connection_cl = m_thd->variables.collation_connection;
129   m_saved_time_zone = m_thd->variables.time_zone;
130 }
~Routine_event_context_guard()131 Routine_event_context_guard::~Routine_event_context_guard() {
132   m_thd->variables.sql_mode = m_sql_mode;
133   m_thd->variables.character_set_client = m_client_cs;
134   m_thd->variables.collation_connection = m_connection_cl;
135   m_thd->variables.time_zone = m_saved_time_zone;
136 }
137 
138 /***************************************************************************
139  * Syntax_error_handler implementation
140  ***************************************************************************/
141 
142 uint Syntax_error_handler::parse_error_count = 0;
143 bool Syntax_error_handler::is_parse_error = false;
144 dd::String_type Syntax_error_handler::reason = "";
145 const uint Syntax_error_handler::MAX_SERVER_CHECK_FAILS = 50;
146 
handle_condition(THD *,uint sql_errno,const char *,Sql_condition::enum_severity_level *,const char * msg)147 bool Syntax_error_handler::handle_condition(
148     THD *, uint sql_errno, const char *, Sql_condition::enum_severity_level *,
149     const char *msg) {
150   if (sql_errno == ER_PARSE_ERROR) {
151     parse_error_count++;
152     if (m_global_counter) (*m_global_counter)++;
153     is_parse_error = true;
154     reason = msg;
155   } else {
156     is_parse_error = false;
157     reason = "";
158   }
159   return false;
160 }
161 
has_too_many_errors()162 bool Syntax_error_handler::has_too_many_errors() {
163   return parse_error_count > MAX_SERVER_CHECK_FAILS;
164 }
165 
has_errors()166 bool Syntax_error_handler::has_errors() { return parse_error_count > 0; }
167 
error_message()168 const char *Syntax_error_handler::error_message() { return reason.c_str(); }
169 
170 /***************************************************************************
171  * Upgrade_error_handler implementation
172  ***************************************************************************/
173 
has_errors()174 bool Upgrade_error_counter::has_errors() { return (m_error_count > 0); }
has_too_many_errors()175 bool Upgrade_error_counter::has_too_many_errors() {
176   return (m_error_count > ERROR_LIMIT);
177 }
operator ++(int)178 Upgrade_error_counter Upgrade_error_counter::operator++(int) {
179   m_error_count++;
180   return *this;
181 }
182 
183 namespace {
184 
185 static std::vector<uint> ignored_errors{
186     ER_DUP_FIELDNAME, ER_DUP_KEYNAME, ER_BAD_FIELD_ERROR,
187     ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2, ER_DUP_ENTRY};
188 
189 template <typename T, typename CLOS>
examine_each(Upgrade_error_counter * error_count,std::vector<const T * > * list,CLOS && clos)190 bool examine_each(Upgrade_error_counter *error_count,
191                   std::vector<const T *> *list, CLOS &&clos) {
192   for (const T *item : *list) {
193     DBUG_ASSERT(item != nullptr);
194     clos(item);
195     if (error_count->has_too_many_errors()) return true;
196   }
197   return false;
198 }
199 
200 template <typename T>
201 class Server_option_guard {
202   T *server_opt;
203   T old_value;
204 
205  public:
Server_option_guard(T * opt,T new_value)206   Server_option_guard(T *opt, T new_value) : server_opt(opt), old_value(*opt) {
207     *server_opt = new_value;
208   }
209 
~Server_option_guard()210   ~Server_option_guard() { *server_opt = old_value; }
211 };
212 
213 class MySQL_check {
214  private:
215   std::vector<dd::String_type> alter_cmds, repairs;
216   bool needs_repair;
217 
escape_str(const dd::String_type & src)218   static dd::String_type escape_str(const dd::String_type &src) {
219     dd::String_type res = "`";
220     for (size_t i = 0; i < src.size(); i++) {
221       if (src[i] == '`') res += '`';
222       res += src[i];
223     }
224     res += "`";
225     return res;
226   }
227 
comma_seperated_join(std::vector<dd::String_type> & list,dd::String_type & dest)228   void comma_seperated_join(std::vector<dd::String_type> &list,
229                             dd::String_type &dest) {
230     dest = list[0];
231     for (auto it = list.begin() + 1; it != list.end(); it++) dest += "," + *it;
232   }
233 
get_schema_tables(THD * thd,const char * schema,dd::String_type & tables_list)234   bool get_schema_tables(THD *thd, const char *schema,
235                          dd::String_type &tables_list) {
236     Schema_MDL_locker mdl_handler(thd);
237     dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
238     const dd::Schema *sch = nullptr;
239     std::vector<const dd::Table *> tables;
240     dd::Stringstream_type t_list;
241 
242     if (mdl_handler.ensure_locked(schema) ||
243         thd->dd_client()->acquire(schema, &sch) ||
244         thd->dd_client()->fetch_schema_components(sch, &tables)) {
245       LogErr(ERROR_LEVEL, ER_DD_UPGRADE_FAILED_TO_FETCH_TABLES);
246       return (true);
247     }
248 
249     bool first = true;
250     std::for_each(tables.begin(), tables.end(), [&](const dd::Table *table) {
251       if (table->type() != dd::enum_table_type::BASE_TABLE ||
252           table->hidden() != dd::Abstract_table::HT_VISIBLE)
253         return;
254       if (!first) t_list << ", ";
255       first = false;
256       t_list << escape_str(sch->name()) << "." << escape_str(table->name());
257     });
258 
259     tables_list = t_list.str();
260     return false;
261   }
262 
check_table(List<Ed_row>::iterator & it,const List<Ed_row>::iterator & end,bool repair)263   bool check_table(List<Ed_row>::iterator &it,
264                    const List<Ed_row>::iterator &end, bool repair) {
265     Ed_row &row = *it;
266     const char *table = row[0].str, *alter_txt = nullptr;
267     bool found_error = false;
268     it++;
269 
270     while (strcmp(row[2].str, "status")) {
271       if (strcmp(row[2].str, "note")) {
272         found_error = true;
273         alter_txt = strstr(row[3].str, "ALTER TABLE");
274       }
275       if (it == end || strcmp((*it)[0].str, table)) break;
276       row = *it;
277       ++it;
278     }
279 
280     if (found_error && strcmp(row[3].str, "OK")) {
281       if (repair) {
282         LogErr(ERROR_LEVEL, ER_SERVER_UPGRADE_REPAIR_STATUS, table, "failed");
283         return true;
284       } else
285         LogErr(WARNING_LEVEL, ER_SERVER_UPGRADE_REPAIR_REQUIRED, table);
286       if (alter_txt)
287         alter_cmds.push_back(dd::String_type(alter_txt));
288       else
289         repairs.push_back(dd::String_type(table));
290     } else if (repair) {
291       LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_REPAIR_STATUS, table,
292              "successful");
293     } else
294       found_error = false;
295 
296     return found_error;
297   }
298 
verify_response(List<Ed_row> & rset,bool repair)299   bool verify_response(List<Ed_row> &rset, bool repair) {
300     auto it = rset.begin();
301     bool error = false;
302     while (it != rset.end()) error |= check_table(it, rset.end(), repair);
303     return error;
304   }
305 
306   /**
307     Returns true if something went wrong while retreving the table list or
308     executing CHECK TABLE statements.
309   */
check_tables(THD * thd,const char * schema)310   bool check_tables(THD *thd, const char *schema) {
311     Ed_connection con(thd);
312     dd::String_type tables;
313     LEX_STRING str;
314 
315     LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_CHECKING_DB, schema);
316     if (get_schema_tables(thd, schema, tables)) return true;
317     if (tables.size() == 0) return false;
318 
319     dd::String_type query = "CHECK TABLE " + tables + " FOR UPGRADE";
320     lex_string_strmake(thd->mem_root, &str, query.c_str(), query.size());
321     if (con.execute_direct(str)) return true;
322 
323     needs_repair |= verify_response(*con.get_result_sets(), false);
324     return false;
325   }
326 
327  public:
MySQL_check()328   MySQL_check() : needs_repair(false) {}
329 
check_all_schemas(THD * thd)330   bool check_all_schemas(THD *thd) {
331     std::vector<dd::String_type> schemas;
332     if (thd->dd_client()->fetch_global_component_names<dd::Schema>(&schemas))
333       return true;
334     for (dd::String_type &schema : schemas) {
335       if (schema.compare("information_schema") == 0 ||
336           schema.compare("performance_schema") == 0)
337         continue;
338       if (check_tables(thd, schema.c_str())) return true;
339     }
340     return false;
341   }
342 
check_system_schemas(THD * thd)343   bool check_system_schemas(THD *thd) {
344     return check_tables(thd, "mysql") || check_tables(thd, "sys");
345   }
346 
repair_tables(THD * thd)347   bool repair_tables(THD *thd) {
348     if (!needs_repair) return false;
349 
350     for (auto &alter : alter_cmds)
351       if (dd::execute_query(thd, alter)) return true;
352     alter_cmds.clear();
353 
354     if (repairs.size() == 0) return false;
355     dd::String_type tables;
356     comma_seperated_join(repairs, tables);
357 
358     Ed_connection con(thd);
359     LEX_STRING str;
360     dd::String_type query = "REPAIR TABLE " + tables;
361     lex_string_strmake(thd->mem_root, &str, query.c_str(), query.size());
362     if (con.execute_direct(str)) return true;
363     repairs.clear();
364     needs_repair = false;
365     (void)verify_response(*con.get_result_sets(), true);
366     return false;
367   }
368 };
369 
ignore_error_and_execute(THD * thd,const char * query_ptr)370 bool ignore_error_and_execute(THD *thd, const char *query_ptr) {
371   Ed_connection con(thd);
372   LEX_STRING str;
373   lex_string_strmake(thd->mem_root, &str, query_ptr, strlen(query_ptr));
374 
375   // These are the same errors ignored in the mysql_upgrade client
376   if (con.execute_direct(str) &&
377       std::find(ignored_errors.begin(), ignored_errors.end(),
378                 con.get_last_errno()) == ignored_errors.end()) {
379     LogErr(ERROR_LEVEL, ER_DD_INITIALIZE_SQL_ERROR, query_ptr,
380            con.get_last_errno(), con.get_last_error());
381     return true;
382   }
383   return false;
384 }
385 
fix_sys_schema(THD * thd)386 bool fix_sys_schema(THD *thd) {
387   /*
388     Re-create SYS schema if:
389 
390     - There is a server upgrade going on.
391     - Or the SYS schema does not exist.
392 
393     With the SYS schema versioning removed, we make sure there is indeed
394     a server upgrade going on before we re-create the SYS schema. This has
395     the consequence that upgrade=FORCE will not re-create the SYS schema,
396     unless it does not exist. This is in line with the old behavior of the
397     SYS schema versioning and upgrade.
398   */
399   Schema_MDL_locker mdl_handler(thd);
400   dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
401   const dd::Schema *sch = nullptr;
402   if (mdl_handler.ensure_locked("sys") ||
403       thd->dd_client()->acquire("sys", &sch))
404     return true;
405 
406   if (sch != nullptr &&
407       !dd::bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade() &&
408       (opt_upgrade_mode != UPGRADE_FORCE))
409     return false;
410 
411   const char **query_ptr;
412   LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_SYS_SCHEMA);
413   thd->user_var_events_alloc = thd->mem_root;
414   for (query_ptr = &mysql_sys_schema[0]; *query_ptr != nullptr; query_ptr++)
415     if (ignore_error_and_execute(thd, *query_ptr)) return true;
416   thd->mem_root->Clear();
417   return false;
418 }
419 
fix_mysql_tables(THD * thd)420 bool fix_mysql_tables(THD *thd) {
421   const char **query_ptr;
422 
423   if (ignore_error_and_execute(thd, "USE mysql")) {
424     LogErr(ERROR_LEVEL, ER_DD_UPGRADE_FAILED_FIND_VALID_DATA_DIR);
425     return true;
426   }
427 
428   LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_MYSQL_TABLES);
429   for (query_ptr = &mysql_fix_privilege_tables[0]; *query_ptr != nullptr;
430        query_ptr++)
431     if (ignore_error_and_execute(thd, *query_ptr)) return true;
432 
433   LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_SYSTEM_TABLES);
434   for (query_ptr = &mysql_system_tables_data_fix[0]; *query_ptr != nullptr;
435        query_ptr++)
436     if (ignore_error_and_execute(thd, *query_ptr)) return true;
437 
438   return false;
439 }
440 
upgrade_help_tables(THD * thd)441 bool upgrade_help_tables(THD *thd) {
442   if (dd::execute_query(thd, "USE mysql")) {
443     LogErr(ERROR_LEVEL, ER_DD_UPGRADE_FAILED_FIND_VALID_DATA_DIR);
444     return true;
445   }
446   LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_HELP_TABLE_STATUS, "started");
447   for (const char **query_ptr = &fill_help_tables[0]; *query_ptr != nullptr;
448        query_ptr++)
449     if (dd::execute_query(thd, *query_ptr)) {
450       LogErr(ERROR_LEVEL, ER_SERVER_UPGRADE_HELP_TABLE_STATUS, "failed");
451       return true;
452     }
453   LogErr(INFORMATION_LEVEL, ER_SERVER_UPGRADE_HELP_TABLE_STATUS, "completed");
454   return false;
455 }
456 
create_upgrade_file()457 static void create_upgrade_file() {
458   FILE *out;
459   char upgrade_info_file[FN_REFLEN] = {0};
460   fn_format(upgrade_info_file, "mysql_upgrade_info", mysql_real_data_home_ptr,
461             "", MYF(0));
462 
463   if ((out = my_fopen(upgrade_info_file, O_TRUNC | O_WRONLY, MYF(0)))) {
464     /* Write new version to file */
465     fputs(MYSQL_SERVER_VERSION, out);
466     my_fclose(out, MYF(0));
467     return;
468   }
469   LogErr(WARNING_LEVEL, ER_SERVER_UPGRADE_INFO_FILE, upgrade_info_file);
470 }
471 
472 }  // namespace
473 
474 /*
475   This function runs checks on the database before running the upgrade to make
476   sure that the database is ready to be upgraded to a newer version. New checks
477   can be added as required. Returns false if the database can be upgraded.
478 */
do_server_upgrade_checks(THD * thd)479 bool do_server_upgrade_checks(THD *thd) {
480   if (!dd::bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade_from_after(
481           bootstrap::SERVER_VERSION_50700))
482     return false;
483 
484   dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
485   Upgrade_error_counter error_count;
486 
487   /*
488     For any server upgrade, we will analyze events, routines, views and
489     triggers and reject upgrade if we find invalid syntax that would not
490     have been accepted in a CREATE statement.
491   */
492   std::vector<const dd::Schema *> schema_vector;
493   if (thd->dd_client()->fetch_global_components(&schema_vector))
494     return dd::end_transaction(thd, true);
495 
496   Syntax_error_handler error_handler(&error_count);
497   thd->push_internal_handler(&error_handler);
498 
499   for (const dd::Schema *schema : schema_vector) {
500     std::vector<const dd::Table *> tables;
501     if (thd->dd_client()->fetch_schema_components(schema, &tables))
502       return dd::end_transaction(thd, true);
503 
504     if (examine_each(&error_count, &tables, [&](const dd::Table *table) {
505           (void)invalid_triggers(thd, schema->name().c_str(), *table);
506           // Check for usage of prefix key index in PARTITION BY KEY() function.
507           dd::warn_on_deprecated_prefix_key_partition(
508               thd, schema->name().c_str(), table->name().c_str(), table, true);
509         }))
510       break;
511 
512     std::vector<const dd::Event *> events;
513     if (thd->dd_client()->fetch_schema_components(schema, &events))
514       return dd::end_transaction(thd, true);
515 
516     if (examine_each(&error_count, &events, [&](const dd::Event *event) {
517           dd::String_type sql;
518           if (build_event_sp(thd, event->name().c_str(), event->name().size(),
519                              event->definition().c_str(),
520                              event->definition().size(), &sql) ||
521               invalid_sql(thd, schema->name().c_str(), sql))
522             LogErr(ERROR_LEVEL, ER_UPGRADE_PARSE_ERROR, "Event",
523                    schema->name().c_str(), event->name().c_str(),
524                    Syntax_error_handler::error_message());
525           return false;
526         }))
527       break;
528 
529     std::vector<const dd::Routine *> routines;
530     if (thd->dd_client()->fetch_schema_components(schema, &routines))
531       return dd::end_transaction(thd, true);
532 
533     if (examine_each(&error_count, &routines, [&](const dd::Routine *routine) {
534           if (invalid_routine(thd, *schema, *routine))
535             LogErr(ERROR_LEVEL, ER_UPGRADE_PARSE_ERROR, "Routine",
536                    schema->name().c_str(), routine->name().c_str(),
537                    Syntax_error_handler::error_message());
538           return false;
539         }))
540       break;
541 
542     std::vector<const dd::View *> views;
543     if (thd->dd_client()->fetch_schema_components(schema, &views))
544       return dd::end_transaction(thd, true);
545 
546     if (examine_each(&error_count, &views, [&](const dd::View *view) {
547           if (invalid_sql(thd, schema->name().c_str(), view->definition()))
548             LogErr(ERROR_LEVEL, ER_UPGRADE_PARSE_ERROR, "View",
549                    schema->name().c_str(), view->name().c_str(),
550                    Syntax_error_handler::error_message());
551           return false;
552         }))
553       break;
554   }
555   thd->pop_internal_handler();
556 
557   /*
558     If upgrade is crossing 8.0.13, we need to look out for partitioned
559     tables having partitions in shared tablespaces, and err out
560     if this is found. We reuse the schema vector that was retrieved above.
561     We do this only if the number of soft errors found so far is below the
562     defined limit.
563   */
564   if (!error_count.has_too_many_errors() &&
565       dd::bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade_from_before(
566           bootstrap::SERVER_VERSION_80013)) {
567     /*
568       Get hold of the InnoDB handlerton. The check for partitioned tables
569       using shared tablespaces is only relevant for InnoDB.
570     */
571     plugin_ref pr =
572         ha_resolve_by_name_raw(thd, LEX_CSTRING{STRING_WITH_LEN("InnoDB")});
573     handlerton *hton =
574         (pr != nullptr ? plugin_data<handlerton *>(pr) : nullptr);
575     DBUG_ASSERT(hton != nullptr && hton->get_tablespace_type);
576 
577     /*
578       Get hold of all tablespaces, keep the non-implicit InnoDB spaces
579       in a map.
580     */
581     std::vector<const dd::Tablespace *> tablespaces;
582     if (thd->dd_client()->fetch_global_components(&tablespaces))
583       return dd::end_transaction(thd, true);
584 
585     std::map<const String_type, const dd::Tablespace *> invalid_spaces;
586     for (const dd::Tablespace *space : tablespaces) {
587       if (my_strcasecmp(system_charset_info, space->engine().c_str(),
588                         "InnoDB") != 0)
589         continue;
590 
591       Tablespace_type space_type;
592       if (hton->get_tablespace_type(*space, &space_type)) {
593         LogErr(ERROR_LEVEL, ER_UNKNOWN_TABLESPACE_TYPE, space->name().c_str());
594         return dd::end_transaction(thd, true);
595       }
596 
597       if (space_type != Tablespace_type::SPACE_TYPE_IMPLICIT) {
598         invalid_spaces.insert(
599             std::pair<const String_type, const dd::Tablespace *>(space->name(),
600                                                                  space));
601       }
602     }
603 
604     /*
605       For each schema, get all tables, check if the partitioned InnoDB tables
606       are using a shared tablespace. If so, print an error in the error log,
607       but continue to analyze additional tables.
608     */
609     for (const dd::Schema *schema : schema_vector) {
610       /*
611         If we got to the error limit, exit. We check this only here, since if
612         we get hold of all tables in a schema (i.e., complete the expensive
613         part), we may as well analyze them all before checking if we exceeded
614         the error limit.
615       */
616       if (error_count.has_too_many_errors()) break;
617 
618       std::vector<const dd::Table *> tables;
619       /* Cannot continue if we have a DD error. */
620       if (thd->dd_client()->fetch_schema_components(schema, &tables))
621         return dd::end_transaction(thd, true);
622 
623       for (const dd::Table *table : tables) {
624         /* Only consider partitioned InnoDB tables. */
625         if (table->partition_type() == dd::Table::PT_NONE ||
626             my_strcasecmp(system_charset_info, table->engine().c_str(),
627                           "InnoDB") != 0)
628           continue;
629 
630         Tablespace_hash_set space_names(PSI_INSTRUMENT_ME);
631         if (fill_table_and_parts_tablespace_names(thd, schema->name().c_str(),
632                                                   table->name().c_str(),
633                                                   &space_names))
634           return dd::end_transaction(thd, true);
635 
636         for (const std::string &name : space_names) {
637           if (invalid_spaces.find(String_type(name.c_str())) !=
638               invalid_spaces.end()) {
639             error_count++;
640             LogErr(ERROR_LEVEL, ER_SHARED_TABLESPACE_USED_BY_PARTITIONED_TABLE,
641                    table->name().c_str(), name.c_str());
642           }
643         }
644       }
645     }
646   }
647 
648   /*
649     If there are errors from any of the checks, we abort upgrade.
650   */
651   if (error_count.has_errors()) return dd::end_transaction(thd, true);
652 
653   return false;
654 }
655 
656 /**
657   Validate a dd::Routine object.
658 */
invalid_routine(THD * thd,const dd::Schema & schema,const dd::Routine & routine)659 bool invalid_routine(THD *thd, const dd::Schema &schema,
660                      const dd::Routine &routine) {
661   Routine_event_context_guard guard(thd);
662   sp_head *sp = nullptr;
663   st_sp_chistics chistics;
664   prepare_sp_chistics_from_dd_routine(&routine, &chistics);
665 
666   dd::String_type return_type_str;
667   prepare_return_type_string_from_dd_routine(thd, &routine, &return_type_str);
668 
669   // Create SP creation context to be used in db_load_routine()
670   Stored_program_creation_ctx *creation_ctx =
671       Stored_routine_creation_ctx::create_routine_creation_ctx(&routine);
672 
673   thd->variables.character_set_client = creation_ctx->get_client_cs();
674   thd->variables.collation_connection = creation_ctx->get_connection_cl();
675   thd->update_charset();
676 
677   enum_sp_return_code error = db_load_routine(
678       thd,
679       routine.type() == dd::Routine::RT_FUNCTION ? enum_sp_type::FUNCTION
680                                                  : enum_sp_type::PROCEDURE,
681       schema.name().c_str(), schema.name().size(), routine.name().c_str(),
682       routine.name().size(), &sp, routine.sql_mode(),
683       routine.parameter_str().c_str(), return_type_str.c_str(),
684       routine.definition().c_str(), &chistics, routine.definer_user().c_str(),
685       routine.definer_host().c_str(), routine.created(true),
686       routine.last_altered(true), creation_ctx);
687 
688   if (sp != nullptr)  // To be safe
689     sp_head::destroy(sp);
690 
691   if (error) return (thd->get_stmt_da()->mysql_errno() == ER_PARSE_ERROR);
692   thd->clear_error();
693   return false;
694 }
695 
696 /**
697   Validate all the triggers of the given table.
698 */
invalid_triggers(THD * thd,const char * schema_name,const dd::Table & table)699 bool invalid_triggers(THD *thd, const char *schema_name,
700                       const dd::Table &table) {
701   if (!table.has_trigger()) return false;
702   List<::Trigger> triggers;
703   if (dd::load_triggers(thd, thd->mem_root, schema_name, table.name().c_str(),
704                         table, &triggers))
705     return true;
706   for (::Trigger &t : triggers) {
707     if (t.parse(thd, false) || t.has_parse_error()) {
708       LogEvent()
709           .type(LOG_TYPE_ERROR)
710           .subsys(LOG_SUBSYSTEM_TAG)
711           .prio(ERROR_LEVEL)
712           .errcode(ER_UPGRADE_PARSE_ERROR)
713           .verbatim(t.get_parse_error_message());
714       thd->clear_error();
715     }
716     sp_head::destroy(t.get_sp());
717     if (Syntax_error_handler::has_too_many_errors()) return true;
718   }
719   return Syntax_error_handler::has_errors();
720 }
721 
invalid_sql(THD * thd,const char * dbname,const dd::String_type & sql)722 bool invalid_sql(THD *thd, const char *dbname, const dd::String_type &sql) {
723   bool error = false;
724   Parser_state *old = thd->m_parser_state;
725   Parser_state parser_state;
726 
727   if (parser_state.init(thd, sql.c_str(), sql.size())) return true;
728 
729   LEX_CSTRING old_db = thd->db();
730   LEX lex, *lex_saved = thd->lex;
731 
732   thd->reset_db(to_lex_cstring(dbname));
733   thd->lex = &lex;
734   lex_start(thd);
735 
736   thd->m_parser_state = &parser_state;
737   parser_state.m_lip.m_digest = nullptr;
738 
739   if (thd->sql_parser())
740     error = (thd->get_stmt_da()->mysql_errno() == ER_PARSE_ERROR);
741 
742   lex_end(thd->lex);
743   thd->lex = lex_saved;
744   thd->reset_db(old_db);
745   thd->m_parser_state = old;
746   thd->clear_error();
747 
748   return error;
749 }
750 
751 /**
752   Helper function to create a stored procedure from an event body.
753 */
build_event_sp(const THD * thd,const char * name,size_t name_len,const char * body,size_t body_len,dd::String_type * sp_sql)754 bool build_event_sp(const THD *thd, const char *name, size_t name_len,
755                     const char *body, size_t body_len,
756                     dd::String_type *sp_sql) {
757   const uint STATIC_SQL_LENGTH = 44;
758   String temp(STATIC_SQL_LENGTH + name_len + body_len);
759 
760   temp.append(STRING_WITH_LEN("CREATE "));
761   temp.append(STRING_WITH_LEN("PROCEDURE "));
762 
763   append_identifier(thd, &temp, name, name_len);
764 
765   temp.append(STRING_WITH_LEN("() SQL SECURITY INVOKER "));
766   temp.append(body, body_len);
767 
768   *sp_sql = temp.ptr();
769   return false;
770 }
771 
upgrade_system_schemas(THD * thd)772 bool upgrade_system_schemas(THD *thd) {
773   Disable_autocommit_guard autocommit_guard(thd);
774   Bootstrap_error_handler bootstrap_error_handler;
775 
776   Server_option_guard<bool> acl_guard(&opt_noacl, true);
777   Server_option_guard<bool> general_log_guard(&opt_general_log, false);
778   Server_option_guard<bool> slow_log_guard(&opt_slow_log, false);
779   Server_option_guard<bool> bin_log_guard(&thd->variables.sql_log_bin, false);
780 
781   uint server_version = MYSQL_VERSION_ID;
782   bool exists_version = false;
783 
784   if (dd::tables::DD_properties::instance().get(
785           thd, "MYSQLD_VERSION_UPGRADED", &server_version, &exists_version) ||
786       !exists_version)
787     if (dd::tables::DD_properties::instance().get(
788             thd, "MYSQLD_VERSION", &server_version, &exists_version) ||
789         !exists_version)
790       return true;
791 
792   MySQL_check check;
793 
794   LogErr(SYSTEM_LEVEL, ER_SERVER_UPGRADE_STATUS, server_version,
795          MYSQL_VERSION_ID, "started");
796   log_sink_buffer_check_timeout();
797   sysd::notify("STATUS=Server upgrade in progress\n");
798 
799   bootstrap_error_handler.set_log_error(false);
800   bool err =
801       fix_mysql_tables(thd) || fix_sys_schema(thd) ||
802       upgrade_help_tables(thd) ||
803       (DBUG_EVALUATE_IF(
804            "force_fix_user_schemas", true,
805            dd::bootstrap::DD_bootstrap_ctx::instance()
806                .is_server_upgrade_from_before(bootstrap::SERVER_VERSION_80011))
807            ? check.check_all_schemas(thd)
808            : check.check_system_schemas(thd)) ||
809       check.repair_tables(thd) ||
810       dd::tables::DD_properties::instance().set(thd, "MYSQLD_VERSION_UPGRADED",
811                                                 MYSQL_VERSION_ID);
812 
813   create_upgrade_file();
814   bootstrap_error_handler.set_log_error(true);
815 
816   if (!err)
817     LogErr(SYSTEM_LEVEL, ER_SERVER_UPGRADE_STATUS, server_version,
818            MYSQL_VERSION_ID, "completed");
819   log_sink_buffer_check_timeout();
820   sysd::notify("STATUS=Server upgrade complete\n");
821 
822   /*
823    * During server startup, dd::reset_tables_and_tablespaces is called, which
824    * calls innobase_dict_cache_reset_tables_and_tablespaces. This tries to clear
825    * the open tables cache. But not able to, which causes an assert. So we force
826    * close everything.
827    */
828   close_thread_tables(thd);
829   close_cached_tables(nullptr, nullptr, false, LONG_TIMEOUT);
830 
831   return dd::end_transaction(thd, err);
832 }
833 
no_server_upgrade_required()834 bool no_server_upgrade_required() {
835   return !(dd::bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade() ||
836            opt_upgrade_mode == UPGRADE_FORCE);
837 }
838 
I_S_upgrade_required()839 bool I_S_upgrade_required() {
840   return dd::bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade() ||
841          dd::bootstrap::DD_bootstrap_ctx::instance().I_S_upgrade_done() ||
842          opt_upgrade_mode == UPGRADE_FORCE;
843 }
844 
845 }  // namespace upgrade
846 }  // namespace dd
847