Chat (Lingr.com)
Informaiton
Daily
Column
- MySQL日本語の旅(5/1)
- アクセス向上秘伝(5/9)
- 一風変ったHaskellλ門(6/13)
- SICP Answer Book (5/31) 問題3.26追加
Zope Solution
Extra
アーカイブ
OSS案内所
Site Info
関連リンク
もう一度、足早にgdbを立ち上げるところからやってみよう。
shell$ gdb /usr/local/mysql/bin/mysql GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"... (gdb)
ここで、いきなり mysql.cc の 2232行 にブレイクポイントを設定しよう。
(gdb) b mysql.cc:2232 Breakpoint 1 at 0x8054f62: file mysql.cc, line 2232. (gdb)
コマンドで起動し、漢字として問題が発生するであろう半角カタカナを使ってみる。
(gdb) r -u root Starting program: /usr/local/mysql/bin/mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 30 to server version: 5.0.10-beta-debug-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SET NAMES eucjpms; Query OK, 0 rows affected (0.00 sec) mysql> select 'サカマチ'; +----------+ | サカマチ | +----------+ Breakpoint 1, print_table_data (result=0x809c9f8) at mysql.cc:2232 2232 uint currlength= (uint) lengths[off]; (gdb)
指定した位置でちゃんと止まったようだ。
タイトルも半角カタカナが表示されるのだが、変になっている。
2232 uint currlength= (uint) lengths[off]; 2233 uint numcells= charset_info->cset->numcells(charset_info, 2234 str, str + currlength); 2235 tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|", 2236 maxlength + currlength - numcells, str);
ここからは、1行ずつ実行しながら結果を見ていこう。
2246 static void (gdb) n 2233 uint numcells= charset_info->cset->numcells(charset_info, (gdb) p currlength $1 = 8 (gdb) n 2235 tee_fprintf(PAGER, num_flag[off] ? "%*s |" : " %-*s|", (gdb) p numcells $2 = 8 (gdb) p maxlength + currlength - numcells $3 = 9
ということで、%*s の 可変幅の部分(*)は9になる。
(gdb) p num_flag[off] $5 = false
なので、 書式は " %-*s|" の方が採用される。 普通のprintfと同じ動きをするのであれば、'サカマチ' は8バイトなので、 後に空白が1つ付く。前には元々1つついているので、 全体としては
空白1文字 + サカマチ + 空白1文字 + |
が出力される。したがって詰まる訳だ。
その後もnで1行毎に実行すると、以下のように、表が出力される様子が分かる。
(gdb) n
2220 for (uint off= 0; off < mysql_num_fields(result); off++)
(gdb) n
2239 (void) tee_fputs("\n", PAGER);
(gdb) n
| サカマチ |
87 inline const char *ptr() const { return Ptr; }
(gdb) n
+----------+
78 ~String() { free(); }
(gdb)
charset_infoはどうなっているか
文字列の表示幅を求めるところは
2233 uint numcells= charset_info->cset->numcells(charset_info, 2234 str, str + currlength);
となっていて、charset_infからポインタを辿った先にある関数で処理されている。 この charset_info の値を見てみよう。
(gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /usr/local/mysql/bin/mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 31 to server version: 5.0.10-beta-debug-log Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SET NAMES eucjpms; Query OK, 0 rows affected (0.03 sec) mysql> select 'サカマチ'; +----------+ | サカマチ | +----------+ Breakpoint 1, print_table_data (result=0x809c9f8) at mysql.cc:2232 2232 uint currlength= (uint) lengths[off]; (gdb) p charset_info $6 = (CHARSET_INFO *) 0x80766a0 (gdb)
charset_infoはポインタなので、中味を見るには * を付けないといけない。
(gdb) p *charset_info
$7 = {number = 8, primary_number = 0, binary_number = 0, state = 801,
csname = 0x808c158 "latin1", name = 0x8090998 "latin1_swedish_ci",
comment = 0x8090978 "ISO 8859-1 West European", tailoring = 0x0, ctype = 0x400bca20 "",
to_lower = 0x400bcb40 "", to_upper = 0x400bcc40 "", sort_order = 0x400bcd40 "",
contractions = 0x0, sort_order_big = 0x0, tab_to_uni = 0x400bce40, tab_from_uni = 0x0,
caseinfo = 0x4012b960,
state_map = 0x8086580 .....以下省略 ,
ident_map = 0x8086680 "", strxfrm_multiply = 1, caseup_multiply = 1 '\001',
casedn_multiply = 1 '\001', mbminlen = 1, mbmaxlen = 1, min_sort_char = 0,
max_sort_char = 255, cset = 0x400bdc60, coll = 0x400be020}
(gdb)
SET NAMES eucjpms とやったにもかかわらず、chasetinfo->csname は "latin1" となっている。eucjpmpは反映されていない。
ということは、8バイトの文字列 'サカマチ' は、latin1の文字として解釈され、 きっとlatin1では、全ての文字は1バイトが1セルと計算されるので、 思った通り変になっているのであろう。
戻る:print_table_data()にブレークポイントを設定
フィードバック:
There is no comment.