Pg 提供了两种存储二进制文件的方法:
表中的大对象,pg_largeobject
由oid
. 通常通过lo
扩展使用。可装载lo_import
.
常规表中的bytea 列。在 PostgreSQL 9.0 及更低版本中表示为八进制转义\000\001\002fred\004
,或在 Pg 9.1 及更高版本中默认为十六进制转义,例如\x0102
. 该设置允许您在具有格式的版本中bytea_output
选择escape
(八进制)和格式。hex
hex
您正在尝试使用lo_import
将数据加载到bytea
列中。那是行不通的。
您需要做的是发送 PostgreSQL 正确转义的 bytea 数据。在受支持的当前 PostgreSQL 版本中,您只需将其格式化为十六进制,\x
在前面敲一个,就可以了。在您的版本中,您必须将其作为八进制反斜杠序列转义,并且(因为您使用的是不使用的旧 PostgreSQL standard_conforming_strings
)可能也必须将反斜杠加倍。
这个邮件列表帖子提供了一个很好的示例,可以在您的版本上运行,后续消息甚至解释了如何修复它以使其也适用于史前较少的 PostgreSQL 版本。它展示了如何使用参数绑定来强制 bytea 引用。
基本上,您需要读取文件数据。您不能只将文件名作为参数传递 - 数据库服务器将如何访问本地文件并读取它?它会在服务器上寻找路径。
读入数据后,您需要将其作为 bytea 转义并将其作为参数发送到服务器。
更新:像这样:
use strict;
use warnings;
use 5.16.3;
use DBI;
use DBD::Pg;
use DBD::Pg qw(:pg_types);
use File::Slurp;
die("Usage: $0 filename") unless defined($ARGV[0]);
die("File $ARGV[0] doesn't exist") unless (-e $ARGV[0]);
my $filename = $ARGV[0];
my $dbh = DBI->connect("dbi:Pg:dbname=regress","","", {AutoCommit=>0});
$dbh->do(q{
DROP TABLE IF EXISTS byteatest;
CREATE TABLE byteatest( blah bytea not null );
});
$dbh->commit();
my $filedata = read_file($filename);
my $sth = $dbh->prepare("INSERT INTO byteatest(blah) VALUES (?)");
# Note the need to specify bytea type. Otherwise the text won't be escaped,
# it'll be sent assuming it's text in client_encoding, so NULLs will cause the
# string to be truncated. If it isn't valid utf-8 you'll get an error. If it
# is, it might not be stored how you want.
#
# So specify {pg_type => DBD::Pg::PG_BYTEA} .
#
$sth->bind_param(1, $filedata, { pg_type => DBD::Pg::PG_BYTEA });
$sth->execute();
undef $filedata;
$dbh->commit();