我想创建触发器函数,不指定其他列的名称,这些列不能更新。
示例:
Create table test(id integer, name text, amount numeric);
我想阻止更新除amount
以外的任何列,但要避免像这样通过名称指定列id
和name
IF NEW.id <> OLD.id or NEW.name <> OLD.name THEN RAISE EXCEPTION 'UPDATE DISALLOWED'; END IF;
我想将此触发器应用于多个表,因此不想指定其他列。
也许它是某种可能使用行级安全?但我需要防止也postgres角色从更新.我还没有找到如何做到这一点.
@Edit提示后我想我已经接近解决方案,但在尝试执行生成的IF语句时出现语法错误。https://dbfiddle.uk/vp85wHgc
3条答案
按热度按时间vngu2lb81#
我想出了以下解决方案:
htrmnn0y2#
您可以这样做,但是确定更改的列可能需要动态SQL。
mm5n2pyu3#
使用@RichardHuxton的答案。但是如果你想要动态SQL,你可以得到一个列列表作为字符串列表。然后将它们拆分。表名看起来像是触发器函数的预定义变量TG_TABLE_NAME。
要获得列列表,这是典型的方法。但是,除非显式列出列,否则这里的ORDER BY不会正确地给予列的顺序。99/100 ORDER BY将是正确的,但不要相信它。
如果你想要你构建表的顺序,而不是 * 在Postgres中显示列的顺序,你需要看这个。attnum是顺序索引。attname是列名。
参考文献:
https://www.postgresql.org/docs/current/plpgsql-trigger.html
动态SQL示例:
EXECUTE之后的字符串中的任何内容都是你通常会拥有的有效SQL代码。所以IF语句在那里。如果IF语句包含赋给变量的值,那么就像我对TG_TABLE_NAME所做的那样将变量连接到字符串。
根据你的问题代码,我们就有了这个。
现在更进一步,使用上面的查询查找ID_COLUMN和NAME_COLUMN变量来查找列名。如果id是第一列,name是第二列,指定列名列表(按正确顺序)使用结果集列表函数返回到变量COLUMN_LIST(这是你的作业)。然后在Postgres中找到函数来抓取片段1并将其分配给ID_COLUMN变量,片段2分配给NAME_COLUMN。
你的代码中的IF语句的错误是在THEN之前没有空格。我把所有的东西都推到了一行。