From: magnus.blaudd Date: May 23 2011 3:35pm Subject: bzr push into mysql-5.1-telco-7.1 branch (magnus.blaudd:4212 to 4214) List-Archive: http://lists.mysql.com/commits/137880 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4214 magnus.blaudd@stripped 2011-05-23 ndbinfo - use the new ndbinfo_offline mode in the mysql_system_table.sql script (which is used by mysql_upgrade) modified: scripts/mysql_system_tables.sql 4213 magnus.blaudd@stripped 2011-05-23 [merge] Merge 7.0 -> 7.1 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/include/ndbapi/ndb_cluster_connection.hpp storage/ndb/src/ndbapi/NdbInfo.cpp storage/ndb/src/ndbapi/NdbInfo.hpp storage/ndb/src/ndbapi/NdbInfoRecAttr.hpp storage/ndb/src/ndbapi/NdbInfoScanOperation.cpp storage/ndb/src/ndbapi/TransporterFacade.hpp storage/ndb/src/ndbapi/ndb_cluster_connection.cpp storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp storage/ndb/tools/ndbinfo_sql.cpp 4212 magnus.blaudd@stripped 2011-05-23 [merge] Merge 7.0 -> 7.1 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 storage/ndb/include/util/NdbPack.hpp storage/ndb/src/common/util/NdbPack.cpp modified: storage/ndb/CMakeLists.txt storage/ndb/include/util/NdbSqlUtil.hpp storage/ndb/src/common/util/CMakeLists.txt storage/ndb/src/common/util/Makefile.am storage/ndb/src/common/util/NdbSqlUtil.cpp storage/ndb/src/kernel/blocks/ERROR_codes.txt storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp storage/ndb/src/kernel/blocks/dbtux/DbtuxBuild.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp 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 storage/ndb/src/ndbapi/NdbIndexStat.cpp storage/ndb/src/ndbapi/NdbQueryBuilder.cpp storage/ndb/src/ndbapi/NdbScanOperation.cpp storage/ndb/test/run-test/conf-blade08.cnf storage/ndb/test/run-test/conf-dl145a.cnf storage/ndb/test/run-test/conf-fimafeng08.cnf storage/ndb/test/run-test/conf-fimafeng09.cnf* storage/ndb/test/run-test/conf-loki27.cnf* storage/ndb/test/run-test/conf-ndb07.cnf storage/ndb/test/run-test/conf-ndbmaster.cnf storage/ndb/test/run-test/conf-repl.cnf storage/ndb/test/run-test/conf-techra29.cnf* storage/ndb/test/run-test/conf-test.cnf storage/ndb/test/run-test/conf-tyr64.cnf* storage/ndb/test/run-test/conf-upgrade.cnf === modified file 'mysql-test/suite/ndb/r/ndbinfo.result' --- a/mysql-test/suite/ndb/r/ndbinfo.result 2010-11-03 09:49:39 +0000 +++ b/mysql-test/suite/ndb/r/ndbinfo.result 2011-05-23 14:50:45 +0000 @@ -135,6 +135,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 @@ -178,20 +179,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 @@ -218,6 +254,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; @@ -237,3 +293,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:49:39 +0000 +++ b/mysql-test/suite/ndb/t/ndbinfo.test 2011-05-23 14:50:45 +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 'scripts/mysql_system_tables.sql' --- a/scripts/mysql_system_tables.sql 2011-04-12 15:01:48 +0000 +++ b/scripts/mysql_system_tables.sql 2011-05-23 15:29:50 +0000 @@ -135,6 +135,14 @@ PREPARE stmt FROM @str; EXECUTE stmt; DROP PREPARE stmt; +# Set NDBINFO in offline mode during (re)create of tables +# and views to avoid errors caused by no such table or +# different table definition in NDB +SET @str=IF(@have_ndbinfo,'SET @@global.ndbinfo_offline=TRUE','SET @dummy = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; + # Drop any old views in ndbinfo SET @str=IF(@have_ndbinfo,'DROP VIEW IF EXISTS ndbinfo.transporters','SET @dummy = 0'); PREPARE stmt FROM @str; @@ -377,3 +385,9 @@ SET @str=IF(@have_ndbinfo,'CREATE OR REP PREPARE stmt FROM @str; EXECUTE stmt; DROP PREPARE stmt; + +# Finally turn off offline mode +SET @str=IF(@have_ndbinfo,'SET @@global.ndbinfo_offline=FALSE','SET @dummy = 0'); +PREPARE stmt FROM @str; +EXECUTE stmt; +DROP PREPARE stmt; === 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 18:34:09 +0000 +++ b/storage/ndb/include/ndbapi/ndb_cluster_connection.hpp 2011-05-23 14:50:45 +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 17:56:38 +0000 +++ b/storage/ndb/src/ndbapi/ndb_cluster_connection.cpp 2011-05-23 14:50:45 +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 13:59:32 +0000 +++ b/storage/ndb/tools/ndbinfo_sql.cpp 2011-05-23 14:50:45 +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).