From 2c3f907d6cca6a13a0186392f7d2fcacc9c34c3f Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" Date: Tue, 19 Nov 2019 23:20:12 +0100 Subject: [PATCH] B #3946: Check database and table encodings. This may break dump -> mysql upgrade (change default encoding) -> restore --- src/onedb/onedb_backend.rb | 18 ++++++- src/sql/MySqlDB.cc | 97 +++++++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/onedb/onedb_backend.rb b/src/onedb/onedb_backend.rb index 7ccdde0dd1..4432a28dfc 100644 --- a/src/onedb/onedb_backend.rb +++ b/src/onedb/onedb_backend.rb @@ -288,14 +288,28 @@ class BackEndMySQL < OneDBBacKEnd def encoding @encoding = '' + db_enc = '' + table_enc = '' + connect_db @db.fetch('select default_character_set_name FROM information_schema.SCHEMATA'\ " WHERE schema_name = \"#{@db_name}\"") do |row| - @encoding = row[:default_character_set_name] + db_enc = row[:default_character_set_name] end - @encoding + @db.fetch('select CCSA.character_set_name FROM information_schema.`TABLES`'\ + ' T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA '\ + 'WHERE CCSA.collation_name = T.table_collation AND T.table_schema = '\ + "\"#{@db_name}\" AND T.table_name = \"system_attributes\"") do |row| + table_enc = row[:character_set_name] + end + + if db_enc != table_enc + raise "Table and database charset (#{db_enc}, #{table_enc}) differs" + end + + @encoding = table_enc end def restore(bck_file, force=nil, federated=false) diff --git a/src/sql/MySqlDB.cc b/src/sql/MySqlDB.cc index f1e0a92f37..1a155b1c3a 100644 --- a/src/sql/MySqlDB.cc +++ b/src/sql/MySqlDB.cc @@ -25,6 +25,44 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +static std::string get_encoding(MYSQL * c, const std::string& sql, + std::string& error) +{ + std::string encoding; + + if ( mysql_query(c, sql.c_str()) != 0 ) + { + error = "Could not read database encoding."; + return ""; + } + + MYSQL_RES * result = mysql_store_result(c); + + if (result == nullptr) + { + error = "Could not read database encoding: "; + error.append(mysql_error(c)); + + return ""; + } + + MYSQL_ROW row = mysql_fetch_row(result); + + if ( row == nullptr ) + { + error = "Could not read databse encoding"; + return ""; + } + + encoding = ((char **) row)[0]; + + mysql_free_result(result); + + return encoding; +} + +/* -------------------------------------------------------------------------- */ + int MySqlDB::db_encoding(std::string& error) { MYSQL * connection = mysql_init(nullptr); @@ -46,39 +84,34 @@ int MySqlDB::db_encoding(std::string& error) return -1; } + //Get encodings for database and tables if (encoding.empty()) { - //Set encoding for the database clients - std::string encoding_sql = "SELECT default_character_set_name FROM " - "information_schema.SCHEMATA WHERE schema_name = \"" + database + "\""; + std::string db_sql = "SELECT default_character_set_name FROM " + "information_schema.SCHEMATA WHERE schema_name = \"" + database + "\""; - if ( mysql_query(connection, encoding_sql.c_str()) != 0 ) + std::string db_enc = get_encoding(connection, db_sql, error); + + if ( db_enc.empty() ) { - error = "Could not read database encoding."; return -1; } - MYSQL_RES * result = mysql_store_result(connection); + std::string table_sql = "SELECT CCSA.character_set_name FROM " + "information_schema.`TABLES` T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY`" + " CCSA WHERE CCSA.collation_name = T.table_collation AND T.table_schema = " + "\"" + database + "\" AND T.table_name = \"system_attributes\""; - if (result == nullptr) + std::string table_enc = get_encoding(connection, table_sql, error); + + if ( !table_enc.empty() && table_enc != db_enc) { - error = "Could not read database encoding: "; - error.append(mysql_error(connection)); - + error = "Database and table charsets (" + db_enc + ", " + table_enc + + ") differs"; return -1; } - MYSQL_ROW row = mysql_fetch_row(result); - - if ( row == nullptr ) - { - error = "Could not read databse encoding"; - return -1; - } - - encoding = ((char **) row)[0]; - - mysql_free_result(result); + encoding = db_enc; } mysql_close(connection); @@ -89,30 +122,16 @@ int MySqlDB::db_encoding(std::string& error) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -MySqlDB::MySqlDB( - const string& _server, - int _port, - const string& _user, - const string& _password, - const string& _database, - const string& _encoding, - int _max_connections) +MySqlDB::MySqlDB(const string& s, int p, const string& u, const string& _p, + const string& d, const string& e, int m):max_connections(m), server(s), + port(p), user(u), password(_p), database(d), encoding(e) { - vector connections(_max_connections); + vector connections(max_connections); MYSQL * rc; ostringstream oss; std::string error; - server = _server; - port = _port; - user = _user; - password = _password; - database = _database; - encoding = _encoding; - - max_connections = _max_connections; - // Initialize the MySQL library mysql_library_init(0, NULL, NULL);