Я понял, что не могу создавать триггеры для 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.
Спасибо, сейчас поменял. Я использую PostgreSql
Документация говорит:
Currently, there can be only one action in an
ON SELECT
rule, and it must be an unconditionalSELECT
action that isINSTEAD
. This restriction was required to make rules safe enough to open them for ordinary users, and it restrictsON 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 (условные или нет) для конкретной таблицы.
Я расширил ответ, чтобы объяснить это.
Спасибо за обновление ответа! однако у меня есть log_statement = all и og_min_duration_statement = 0, операции SELECT регистрируются, но ответ, полученный от запроса выбора, не будет. Чего я и пытаюсь достичь. Что касается крючков, дайте мне взглянуть на это, спасибо за ссылку.
Запечатлеть результат — совсем другая пара обуви и, вероятно, будет сложнее. Почему бы вам не написать прокси, который находится между клиентом и сервером? Протокол хорошо задокументировано. Это было бы намного проще.
у меня была такая же мысль, но я стремлюсь оставаться на уровне базы данных и не заставлять какое-либо приложение/прокси вести журнал. Я сравниваю конкретный вариант использования.
Как указал Лоренц, с правилом это невозможно.
Но рассматривали ли вы функцию, которая дает доступ к этой таблице, а не прямой доступ к самой таблице?
Вы можете создать функцию, которая выполняет запрос, сохраняет результат и возвращает его. Затем только предоставьте привилегию выполнения функции и отмените любой прямой доступ к этой таблице.
Что-то типа:
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), но это также быстро становится уродливым.
MySQL, Oracle или PostgreSQL? Я не думаю, что вы используете все три для выполнения одного и того же запроса, но вы пометили их всех.