#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#12581895 | magnus.blaudd | 23 May |