【问题标题】:Constructing array literal as input for PL/pgSQL function构造数组文字作为 PL/pgSQL 函数的输入
【发布时间】:2020-06-25 03:19:39
【问题描述】:

如何在函数调用中包含具有复合类型元素的数组?

在网上查阅资源并尝试不同的变体后,我继续收到解析器错误。下面我介绍了类型、表、函数和执行尝试。

类型

CREATE TYPE jobs_v0.insertable_program AS (
       handle text,
       zip bytea
);

表格

CREATE TABLE jobs_v0.jobs (
       id bigserial PRIMARY KEY NOT NULL,
       manifest_cid text NOT NULL,
       created_at timestamp NOT NULL DEFAULT now()
);

CREATE TABLE jobs_v0.programs (
       id bigserial PRIMARY KEY NOT NULL,
       job bigserial REFERENCES jobs_v0.jobs(id) NOT NULL,
       handle text NOT NULL,
       package bytea NOT NULL
);

功能:

CREATE OR REPLACE FUNCTION jobs_v0.insert_job(
       manifest_cid text,
       programs jobs_v0.insertable_program[]
) RETURNS void AS
$$
DECLARE
       job_id jobs_v0.jobs.id%TYPE;
       program jobs_v0.insertable_program;
       inserted_programs jobs_v0.programs[];
BEGIN
       -- Insert job
       INSERT INTO jobs_v0.jobs(manifest_cid) VALUES (manifest_cid)
       RETURNING id INTO job_id;

       -- Insert programs
       INSERT INTO jobs_v0.programs(job, handle, package)
       SELECT job_id, * FROM unnest(programs)
       RETURNING * INTO inserted_programs;
END;
$$ LANGUAGE plpgsql;

执行尝试和错误:

select jobs_v0.insert_job('QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9', '{"(main, 0xdeadbeef)"}'::jobs_v0.insertable_program[]);
ERROR:  malformed array literal: "12"
DETAIL:  Array value must start with "{" or dimension information.
CONTEXT:  PL/pgSQL function jobs_v0.insert_job(text,jobs_v0.insertable_program[]) line 12 at SQL statement

---

select jobs_v0.insert_job('QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9', array[row('main', E'\\xdeadbeef')]::jobs_v0.insertable_program[]);
ERROR:  malformed array literal: "13"
DETAIL:  Array value must start with "{" or dimension information.


【问题讨论】:

    标签: postgresql plpgsql composite-types


    【解决方案1】:

    数组字面量应如下所示:

    select jobs_v0.insert_job(
              'QmTXzATwNfgGVukV1fX2T6xw9f6LAYRVWpsdXyRWzUR2H9',
              '{"(main,\"\\\\xdeadbeef\")"}'
           );
    

    但是bug在函数代码中:

    INSERT INTO jobs_v0.programs(job, handle, package)
    SELECT job_id, * FROM unnest(programs)
    RETURNING * INTO inserted_programs;
    

    RETRUNING * 中的* 确实引用了jobs_v0.programs 的所有列,不是引用了jobs_v0.insertable_program 的所有列,正如您所期望的那样。

    此外,inserted_programs 不能是数组类型,它必须是 jobs_v0.insertable_program 类型,并且只能包含一个结果。如果INSERT 插入多行,则只会返回第一行。

    【讨论】:

    • 感谢您的回复。如果我删除 RETURNING 声明一切都很好。但是,我的目标是获取programs 变量中的所有insertable_programs,将它们全部插入第一个语句中生成的作业ID,然后将插入的行累积到inserted_programs 变量中。那该怎么做呢?
    • 然后LOOP通过INSERT ... RETURNING的结果将行一一添加到数组中。你打算用数组做什么?
    猜你喜欢
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 2015-02-26
    • 2016-01-21
    相关资源
    最近更新 更多