From: magnus.blaudd Date: May 23 2011 3:31pm Subject: bzr push into mysql-5.1-telco-7.0 branch (magnus.blaudd:4399 to 4403) Bug#12581954 List-Archive: http://lists.mysql.com/commits/137879 X-Bug: 12581954 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4403 magnus.blaudd@stripped 2011-05-23 Bug#12581954 - ndbinfo need to reload its cache of ndbinfo tables during online upgrade - When upgrading the MySQL Servers in a cluster before the datanodes, the ndbinfo API does not flush it's cache of ndbinfo tables and columns. Only full disconnect of the cluster is currently detected. And of course restarting the MySQL Server - Make ndbinfo api detect when the "min db version" of cluster has changed. modified: storage/ndb/include/ndbapi/ndb_cluster_connection.hpp storage/ndb/src/ndbapi/NdbInfo.cpp storage/ndb/src/ndbapi/NdbInfo.hpp storage/ndb/src/ndbapi/TransporterFacade.hpp storage/ndb/src/ndbapi/ndb_cluster_connection.cpp storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp 4402 magnus.blaudd@stripped 2011-05-23 Bug#12581895 - ndbinfo should support opening tables with more or differently named columns - Add support for opening a table with more fields than exist in NDBINFO, all fields not sent by NDB will be set to NULL - Add check to prevent opening a table with fields which are NOT NULL - Extend NdbInfoRecAttr with isNULL() modified: mysql-test/suite/ndb/r/ndbinfo.result mysql-test/suite/ndb/t/ndbinfo.test sql/ha_ndbinfo.cc storage/ndb/src/ndbapi/NdbInfoRecAttr.hpp storage/ndb/src/ndbapi/NdbInfoScanOperation.cpp 4401 magnus.blaudd@stripped 2011-05-23 ndbinfo - rename all option variables in ndbinfo to have "opt_ndbinfo_" as prefix modified: sql/ha_ndbinfo.cc 4400 magnus.blaudd@stripped 2011-05-23 Bug#11885602 - mysql_upgrade fails upgrading from 7.1.8 to later release - It was allowed to CREATE TABLE which was not in NDB, but creating a view on that table failed since the table has to be opened as part of the create. - Make it possible to workaround this with a new "ndbinfo_offline" mode which allows tables to be created and opened although they don't exist or have different table definition. This is exactly the same behaviour as when NDBCLUSTER is disabled. SELECTs on a table which has been opened in offline mode, return no rows and a warning is printed(like before). modified: mysql-test/suite/ndb/r/ndbinfo.result mysql-test/suite/ndb/t/ndbinfo.test sql/ha_ndbinfo.cc sql/ha_ndbinfo.h storage/ndb/tools/ndbinfo_sql.cpp 4399 Jonas Oreland 2011-05-23 ndb - bug#12581213 fix accounting of MaxNoOfOpenFiles vs. unbound files (data files) added: mysql-test/suite/ndb/r/ndb_dd_bug12581213.result mysql-test/suite/ndb/t/ndb_dd_bug12581213.cnf mysql-test/suite/ndb/t/ndb_dd_bug12581213.test modified: storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.cpp storage/ndb/src/kernel/blocks/ndbfs/AsyncIoThread.hpp storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp storage/ndb/src/kernel/blocks/ndbfs/Pool.hpp === modified file 'mysql-test/suite/ndb/r/ndbinfo.result' --- a/mysql-test/suite/ndb/r/ndbinfo.result 2010-11-03 09:48:25 +0000 +++ b/mysql-test/suite/ndb/r/ndbinfo.result 2011-05-23 13:45:57 +0000 @@ -136,6 +136,7 @@ Variable_name Value ndbinfo_database ndbinfo ndbinfo_max_bytes 0 ndbinfo_max_rows 10 +ndbinfo_offline OFF ndbinfo_show_hidden OFF ndbinfo_table_prefix ndb$ ndbinfo_version NDB_VERSION_D @@ -179,20 +180,55 @@ node_id != 0 1 Warnings: Warning 40001 Table 'ndb$test' is defined differently in NDB, there are more columns available. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' - -## 2) Column does not exist in NDB -> error, with warning DROP TABLE ndb$test; + +## 2) Column does not exist in NDB -> allowed, with warning, non existing +## column(s) return NULL +## 2a) Extra column at end CREATE TABLE ndb$test (node_id int, non_existing int) ENGINE = ndbinfo; -SELECT * FROM ndb$test; -ERROR HY000: Got error 40001 'Incompatible table definitions' from NDBINFO -SHOW WARNINGS; -Level Code Message +SELECT DISTINCT node_id, non_existing FROM ndb$test; +node_id non_existing +1 NULL +2 NULL +Warnings: Error 40001 Table 'ndb$test' is defined differently in NDB, column 'non_existing' does not exist. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' -Error 1296 Got error 40001 'Incompatible table definitions' from NDBINFO +Warning 40001 Table 'ndb$test' is defined differently in NDB, there are more columns available. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +DROP TABLE ndb$test; + +## 2b) Extra column(s) in middle +CREATE TABLE ndb$test ( + node_id int unsigned, + non_existing int unsigned, + block_number int unsigned, + block_instance int unsigned, + counter int unsigned, + counter2 bigint unsigned +) ENGINE = ndbinfo; +SELECT DISTINCT node_id, non_existing, block_number FROM ndb$test; +node_id non_existing block_number +1 NULL 249 +2 NULL 249 +Warnings: +Error 40001 Table 'ndb$test' is defined differently in NDB, column 'non_existing' does not exist. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +DROP TABLE ndb$test; + +## 2c) Extra column first +CREATE TABLE ndb$test (non_existing int, node_id int) ENGINE = ndbinfo; +SELECT DISTINCT node_id, non_existing FROM ndb$test; +node_id non_existing +1 NULL +2 NULL +Warnings: +Error 40001 Table 'ndb$test' is defined differently in NDB, column 'non_existing' does not exist. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +Warning 40001 Table 'ndb$test' is defined differently in NDB, there are more columns available. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +SELECT DISTINCT non_existing, node_id FROM ndb$test; +non_existing node_id +NULL 1 +NULL 2 +DROP TABLE ndb$test; ## 3) Incompatible column type -> error, with warning ## 3a) int instead of bigint -DROP TABLE ndb$test; CREATE TABLE ndb$test (counter2 int) ENGINE = ndbinfo; SELECT * FROM ndb$test; ERROR HY000: Got error 40001 'Incompatible table definitions' from NDBINFO @@ -219,6 +255,26 @@ Level Code Message Error 40001 Table 'ndb$test' is defined differently in NDB, column 'node_id' is not compatible. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' Error 1296 Got error 40001 'Incompatible table definitions' from NDBINFO DROP TABLE ndb$test; +## 3d) column which is NOT NULL +CREATE TABLE ndb$test (node_id int unsigned NOT NULL) ENGINE = ndbinfo; +SELECT * FROM ndb$test; +ERROR HY000: Got error 40001 'Incompatible table definitions' from NDBINFO +SHOW WARNINGS; +Level Code Message +Error 40001 Table 'ndb$test' is defined differently in NDB, column 'node_id' is NOT NULL. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +Error 1296 Got error 40001 'Incompatible table definitions' from NDBINFO +DROP TABLE ndb$test; +## 3e) non existing column which is NOT NULL +CREATE TABLE ndb$test ( + block_number int unsigned, + non_existing int NOT NULL) ENGINE = ndbinfo; +SELECT * FROM ndb$test; +ERROR HY000: Got error 40001 'Incompatible table definitions' from NDBINFO +SHOW WARNINGS; +Level Code Message +Error 40001 Table 'ndb$test' is defined differently in NDB, column 'non_existing' is NOT NULL. The SQL to regenerate is: 'CREATE TABLE `ndbinfo`.`ndb$test` (`node_id` INT UNSIGNED, `block_number` INT UNSIGNED, `block_instance` INT UNSIGNED, `counter` INT UNSIGNED, `counter2` BIGINT UNSIGNED) ENGINE=NDBINFO' +Error 1296 Got error 40001 'Incompatible table definitions' from NDBINFO +DROP TABLE ndb$test; ## 4) Table with primary key/indexes not supported CREATE TABLE ndb$test (node_id int, block_number int PRIMARY KEY) ENGINE = ndbinfo; @@ -238,3 +294,55 @@ node_id 1 2 +set @@ndbinfo_offline=1; +ERROR HY000: Variable 'ndbinfo_offline' is a GLOBAL variable and should be set with SET GLOBAL + +SELECT DISTINCT(node_id) FROM ndbinfo.counters ORDER BY node_id; +node_id +1 +2 + +set @@global.ndbinfo_offline=TRUE; +select @@ndbinfo_offline; +@@ndbinfo_offline +1 + +CREATE TABLE ndb$does_not_exist_in_ndb( + node_id int, + message varchar(255) +) ENGINE = ndbinfo; + +CREATE VIEW view_on_table_which_does_not_exist_in_ndb AS + SELECT node_id, message + FROM ndbinfo.ndb$does_not_exist_in_ndb; + +SHOW CREATE TABLE ndb$does_not_exist_in_ndb; +Table Create Table +ndb$does_not_exist_in_ndb CREATE TABLE `ndb$does_not_exist_in_ndb` ( + `node_id` int(11) DEFAULT NULL, + `message` varchar(255) DEFAULT NULL +) ENGINE=NDBINFO DEFAULT CHARSET=latin1 + +SELECT * FROM view_on_table_which_does_not_exist_in_ndb; +node_id message +Warnings: +Note 1 'NDBINFO' has been started in offline mode since the 'NDBCLUSTER' engine is disabled or @@global.ndbinfo_offline is turned on - no rows can be returned +SELECT * FROM ndb$does_not_exist_in_ndb; +node_id message +Warnings: +Note 1 'NDBINFO' has been started in offline mode since the 'NDBCLUSTER' engine is disabled or @@global.ndbinfo_offline is turned on - no rows can be returned +SELECT DISTINCT(node_id) FROM ndbinfo.counters ORDER BY node_id; +node_id +Warnings: +Note 1 'NDBINFO' has been started in offline mode since the 'NDBCLUSTER' engine is disabled or @@global.ndbinfo_offline is turned on - no rows can be returned + +DROP VIEW view_on_table_which_does_not_exist_in_ndb; +DROP TABLE ndb$does_not_exist_in_ndb; + +set @@global.ndbinfo_offline = FALSE; + +SELECT DISTINCT(node_id) FROM ndbinfo.counters ORDER BY node_id; +node_id +1 +2 + === modified file 'mysql-test/suite/ndb/t/ndbinfo.test' --- a/mysql-test/suite/ndb/t/ndbinfo.test 2010-11-03 09:48:25 +0000 +++ b/mysql-test/suite/ndb/t/ndbinfo.test 2011-05-23 13:45:57 +0000 @@ -98,17 +98,35 @@ SELECT count(*) >= 20 FROM blocks; DROP TABLE ndb$test; CREATE TABLE ndb$test (node_id int unsigned) ENGINE = ndbinfo; SELECT node_id != 0 FROM ndb$test LIMIT 1; - -## 2) Column does not exist in NDB -> error, with warning DROP TABLE ndb$test; + +## 2) Column does not exist in NDB -> allowed, with warning, non existing +## column(s) return NULL +## 2a) Extra column at end CREATE TABLE ndb$test (node_id int, non_existing int) ENGINE = ndbinfo; ---error ER_GET_ERRMSG -SELECT * FROM ndb$test; -SHOW WARNINGS; +SELECT DISTINCT node_id, non_existing FROM ndb$test; +DROP TABLE ndb$test; + +## 2b) Extra column(s) in middle +CREATE TABLE ndb$test ( + node_id int unsigned, + non_existing int unsigned, + block_number int unsigned, + block_instance int unsigned, + counter int unsigned, + counter2 bigint unsigned +) ENGINE = ndbinfo; +SELECT DISTINCT node_id, non_existing, block_number FROM ndb$test; +DROP TABLE ndb$test; + +## 2c) Extra column first +CREATE TABLE ndb$test (non_existing int, node_id int) ENGINE = ndbinfo; +SELECT DISTINCT node_id, non_existing FROM ndb$test; +SELECT DISTINCT non_existing, node_id FROM ndb$test; +DROP TABLE ndb$test; ## 3) Incompatible column type -> error, with warning ## 3a) int instead of bigint -DROP TABLE ndb$test; CREATE TABLE ndb$test (counter2 int) ENGINE = ndbinfo; --error ER_GET_ERRMSG SELECT * FROM ndb$test; @@ -126,6 +144,21 @@ CREATE TABLE ndb$test (node_id varchar(2 SELECT * FROM ndb$test; SHOW WARNINGS; DROP TABLE ndb$test; +## 3d) column which is NOT NULL +CREATE TABLE ndb$test (node_id int unsigned NOT NULL) ENGINE = ndbinfo; +--error ER_GET_ERRMSG +SELECT * FROM ndb$test; +SHOW WARNINGS; +DROP TABLE ndb$test; +## 3e) non existing column which is NOT NULL +CREATE TABLE ndb$test ( + block_number int unsigned, + non_existing int NOT NULL) ENGINE = ndbinfo; +--error ER_GET_ERRMSG +SELECT * FROM ndb$test; +SHOW WARNINGS; +DROP TABLE ndb$test; + ## 4) Table with primary key/indexes not supported --error ER_TOO_MANY_KEYS @@ -148,4 +181,52 @@ CREATE TABLE ndb$test (node_id int AUTO_ select distinct node_id from ndbinfo.diskpagebuffer; + +# +# BUG#11885602 +# - It was allowed to CREATE TABLE which was not in NDB, but +# creating a view on that table failed. Implement ndbinfo_offline +# mode which allows tables to be created and opened although they +# don't exists or have different table definition. +# This is exactly the same behaviour as when NDBCLUSTER +# is disabled +# + +# Check ndbinfo_offline is GLOBAL variable +--error ER_GLOBAL_VARIABLE +set @@ndbinfo_offline=1; + +# Query used to check that open tables are closed +# when offline mode is turned on and off +let $q1 = SELECT DISTINCT(node_id) FROM ndbinfo.counters ORDER BY node_id; +eval $q1; + +# Turn on ndbinfo_offline +set @@global.ndbinfo_offline=TRUE; +select @@ndbinfo_offline; + +CREATE TABLE ndb$does_not_exist_in_ndb( + node_id int, + message varchar(255) +) ENGINE = ndbinfo; + +CREATE VIEW view_on_table_which_does_not_exist_in_ndb AS + SELECT node_id, message + FROM ndbinfo.ndb$does_not_exist_in_ndb; + +SHOW CREATE TABLE ndb$does_not_exist_in_ndb; + +# SELECTs return no rows in offline mode +SELECT * FROM view_on_table_which_does_not_exist_in_ndb; +SELECT * FROM ndb$does_not_exist_in_ndb; +eval $q1; + +DROP VIEW view_on_table_which_does_not_exist_in_ndb; +DROP TABLE ndb$does_not_exist_in_ndb; + +# Restore original value +set @@global.ndbinfo_offline = FALSE; + +eval $q1; + --source ndbinfo_drop.inc === modified file 'sql/ha_ndbinfo.cc' --- a/sql/ha_ndbinfo.cc 2010-11-10 14:17:13 +0000 +++ b/sql/ha_ndbinfo.cc 2011-05-23 13:45:57 +0000 @@ -56,10 +56,10 @@ static MYSQL_THDVAR_BOOL( FALSE /* default */ ); -static char* ndbinfo_dbname = (char*)"ndbinfo"; +static char* opt_ndbinfo_dbname = (char*)"ndbinfo"; static MYSQL_SYSVAR_STR( database, /* name */ - ndbinfo_dbname, /* var */ + opt_ndbinfo_dbname, /* var */ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Name of the database used by ndbinfo", NULL, /* check func. */ @@ -67,10 +67,10 @@ static MYSQL_SYSVAR_STR( NULL /* default */ ); -static char* table_prefix = (char*)"ndb$"; +static char* opt_ndbinfo_table_prefix = (char*)"ndb$"; static MYSQL_SYSVAR_STR( table_prefix, /* name */ - table_prefix, /* var */ + opt_ndbinfo_table_prefix, /* var */ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Prefix to use for all virtual tables loaded from NDB", NULL, /* check func. */ @@ -78,10 +78,10 @@ static MYSQL_SYSVAR_STR( NULL /* default */ ); -static Uint32 version = NDB_VERSION_D; +static Uint32 opt_ndbinfo_version = NDB_VERSION_D; static MYSQL_SYSVAR_UINT( version, /* name */ - version, /* var */ + opt_ndbinfo_version, /* var */ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY, "Compile version for ndbinfo", NULL, /* check func. */ @@ -92,6 +92,45 @@ static MYSQL_SYSVAR_UINT( 0 /* block */ ); +static my_bool opt_ndbinfo_offline; + +static +void +offline_update(THD* thd, struct st_mysql_sys_var* var, + void* var_ptr, const void* save) +{ + DBUG_ENTER("offline_update"); + + const my_bool new_offline = + (*(static_cast(save)) != 0); + if (new_offline == opt_ndbinfo_offline) + { + // No change + DBUG_VOID_RETURN; + } + + // Set offline mode, any tables opened from here on will + // be opened in the new mode + opt_ndbinfo_offline = new_offline; + + // Close any open tables which may be in the old mode + (void)close_cached_tables(thd, NULL, false, true, false); + + DBUG_VOID_RETURN; +} + +static MYSQL_SYSVAR_BOOL( + offline, /* name */ + opt_ndbinfo_offline, /* var */ + PLUGIN_VAR_NOCMDOPT, + "Set ndbinfo in offline mode, tables and views can " + "be opened even if they don't exist or have different " + "definition in NDB. No rows will be returned.", + NULL, /* check func. */ + offline_update, /* update func. */ + 0 /* default */ +); + static NdbInfo* g_ndbinfo; @@ -124,10 +163,15 @@ struct ha_ndbinfo_impl Vector m_columns; bool m_first_use; + // Indicates if table has been opened in offline mode + // can only be reset by closing the table + bool m_offline; + ha_ndbinfo_impl() : m_table(NULL), m_scan_op(NULL), - m_first_use(true) + m_first_use(true), + m_offline(false) { } }; @@ -211,7 +255,7 @@ static void generate_sql(const NdbInfo::Table* ndb_tab, BaseString& sql) { sql.appfmt("'CREATE TABLE `%s`.`%s%s` (", - ndbinfo_dbname, table_prefix, ndb_tab->getName()); + opt_ndbinfo_dbname, opt_ndbinfo_table_prefix, ndb_tab->getName()); const char* separator = ""; for (unsigned i = 0; i < ndb_tab->columns(); i++) @@ -265,7 +309,7 @@ warn_incompatible(const NdbInfo::Table* msg.assfmt("Table '%s%s' is defined differently in NDB, %s. The " "SQL to regenerate is: ", - table_prefix, ndb_tab->getName(), explanation); + opt_ndbinfo_table_prefix, ndb_tab->getName(), explanation); generate_sql(ndb_tab, msg); const MYSQL_ERROR::enum_warning_level level = @@ -289,12 +333,18 @@ bool ha_ndbinfo::is_open(void) const return m_impl.m_table != NULL; } +bool ha_ndbinfo::is_offline(void) const +{ + return m_impl.m_offline; +} + int ha_ndbinfo::open(const char *name, int mode, uint test_if_locked) { DBUG_ENTER("ha_ndbinfo::open"); DBUG_PRINT("enter", ("name: %s, mode: %d", name, mode)); assert(is_closed()); + assert(!is_offline()); // Closed table can not be offline if (mode == O_RDWR) { @@ -307,9 +357,11 @@ int ha_ndbinfo::open(const char *name, i DBUG_ASSERT(false); } - if (ndbcluster_is_disabled()) + if (opt_ndbinfo_offline || + ndbcluster_is_disabled()) { - // Allow table to be opened with ndbcluster disabled + // Mark table as being offline and allow it to be opened + m_impl.m_offline = true; DBUG_RETURN(0); } @@ -321,21 +373,36 @@ int ha_ndbinfo::open(const char *name, i DBUG_RETURN(err2mysql(err)); } + /* + Check table def. to detect incompatible differences which should + return an error. Differences which only generate a warning + is checked on first use + */ DBUG_PRINT("info", ("Comparing MySQL's table def against NDB")); const NdbInfo::Table* ndb_tab = m_impl.m_table; for (uint i = 0; i < table->s->fields; i++) { const Field* field = table->field[i]; - const NdbInfo::Column* col = ndb_tab->getColumn(field->field_name); - if (!col) + + // Check if field is NULLable + if (const_cast(field)->real_maybe_null() == false) { - // The column didn't exist + // Only NULLable fields supported warn_incompatible(ndb_tab, true, - "column '%s' does not exist", + "column '%s' is NOT NULL", field->field_name); DBUG_RETURN(ERR_INCOMPAT_TABLE_DEF); } + // Check if column exist in NDB + const NdbInfo::Column* col = ndb_tab->getColumn(field->field_name); + if (!col) + { + // The column didn't exist + continue; + } + + // Check compatible field and column type bool compatible = false; switch(col->m_type) { @@ -378,7 +445,7 @@ int ha_ndbinfo::close(void) { DBUG_ENTER("ha_ndbinfo::close"); - if (ndbcluster_is_disabled()) + if (is_offline()) DBUG_RETURN(0); assert(is_open()); @@ -395,12 +462,13 @@ int ha_ndbinfo::rnd_init(bool scan) DBUG_ENTER("ha_ndbinfo::rnd_init"); DBUG_PRINT("info", ("scan: %d", scan)); - if (ndbcluster_is_disabled()) + if (is_offline()) { push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 1, - "'NDBINFO' has been started " - "in limited mode since the 'NDBCLUSTER' " - "engine is disabled - no rows can be returned"); + "'NDBINFO' has been started in offline mode " + "since the 'NDBCLUSTER' engine is disabled " + "or @@global.ndbinfo_offline is turned on " + "- no rows can be returned"); DBUG_RETURN(0); } @@ -412,13 +480,30 @@ int ha_ndbinfo::rnd_init(bool scan) m_impl.m_first_use = false; /* - Due to different code paths in MySQL Server - for prepared statement protocol, some warnings - from 'handler::open' are lost and need to be - deffered to first use instead + Check table def. and generate warnings for incompatibilites + which is allowed but should generate a warning. + (Done this late due to different code paths in MySQL Server for + prepared statement protocol, where warnings from 'handler::open' + are lost). */ + uint fields_found_in_ndb = 0; const NdbInfo::Table* ndb_tab = m_impl.m_table; - if (table->s->fields < ndb_tab->columns()) + for (uint i = 0; i < table->s->fields; i++) + { + const Field* field = table->field[i]; + const NdbInfo::Column* col = ndb_tab->getColumn(field->field_name); + if (!col) + { + // The column didn't exist + warn_incompatible(ndb_tab, true, + "column '%s' does not exist", + field->field_name); + continue; + } + fields_found_in_ndb++; + } + + if (fields_found_in_ndb < ndb_tab->columns()) { // There are more columns available in NDB warn_incompatible(ndb_tab, false, @@ -466,7 +551,7 @@ int ha_ndbinfo::rnd_end() { DBUG_ENTER("ha_ndbinfo::rnd_end"); - if (ndbcluster_is_disabled()) + if (is_offline()) DBUG_RETURN(0); assert(is_open()); @@ -486,7 +571,7 @@ int ha_ndbinfo::rnd_next(uchar *buf) int err; DBUG_ENTER("ha_ndbinfo::rnd_next"); - if (ndbcluster_is_disabled()) + if (is_offline()) DBUG_RETURN(HA_ERR_END_OF_FILE); assert(is_open()); @@ -546,7 +631,7 @@ ha_ndbinfo::unpack_record(uchar *dst_row { Field *field = table->field[i]; const NdbInfoRecAttr* record = m_impl.m_columns[i]; - if (m_impl.m_columns[i]) + if (record && !record->isNULL()) { field->set_notnull(); field->move_field_offset(dst_offset); @@ -617,7 +702,7 @@ ndbinfo_find_files(handlerton *hton, THD List_iterator it(*files); while ((dir_name=it++)) { - if (strcmp(dir_name->str, ndbinfo_dbname)) + if (strcmp(dir_name->str, opt_ndbinfo_dbname)) continue; DBUG_PRINT("info", ("Hiding own databse '%s'", dir_name->str)); @@ -628,7 +713,7 @@ ndbinfo_find_files(handlerton *hton, THD } DBUG_ASSERT(db); - if (strcmp(db, ndbinfo_dbname)) + if (strcmp(db, opt_ndbinfo_dbname)) DBUG_RETURN(0); // Only hide files in "our" db /* Hide all files that start with "our" prefix */ @@ -636,7 +721,7 @@ ndbinfo_find_files(handlerton *hton, THD List_iterator it(*files); while ((file_name=it++)) { - if (is_prefix(file_name->str, table_prefix)) + if (is_prefix(file_name->str, opt_ndbinfo_table_prefix)) { DBUG_PRINT("info", ("Hiding '%s'", file_name->str)); it.remove(); @@ -668,11 +753,11 @@ int ndbinfo_init(void *plugin) char prefix[FN_REFLEN]; build_table_filename(prefix, sizeof(prefix) - 1, - ndbinfo_dbname, table_prefix, "", 0); + opt_ndbinfo_dbname, opt_ndbinfo_table_prefix, "", 0); DBUG_PRINT("info", ("prefix: '%s'", prefix)); assert(g_ndb_cluster_connection); g_ndbinfo = new NdbInfo(g_ndb_cluster_connection, prefix, - ndbinfo_dbname, table_prefix); + opt_ndbinfo_dbname, opt_ndbinfo_table_prefix); if (!g_ndbinfo) { sql_print_error("Failed to create NdbInfo"); @@ -712,6 +797,7 @@ struct st_mysql_sys_var* ndbinfo_system_ MYSQL_SYSVAR(database), MYSQL_SYSVAR(table_prefix), MYSQL_SYSVAR(version), + MYSQL_SYSVAR(offline), NULL }; === modified file 'sql/ha_ndbinfo.h' --- a/sql/ha_ndbinfo.h 2011-02-01 14:58:21 +0000 +++ b/sql/ha_ndbinfo.h 2011-05-23 11:57:55 +0000 @@ -83,6 +83,8 @@ private: bool is_open(void) const; bool is_closed(void) const { return ! is_open(); }; + bool is_offline(void) const; + struct ha_ndbinfo_impl& m_impl; }; === modified file 'storage/ndb/include/ndbapi/ndb_cluster_connection.hpp' --- a/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp 2011-02-04 17:52:38 +0000 +++ b/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp 2011-05-23 14:05:08 +0000 @@ -192,6 +192,7 @@ public: unsigned max_nodegroup(); unsigned node_id(); unsigned get_connect_count() const; + unsigned get_min_db_version() const; void init_get_next_node(Ndb_cluster_connection_node_iter &iter); unsigned int get_next_node(Ndb_cluster_connection_node_iter &iter); === modified file 'storage/ndb/src/ndbapi/NdbInfo.cpp' --- a/storage/ndb/src/ndbapi/NdbInfo.cpp 2011-02-02 00:40:07 +0000 +++ b/storage/ndb/src/ndbapi/NdbInfo.cpp 2011-05-23 14:05:08 +0000 @@ -23,6 +23,7 @@ NdbInfo::NdbInfo(class Ndb_cluster_conne const char* prefix, const char* dbname, const char* table_prefix) : m_connect_count(connection->get_connect_count()), + m_min_db_version(0), m_connection(connection), m_tables_table(NULL), m_columns_table(NULL), m_prefix(prefix), @@ -270,7 +271,9 @@ bool NdbInfo::load_tables() } // After sucessfull load of the tables, set connect count + // and the min db version of cluster m_connect_count = m_connection->get_connect_count(); + m_min_db_version = m_connection->get_min_db_version(); return true; } @@ -328,12 +331,14 @@ void NdbInfo::flush_tables() bool NdbInfo::check_tables() { - if (m_connection->get_connect_count() != m_connect_count) + if (unlikely(m_connection->get_connect_count() != m_connect_count || + m_connection->get_min_db_version() != m_min_db_version)) { - // Connect count has changed -> flush the cached table definitions + // Connect count or min db version of cluster has changed + // -> flush the cached table definitions flush_tables(); } - if (m_tables.entries() <= NUM_HARDCODED_TABLES) + if (unlikely(m_tables.entries() <= NUM_HARDCODED_TABLES)) { // Global table cache is not loaded yet or has been // flushed, try to load it === modified file 'storage/ndb/src/ndbapi/NdbInfo.hpp' --- a/storage/ndb/src/ndbapi/NdbInfo.hpp 2011-02-02 00:40:07 +0000 +++ b/storage/ndb/src/ndbapi/NdbInfo.hpp 2011-05-23 14:05:08 +0000 @@ -89,8 +89,6 @@ public: bool init(void); ~NdbInfo(); - void flush_tables(); - int openTable(const char* table_name, const Table**); int openTable(Uint32 tableId, const Table**); void closeTable(const Table* table); @@ -103,6 +101,7 @@ public: private: static const size_t NUM_HARDCODED_TABLES = 2; unsigned m_connect_count; + unsigned m_min_db_version; class Ndb_cluster_connection* m_connection; pthread_mutex_t m_mutex; HashMap m_tables; @@ -119,6 +118,7 @@ private: bool load_hardcoded_tables(void); bool load_tables(); bool check_tables(); + void flush_tables(); BaseString mysql_table_name(const char* table_name) const; === modified file 'storage/ndb/src/ndbapi/NdbInfoRecAttr.hpp' --- a/storage/ndb/src/ndbapi/NdbInfoRecAttr.hpp 2011-02-02 00:40:07 +0000 +++ b/storage/ndb/src/ndbapi/NdbInfoRecAttr.hpp 2011-05-23 13:45:57 +0000 @@ -46,13 +46,18 @@ public: return m_len; } + bool isNULL() const { + return !m_defined; + } + protected: friend class NdbInfoScanOperation; - NdbInfoRecAttr() : m_data(NULL), m_len(0) {}; + NdbInfoRecAttr() : m_data(NULL), m_len(0), m_defined(false) {}; ~NdbInfoRecAttr() {}; private: const char* m_data; Uint32 m_len; + bool m_defined; }; #endif === modified file 'storage/ndb/src/ndbapi/NdbInfoScanOperation.cpp' --- a/storage/ndb/src/ndbapi/NdbInfoScanOperation.cpp 2011-02-02 00:40:07 +0000 +++ b/storage/ndb/src/ndbapi/NdbInfoScanOperation.cpp 2011-05-23 13:45:57 +0000 @@ -418,34 +418,35 @@ NdbInfoScanOperation::execDBINFO_TRANSID m_rows_received++; DBUG_PRINT("info", ("rows received: %d", m_rows_received)); - const Uint32* start = signal->ptr[0].p; - const Uint32* end = start + signal->ptr[0].sz; - - DBUG_PRINT("info", ("start: %p, end: %p", start, end)); - for (unsigned col = 0; col < m_table->columns(); col++) + // Reset all recattr values before reading the new row + for (unsigned i = 0; i < m_recAttrs.size(); i++) { + if (m_recAttrs[i]) + m_recAttrs[i]->m_defined = false; + } - // Read attribute header - const AttributeHeader ah(*start); - const Uint32 len = ah.getByteSize(); + // Read attributes from long signal section + AttributeHeader* attr = (AttributeHeader*)signal->ptr[0].p; + AttributeHeader* last = (AttributeHeader*)(signal->ptr[0].p + + signal->ptr[0].sz); + while (attr < last) + { + const Uint32 col = attr->getAttributeId(); + const Uint32 len = attr->getByteSize(); DBUG_PRINT("info", ("col: %u, len: %u", col, len)); - - // Step past attribute header - start += ah.getHeaderSize(); - - NdbInfoRecAttr* attr = m_recAttrs[col]; - if (attr) + if (col < m_recAttrs.size()) { - // Update NdbInfoRecAttr pointer and length - attr->m_data = (const char*)start; - attr->m_len = len; + NdbInfoRecAttr* rec_attr = m_recAttrs[col]; + if (rec_attr) + { + // Update NdbInfoRecAttr pointer, length and defined flag + rec_attr->m_data = (const char*)attr->getDataPtr(); + rec_attr->m_len = len; + rec_attr->m_defined = true; + } } - // Step to next attribute header - start += ah.getDataSize(); - - // No reading beyond end of signal size - assert(start <= end); + attr = attr->getNext(); } DBUG_RETURN(false); // Don't wait more, process this row === modified file 'storage/ndb/src/ndbapi/TransporterFacade.hpp' --- a/storage/ndb/src/ndbapi/TransporterFacade.hpp 2011-02-24 07:47:22 +0000 +++ b/storage/ndb/src/ndbapi/TransporterFacade.hpp 2011-05-23 14:05:08 +0000 @@ -303,6 +303,12 @@ unsigned Ndb_cluster_connection_impl::ge } inline +unsigned Ndb_cluster_connection_impl::get_min_db_version() const +{ + return m_transporter_facade->getMinDbNodeVersion(); +} + +inline bool TransporterFacade::get_node_alive(NodeId n) const { if (theClusterMgr) === modified file 'storage/ndb/src/ndbapi/ndb_cluster_connection.cpp' --- a/storage/ndb/src/ndbapi/ndb_cluster_connection.cpp 2011-04-15 06:29:59 +0000 +++ b/storage/ndb/src/ndbapi/ndb_cluster_connection.cpp 2011-05-23 14:05:08 +0000 @@ -332,6 +332,11 @@ unsigned Ndb_cluster_connection::get_con return m_impl.get_connect_count(); } +unsigned Ndb_cluster_connection::get_min_db_version() const +{ + return m_impl.get_min_db_version(); +} + int Ndb_cluster_connection::get_latest_error() const { return m_impl.m_latest_error; === modified file 'storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp' --- a/storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp 2011-02-04 17:52:38 +0000 +++ b/storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp 2011-05-23 14:05:08 +0000 @@ -67,6 +67,7 @@ class Ndb_cluster_connection_impl : publ Uint32 get_next_alive_node(Ndb_cluster_connection_node_iter &iter); inline unsigned get_connect_count() const; + inline unsigned get_min_db_version() const; public: inline Uint64 *get_latest_trans_gci() { return &m_latest_trans_gci; } === modified file 'storage/ndb/tools/ndbinfo_sql.cpp' --- a/storage/ndb/tools/ndbinfo_sql.cpp 2011-04-12 11:59:36 +0000 +++ b/storage/ndb/tools/ndbinfo_sql.cpp 2011-05-23 11:57:55 +0000 @@ -327,6 +327,12 @@ int main(int argc, char** argv){ sql.assfmt("CREATE DATABASE IF NOT EXISTS `%s`", opt_ndbinfo_db); print_conditional_sql(sql); + printf("# Set NDBINFO in offline mode during (re)create of tables\n"); + printf("# and views to avoid errors caused by no such table or\n"); + printf("# different table definition in NDB\n"); + sql.assfmt("SET @@global.ndbinfo_offline=TRUE"); + print_conditional_sql(sql); + printf("# Drop any old views in %s\n", opt_ndbinfo_db); for (size_t i = 0; i < num_views; i++) { @@ -430,6 +436,10 @@ int main(int argc, char** argv){ print_conditional_sql(sql); } + printf("# Finally turn off offline mode\n"); + sql.assfmt("SET @@global.ndbinfo_offline=FALSE"); + print_conditional_sql(sql); + return 0; } No bundle (reason: useless for push emails).