1

我在 PostgreSQL 9.2 上对表进行了分区,每个表都具有如下所示的分区函数:

CREATE OR REPLACE FUNCTION myPartitionSelectionFunction()
  RETURNS trigger AS
$BODY$
BEGIN
    IF ( NEW.PartitionColumn < DATE '2010-08-08 00:00:00') THEN INSERT INTO MyPartitionedTable_Week_31_2010 VALUES (NEW.*);
    ELSIF ( NEW.PartitionColumn < DATE '2010-08-15 00:00:00' AND NEW.PartitionColumn >=  DATE '2010-08-08 00:00:00') THEN INSERT INTO MyPartitionedTable_Week_32_2010 VALUES (NEW.*);
    ELSE
        RAISE EXCEPTION 'PartitionColumn out of range. Update myPartitionSelectionFunction()';
    END IF;
    RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql

所以,每周都是一个新的分区。问题是每周更新数百个函数。我必须自动化,每个插入的触发器是不可行的。这个想法是创建一个由 cron 调用的函数来更新每个分区函数,在最终的 ELSE 之前添加另一个 ELSIF。但是我找不到一种方法来遍历每个具有“分区”名称的函数,然后检索它的代码(像 \d 这样的 psql 命令在函数中不起作用,对吧?)以添加新的 ELSIF 和相应地更新(ALTER)每个函数,在此过程中创建一个新分区。

所以,我现在最大的问题是:

一旦有“分区”名称,我如何迭代(使用光标?)每个函数,然后检索它的代码,在 ELSE 之前添加另一个 ELSIF 并更新(ALTER)它的内容不会有陷入无限循环的风险?

任何帮助深表感谢。谢谢。

4

1 回答 1

4

虽然您可以从 中检索函数源pg_proc,但尝试检索、编辑和更新函数是痛苦和痛苦的秘诀。

相反,编写一个 PL/PgSQL 过程来生成完整的函数文本。对information_schemaor使用查询pg_catalog.pg_class来获取所需的表列表、约束、继承等。循环查询结果,生成函数主体,然后将其全部连接成一个文本块并将其传递给EXECUTE.

这是一个函数生成另一个函数的玩具示例:

CREATE OR REPLACE FUNCTION very_meta(func_name text, message text) RETURNS void AS 
$$
DECLARE
    func_lines text;
BEGIN
    -- In reality you'd build this iteratively, or preferably use `string_agg` over
    -- a query, but I'm just going to supply a single line function body for this
    -- example:
    func_lines := format($LINE$RAISE NOTICE 'It works, message is %%!','%s';$LINE$, message);
    -- Now, build the function creation statement and execute it:
    EXECUTE format(
    $INNER$
        -- this is the SQL text we're going to execute, with the %%I placeholder
        -- to be replaced by the format(...) function:
        --
        CREATE OR REPLACE FUNCTION %I() RETURNS void AS
        $INNERBODY$
        BEGIN
            -- and this is the body of the function we're generating
            -- in this case it's going to be substituted in as func_lines
            -- by format(...)
            %s
        END;
        $INNERBODY$
        LANGUAGE plpgsql;
    $INNER$, func_name, func_lines);
END;
$$ LANGUAGE plpgsql;

演示:

regress=> SELECT very_meta('lessmeta', 'Secret Message');
 very_meta 
-----------

(1 row)

regress=> SELECT lessmeta();
NOTICE:  It works, message is Secret Message!
 lessmeta 
----------

(1 row)

这可以与针对information_schema和/或系统目录的适当查询相结合,以获取表列表、创建一系列条件测试等。我不久前写的这个答案详细说明了如何查询目录的继承关系,这可能很有用,但您还需要确定CHECK使用中的约束。如果您有一个命名约定,那么仅仅依靠它并搜索pg_class.

请记住,如果这样的话,PostgreSQL 的分区最多可以处理几百个表。由于表数较大的查询计划成本,性能将显着下降。

于 2013-07-20T13:45:10.490 回答