diff --git a/extra/comp_err.c b/extra/comp_err.c index e36e85f6f0c..9326444ade9 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -660,7 +660,7 @@ static ha_checksum checksum_format_specifier(const char* msg) case 'u': case 'x': case 's': - chksum= my_checksum(chksum, start, (uint) (p - start)); + chksum= my_checksum(chksum, start, (uint) (p + 1 - start)); start= 0; /* Not in format specifier anymore */ break; @@ -1030,8 +1030,10 @@ static char *parse_text_line(char *pos) { int i, nr; char *row= pos; + size_t len; DBUG_ENTER("parse_text_line"); + len= strlen (pos); while (*pos) { if (*pos == '\\') @@ -1039,11 +1041,11 @@ static char *parse_text_line(char *pos) switch (*++pos) { case '\\': case '"': - VOID(strmov(pos - 1, pos)); + VOID(memmove (pos - 1, pos, len - (row - pos))); break; case 'n': pos[-1]= '\n'; - VOID(strmov(pos, pos + 1)); + VOID(memmove (pos, pos + 1, len - (row - pos))); break; default: if (*pos >= '0' && *pos < '8') @@ -1053,10 +1055,10 @@ static char *parse_text_line(char *pos) nr= nr * 8 + (*(pos++) - '0'); pos -= i; pos[-1]= nr; - VOID(strmov(pos, pos + i)); + VOID(memmove (pos, pos + i, len - (row - pos))); } else if (*pos) - VOID(strmov(pos - 1, pos)); /* Remove '\' */ + VOID(memmove (pos - 1, pos, len - (row - pos))); /* Remove '\' */ } } else diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 2306f8b501e..ab40eefdc82 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1603,4 +1603,21 @@ SELECT str_to_date('', '%Y-%m-%d'); str_to_date('', '%Y-%m-%d') 0000-00-00 DROP TABLE t1, t2; +# +# Bug #48665: sql-bench's insert test fails due to wrong result +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)); +INSERT INTO t1 VALUES (0,0), (1,1); +EXPLAIN +SELECT * FROM t1 FORCE INDEX (PRIMARY) +WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); +id select_type table type possible_keys key key_len ref rows Extra +@ @ @ range @ @ @ @ @ @ +# Should return 2 rows +SELECT * FROM t1 FORCE INDEX (PRIMARY) +WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); +a b +0 0 +1 1 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 3a845471cd0..736d65792c5 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1260,4 +1260,25 @@ SELECT str_to_date('', '%Y-%m-%d'); DROP TABLE t1, t2; + +--echo # +--echo # Bug #48665: sql-bench's insert test fails due to wrong result +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)); + +INSERT INTO t1 VALUES (0,0), (1,1); + +--replace_column 1 @ 2 @ 3 @ 5 @ 6 @ 7 @ 8 @ 9 @ 10 @ +EXPLAIN +SELECT * FROM t1 FORCE INDEX (PRIMARY) + WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); + +--echo # Should return 2 rows +SELECT * FROM t1 FORCE INDEX (PRIMARY) + WHERE (a>=1 AND a<=2) OR (a>=4 AND a<=5) OR (a>=0 AND a <=10); + +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b5037c08b3c..b293145cc27 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -386,7 +386,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, if (tmp - val > 6) tmp= (char*) val + 6; l_time->second_part= (int) my_strtoll10(val, &tmp, &error); - frac_part= 6 - (uint) (tmp - val); + frac_part= 6 - (int) (tmp - val); if (frac_part > 0) l_time->second_part*= (ulong) log_10_int[frac_part]; val= tmp; @@ -876,9 +876,9 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, value= value*LL(10) + (longlong) (*str - '0'); if (transform_msec && i == count - 1) // microseconds always last { - long msec_length= 6 - (uint) (str - start); + int msec_length= 6 - (int)(str - start); if (msec_length > 0) - value*= (long) log_10_int[msec_length]; + value*= (long)log_10_int[msec_length]; } values[i]= value; while (str != end && !my_isdigit(cs,*str)) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5f9bae22c70..909e3d36be5 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6671,6 +6671,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) else if ((cmp=tmp->cmp_max_to_min(key2)) < 0) { // Found tmp.max < key2.min SEL_ARG *next=tmp->next; + /* key1 on the left of key2 non-overlapping */ if (cmp == -2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // Join near ranges like tmp.max < 0 and key2.min >= 0 @@ -6699,6 +6700,7 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) int tmp_cmp; if ((tmp_cmp=tmp->cmp_min_to_max(key2)) > 0) // if tmp.min > key2.max { + /* tmp is on the right of key2 non-overlapping */ if (tmp_cmp == 2 && eq_tree(tmp->next_key_part,key2->next_key_part)) { // ranges are connected tmp->copy_min_to_min(key2); @@ -6733,25 +6735,52 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) } } - // tmp.max >= key2.min && tmp.min <= key.max (overlapping ranges) + /* + tmp.min >= key2.min && tmp.min <= key.max (overlapping ranges) + key2.min <= tmp.min <= key2.max + */ if (eq_tree(tmp->next_key_part,key2->next_key_part)) { if (tmp->is_same(key2)) { + /* + Found exact match of key2 inside key1. + Use the relevant range in key1. + */ tmp->merge_flags(key2); // Copy maybe flags key2->increment_use_count(-1); // Free not used tree } else { SEL_ARG *last=tmp; + SEL_ARG *first=tmp; + /* + Find the last range in tmp that overlaps key2 and has the same + condition on the rest of the keyparts. + */ while (last->next && last->next->cmp_min_to_max(key2) <= 0 && eq_tree(last->next->next_key_part,key2->next_key_part)) { + /* + We've found the last overlapping key1 range in last. + This means that the ranges between (and including) the + first overlapping range (tmp) and the last overlapping range + (last) are fully nested into the current range of key2 + and can safely be discarded. We just need the minimum endpoint + of the first overlapping range (tmp) so we can compare it with + the minimum endpoint of the enclosing key2 range. + */ SEL_ARG *save=last; last=last->next; key1=key1->tree_delete(save); } - last->copy_min(tmp); + /* + The tmp range (the first overlapping range) could have been discarded + by the previous loop. We should re-direct tmp to the new united range + that's taking its place. + */ + tmp= last; + last->copy_min(first); bool full_range= last->copy_min(key2); if (!full_range) {