我在 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)它的内容不会有陷入困境的风险无限循环?
非常感谢任何帮助。谢谢。
最佳答案
虽然您可以从 pg_proc
检索函数源代码,但尝试检索它、编辑它并更新函数是痛苦和折磨的良方。
相反,编写一个 PL/PgSQL 过程来生成完整的函数文本。使用对 information_schema
或 pg_catalog.pg_class
的查询来获取所需的表列表、约束、继承等。循环查询结果,生成函数的主体,然后将它们全部合并为一个文本 block 并将其传递给 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
和/或系统目录的适当查询相结合,以获取表列表、创建一系列条件测试等。This answer I wrote a while ago details how to query the catalogs for inheritance relationships ,这可能会有用,但您还需要确定正在使用的 CHECK
约束。如果您有命名约定,那么仅依赖它并搜索 pg_class
可能会更简单。
请记住,如果有的话,PostgreSQL 的分区最多只能处理几百个表。由于表数较大时的查询计划成本,性能将显着下降。
关于更新 (ALTER) 另一个函数/过程的函数/过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17747317/