List:Commits« Previous MessageNext Message »
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)
View as plain text  
 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<const my_bool*>(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<const NdbInfoRecAttr *> 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*>(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<LEX_STRING> 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<LEX_STRING> 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<BaseString, Table, BaseString_get_key> 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).
Thread
bzr push into mysql-5.1-telco-7.1 branch (magnus.blaudd:4212 to 4214) magnus.blaudd23 May