=== modified file 'mysql-test/suite/ndb/r/ndb_index_ordered.result' --- mysql-test/suite/ndb/r/ndb_index_ordered.result 2007-06-27 12:28:02 +0000 +++ mysql-test/suite/ndb/r/ndb_index_ordered.result 2009-03-16 15:51:58 +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' --- mysql-test/suite/ndb/t/ndb_index_ordered.test 2007-07-04 20:38:53 +0000 +++ mysql-test/suite/ndb/t/ndb_index_ordered.test 2009-03-16 15:51:02 +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' --- storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2008-08-07 06:24:52 +0000 +++ storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2009-03-16 11:44:12 +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' --- storage/ndb/src/ndbapi/NdbScanOperation.cpp 2009-02-10 08:05:16 +0000 +++ storage/ndb/src/ndbapi/NdbScanOperation.cpp 2009-03-16 15:24:00 +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; jkey_indexes[j], - bound.low_key, bound_type); - } - /* If key is part of upper bound */ - if (bound.high_key && jkey_indexes[j], - bound.high_key, bound_type); + for (j= 0; jkey_indexes[j], + bound.low_key, bound_type); + } + /* If key is part of upper bound */ + if (bound.high_key && jkey_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' --- storage/ndb/src/ndbapi/ndberror.c 2009-03-13 00:15:47 +0000 +++ storage/ndb/src/ndbapi/ndberror.c 2009-03-16 16:16:31 +0000 @@ -588,7 +588,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 /* 4542-4546 used in later releases */ { 4547, DMEC, AE, "RecordSpecification has overlapping offsets" }, { 4548, DMEC, AE, "RecordSpecification has too many elements" },