mysql:1792
From: とみたまさひろ <とみたまさひろ <tommy@xxxxxxxxxx>>
Date: Wed, 22 Mar 2000 01:52:02 +0900
Subject: [mysql 01792] Re: sjis & order by
とみたです。 At Tue, 21 Mar 2000 20:18:42 +0900, takeshi@xxxxxxxxxx wrote: > 現在の MySQL のコードでは、char 型に代入された SJIS 文字の > 2byte 目が 0x41-0x5a (=[a-z]), 0x61-0x7a (=[A-Z]) の時に、 > 2byte 目が ケース非依存でソートされてしまいます。 ああ、SJIS にはそういう問題があったんですね。試してみると確かに "1", "A", "B" が "B", "1", "A" の順に並んじゃいますね。気づきませんでし た。 > MySQL を --with-charset=sjis で作成して、 > char 型(binary 属性はつけない)に sjis データを入れた時、 > order by が一部、正しく出なかったのを修正するパッチです。 > 検証してみてください。 > 3.22.32用のパッチです いくつかまずいところがあるようです。実際に問題が発生するのを確認したわけ ではありませんが。バッファをオーバーしてデータを読み書きする可能性があっ たり、「\」の後に2バイトデータが来ることが考慮されてなかったり…。 # GBK という名称が残ってたり… :-) ということで私もパッチを作ってみました(ctype-sjis.c だけ)。strnxfrm とか like_range とかを良く理解せずに書いているので、変かもしれません… (^^; # ぢつわ GBK のコードの方が正しかったりして… (^^;; -- とみたまさひろ <tommy@xxxxxxxxxx> *** ctype-sjis.c.orig Sun Apr 26 20:35:20 1998 --- ctype-sjis.c Wed Mar 22 01:28:44 2000 *************** *** 2,7 **** --- 2,8 ---- */ #include <global.h> #include "m_string.h" + #include "m_ctype.h" uchar NEAR ctype_sjis[257] = { *************** *** 147,149 **** --- 148,270 ---- '\360','\361','\362','\363','\364','\365','\366','\367', '\370','\371','\372','\373','\374','\375','\376','\377', }; + + #define sjiscode(c,d) (((uchar)(c) << 8) | (uchar)(d)) + + uint MY_STRXFRM_MULTIPLY=1; + + int my_strnncoll(const uchar *s1, int len1, const uchar *s2, int len2) + { + const uchar *e1 = s1 + len1; + const uchar *e2 = s2 + len2; + while (s1 < e1 && s2 < e2) { + if (ismbchar(s1, e1) && ismbchar(s2, e2)) { + uint c1 = sjiscode(*s1, *(s1+1)); + uint c2 = sjiscode(*s2, *(s2+1)); + if (c1 != c2) + return c1 - c2; + s1 += 2; + s2 += 2; + } else { + if (my_sort_order[(uchar)*s1] != my_sort_order[(uchar)*s2]) + return my_sort_order[(uchar)*s1] - my_sort_order[(uchar)*s2]; + s1++; + s2++; + } + } + return len1 - len2; + } + + int my_strcoll(const uchar *s1, const uchar *s2) + { + return my_strnncoll(s1, strlen(s1), s2, strlen(s2)); + } + + int my_strnxfrm(uchar *dest, uchar *src, int len, int srclen) + { + uchar *dend = dest + len; + uchar *send = src + srclen; + while (dest < dend && src < send) { + if (ismbchar(src, send)) { + *dest++ = *src++; + if (dest < dend && src < send) + *dest++ = *src++; + } else { + *dest++ = my_sort_order[(uchar)*src++]; + } + } + return srclen; + } + + int my_strxfrm(uchar *dest, uchar *src, int len) + { + return my_strnxfrm(dest, src, len, strlen(src)); + } + + + /* + ** Calculate min_str and max_str that ranges a LIKE string. + ** Arguments: + ** ptr Pointer to LIKE string. + ** ptr_length Length of LIKE string. + ** escape Escape character in LIKE. (Normally '\'). + ** All escape characters should be removed from min_str and max_str + ** res_length Length of min_str and max_str. + ** min_str Smallest case sensitive string that ranges LIKE. + ** Should be space padded to res_length. + ** max_str Largest case sensitive string that ranges LIKE. + ** Normally padded with the biggest character sort value. + ** + ** The function should return 0 if ok and 1 if the LIKE string can't be + ** optimized ! + */ + + #define max_sort_char 255 + #define wild_one '_' + #define wild_many '%' + + my_bool my_like_range(const char *ptr,uint ptr_length,pchar escape, + uint res_length, char *min_str,char *max_str, + uint *min_length,uint *max_length) + { + const char *end=ptr+ptr_length; + char *min_org=min_str; + char *min_end=min_str+res_length; + + while (ptr < end && min_str < min_end) { + if (ismbchar(ptr, end)) { + *min_str++ = *max_str++ = *ptr++; + if (min_str < min_end) + *min_str++ = *max_str++ = *ptr++; + continue; + } + if (*ptr == escape && ptr+1 < end) { + ptr++; // Skip escape + if (ismbchar(ptr, end)) + *min_str++ = *max_str++ = *ptr++; + if (min_str < min_end) + *min_str++ = *max_str++ = *ptr++; + continue; + } + if (*ptr == wild_one) { // '_' in SQL + *min_str++ = '\0'; // This should be min char + *max_str++ = max_sort_char; + ptr++; + continue; + } + if (*ptr == wild_many) { // '%' in SQL + *min_length = (uint)(min_str - min_org); + *max_length = res_length; + do { + *min_str++ = ' '; // Because if key compression + *max_str++ = max_sort_char; + } while (min_str < min_end); + return 0; + } + *min_str++ = *max_str++ = *ptr++; + } + *min_length = *max_length = (uint)(min_str - min_org); + while (min_str < min_end) + *min_str++ = *max_str++ = ' '; // Because if key compression + return 0; + }
1790 2000-03-21 20:18 [<takeshi@xxxxxxxxxx>] sjis & order by -> 1792 2000-03-22 01:52 ┗[とみたまさひろ <tomm] 1794 2000-03-22 04:23 ┗[<takeshi@xxxxxxxxxx>]