List:Commits« Previous MessageNext Message »
From:magnus.blaudd Date:May 23 2011 1:45pm
Subject:bzr commit into mysql-5.1-telco-7.0 branch (magnus.blaudd:4402) Bug#12581895
View as plain text  
#At file:///home/msvensson/mysql/bug11885602/7.0/ based on revid:magnus.blaudd@stripped

 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
=== modified file 'mysql-test/suite/ndb/r/ndbinfo.result'
--- a/mysql-test/suite/ndb/r/ndbinfo.result	2011-05-23 11:57:55 +0000
+++ b/mysql-test/suite/ndb/r/ndbinfo.result	2011-05-23 13:45:57 +0000
@@ -180,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
@@ -220,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;

=== modified file 'mysql-test/suite/ndb/t/ndbinfo.test'
--- a/mysql-test/suite/ndb/t/ndbinfo.test	2011-05-23 11:57:55 +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

=== modified file 'sql/ha_ndbinfo.cc'
--- a/sql/ha_ndbinfo.cc	2011-05-23 12:09:04 +0000
+++ b/sql/ha_ndbinfo.cc	2011-05-23 13:45:57 +0000
@@ -373,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)
     {
@@ -465,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,
@@ -599,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);

=== 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


Attachment: [text/bzr-bundle] bzr/magnus.blaudd@oracle.com-20110523134557-gh0ten733aj3k3xg.bundle
Thread
bzr commit into mysql-5.1-telco-7.0 branch (magnus.blaudd:4402) Bug#12581895magnus.blaudd23 May