0

我想在 plperlu 中生成 PDF,将其存储在数据库中,然后将其作为附件添加到电子邮件中。

我正在使用 PDF::Report 来生成 PDF。代码如下所示:-

CREATE OR REPLACE FUNCTION workflow.make_pdf(report_template json, report_json json)
  RETURNS bytea AS
$BODY$

use strict;
use PDF::Report;
my $pdf = new PDF::ReportNG(PageSize => 'A4', PageOrientation => "Landscape");
...
 lots of tricky stuff to make PDF
...
return $pdf->Finish();
$BODY$ LANGUAGE plperlu;

我认为这个错误与invalid input syntax for type bytea创建的 PDF 文档的编码有关。

文档本身很好,因为$pdf->saveAs('/tmp/test.pdf');它创建了一个完全可读的文档。

我在返回结果之前尝试了 base64 编码,因为电子邮件的附件需要在 base64 中。

return MIME::base64::encode($pdf->Finish());

这消除了错误,然后我可以将它存储在一个表中: -

INSERT INTO weekly_report_pdfs(report) 
VALUES (make_pdf(report_template,report_json));

这也可以正常工作,并且可以附加到电子邮件中,但是在 base64 解码后损坏问题仍然存在。

直接从数据库中导出文件并运行仅在一行之后base64 -d test.b64就会出现错误。invalid input

这似乎与 postgres 处理 bytea 的方式有关,因为文件如下所示:-

MDA0OTY1MSAwMDAwMCBuIAowMDAwMDQ5ODU0IDAwMDAwIG4gCjAwMDAwNTAxNjcgMDAwMDAgbiAK\\012dHJhaWxlcgo8PCAvUm9vdCAxIDAgUiAvU2l6ZSA0MCAvSW5mbyA0IDAgUiA+PgpzdGFydHhyZWYK\\012

有很多 \012 分隔符。

任何想法,我一直在这几个小时,完全被难住了。

4

1 回答 1

2

从 plperl 返回二进制文件

当声明为返回时bytea,pl/perl 函数实际上必须返回一个 postgresql 文本表示形式bytea

考虑一下文档中PL/Perl Functions and Arguments的摘录(更具体地说是最后一句话):

函数参数中不是引用的任何内容都是字符串,它是相关数据类型的标准 PostgreSQL 外部文本表示形式。对于普通的数字或文本类型,Perl 只会做正确的事情,程序员通常不必担心。但是,在其他情况下,需要将参数转换为在 Perl 中更可用的形式。例如,decode_bytea 函数可用于将 bytea 类型的参数转换为未转义的二进制文件。

同样,传回 PostgreSQL 的值必须是外部文本表示格式。例如,encode_bytea 函数可用于转义二进制数据以获取类型为 bytea 的返回值。

根据这个,你应该这样做:

return encode_bytea($pdf->Finish());

然后invalid input syntax for type bytea错误就会消失。

返回base64

如果返回 base64,则函数通常应声明为RETURNS textreport列也应声明为text。这将解决让这些\012序列看起来像换行符(ASCII 码 = 12 八进制)的问题,这些序列以 postgresescape格式的字节茶字符串文字表示。换行通常由 base64 编码器每 76 个字符添加一次,以避免 MIME 正文中出现长行 ( RFC-4648)

如果该report列保留bytea并且该函数使用 生成 base64 RETURNS text,则应该在 INSERT 上进行隐式转换,这可能会很好。否则可以使用显式进行转换,convert_to(bytea_plperl_func(), 'US-ASCII') 但存储base64bytea列中没有多大意义。

于 2014-01-17T21:14:55.543 回答