end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

PostgreSQL 9.6 に対し、sjis環境のclient (perl)から機種依存文字を登録 - 環境変数:PGCLIENTENCODINGを利用

ERROR:  invalid byte sequence for encoding "SJIS": ...

きっかけは上記のようなエラー。 機種依存文字が影響していることは、すぐに分かりましたが、client側での対処に手こずった。

随分、久しぶりにpostgresを触ったせいですね。

参考url

https://www.postgresql.jp/document/9.6/html/multibyte.html

サーバ側(postgres)側の環境

今回の為、test DBをencoding=utf8で createdb しています。 ちなみにサーバ側のencodingに、sjisやcp932はないようです。

$ /usr/local/pgsql/bin/psql --version
psql (PostgreSQL) 9.6.5

$ /usr/local/pgsql/bin/psql --username=postgres -l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 test      | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
$ /usr/local/pgsql/bin/psql --username=postgres test

$ test=#  CREATE TABLE test (
        atri_id     serial, /* = AUTO_INCREMENT of mysql */
        atri_val    varchar(20),
        PRIMARY KEY (atri_id) );

test=# \d
                List of relations
 Schema |       Name       |   Type   |  Owner   
--------+------------------+----------+----------
 public | test             | table    | postgres
 public | test_atri_id_seq | sequence | postgres
(2 rows)

test=# \d test
                                    Table "public.test"
  Column  |         Type          |                       Modifiers                        
----------+-----------------------+--------------------------------------------------------
 atri_id  | integer               | not null default nextval('test_atri_id_seq'::regclass)
 atri_val | character varying(20) | 
Indexes:
    "test_pkey" PRIMARY KEY, btree (atri_id)

クライアント側(perl)の環境変数に PGCLIENTENCODING = SJIS を設定

https://www.postgresql.jp/document/9.6/html/multibyte.html

上記のpostgresのdocumentにおいて、client側encodingの指定として 1)「SET CLIENT_ENCODING TO '~'」2)「SET NAMES '~'」3)「$ENV{PGCLIENTENCODING}」 があるように記載されていますが、 私の環境において1),2)は上手く動作せず、3)の$ENV{PGCLIENTENCODING}に落ち着きました。

#!/usr/local/bin/perl
use utf8;
use strict;
use warnings;
use DBI;
use Encode;
use Data::Dumper;

my $DB_CONF =
    {db=>"DBI:Pg:dbname=test;host=localhost;",
     user=>'postgres',
     pass=>'',
     client_encoding => 'SJIS',
     option => {AutoCommit=>0,
#                pg_enable_utf8=>0,
                RaiseError => 1,
                PrintError => 0}
    };


main();

sub main {
    
    $ENV{PGCLIENTENCODING} = $DB_CONF->{client_encoding};
    
    my $dbh = connect_db();

    my $sql =<<EOF;
insert into test (atri_val) values(?)
EOF
    my $sth = $dbh->prepare($sql);

    my $org_val = '髙';
#    my $new_val = Encode::encode('utf8',$org_val);
    my $new_val = Encode::encode('cp932',$org_val);
    
    unless( $sth->execute($new_val) ){
        print STDERR $sth->errstr,"\n";
    }
    $dbh->commit;
    $dbh->disconnect;
}

sub connect_db {
    my $dbh = DBI->connect($DB_CONF->{db},
                           $DB_CONF->{user},
                           $DB_CONF->{pass},
                           $DB_CONF->{option});
#    $dbh->do("SET NAMES '$DB_CONF->{client_encoding}'") or
#        die "cannot set encoding $!";
#    $dbh->do("SET CLIENT_ENCODING TO $DB_CONF->{client_encoding}") or
#        die "cannot set encoding $!";
    return $dbh;
}