如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?

Posted

技术标签:

【中文标题】如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?【英文标题】:How to dump the large object data from Postgres 9.4, and then import it to Postgres8.x? 【发布时间】:2016-12-06 10:30:45 【问题描述】:

我使用pg_dump 从 Postgres 9.4 中导出包括大对象 (LO) 的数据,如下所示:

$ pg_dump fhir -O -b > fhir.sql  

我生成的fhir.sql 中的 LO 语句是这样的:

SET standard_conforming_strings = on;
SELECT pg_catalog.lowrite(0, '\x1f8b0800000000000000a5903b6ec3300c86efa2d9b1dad5a728daa2');

当我在我的 Postgres8.2 中执行 \i fhir.sql 时,我得到了这个错误:

ERROR:  invalid input syntax for type bytea

当我SET standard_conforming_strings = off时,数据被插入了,但是我得到了一个警告,而我pg_largeobject表中的数据是:

14 |      0 | \0378b0800000000000000a5903b6ec3300c86efa2d9b1dad5a728daa2

原来的\x1f改成\037了,我测试了一下,已经不是我原来的zip文件了……

我该如何解决这个问题?

更新

我用Hibernate程序将同样的原始数据插入Greenplum(基于Postgresql8.2),然后用pg_dump导出,格式如下:

SELECT pg_catalog.lowrite(0, '\\037\\213\\010\\000\\000\\000\\000\\000\\000\\000\\245\\220;n\\3030\\014')

【问题讨论】:

【参考方案1】:

问题在于转储使用函数pg_catalog.lowrite(integer, bytea) 来创建大对象,并且bytea 字面量在PostgreSQL 中的默认语法在9.0 版本中发生了变化。

有一个参数bytea_output可以设置为escape,以旧格式输出bytea更高版本的PostgreSQL。唉,pg_dump 在创建转储时不尊重该参数,它始终使用“新”hex 格式。

结果是包含来自 PostgreSQL 9.0 或更高版本的大型对象的转储无法恢复到 9.0 之前的数据库中。

您必须以其他方式传输这些大型对象,可能是通过编写迁移程序。

您可以(在 pgsql-hackers 邮件列表中)向pg_dump 提出一个选项,该选项允许为转储设置bytea_escape,但您可能会遇到阻力,因为将转储从较新的 PostgreSQL 版本恢复到较旧的版本一个不支持。

【讨论】:

很遗憾听到这个消息,我也试过bytea_output,将其设置为escape 不起作用。感谢您的回答。如果还有其他答案对我有帮助,请允许我抱一线希望。 我会尝试使用 pg_dump 的 Greenplum 版本。但是我没有弄乱过大的物体,所以我不知道它是否会起作用。 @JonRoberts 也许 Greenplum 不一样,但是 PostgreSQL 的 pg_dump 拒绝连接到版本比它自己更高的服务器。 [gpadmin@localhost export]$ pg_dump fhir -h 192.168.2.108 -p 5432 -U postgres -O -t hfj_resource -f fhir.dmp Password: pg_dump: server version: 9.4.6; pg_dump version: 8.2.15 pg_dump: aborting because of server version mismatch @YinAqu 是的,这正是我所期望的。【参考方案2】:

UPDATA

我发现了一种更简单的工作方式:只需使用pg_dump -b -Fc 将包括LO 的数据导出到自定义文件中,稍后使用与您用于导出数据的pg_dump 相同版本的pg_restore 导入自定义文件文件数据到greenplum。

脚本:

$ pg_dump fhir -O -a -Fc  -f fhir.dump
$ pg_restore -h mdw -d fhir -U gpadmin -a fhir.dump > errors.log 2>&1

我错过的一点是lo_export 导出的二进制数据可以完美地导入greenplum。

我的解决方案(针对我的情况):

    分别从 Postgres9.4 导出纯数据(使用pg_dump,排除LO)和LO数据(使用lo_export)。 将纯数据转储导入 Greenplum 用lo_import导入LO数据,这会生成一些新的oidlo_importoid从Postgres8.4开始),同时用这些新的@更新引用表对应的oid 987654333@。

示例脚本:

    从 Postgres9.4 导出纯数据

     $ pg_dump fhir -O -a -n public -f fhir.dmp
    

    从包含 LO 数据的某个表中导出 LO,用原始 oid 命名导出的文件

    SELECT lo_export(res_text, '/usr/local/pgsql/export/res_lo/'||res_text) FROM hfj_resource;
    

    将纯数据导入Greenplum

    \i fhir.dmp
    

    在 Greenplum 中创建一个函数来导入 LO 并更新引用的 oid

    CREATE FUNCTION import_lo(tab_name text, lo_path text) RETURNS void AS $$
    
     DECLARE
    
        res record;
    
        new_oid oid;
    
     BEGIN
    
        FOR res in EXECUTE 'select res_text from '||$1 LOOP
    
            new_oid := lo_import($2||'/'||res.res_text);
    
            RAISE NOTICE 'res_text from % to %', res.res_text, new_oid;
    
            EXECUTE 'update '||$1||' set res_text='||new_oid||'where res_text='||res.res_text;
    
        END LOOP;
    
        RAISE NOTICE 'import large object into % finished .....', $1;
    
     END;
    
     $$ LANGUAGE plpgsql;
    

    导入 LO

    SELECT import_lo('hfj_resource', '/home/gpadmin/export/res_lo');
    

【讨论】:

以上是关于如何从 Postgres 9.4 中转储大对象数据,然后将其导入 Postgres8.x?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Postgres 9.4 中对 JSONB 类型的列执行更新操作

RDS postgres 从 9.4 升级到 9.5,CPU 卡在 100% 几个小时

如何从 Postgres Heroku 上的先前备份中恢复特定数据? (例如,意外删除的行)

如何安装/更新到 Postgres 9.4?

在较旧的 Postgres (9.4) 上使用 Django 3+

从 Mac 中删除旧的 Postgres 版本 [重复]