17
17
18
18
#include " ../client_priv.h"
19
19
#include < string>
20
+ #include < sstream>
20
21
#include < vector>
21
22
#include < algorithm>
22
23
#include < memory>
26
27
#include " my_default.h"
27
28
#include " check/mysqlcheck.h"
28
29
#include " ../scripts/mysql_fix_privilege_tables_sql.c"
30
+ #include " ../scripts/sql_commands_sys_schema.h"
29
31
30
32
#include " base/abstract_connection_program.h"
31
33
#include " base/abstract_options_provider.h"
32
34
#include " show_variable_query_extractor.h"
33
35
34
36
using std::string;
35
37
using std::vector;
38
+ using std::stringstream;
36
39
37
40
int mysql_check_errors;
38
41
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
+
39
48
/* *
40
49
Error callback to be called from mysql_check functionality.
41
50
*/
@@ -57,6 +66,7 @@ namespace Upgrade{
57
66
58
67
using std::vector;
59
68
using std::string;
69
+ using std::stringstream;
60
70
61
71
enum exit_codes
62
72
{
@@ -184,6 +194,226 @@ class Program : public Base::Abstract_connection_program
184
194
}
185
195
}
186
196
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
+
187
417
if (!this ->m_upgrade_systables_only )
188
418
{
189
419
this ->print_verbose_message (" Checking databases." );
@@ -236,6 +466,10 @@ class Program : public Base::Abstract_connection_program
236
466
" Force execution of SQL statements even if mysql_upgrade has already "
237
467
" been executed for the current version of MySQL." )
238
468
->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 );
239
473
}
240
474
241
475
void error (int error_code)
@@ -322,6 +556,39 @@ class Program : public Base::Abstract_connection_program
322
556
return 0 ;
323
557
}
324
558
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
+
325
592
/* *
326
593
Gets path to file to write upgrade info into. Path is based on datadir of
327
594
server.
@@ -637,6 +904,7 @@ class Program : public Base::Abstract_connection_program
637
904
Mysql_query_runner* m_query_runner;
638
905
bool m_write_binlog;
639
906
bool m_upgrade_systables_only;
907
+ bool m_skip_sys_schema;
640
908
bool m_check_version;
641
909
bool m_ignore_errors;
642
910
bool m_verbose;
0 commit comments