【问题标题】:Postgres COPY command escapes new lines and tabsPostgres COPY 命令转义新行和制表符
【发布时间】:2015-04-13 05:32:44
【问题描述】:

我有一个sql函数:

CREATE OR REPLACE FUNCTION dump_func()
  RETURNS void AS
$BODY$
DECLARE

r  record;

loc varchar(100);

BEGIN

    for r in (SELECT f.oid as oid, proname, pg_get_functiondef(f.oid) as src
            FROM pg_catalog.pg_proc f
            INNER JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid)
            WHERE n.nspname = 'public') loop

        loc = '/Users/raman/Desktop/functions/' || r.proname || '.sql';

        raise notice '% - %', r.oid, loc;
        raise notice 'func: %', r.src;

         EXECUTE format('COPY (
            SELECT pg_get_functiondef(f.oid)
                FROM pg_catalog.pg_proc f
                INNER JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid)
            WHERE n.nspname = ''public'' and f.oid=%s
            ) TO ''%s'' ', r.oid, loc); 

    end loop;
end
$BODY$
  LANGUAGE plpgsql;

使用 COPY 命令将 postgres 中的每个 db 函数导出到单独的文件中。除了在导出的 sql 文件中转义新行和制表符之外,一切正常,例如:

创建或替换函数 public.is_numeric(text)\n RETURNS boolean\n 语言 plpgsql\n IMMUTABLE\nAS $function$\nDECLARE x NUMERIC;\nBEGIN\n x = $1::NUMERIC;\n 返回 TRUE;\n例外 WHEN 其他 THEN\n RETURN FALSE;\nEND;\n$function$\n

你可以看到新的行和标签被转义了,如何解决这个问题?

【问题讨论】:

  • 默认列分隔符不是 csv 格式的 os 选项卡,行分隔符总是换行...您可以指定其他分隔符,但您仍然无法摆脱 ASCII(10)
  • COPY是多行多列的,所以行和列之间必须有分隔符。这些分隔符可能总是与任意内容冲突。考虑在文件中使用客户端 SELECT 而不是服务器端 COPY
  • 感谢 cmets,正如@Daniel 所说,使用客户端查询会更加灵活。我想一些 ant 脚本可能会解决这个问题。

标签: postgresql function


【解决方案1】:

其实这是可以做到的。哈奇虽然它是你只需使用regexp_split_to_table 并在\n 字符上拆分。我只是想自己解决同样的问题。这是我最终得到的代码:

DO $$

  DECLARE
    v_row record;
    v_proname text;
    v_sql text;

BEGIN

  FOR v_row IN (
    SELECT f.proname
    FROM pg_catalog.pg_proc AS f
    INNER JOIN pg_catalog.pg_namespace AS n ON (f.pronamespace = n.oid)
    WHERE n.nspname = 'public' AND f.proisagg = false
  ) LOOP

    SELECT v_row.proname::text INTO v_proname;
    EXECUTE FORMAT('COPY (
      SELECT regexp_split_to_table(regexp_replace(pg_get_functiondef(oid), ''\t'', ''   '', ''g''), ''\n'')
      FROM pg_catalog.pg_proc WHERE proname = ''%s'')
      TO ''C:\pg\%s.sql'';'
      , v_proname, v_proname);

  END LOOP;

END $$

【讨论】:

    【解决方案2】:

    安德鲁的回答是正确的,也帮我格式化了。

    我想出了一个类似的函数,但要在 PSQL 中打印所有用户定义的函数。希望对需要的人有所帮助:

    CREATE OR REPLACE FUNCTION printFunctions(stage VARCHAR, ischema VARCHAR, file_path VARCHAR)
      RETURNS VARCHAR AS
    $$
    DECLARE
      func VARCHAR;
      file_location TEXT;
    BEGIN
      FOR func IN SELECT procname FROM listfunctions()
        LOOP
        SELECT (file_path || '/' || func || '_' || stage || '.sql') INTO file_location;
        IF (SELECT regexp_matches(func, '(pldb|plpg)')) IS NULL
          THEN
            EXECUTE 'COPY ' ||
                    '(SELECT regexp_split_to_table(regexp_replace(pg_get_functiondef(oid), ''\t'', ''   '', ''g''),''\n'') from pg_proc where proname=' ||
                    '''' || func || '''' ||
                    ' and pronamespace=(select oid from pg_namespace where nspname=' ||
                    '''' || ischema || ''''
                    ')) TO ' || '''' || file_location || '''';
        END IF;
      END LOOP;
      RETURN stage;
    END
    $$
    LANGUAGE 'plpgsql';
    

    你可以这样称呼它:

    SELECT * FROM printFunctions('dev', 'public', '/tmp');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      • 1970-01-01
      • 2014-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-03
      相关资源
      最近更新 更多