Postgresql 如何在触发器函数中从信息模式动态复制表
我有一个insert触发器函数,其中NEW.schema_name引用一个模式。我想动态地将该模式中的表('foobaz','barbaz')复制为'foo'和'bar'。然后,我可以在没有动态sql的情况下执行查询 我如何创建一个函数,或者简单地复制/粘贴相同的代码块来实现它 编辑: 我无法使动态查询正常工作。 WITH语句中的部分正在工作。 不是底部的“执行”部分。我不知道这是否是语法问题,或者是错误的强制转换,或者是pgsql中的任何约束导致它无法工作Postgresql 如何在触发器函数中从信息模式动态复制表,postgresql,Postgresql,我有一个insert触发器函数,其中NEW.schema_name引用一个模式。我想动态地将该模式中的表('foobaz','barbaz')复制为'foo'和'bar'。然后,我可以在没有动态sql的情况下执行查询 我如何创建一个函数,或者简单地复制/粘贴相同的代码块来实现它 编辑: 我无法使动态查询正常工作。 WITH语句中的部分正在工作。 不是底部的“执行”部分。我不知道这是否是语法问题,或者是错误的强制转换,或者是pgsql中的任何约束导致它无法工作 WITH info_schema_s
WITH info_schema_subset_table as (SELECT table_schema, table_name,
array_to_string((regexp_split_to_array(table_name,'_'))[4:array_length(regexp_split_to_array(table_name,'_'),1)-1] as new_table
FROM information_schema.tables
where table_schema = "schema_searched"
ORDER BY new_table ASC)
EXECUTE 'CREATE TABLE $2 as (SELECT * FROM $1)'
USING info_schema_subset_table.table_schema || '.' ||info_schema_subset_table.table_name,info_schema_subset_table.new_table;
编辑2
。。。已删除损坏的代码
在下面的代码中,我不确定语法是否正确,我从触发器中得到以下内容
提供程序错误:
添加功能时PostGIS错误:ERREUR:l'opérateur n'existe pas:record~~unknown
第1行:选择像“%ens%”这样的旧表
^
提示:所有操作都对应于名称和参数类型。
Vous devez AJAOUTER des转换明确了de类型。
查询:选择像“%ens%”这样的旧表
上下文:fontion PL/pgsql validation\u sio.afi\u validation\u sio(),ligne 18áCASE
编辑3:
CREATE OR REPLACE FUNCTION foo.foo()
RETURNS TRIGGER AS
$BODY$
DECLARE
old_table record;
new_table record;
dynamic_query text;
BEGIN
IF TG_OP = 'INSERT'
THEN
FOR old_table IN SELECT table_schema|| '.' ||table_name
FROM information_schema.tables
where table_schema = NEW.nom_schema
LOOP
CASE
WHEN
old_table LIKE '%ens%' THEN
new_table := concat('SIT_',array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
ELSE
new_table := concat('SID_',array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
END CASE;
dynamic_query := format('SELECT * FROM' || old_table ||);
EXECUTE dynamic_query
INTO new_table;
END LOOP;
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER foo
AFTER INSERT ON validation.validationfoo
FOR EACH ROW EXECUTE PROCEDURE foo.foo();
SQL语句中不能有
EXECUTE
,它是PL/pgSQL语句
循环浏览表格,并为每个表格发出一个EXECUTE
请注意,您不能将模式或表名作为参数使用USING
,因为需要在解析时知道这些名称
使用
format
函数构造动态语句,这样可以避免恶意创建具有奇怪名称的表的用户进行SQL注入。我对触发器函数进行了一些重新格式化,并更改了一些内容,看看这是否有效
CREATE OR REPLACE FUNCTION foo.foo()
RETURNS TRIGGER AS
$BODY$
DECLARE
old_table record;
new_table record;
dynamic_query text;
BEGIN
IF TG_OP = 'INSERT' THEN
FOR old_table IN
SELECT table_schema || '.' || table_name AS old_table_name
FROM information_schema.tables
WHERE table_schema = NEW.nom_schema
LOOP
new_table := concat(CASE WHEN old_table.old_table_name LIKE '%ens%' THEN 'SIT_' ELSE 'SID_' END,array_to_string((regexp_split_to_array(info_schema.old_table,'_'))[4:array_length(regexp_split_to_array(info_schema.old_table,'_'),1)-1],'_'));
dynamic_query := 'CREATE TABLE ' || new_table || ' AS SELECT * FROM ' || old_table.old_table_name;
EXECUTE dynamic_query;
END LOOP;
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
所以主要的事情是:
是一条记录,因此将其与old_table
字符串进行比较失败。您需要使用字段名。因此,我给了您的字段一个名称,并在LIKE
类似的比较中使用了该字段名称
- 更改了
赋值,将new_table
语句仅放在发生更改的一项上,以使差异更加明显,代码更加简洁。请注意,我不知道这句话的其余部分是否有效,我只是保持原样CASE
- 更改了创建
。正如我在评论中所说的,动态\u查询
函数被错误地使用,所以我只使用了标准的字符串连接李>格式
- 将
的SQL更改为我认为您实际上希望它执行的操作。您希望它将表的内容复制到新表中,对吗?这样就可以了dynamic\u query
is
用作别名,它是postgres关键字。您使用的格式不正确。执行dynamic_query:='SELECT*FROM'| | old_table
或执行dynamic_query:=format('SELECT*FROM%s',old_table)
。我根本不懂[format]。谢谢它类似于python。你能看看我的编辑并告诉我它是否正确吗?编辑的代码充满了语法错误、没有结束分号的语句、没有结束循环的循环等等,所以很难说。但你正朝着正确的方向前进。此外,您仍然容易受到奇怪表名的SQL注入的攻击。我对DO
语句的建议是错误的-我没有意识到您在PL/pgSQL代码中(您没有发布整个函数)。所以你不需要一个DO
语句。好吧,我就是这么想的。格式是否阻止注入?据我所知,表名可以对应于正在注入的查询。格式是否通过引用所有名称来防止这种情况?我或多或少是sql新手……如果TG_OP='INSERT',那么在FOR之后我会得到一个错误,我的语法正确吗?对于选择表| | |'.| |表|名称为旧_tableNo中的信息_schema,您的语法已损坏,无法修复。首先删除DO
语句。每个语句都必须以结尾
,每个IF
都需要一个结束IF
,每个循环
需要和结束循环代码>。从这些方面开始,然后继续。这很容易受到SQL注入的影响。如果我用正确的名称创建一个表,我可以破坏你的函数或滥用它。当然,尽管我不太在意,因为首先,这只是对OP的代码进行一些更改以实现他想要的,这不是完美触发器的全面示例;第二,用于创建动态sql语句的数据完全来自表中的现有数据,我们不知道用户是否有权写入这些表等。好的,第一部分,但我们知道哪些用户有权写入这些表:所有能够创建表的人。我不是说你的答案不好,我只是觉得可以改进。有足够多的人盲目地复制像您这样的代码示例,并将其用作金标准。这不是你的错,但我认为我们应该尽可能提高对SQL注入的认识。