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

Я понял, что не могу создавать триггеры для 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.

По сути, я хочу вставлять строки в таблицу2, когда пользователь делает SELECT в таблице1.

MySQL, Oracle или PostgreSQL? Я не думаю, что вы используете все три для выполнения одного и того же запроса, но вы пометили их всех.

Sami Kuhmonen 10.04.2019 06:14

Спасибо, сейчас поменял. Я использую PostgreSql

BrewM4ster 10.04.2019 06:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Документация говорит:

Currently, there can be only one action in an ON SELECT rule, and it must be an unconditional SELECT action that is INSTEAD. This restriction was required to make rules safe enough to open them for ordinary users, and it restricts ON SELECT rules to act like views.

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

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

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

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

Спасибо за ответ на вопрос. Не могли бы вы уточнить «использовать файл журнала», пожалуйста? мои журналы настроены на уровень отладки2, и я не ожидаю, что там будет зарегистрирован какой-либо ответ SELECT. И я не копался в кодовой базе Postgres, поэтому не уверен, где именно мне нужно поставить хуки. Цель состоит в том, чтобы регистрировать запросы SELECT (условные или нет) для конкретной таблицы.

BrewM4ster 10.04.2019 08:39

Я расширил ответ, чтобы объяснить это.

Laurenz Albe 10.04.2019 09:15

Спасибо за обновление ответа! однако у меня есть log_statement = all и og_min_duration_statement = 0, операции SELECT регистрируются, но ответ, полученный от запроса выбора, не будет. Чего я и пытаюсь достичь. Что касается крючков, дайте мне взглянуть на это, спасибо за ссылку.

BrewM4ster 10.04.2019 09:28

Запечатлеть результат — совсем другая пара обуви и, вероятно, будет сложнее. Почему бы вам не написать прокси, который находится между клиентом и сервером? Протокол хорошо задокументировано. Это было бы намного проще.

Laurenz Albe 10.04.2019 09:35

у меня была такая же мысль, но я стремлюсь оставаться на уровне базы данных и не заставлять какое-либо приложение/прокси вести журнал. Я сравниваю конкретный вариант использования.

BrewM4ster 10.04.2019 09:49
Ответ принят как подходящий

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

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

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

Что-то типа:

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), но это также быстро становится уродливым.

Другие вопросы по теме