1

我意识到我无法为 SELECT 创建触发器,因此依赖于 RULES。

CREATE OR REPLACE RULE log_select AS 
ON SELECT TO usertable 
DO ALSO INSERT INTO selectLOG(prim_key,val)
VALUES(prim_key,val);

上面的示例不适用于以下错误:

ERROR:  column "prim_key" does not exist
LINE 4: VALUES(prim_key,val)
               ^
HINT:  There is a column named "prim_key" in table "old", but 
it cannot be referenced from this part of the query.

基本上,当用户在 table1 上进行 SELECT 时,我想将行插入 table2。

4

2 回答 2

0

正如 Laurenz 指出的那样,这是不可能的。

但是您是否考虑过一个可以访问该表的函数,而不是直接访问该表本身的函数?

您可以创建一个函数来运行查询、存储结果并返回它。然后只授予对该函数的执行权限并撤销对该表的任何直接访问。

就像是:

create function get_usertable(p_key integer)
  returns setof usertable
as
$$
  with result as (
     select *
     from usertable
     where id = p_key
  ), log_query as (
     insert into selectlog (prim_key, val)
     select *
     from result
  )
  select *
  from result;
$$
language sql;

此解决方案的主要缺点是,您必须为可能需要的任何条件提供参数(该参数p_key只是一个示例)。如果该WHERE子句的选项有限,那么这可能是一个替代方案。如果您需要更复杂的 where 条件,您可以使用动态 SQL(以及 PL/pgSQL 函数而不是 SQL 函数)来实现,但这也会很快变得丑陋。

于 2019-04-10T08:50:48.707 回答
0

文档说:

目前,规则中只能有一个动作ON SELECT,并且必须是无条件SELECT动作,即INSTEAD. 需要此限制以使规则足够安全以向普通用户打开它们,并将规则限制ON SELECT为类似于视图。

所以你将无法做你想做的事。

您可以选择使用日志文件或编写挂钩到查询执行器的 C 代码。

如果要使用日志记录、setlog_statement = all或,则将记录包括 s在内的log_min_duration_statement = 0所有语句。SELECT

作为源代码中的钩子,您可以使用ExecutorEnd_hookfrom include/executor/executor.h。这将在执行程序结束时调用,queryDesc->sourceText并将指向正在处理的语句。阅读auto_explain如何使用这个钩子的例子。

于 2019-04-10T06:14:53.677 回答