Home

memo-space

DBD::PgとEvent::Libで非同期通知

DBの変更をトリガーにしてPushしたいなら、PostgreSQLのLISTEN/NOTIFYですよ。 最近のDBD::Pgは$dbh->func('getfd')というのが使えるらしい。

POEとかよく知りませんが、libeventならCから使ったことがあるので書いてみた。 こんな感じ。

#!/usr/local/bin/perl
use strict;
use warnings;
use IO::Handle;
use Event::Lib;
use DBI;
use Data::Dumper;

sub listener {
    my ($ev, $type, $dbh) = @_;

    print Dumper($dbh->func('pg_notifies'));
}

my $dbh = DBI->connect("dbi:Pg:", "", "");
$dbh->do("listen hoge");

my $reader = event_new(
    IO::Handle->new_from_fd($dbh->func('getfd'), "r"),
    EV_READ | EV_PERSIST, \&listener, $dbh);

$reader->add;

event_mainloop;

ファイルディスクリプタからファイルハンドルを得るあたりが自信無し。

# 実行
$ perl notify.pl
...
# 別端末でpsqlからnotifyすると、
=> notify hoge;
=> notify hoge;
...
# 非同期通知。ってこの説明で伝わるのか!?
$VAR1 = [
      'hoge',
      15164
    ];
$VAR1 = [
      'hoge',
      15164
    ];

普通はトリガと一緒に使います。

=> create or replace function t1_trig_func() returns trigger as
     $$begin notify hoge; end;$$ language plpgsql;
CREATE FUNCTION
=> create trigger t1_trigger after insert or update or delete on t1
     for each statement execute procedure t1_trig_func();
CREATE TRIGGER
=> insert into t1 values(1);

以下、関連するPostgreSQLのドキュメント

Perlのutf8フラグとDBI::Pg - その2

Perlのutf8フラグとDBI::Pgの続き。

DBD::Pg で取得した文字列に自動的に utf8 フラグを付けるには、$dbh->{pg_enable_utf8} を 1 にする。 ただ、これは本当に utf8 フラグを付けるということしかしないようなので、client_encoding を utf8 にするのは自分でやらなきゃいけないようだ。 client_encoding と連動してくれても良さそうな気もする。

データベースが euc-jp、ソースコードが utf-8 の例はこんな感じ。

#!/usr/bin/perl
use Encode;
use DBI;
use Data::Dumper;

my $dbh = DBI->connect("dbi:Pg:options='-c client_encoding=utf8'", "", "");
my $q = "select 'あいうえお'::text";

$dbh->{pg_enable_utf8} = 1;
my $s = $dbh->selectall_arrayref($q)->[0][0];
print utf8::is_utf8($s) ? "utf8": "not utf8", "\n";
print Encode::encode_utf8($s), "\n";

ところで、この pg_enable_utf8 は、取得した値のデータ型見て、text 型や varchar 型などの文字列型であれば utf8 フラグを付ける。その為以下のコードだと utf8 フラグは付かない。

my $q = "select 'あいうえお'";

何故かというと、明示的な型指定がない文字列リテラルは、PostgreSQL では unknown 型だからだ。

Perlのutf8フラグとDBI::Pg

Perl5.8 から、文字列を内部で Unicode で扱えるようになった。

  • utf8 フラグ無し -> バイナリ列
  • utf8 フラグ付き -> 文字列の内部形式

みたいな感じだと思う。 utf8 フラグを付ける(内部形式にする)ことを decode、その逆を encode と言う。 なので、Perl でマルチバイトを扱うときは、

  • 外部からのマルチバイト文字列の入力を decode する。(utf8 フラグを付ける)。
  • で、いろいろ文字列を処理。
  • 出力するときは encode してから出力。

utf8 フラグ付きのマルチバイト文字列をそのまま出力しようとすると警告がでる。

コードはこんな感じ。ソースは euc-jp で書いてます。

#!/usr/bin/perl
use strict;
use Encode;
# $s1 は utf8 フラグ無し、$s2 は utf8 フラグ付き
my $s1 = "あいうえお";
my $s2 = Encode::decode("euc-jp", "あいうえお");

print $s1, "\n";
print $s2, "\n";    # そのまま出力すると警告

print "s1 len = ", length($s1), "\n";
print "s2 len = ", length($s2), "\n";

$s1 =~ s/./$&,/g;
$s2 =~ s/./$&,/g;   # 正規表現も使えます

print $s1, "\n";
print Encode::encode("euc-jp", $s2), "\n";

実行結果

あいうえお
Wide character in print at pg.pl line 9.


s1 len = 10
s2 len = 5
が↑がががΜが━が

YAPC聞きまくり

ずっと YAPCmp3 を聞いている。いつになったら聞き終るんだろう。 高橋さんのオチは見事だなぁ。テレビでよく聞く弾さんの声はすぐわかる。 英語はほとんどワカラン。「ラク…ラクダ?」とか言ってるのが実はLarryか。

思わず吹いたのは、mixi に関する質疑応答で「今後 mixi がオフィシャルにソースを公開することはありますか?」ってw。

mod_perl など

mod_perl といえば cgi が速くなるやつ、くらいの認識しかなかったんだけど 全然ちがったよ。 apache モジュール相当のことを perl で書けるんだ。 正直スマンかった。これすげーじゃん。 いや、mod_python も mod_ruby もそうなんだけどさ。

これなら、perl でプロトタイプ書いておいてあとで C で実装 するというのもアリだな。

あと、mod_python のマニュアルが素敵すぎる。やっぱ python 方面はドキュメントが しっかりしてる印象があるなぁ。

/gと\G

perlの正規表現の m/../g と \G の働きがよくわからん。 m/../g はスカラコンテキストでは、 前回マッチした位置から開始して、マッチしたかどうかを返すらしい。 でも「前回マッチした結果」って何だ?

$a = 'abcde';

print "$&\n" if $a =~ m/[ace]/g;
print "$&\n" if $a =~ m/[ace]/g;
print "$&\n" if $a =~ m/[ace]/g;

$ perl x.pl
a
c
e

なるほど。これはわかる。 ではこの $a を文字列リテラルにしてみる。

print "$&\n" if 'abcde' =~ m/[ace]/g;
print "$&\n" if 'abcde' =~ m/[ace]/g;
print "$&\n" if 'abcde' =~ m/[ace]/g;

$ perl x.pl
a
a
a

この場合は「前回マッチした」とは扱われないようだ。 さっきの例の $a を途中で書き変えてみるとどうなるだろう。

$a = 'abcde';

print "$& $'\n" if $a =~ m/[ace]/g; $a = 'abeee';
print "$& $'\n" if $a =~ m/[ace]/g;
print "$& $'\n" if $a =~ m/[ace]/g;

$ perl x.pl
a
a
e

途中で書き換えると、また先頭からマッチを始めている。 さてこれをふまえて、\Gについてはまた今度 (続く)。

Home

Search
Feeds
Profile
石田@苫小牧市と名乗りつつ札幌の某社に勤務するプログラマ
書いた本
Links

Page Top