#At file:///home/frazer/bzr/mysql-5.1-telco-6.2/
2877 Frazer Clement 2009-03-16
Bug#42857 Got error 4541 Indexbound has no bound information from NDBCLUSTER
MySQLD calls NdbIndexScanOperation::setBound() with an empty ('open range')
IndexBound with the query given.
setBound() is modified to handle this by inserting an 'open range' bound
which is actually a lower bound of LE NULL on the first column in the index.
The example testcase is added to ndb_index_ordered.
modified:
mysql-test/suite/ndb/r/ndb_index_ordered.result
mysql-test/suite/ndb/t/ndb_index_ordered.test
storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp
storage/ndb/src/ndbapi/NdbScanOperation.cpp
storage/ndb/src/ndbapi/ndberror.c
=== modified file 'mysql-test/suite/ndb/r/ndb_index_ordered.result'
--- a/mysql-test/suite/ndb/r/ndb_index_ordered.result 2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_index_ordered.result 2009-03-16 18:08:48 +0000
@@ -852,3 +852,12 @@ PRIMARY KEY (DishID)
create index i on nationaldish(countrycode,calories) using hash;
ERROR 42000: Table 'nationaldish' uses an extension that doesn't exist in this MySQL version
drop table nationaldish;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+create table t1(c1 varchar(20) primary key, c2 char(20)) engine=ndbcluster;
+insert into t1(c1,c2) values ('ddd','jg');
+select * from t1 where (c2 < 'b' AND c1 <> 'g') OR (c2 <> 'a' AND c1 <> 'd');
+c1 c2
+ddd jg
+drop table t1;
=== modified file 'mysql-test/suite/ndb/t/ndb_index_ordered.test'
--- a/mysql-test/suite/ndb/t/ndb_index_ordered.test 2007-07-04 20:38:53 +0000
+++ b/mysql-test/suite/ndb/t/ndb_index_ordered.test 2009-03-16 18:08:48 +0000
@@ -478,3 +478,12 @@ create table nationaldish (DishID int(10
create index i on nationaldish(countrycode,calories) using hash;
drop table nationaldish;
+
+# bug#42857 Got error 4541 -IndexBound has no bound information- from NDBCLUSTER
+# Test that query returns results expected
+
+drop table if exists t1;
+create table t1(c1 varchar(20) primary key, c2 char(20)) engine=ndbcluster;
+insert into t1(c1,c2) values ('ddd','jg');
+select * from t1 where (c2 < 'b' AND c1 <> 'g') OR (c2 <> 'a' AND c1 <> 'd');
+drop table t1;
=== modified file 'storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2008-08-07 06:24:52 +0000
+++ b/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2009-03-16 18:08:48 +0000
@@ -266,6 +266,7 @@ private:
Uint32 column_index,
const char *row,
Uint32 bound_type);
+ int insert_open_bound(const NdbRecord* key_record);
virtual int equal_impl(const NdbColumnImpl*, const char*);
virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*);
=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2009-02-10 08:05:16 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2009-03-16 18:08:48 +0000
@@ -611,14 +611,12 @@ NdbIndexScanOperation::setBound(const Nd
return -1;
}
- if (((bound.low_key == NULL) && (bound.high_key == NULL)) ||
- ((bound.low_key_count == 0) && (bound.high_key_count == 0)))
- {
- /* IndexBound passed has no bound information */
- setErrorCodeAbort(4541);
- return -1;
- }
-
+ /* Has the user supplied an open range (no bounds)? */
+ const bool openRange= (((bound.low_key == NULL) &&
+ (bound.high_key == NULL)) ||
+ ((bound.low_key_count == 0) &&
+ (bound.high_key_count == 0)));
+
m_num_bounds++;
if (unlikely((m_num_bounds > 1) &&
@@ -670,28 +668,39 @@ NdbIndexScanOperation::setBound(const Nd
return -1;
}
- for (j= 0; j<key_count; j++)
+ if (likely(!openRange))
{
- Uint32 bound_type;
- /* If key is part of lower bound */
- if (bound.low_key && j<bound.low_key_count)
- {
- /* Inclusive if defined, or matching rows can include this value */
- bound_type= bound.low_inclusive || j+1 < bound.low_key_count ?
- BoundLE : BoundLT;
- ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
- bound.low_key, bound_type);
- }
- /* If key is part of upper bound */
- if (bound.high_key && j<bound.high_key_count)
- {
- /* Inclusive if defined, or matching rows can include this value */
- bound_type= bound.high_inclusive || j+1 < bound.high_key_count ?
- BoundGE : BoundGT;
- ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
- bound.high_key, bound_type);
+ for (j= 0; j<key_count; j++)
+ {
+ Uint32 bound_type;
+ /* If key is part of lower bound */
+ if (bound.low_key && j<bound.low_key_count)
+ {
+ /* Inclusive if defined, or matching rows can include this value */
+ bound_type= bound.low_inclusive || j+1 < bound.low_key_count ?
+ BoundLE : BoundLT;
+ ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
+ bound.low_key, bound_type);
+ }
+ /* If key is part of upper bound */
+ if (bound.high_key && j<bound.high_key_count)
+ {
+ /* Inclusive if defined, or matching rows can include this value */
+ bound_type= bound.high_inclusive || j+1 < bound.high_key_count ?
+ BoundGE : BoundGT;
+ ndbrecord_insert_bound(key_record, key_record->key_indexes[j],
+ bound.high_key, bound_type);
+ }
}
}
+ else
+ {
+ /* Open range - all rows must be returned.
+ * To encode this, we'll request all rows where the first
+ * key column value is >= NULL
+ */
+ insert_open_bound(key_record);
+ }
/* Set the length of this bound
* Length = bound end - bound start
@@ -730,8 +739,11 @@ NdbIndexScanOperation::setBound(const Nd
bound.low_key,
bound.high_key,
distkey_min))
+ {
+ assert(! openRange);
setDistKeyFromRange(key_record, m_attribute_record,
bound.low_key, distkey_min);
+ }
}
return 0;
} // ::setBound();
@@ -2987,6 +2999,32 @@ NdbIndexScanOperation::ndbrecord_insert_
return 0;
}
+int
+NdbIndexScanOperation::insert_open_bound(const NdbRecord* key_record)
+{
+ /* We want to insert an open bound into a scan
+ * This is done by requesting all rows with first key column
+ * >= NULL (so, confusingly, bound is <= NULL)
+ * Sending this as bound info for an open bound allows us to
+ * also send the range number etc so that MRR scans can include
+ * open ranges.
+ * Note that MRR scans with open ranges are an inefficient use of
+ * MRR. Really the application should realise that all rows are
+ * being processed and only fetch them once.
+ */
+ const NdbRecord::Attr *column= &key_record->columns[0];
+
+ /* Create NULL attribute header. */
+ AttributeHeader ah(column->index_attrId, 0);
+
+ Uint32 buf[2] = { NdbIndexScanOperation::BoundLE, ah.m_value };
+ insertBOUNDS(buf, 2);
+
+ theTupKeyLen+= 2;
+
+ return 0;
+}
+
/* IndexScan readTuples - part of old scan API
* This call does the minimum amount of validation and state
* storage possible. Most of the scan initialisation is done
=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c 2009-03-13 07:51:21 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c 2009-03-16 18:08:48 +0000
@@ -589,7 +589,7 @@ ErrorBundle ErrorCodes[] = {
{ 4538, DMEC, AE, "NdbInterpretedCode instruction requires that table is set" },
{ 4539, DMEC, AE, "NdbInterpretedCode not supported for operation type" },
{ 4540, DMEC, AE, "Attempt to pass an Index column to createRecord. Use base table columns only" },
- { 4541, DMEC, AE, "IndexBound has no bound information" },
+ { 4541, DMEC, AE, "IndexBound has no bound information" }, // No longer generated
{ 4200, DMEC, AE, "Status Error when defining an operation" },
{ 4201, DMEC, AE, "Variable Arrays not yet supported" },
Thread |
---|
• bzr commit into mysql-5.1-telco-6.2 branch (frazer:2877) Bug#42857 | Frazer Clement | 16 Mar |