Как я могу создать ПРАВИЛО, которое ВСТАВЛЯЕТ значения TABLE1 в TABLE2 при выполнении запроса SELECT для TABLE1 - PullRequest
1 голос
/ 10 апреля 2019

Я понял, что не могу создавать триггеры для SELECT, поэтому делаю ставку на ПРАВИЛА.

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.

По сути, я хочу вставить строки в table2, когда пользователь выполняет SELECT для table1.

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Как указывал Лоренц, это невозможно с помощью правила.

Но рассматривали ли вы функцию, которая дает доступ к этой таблице, а не прямой доступ к самой таблице?

Вы можете создать функцию, которая запускает запрос, сохраняет результат и возвращает его. Затем только предоставьте привилегию на выполнение функции и отзовите любой прямой доступ к этой таблице.

Что-то вроде:

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 ограничены, это может быть альтернативой. Если вам нужны более сложные условия, вы можете сделать это с помощью динамического SQL (и функции PL / pgSQL вместо функции SQL), но это также становится ужасно быстрым.

0 голосов
/ 10 апреля 2019

Документация гласит:

В настоящее время в правиле ON SELECT может быть только одно действие, и оно должно быть безусловным SELECT действием, которое INSTEAD.Это ограничение было необходимо, чтобы сделать правила достаточно безопасными, чтобы открывать их для обычных пользователей, и оно ограничивает правила ON SELECT, чтобы они действовали как представления.

Таким образом, вы не сможете делать то, что хотите.

У вас есть варианты: использовать файл журнала или написать код C, который подключается к исполнителю запроса.

Если вы хотите использовать ведение журнала, установите log_statement = all или log_min_duration_statement = 0, тогда все операторы, включая SELECT s, будут записаны.

В качестве хука в исходном коде вы можете использовать ExecutorEnd_hook из include/executor/executor.h.Это будет вызвано, когда исполнитель закроется, и queryDesc->sourceText будет указывать на обрабатываемый оператор.Прочитайте auto_explain, чтобы узнать, как можно использовать этот хук.

...