Skip to content

Commit bbcf89b

Browse files
committed
Bug#36390313 PB2: join_pushdown tests fail in Windows due to node failure
Bug#36513270 join_pushdown_default test fails due to an assertion failure The push down join functionality for NDB expects pushed down conditions to filter exactly, no rows that do not match the condition must not be returned (and all rows that do match the condition must be returned). When condition contained a BINARY value compared to a BINARY column this was not always true. If the BINARY value was shorter than the BINARY column size it was zero extended and could compare equal to a BINARY column value despite having different lengths, if condition was pushed down to NDB. This became more visible with fix for bug#36364619 which added implicit casts of values to BINARY if compared to BINARY columns, which in turn allowed more conditions to be pushed down to NDB. The tests ndb_opt.join_pushdown_bka and ndb_opt.join_pushdown_default started to fail. The fix is when deciding if condition is pushable or not to also make sure that the BINARY value length exactly matches the BINARY column size. Furtermore when binary string values were used in conditions with BINARY or VARBINARY columns the actual length of string value were not used but an overestimate of its length. That is now changed and will allow more conditions comparing short string values with VARBINARY columns to be pushed down. Change-Id: Iff7b43bd7069090508f8a99557e98ca8395ae17f
1 parent 0577c77 commit bbcf89b

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

storage/ndb/plugin/ha_ndbcluster_cond.cc

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,16 @@ class Ndb_expect_stack {
321321
static const uint MAX_EXPECT_ITEMS = Item::VIEW_FIXER_ITEM + 1;
322322
static const uint MAX_EXPECT_FIELD_TYPES = MYSQL_TYPE_GEOMETRY + 1;
323323
static const uint MAX_EXPECT_FIELD_RESULTS = DECIMAL_RESULT + 1;
324+
static constexpr Uint32 NO_LENGTH = UINT32_MAX;
324325

325326
public:
326327
Ndb_expect_stack()
327328
: expect_tables(),
328329
other_field(nullptr),
329330
collation(nullptr),
330-
length(0),
331-
max_length(0),
331+
length(NO_LENGTH),
332+
min_length(NO_LENGTH),
333+
max_length(NO_LENGTH),
332334
next(nullptr) {
333335
// Allocate type checking bitmaps using fixed size buffers
334336
// since max size is known at compile time
@@ -438,12 +440,19 @@ class Ndb_expect_stack {
438440
return matching;
439441
}
440442
void expect_length(Uint32 len) { length = len; }
443+
void expect_min_length(Uint32 min) { min_length = min; }
441444
void expect_max_length(Uint32 max) { max_length = max; }
442445
bool expecting_length(Uint32 len) {
443-
return max_length == 0 || len <= max_length;
446+
return (min_length == NO_LENGTH || min_length <= len) &&
447+
(max_length == NO_LENGTH || len <= max_length);
444448
}
445-
bool expecting_max_length(Uint32 max) { return max >= length; }
446-
void expect_no_length() { length = max_length = 0; }
449+
bool expecting_max_length(Uint32 max) {
450+
return (length == NO_LENGTH || max >= length);
451+
}
452+
bool expecting_min_length(Uint32 min) {
453+
return (length == NO_LENGTH || min <= length);
454+
}
455+
void expect_no_length() { length = min_length = max_length = NO_LENGTH; }
447456

448457
private:
449458
Ndb_bitmap_buf<MAX_EXPECT_ITEMS> m_expect_buf;
@@ -456,6 +465,7 @@ class Ndb_expect_stack {
456465
const Field *other_field;
457466
const CHARSET_INFO *collation;
458467
Uint32 length;
468+
Uint32 min_length;
459469
Uint32 max_length;
460470
Ndb_expect_stack *next;
461471
};
@@ -559,6 +569,9 @@ class Ndb_cond_traverse_context {
559569
inline void expect_length(Uint32 length) {
560570
expect_stack.expect_length(length);
561571
}
572+
inline void expect_min_length(Uint32 min) {
573+
expect_stack.expect_min_length(min);
574+
}
562575
inline void expect_max_length(Uint32 max) {
563576
expect_stack.expect_max_length(max);
564577
}
@@ -568,6 +581,9 @@ class Ndb_cond_traverse_context {
568581
inline bool expecting_max_length(Uint32 max) {
569582
return expect_stack.expecting_max_length(max);
570583
}
584+
inline bool expecting_min_length(Uint32 min) {
585+
return expect_stack.expecting_min_length(min);
586+
}
571587
inline void expect_no_length() { expect_stack.expect_no_length(); }
572588

573589
TABLE *const table;
@@ -866,19 +882,27 @@ static void ndb_serialize_cond(const Item *item, void *arg) {
866882
context->supported = false;
867883
break;
868884

869-
case STRING_RESULT:
885+
case STRING_RESULT: {
870886
DBUG_PRINT("info", ("STRING 'VALUE' expression: '%s'",
871887
str.c_ptr_safe()));
872-
// Check that we do support pushing the item value length
888+
size_t item_length = item->max_length;
889+
// For BINARY value the actual value length should be used.
890+
// If the BINARY value comes from a CHAR value casted to BINARY
891+
// it will have max_length as a multiple of connection charset
892+
// max character size.
893+
if (item->collation.collation == &my_charset_bin) {
894+
String buf, *val = const_cast<Item *>(item)->val_str(&buf);
895+
if (val) item_length = val->length();
896+
}
873897
if (context->expecting(Item::STRING_ITEM) &&
874-
context->expecting_length(item->max_length)) {
898+
context->expecting_length(item_length)) {
875899
ndb_item = new (*THR_MALLOC) Ndb_value(item);
876900
if (context->expecting_no_field_result()) {
877901
// We have not seen the field argument yet
878902
context->expect_only_field_from_table(this_table);
879903
context->expect_field_result(STRING_RESULT);
880904
context->expect_collation(item->collation.collation);
881-
context->expect_length(item->max_length);
905+
context->expect_length(item_length);
882906
} else {
883907
// Expect another logical expression
884908
context->expect_only(Item::FUNC_ITEM);
@@ -897,7 +921,7 @@ static void ndb_serialize_cond(const Item *item, void *arg) {
897921
} else
898922
context->supported = false;
899923
break;
900-
924+
}
901925
default:
902926
assert(false);
903927
context->supported = false;
@@ -1006,7 +1030,9 @@ static void ndb_serialize_cond(const Item *item, void *arg) {
10061030
// type.
10071031
if (field->result_type() == STRING_RESULT &&
10081032
!is_supported_temporal_type(type)) {
1009-
if (!context->expecting_max_length(field->field_length)) {
1033+
if (!context->expecting_max_length(field->field_length) ||
1034+
(field->binary() &&
1035+
!context->expecting_min_length(field->field_length))) {
10101036
DBUG_PRINT("info", ("Found non-matching string length %s",
10111037
field->field_name));
10121038
context->supported = false;
@@ -1042,6 +1068,13 @@ static void ndb_serialize_cond(const Item *item, void *arg) {
10421068
context->expect(Item::VARBIN_ITEM);
10431069
context->expect_collation(
10441070
field_item->collation.collation);
1071+
/*
1072+
* For BINARY columns value length must be exactly the
1073+
* same for equality like conditions, since value will be
1074+
* zero padded when compared in NdbSqlUtil::cmpBinary.
1075+
*/
1076+
if (type == MYSQL_TYPE_STRING && field->binary())
1077+
context->expect_min_length(field->field_length);
10451078
context->expect_max_length(field->field_length);
10461079
break;
10471080
case REAL_RESULT:

0 commit comments

Comments
 (0)