1717
1818#include " ../client_priv.h"
1919#include < string>
20+ #include < sstream>
2021#include < vector>
2122#include < algorithm>
2223#include < memory>
2627#include " my_default.h"
2728#include " check/mysqlcheck.h"
2829#include " ../scripts/mysql_fix_privilege_tables_sql.c"
30+ #include " ../scripts/sql_commands_sys_schema.h"
2931
3032#include " base/abstract_connection_program.h"
3133#include " base/abstract_options_provider.h"
3234#include " show_variable_query_extractor.h"
3335
3436using std::string;
3537using std::vector;
38+ using std::stringstream;
3639
3740int mysql_check_errors;
3841
42+ const int SYS_TABLE_COUNT = 1 ;
43+ const int SYS_VIEW_COUNT = 91 ;
44+ const int SYS_TRIGGER_COUNT = 2 ;
45+ const int SYS_FUNCTION_COUNT = 14 ;
46+ const int SYS_PROCEDURE_COUNT = 22 ;
47+
3948/* *
4049 Error callback to be called from mysql_check functionality.
4150 */
@@ -57,6 +66,7 @@ namespace Upgrade{
5766
5867using std::vector;
5968using std::string;
69+ using std::stringstream;
6070
6171enum exit_codes
6272{
@@ -184,6 +194,226 @@ class Program : public Base::Abstract_connection_program
184194 }
185195 }
186196
197+ if (this ->m_skip_sys_schema == false )
198+ {
199+ /*
200+ If the sys schema does not exist, then create it
201+ Otherwise, try to select from sys.version, if this does not
202+ exist but the schema does, then raise an error rather than
203+ overwriting/adding to the existing schema
204+ */
205+ if (mysql_query (this ->m_mysql_connection , " USE sys" ) != 0 )
206+ {
207+ if (this ->run_sys_schema_upgrade () != 0 )
208+ {
209+ return EXIT_UPGRADING_QUERIES_ERROR;
210+ }
211+ } else {
212+ /* If the version is smaller, upgrade */
213+ if (mysql_query (this ->m_mysql_connection , " SELECT * FROM sys.version" ) != 0 )
214+ {
215+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
216+ " A sys schema exists with no sys.version view. "
217+ " If you have a user created sys schema, this must be "
218+ " renamed for the upgrade to succeed." );
219+ } else {
220+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
221+ if (result)
222+ {
223+ MYSQL_ROW row;
224+
225+ while ((row = mysql_fetch_row (result)))
226+ {
227+ ulong sys_version = calc_server_version (row[0 ]);
228+ if (sys_version >= calc_server_version (SYS_SCHEMA_VERSION))
229+ {
230+ stringstream ss;
231+ ss << " The sys schema is already up to date (version " << row[0 ] << " )." ;
232+ this ->print_verbose_message (ss.str ());
233+ } else {
234+ stringstream ss;
235+ ss << " Found outdated sys schema version " << row[0 ] << " ." ;
236+ this ->print_verbose_message (ss.str ());
237+ if (this ->run_sys_schema_upgrade () != 0 )
238+ {
239+ return EXIT_UPGRADING_QUERIES_ERROR;
240+ }
241+ }
242+ }
243+ mysql_free_result (result);
244+ } else {
245+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
246+ " A sys schema exists with a sys.version view, but it returns no results." );
247+ }
248+ }
249+ /*
250+ The version may be the same, but in some upgrade scenarios
251+ such as importing a 5.6 dump in to a fresh 5.7 install that
252+ includes the mysql schema, and then running mysql_upgrade,
253+ the functions/procedures will be removed.
254+
255+ In this case, we check for the expected counts of objects,
256+ and if those do not match, we just re-install the schema.
257+ */
258+ if (mysql_query (this ->m_mysql_connection ,
259+ " SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sys' AND TABLE_TYPE = 'BASE TABLE'" ) != 0 )
260+ {
261+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
262+ " Query against INFORMATION_SCHEMA.TABLES failed when checking the sys schema." );
263+ } else {
264+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
265+ if (result)
266+ {
267+ MYSQL_ROW row;
268+
269+ while ((row = mysql_fetch_row (result)))
270+ {
271+ if (SYS_TABLE_COUNT != atoi (row[0 ]))
272+ {
273+ stringstream ss;
274+ ss << " Found " << row[0 ] << " sys tables, but expected " << SYS_TABLE_COUNT << " ."
275+ " Re-installing the sys schema." ;
276+ this ->print_verbose_message (ss.str ());
277+ if (this ->run_sys_schema_upgrade () != 0 )
278+ {
279+ return EXIT_UPGRADING_QUERIES_ERROR;
280+ }
281+ }
282+ }
283+
284+ mysql_free_result (result);
285+ }
286+ }
287+
288+ if (mysql_query (this ->m_mysql_connection ,
289+ " SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sys' AND TABLE_TYPE = 'VIEW'" ) != 0 )
290+ {
291+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
292+ " Query against INFORMATION_SCHEMA.TABLES failed when checking the sys schema." );
293+ } else {
294+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
295+ if (result)
296+ {
297+ MYSQL_ROW row;
298+
299+ while ((row = mysql_fetch_row (result)))
300+ {
301+ if (SYS_VIEW_COUNT != atoi (row[0 ]))
302+ {
303+ stringstream ss;
304+ ss << " Found " << row[0 ] << " sys views, but expected " << SYS_VIEW_COUNT << " ."
305+ " Re-installing the sys schema." ;
306+ this ->print_verbose_message (ss.str ());
307+ if (this ->run_sys_schema_upgrade () != 0 )
308+ {
309+ return EXIT_UPGRADING_QUERIES_ERROR;
310+ }
311+ }
312+ }
313+
314+ mysql_free_result (result);
315+ }
316+ }
317+
318+ if (mysql_query (this ->m_mysql_connection ,
319+ " SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = 'sys'" ) != 0 )
320+ {
321+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
322+ " Query against INFORMATION_SCHEMA.TABLES failed when checking the sys schema." );
323+ } else {
324+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
325+ if (result)
326+ {
327+ MYSQL_ROW row;
328+
329+ while ((row = mysql_fetch_row (result)))
330+ {
331+ if (SYS_TRIGGER_COUNT != atoi (row[0 ]))
332+ {
333+ stringstream ss;
334+ ss << " Found " << row[0 ] << " sys triggers, but expected " << SYS_TRIGGER_COUNT << " ."
335+ " Re-installing the sys schema." ;
336+ this ->print_verbose_message (ss.str ());
337+ if (this ->run_sys_schema_upgrade () != 0 )
338+ {
339+ return EXIT_UPGRADING_QUERIES_ERROR;
340+ }
341+ }
342+ }
343+
344+ mysql_free_result (result);
345+ }
346+ }
347+
348+ if (mysql_query (this ->m_mysql_connection ,
349+ " SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'sys' AND ROUTINE_TYPE = 'FUNCTION'" ) != 0 )
350+ {
351+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
352+ " Query against INFORMATION_SCHEMA.TABLES failed when checking the sys schema." );
353+ } else {
354+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
355+ if (result)
356+ {
357+ MYSQL_ROW row;
358+
359+ while ((row = mysql_fetch_row (result)))
360+ {
361+ if (SYS_FUNCTION_COUNT != atoi (row[0 ]))
362+ {
363+ stringstream ss;
364+ ss << " Found " << row[0 ] << " sys functions, but expected " << SYS_FUNCTION_COUNT << " ."
365+ " Re-installing the sys schema." ;
366+ this ->print_verbose_message (ss.str ());
367+ if (this ->run_sys_schema_upgrade () != 0 )
368+ {
369+ return EXIT_UPGRADING_QUERIES_ERROR;
370+ }
371+ }
372+ }
373+
374+ mysql_free_result (result);
375+ }
376+ }
377+
378+ if (mysql_query (this ->m_mysql_connection ,
379+ " SELECT COUNT(*) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'sys' AND ROUTINE_TYPE = 'PROCEDURE'" ) != 0 )
380+ {
381+ return this ->print_error (EXIT_UPGRADING_QUERIES_ERROR,
382+ " Query against INFORMATION_SCHEMA.TABLES failed when checking the sys schema." );
383+ } else {
384+ MYSQL_RES *result = mysql_store_result (this ->m_mysql_connection );
385+ if (result)
386+ {
387+ MYSQL_ROW row;
388+
389+ while ((row = mysql_fetch_row (result)))
390+ {
391+ if (SYS_PROCEDURE_COUNT != atoi (row[0 ]))
392+ {
393+ stringstream ss;
394+ ss << " Found " << row[0 ] << " sys procedures, but expected " << SYS_PROCEDURE_COUNT << " ."
395+ " Re-installing the sys schema." ;
396+ this ->print_verbose_message (ss.str ());
397+ if (this ->run_sys_schema_upgrade () != 0 )
398+ {
399+ return EXIT_UPGRADING_QUERIES_ERROR;
400+ }
401+ }
402+ }
403+
404+ mysql_free_result (result);
405+ }
406+ }
407+
408+ }
409+ if (mysql_query (this ->m_mysql_connection , " USE mysql" ) != 0 )
410+ {
411+ return this ->print_error (1 , " Cannot select mysql database." );
412+ }
413+ } else {
414+ this ->print_verbose_message (" Skipping installation/upgrade of the sys schema." );
415+ }
416+
187417 if (!this ->m_upgrade_systables_only )
188418 {
189419 this ->print_verbose_message (" Checking databases." );
@@ -236,6 +466,10 @@ class Program : public Base::Abstract_connection_program
236466 " Force execution of SQL statements even if mysql_upgrade has already "
237467 " been executed for the current version of MySQL." )
238468 ->set_short_character (' f' );
469+
470+ this ->create_new_option (&this ->m_skip_sys_schema , " skip-sys-schema" ,
471+ " Do not upgrade/install the sys schema." )
472+ ->set_value (false );
239473 }
240474
241475 void error (int error_code)
@@ -322,6 +556,39 @@ class Program : public Base::Abstract_connection_program
322556 return 0 ;
323557 }
324558
559+ /* *
560+ Update the sys schema
561+ */
562+ int run_sys_schema_upgrade ()
563+ {
564+ const char **query_ptr;
565+ int result;
566+
567+ Mysql_query_runner runner (*this ->m_query_runner );
568+ runner.add_result_callback (
569+ new Instance_callback<int , vector<string>, Program>(
570+ this , &Program::result_callback));
571+ runner.add_message_callback (
572+ new Instance_callback<int , Mysql_message, Program>(
573+ this , &Program::fix_privilage_tables_error));
574+
575+ this ->print_verbose_message (" Upgrading the sys schema." );
576+
577+ for ( query_ptr= &mysql_sys_schema[0 ];
578+ *query_ptr != NULL ;
579+ query_ptr++
580+ )
581+ {
582+ result= runner.run_query (*query_ptr);
583+ if (!this ->m_ignore_errors && result != 0 )
584+ {
585+ return result;
586+ }
587+ }
588+
589+ return 0 ;
590+ }
591+
325592 /* *
326593 Gets path to file to write upgrade info into. Path is based on datadir of
327594 server.
@@ -637,6 +904,7 @@ class Program : public Base::Abstract_connection_program
637904 Mysql_query_runner* m_query_runner;
638905 bool m_write_binlog;
639906 bool m_upgrade_systables_only;
907+ bool m_skip_sys_schema;
640908 bool m_check_version;
641909 bool m_ignore_errors;
642910 bool m_verbose;
0 commit comments