diff options
author | unknown <bar@mysql.com/bar.myoffice.izhnet.ru> | 2007-06-28 13:34:44 +0500 |
---|---|---|
committer | unknown <bar@mysql.com/bar.myoffice.izhnet.ru> | 2007-06-28 13:34:44 +0500 |
commit | 54344f681dfc75170867c3e92dd726f9c28a3f41 (patch) | |
tree | da899a52dc4bbef9ed8e4bc182401319f6095505 /strings/ctype-ucs2.c | |
parent | 9b940d0cb70508ca295bc68a8bab5832d79ededd (diff) | |
download | mariadb-git-54344f681dfc75170867c3e92dd726f9c28a3f41.tar.gz |
Bug#27345 Incorrect data returned when range-read from utf8_danish_ci indexes
Problem: like_range() returned wrong ranges for contractions (like 'ch' in Czech').
Fix: adding a special code to handle tricky cases:
- contraction head followed by a wild character
- full contraction
- contraction part followed by another contraction part,
but they are not a contraction together.
mysql-test/r/ctype_uca.result:
Adding test case
mysql-test/t/ctype_uca.test:
Adding test case
strings/ctype-mb.c:
Adding test case
strings/ctype-uca.c:
Allocate additional 256 bytes for flags "is contraction part".
strings/ctype-ucs2.c:
Adding test case
Diffstat (limited to 'strings/ctype-ucs2.c')
-rw-r--r-- | strings/ctype-ucs2.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index f3abbaa6e7e..b5353c55e4c 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1524,6 +1524,8 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs, char *min_org=min_str; char *min_end=min_str+res_length; uint charlen= res_length / cs->mbmaxlen; + const char *contraction_flags= cs->contractions ? + ((const char*) cs->contractions) + 0x40*0x40 : NULL; for ( ; ptr + 1 < end && min_str + 1 < min_end && charlen > 0 ; ptr+=2, charlen--) @@ -1545,6 +1547,7 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs, } if (ptr[0] == '\0' && ptr[1] == w_many) /* '%' in SQL */ { +fill_max_and_min: /* Calculate length of keys: 'a\0\0... is the smallest possible string when we have space expand @@ -1561,6 +1564,38 @@ my_bool my_like_range_ucs2(CHARSET_INFO *cs, } while (min_str + 1 < min_end); return 0; } + + if (contraction_flags && ptr + 3 < end && + ptr[0] == '\0' && contraction_flags[(uchar) ptr[1]]) + { + /* Contraction head found */ + if (ptr[2] == '\0' && (ptr[3] == w_one || ptr[3] == w_many)) + { + /* Contraction head followed by a wildcard, quit */ + goto fill_max_and_min; + } + + /* + Check if the second letter can be contraction part, + and if two letters really produce a contraction. + */ + if (ptr[2] == '\0' && contraction_flags[(uchar) ptr[3]] && + cs->contractions[(ptr[1]-0x40)*0x40 + ptr[3] - 0x40]) + { + /* Contraction found */ + if (charlen == 1 || min_str + 2 >= min_end) + { + /* Full contraction doesn't fit, quit */ + goto fill_max_and_min; + } + + /* Put contraction head */ + *min_str++= *max_str++= *ptr++; + *min_str++= *max_str++= *ptr++; + charlen--; + } + } + /* Put contraction tail, or a single character */ *min_str++= *max_str++ = ptr[0]; *min_str++= *max_str++ = ptr[1]; } |