DBD::SQLiteの入出力をちゃんと考えてみる

なんとか上手くいく方法はないものかと。

基本的には、Perlの内部形式の考え方をおさらいする形になった。 プログラムで扱う前にdecode、出力するときはencodeする。 それは、標準入出力だろうが、データベースだろうが、同じ扱い、ということ。 SQLiteはutf8の入出力が(少なくともver3.6.13では)可能のようだ。 まずは出力の時、データベースに渡すステートメントは「Encode::encode_utf8」してから出力する。 そして入力の時、つまり、データベースからデータを取る時は、とって来た後に「Encode::decode_utf8」する。 イメージは下の図。 今回は出力だけなのでSTDINは使っていないが、binmode STDOUTをencodingで使う場合は、あわせて指定しておくのが定石だと思われる。

1
2
3
|     |→(binmode STDIN )→|      |→(encode_utf8)→|      |
|DOS画面|                  |Perl内部|               |データベース|
|     |←(binmode STDOUT)←|    |←(decode_utf8)←|      |

「binmode STDOUT => “:encoding(cp932)";」とやる場合、printする時は内部形式のまま出力するように書けばいいので、他には何もすることがない。

他にも挙動を調べたかったので、中身は少し変えた。

スクリプト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# utf8
use 5.8.1;
use strict;
use warnings;
use utf8;
use DBI;
use Encode;
my $lang_code = 'cp932';
binmode STDOUT => ":encoding($lang_code)";
my $database = ':memory:';                         # DBD::SQLite ver1.27以降
my @dsn      = ("dbi:SQLite:dbname=$database",);
my $dbh      = DBI->connect(@dsn);
printn("ver" . $dbh->{sqlite_version});
my $create_table = 'CREATE TABLE IF NOT EXISTS books (' . 'タイトル,' . '著者' . ');';
sub_do($dbh, $create_table);

# insert文の実行
my $statement;
$statement = qq/insert into books (タイトル, 著者) values ('Perl',   '啓仁');/;
sub_do($dbh, $statement);
$statement = qq/insert into books (タイトル, 著者) values ('C++',    '成憲');/;
sub_do($dbh, $statement);
$statement = qq/insert into books (タイトル, 著者) values ('C#',     '☺鳳☻');/;
sub_do($dbh, $statement);
$statement = q/insert into books (タイトル, 著者) values ('Python', '☻鳳☺');/;
sub_do($dbh, $statement);
$statement = q/insert into books (タイトル, 著者) values ('Java',   'Keva');/;
sub_do($dbh, $statement);

# update文の実行
$statement = q/update books set タイトル = 'Ruby' where 著者 = '成憲'/;    # 著者が'成憲'のタイトルを「Ruby」に更新
sub_do($dbh, $statement);

# delete文の実行
$statement = q/delete from books where 著者 = '☻鳳☺';/;
sub_do($dbh, $statement);

# select文の実行
my $sth = $dbh->prepare("select * from books;");
$sth->execute;

# 各行のフェッチ
while (my $row = $sth->fetchrow_arrayref) {

    # 各行を出力
    my $str = $row->[0] . ":" . $row->[1];
    $str = Encode::decode_utf8($str);
    printn($str);
}
undef $sth;

# データベースの切断
$dbh->disconnect;

sub sub_do {
    my ($dbh, $statement) = @_;
    $statement = Encode::encode_utf8($statement);
    $dbh->do($statement);
}

sub printn {
    print @_;
    print "\n";
}

実行結果

1
2
3
4
5
6
7
"\x{263a}" does not map to cp932.
"\x{263b}" does not map to cp932.
ver3.6.13
Perl:啓仁
Ruby:成憲
C#:\x{263a}鳳\x{263b}
Java:Keva

SQLiteは手軽に使えるので、使い方をちゃんと考えてみるのも良いもんだ。

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy