我正在尝试编写一个触发器函数,将值输入到单独的子表中,但是我收到了以前从未见过的错误。
这是一个设置示例:
-- create initial table
CREATE TABLE public.testlog(
id serial not null,
col1 integer,
col2 integer,
col3 integer,
name text
);
-- create child table
CREATE TABLE public.testlog_a (primary key(id)) INHERITS(public.testlog);
-- make trigger function for insert
CREATE OR REPLACE FUNCTION public.test_log() RETURNS trigger AS
$$
DECLARE
qry text;
BEGIN
qry := 'INSERT INTO public.testlog_' || NEW.name || ' SELECT ($1).*';
EXECUTE qry USING NEW.*;
RETURN OLD;
END
$$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
-- add function to table
CREATE TRIGGER test_log_sorter BEFORE INSERT
ON public.testlog FOR EACH ROW
EXECUTE PROCEDURE public.test_log();
和查询:
INSERT INTO public.testlog (col1, col2, col3, name) values (1, 2, 3, 'a');
错误信息:
[Err] ERROR: query "SELECT NEW.*" returned 5 columns
CONTEXT: PL/pgSQL function test_log() line 7 at EXECUTE statement
5 列正是我想要它返回的内容,所以显然有些东西我不理解,但错误消息似乎没有意义。
谁能解释一下为什么我会得到这个?
最佳答案
您的解决方案修复了行类型 NEW
变量的传递。但是,您的代码中存在一个偷偷摸摸的 SQL 注入(inject)漏洞,这在 SECURITY DEFINER
函数中特别危险。用户输入决不能转换为未转义的 SQL 代码。
像这样 sanitizer :
CREATE OR REPLACE FUNCTION trg_test_log()
RETURNS trigger AS
$$
BEGIN
EXECUTE 'INSERT INTO public.' || quote_ident('testlog_' || NEW.name)
|| ' SELECT ($1).*'
USING NEW;
RETURN NULL;
END
$$
LANGUAGE plpgsql SECURITY DEFINER;
另外:
OLD
未在INSERT
触发器中定义。- 您不需要变量。 plpgsql 中的赋值相对昂贵。
关于postgresql - 为子表插入创建触发器会返回令人困惑的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27321091/