如何跟踪 PostgreSQL 中任何函数的变化
How to track changes in any function in PostgreSQL
我想跟踪 PostgreSQL 中任何函数的变化。
示例 - 假设我在 postgesql 数据库中有函数 fun_name()
并且我正在对函数进行修改。
现在,我想跟踪像
这样的记录
DateTime,Schema_name,Function_name,old_func_text,new_func_text
请建议在 postgresql 中实现此目的的最佳方法。
我正在研究 https://www.postgresql.org/docs/9.3/static/sql-createeventtrigger.html
中的事件触发器
谢谢。
在 Postgres 9.5 中有一个函数 pg_event_trigger_ddl_commands()
可以在事件触发器中使用它来获取 inserted/altered 对象的 oid。
日志table:
create table function_log (
datetime timestamp,
schema_name text,
function_name text,
tag text,
function_body text);
事件函数和触发器:
create or replace function public.on_function_event()
returns event_trigger
language plpgsql
as $function$
begin
insert into function_log
select now(), nspname, proname, command_tag, prosrc
from pg_event_trigger_ddl_commands() e
join pg_proc p on p.oid = e.objid
join pg_namespace n on n.oid = pronamespace;
end
$function$;
create event trigger on_function_event
on ddl_command_end
when tag in ('CREATE FUNCTION', 'ALTER FUNCTION')
execute procedure on_function_event();
示例:
create or replace function test()
returns int as $$ select 1; $$ language sql;
create or replace function test()
returns int as $$ select 2; $$ language sql;
alter function test() immutable;
select *
from function_log;
datetime | schema_name | function_name | tag | function_body
----------------------------+-------------+---------------+-----------------+---------------
2017-02-26 13:05:15.353879 | public | test | CREATE FUNCTION | select 1;
2017-02-26 13:05:15.353879 | public | test | CREATE FUNCTION | select 2;
2017-02-26 13:05:15.353879 | public | test | ALTER FUNCTION | select 2;
(3 rows)
您可以将 DROP FUNCTION
命令标记添加到触发器,然后以类似于 pg_event_trigger_ddl_commands()
.
的方式使用函数 pg_event_trigger_dropped_objects()
不幸的是,Postgres 9.4 中没有 pg_event_trigger_ddl_commands()
。您可以尝试使用 current_query()
获取 inserted/altered 对象或在 C
中编写触发函数。我认为更简单的方法是将 Postgres 升级到 9.5+。
关于约束的一些注意事项。
- 您不能在 PostgreSQL 中的系统 table 上放置触发器,因此无法在这方面创建审计跟踪。
- 您可能需要使用 PostgreSQL 外部的东西来管理版本控制。所以我会推荐像 sqitch 这样的东西。
pgdump 的一个主要问题是不能保证事物的顺序是唯一的,所以简单地转储和版本会给你一个非常糟糕的信噪比。
现在您可以做的一件事是在 ddl 上使用 event triggers 来捕获事件,然后记录和处理。这仍然需要您在设计方面付出很多努力,但这是完全可能的。如果您使用事件触发器,请先在暂存系统上进行彻底测试!
我会说当我需要做这样的事情时我通常使用事件触发器和系统副本 tables 所以我从旧目录更新 table 并记录变化。
带有下降和触发跟踪的完整版本
create schema hist;
create table hist.functions (
datetime timestamp,
schema_name text,
function_name text,
oper char(1),
function_body text,
ip text);
create or replace function hist.on_function_event_hist()
returns event_trigger
language plpgsql
as $function$
begin
insert into hist.functions
select now(),
coalesce(nspname, t.trigger_schema),
coalesce(proname, t.trigger_name),
command_tag::char(1),
coalesce(pg_get_functiondef(p.oid),
'create trigger ' || trigger_name || ' ' || action_timing || ' ' || event_manipulation ||
E'\non\n' || quote_ident(event_object_schema) || '.' || quote_ident(event_object_table) || ' for ' || action_orientation || coalesce(E'\rwhen (' || action_condition || E')\r', E'\r') || action_statement || ';'),
coalesce(inet_client_addr()::text, '::1')
from pg_event_trigger_ddl_commands() e
left join pg_proc p on p.oid = e.objid
left join pg_namespace n on n.oid = pronamespace
left join information_schema.triggers t on object_identity like t.trigger_name || '%';
end
$function$;
create event trigger on_function_event
on ddl_command_end
when tag in ('CREATE FUNCTION', 'ALTER FUNCTION', 'ALTER TRIGGER', 'CREATE TRIGGER')
execute procedure hist.on_function_event_hist();
create or replace function hist.on_function_drop_func()
returns event_trigger
language plpgsql
as $function$
begin
insert into hist.functions
SELECT now(),
schema_name,
object_identity,
'D',
null,
coalesce(inet_client_addr()::text, '::1')
FROM pg_event_trigger_dropped_objects();
end
$function$;
CREATE EVENT TRIGGER on_function_drop
ON sql_drop
EXECUTE PROCEDURE hist.on_function_drop_func();
我想跟踪 PostgreSQL 中任何函数的变化。
示例 - 假设我在 postgesql 数据库中有函数 fun_name()
并且我正在对函数进行修改。
现在,我想跟踪像
这样的记录DateTime,Schema_name,Function_name,old_func_text,new_func_text
请建议在 postgresql 中实现此目的的最佳方法。
我正在研究 https://www.postgresql.org/docs/9.3/static/sql-createeventtrigger.html
中的事件触发器谢谢。
在 Postgres 9.5 中有一个函数 pg_event_trigger_ddl_commands()
可以在事件触发器中使用它来获取 inserted/altered 对象的 oid。
日志table:
create table function_log (
datetime timestamp,
schema_name text,
function_name text,
tag text,
function_body text);
事件函数和触发器:
create or replace function public.on_function_event()
returns event_trigger
language plpgsql
as $function$
begin
insert into function_log
select now(), nspname, proname, command_tag, prosrc
from pg_event_trigger_ddl_commands() e
join pg_proc p on p.oid = e.objid
join pg_namespace n on n.oid = pronamespace;
end
$function$;
create event trigger on_function_event
on ddl_command_end
when tag in ('CREATE FUNCTION', 'ALTER FUNCTION')
execute procedure on_function_event();
示例:
create or replace function test()
returns int as $$ select 1; $$ language sql;
create or replace function test()
returns int as $$ select 2; $$ language sql;
alter function test() immutable;
select *
from function_log;
datetime | schema_name | function_name | tag | function_body
----------------------------+-------------+---------------+-----------------+---------------
2017-02-26 13:05:15.353879 | public | test | CREATE FUNCTION | select 1;
2017-02-26 13:05:15.353879 | public | test | CREATE FUNCTION | select 2;
2017-02-26 13:05:15.353879 | public | test | ALTER FUNCTION | select 2;
(3 rows)
您可以将 DROP FUNCTION
命令标记添加到触发器,然后以类似于 pg_event_trigger_ddl_commands()
.
pg_event_trigger_dropped_objects()
不幸的是,Postgres 9.4 中没有 pg_event_trigger_ddl_commands()
。您可以尝试使用 current_query()
获取 inserted/altered 对象或在 C
中编写触发函数。我认为更简单的方法是将 Postgres 升级到 9.5+。
关于约束的一些注意事项。
- 您不能在 PostgreSQL 中的系统 table 上放置触发器,因此无法在这方面创建审计跟踪。
- 您可能需要使用 PostgreSQL 外部的东西来管理版本控制。所以我会推荐像 sqitch 这样的东西。
pgdump 的一个主要问题是不能保证事物的顺序是唯一的,所以简单地转储和版本会给你一个非常糟糕的信噪比。
现在您可以做的一件事是在 ddl 上使用 event triggers 来捕获事件,然后记录和处理。这仍然需要您在设计方面付出很多努力,但这是完全可能的。如果您使用事件触发器,请先在暂存系统上进行彻底测试!
我会说当我需要做这样的事情时我通常使用事件触发器和系统副本 tables 所以我从旧目录更新 table 并记录变化。
带有下降和触发跟踪的完整版本
create schema hist;
create table hist.functions (
datetime timestamp,
schema_name text,
function_name text,
oper char(1),
function_body text,
ip text);
create or replace function hist.on_function_event_hist()
returns event_trigger
language plpgsql
as $function$
begin
insert into hist.functions
select now(),
coalesce(nspname, t.trigger_schema),
coalesce(proname, t.trigger_name),
command_tag::char(1),
coalesce(pg_get_functiondef(p.oid),
'create trigger ' || trigger_name || ' ' || action_timing || ' ' || event_manipulation ||
E'\non\n' || quote_ident(event_object_schema) || '.' || quote_ident(event_object_table) || ' for ' || action_orientation || coalesce(E'\rwhen (' || action_condition || E')\r', E'\r') || action_statement || ';'),
coalesce(inet_client_addr()::text, '::1')
from pg_event_trigger_ddl_commands() e
left join pg_proc p on p.oid = e.objid
left join pg_namespace n on n.oid = pronamespace
left join information_schema.triggers t on object_identity like t.trigger_name || '%';
end
$function$;
create event trigger on_function_event
on ddl_command_end
when tag in ('CREATE FUNCTION', 'ALTER FUNCTION', 'ALTER TRIGGER', 'CREATE TRIGGER')
execute procedure hist.on_function_event_hist();
create or replace function hist.on_function_drop_func()
returns event_trigger
language plpgsql
as $function$
begin
insert into hist.functions
SELECT now(),
schema_name,
object_identity,
'D',
null,
coalesce(inet_client_addr()::text, '::1')
FROM pg_event_trigger_dropped_objects();
end
$function$;
CREATE EVENT TRIGGER on_function_drop
ON sql_drop
EXECUTE PROCEDURE hist.on_function_drop_func();