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