Bem... Vamos lá ...
Você esta criando uma função para cada tabela que deseja auditar .. ??
Vou postar aqui uma pequena parte do sistema de replicação que estou
desenvolvendo, que é justamente a parte necessária para "LOGAR" as
operações executadas nas tabelas, e salvá-las em duas tabelas (Uma da
operação e outra com os campos e valores alterados/inseridos)....
O detalhe é que isso não pode ser feito em plpgsql, pois esta não
permite a manipulação dinamica dos campos do tipo RECORD, então
preferi usar a plperl, mas também pode ser feita em C ou plphp,
etc....
Aqui vai o protótipo (Funciona, mas pode ser aperfeiçoado em alguns pontos ...)
-- INICIO DO CÓDIGO SQL --
-- Tabela para armazenar as operações executadas
create table tzrepl.tzr_log
(
id_log serial primary key not null,
schema_name varchar,
table_name varchar,
op_type varchar,
time timestamp default current_timestamp,
pk_field varchar,
pk_value varchar,
received char default 'f'
) WITH OIDS;
-- Tabela para armezenar os campos e valores Alterados / Inseridos.
create table tzrepl.tzr_log_detail (
id_log_detail serial primary key not null,
id_log int references tzrepl.tzr_log(id_log) ON DELETE CASCADE ON
UPDATE CASCADE,
column_name varchar,
old_value varchar,
new_value varchar,
time timestamp default current_timestamp
);
-- FUNCAO QUE INSERE OS LOGS NA TABELA
CREATE OR REPLACE FUNCTION tzrepl.tzr_log_command() RETURNS trigger AS $$
#-- Tipo de Evento (INSERT / UPDATE / DELETE)
my $tg_ev = $_TD->{event};
#-- OID da tabela que recebeu o comando
my $table_OID = $_TD->{relid};
#-- Nome da tabela que recebeu o comando
my $table_name_value = $_TD->{relname};
#-- Chave Primária da Tabela
$rs_pk = spi_exec_query("SELECT
tzrepl.tzr_get_pk_field_by_oid($table_OID) AS pk");
if($rs_pk{status} == SPI_OK_SELECT)
{
$pk_column = $rs_pk->{rows}[0]->{pk};
$pk_value = defined $_TD->{"new"}{$pk_column} ?
$_TD->{"new"}{$pk_column} : $_TD->{"old"}{$pk_column};
}
#-- Verifica se não é um registro recebido via replicação
$rs_rcv = spi_exec_query("SELECT tzrepl.tzr_check_received_log() AS
rcv");
if($rs_rcv{status} == SPI_OK_SELECT)
{
$rcv = $rs_rcv->{rows}[0]->{rcv};
}
else
{
$rcv = 'f';
}
#-- Insere o Log
$rs_log = spi_exec_query("INSERT INTO tzrepl.tzr_log
(table_name,op_type,pk_value,pk_field,received) VALUES
('$table_name_value','$tg_ev','$pk_value','$pk_column','$rcv')");
if($rs_log{status} == SPI_OK_INSERT)
{
#-- Obtem o ID do log inserido
$rs_log_value = spi_exec_query("SELECT
currval('tzrepl.tzr_log_id_log_seq') as id_log");
if($rs_log_value{status} == SPI_OK_SELECT)
{
#-- Restaurando o ID do log inserido
$id_log = $rs_log_value->{rows}[0]->{id_log};
#-- Colunas da tabela
$rs_columns = spi_exec_query("SELECT * FROM
tzrepl.tzr_get_table_columns_by_oid($table_OID)");
my $nrows = $rs_columns->{processed};
foreach my $rn (0 .. $nrows - 1)
{
my $row = $rs_columns->{rows}[$rn];
$column = $row->{attname};
$exec = 0;
if($tg_ev eq 'INSERT')
{
$exec = 1;
$old_val = '';
$new_val = $_TD->{new}{$column};
}
elsif($tg_ev eq 'DELETE')
{
$exec = 1;
$old_val = $_TD->{old}{$column};
$new_val = '';
}
elsif($tg_ev eq 'UPDATE')
{
$old_val = $_TD->{old}{$column};
$new_val = $_TD->{new}{$column};
if($_TD->{new}{$column} eq
$_TD->{old}{$column})
{
$exec = 0;
}
else
{
$exec = 1;
}
}
$old_val =~ s/\'/\'\'/g;
$new_val =~ s/\'/\'\'/g;
$old_val = (!defined $old_val) ? "NULL" :
"'$old_val'";
$new_val = (!defined $new_val) ? "NULL" :
"'$new_val'";
if($exec == 1)
{
$query_log_det = "INSERT INTO
tzrepl.tzr_log_detail
(id_log,column_name,new_value,old_value) VALUES
('$id_log','$column',$new_val,$old_val)";
$rs_log_det =
spi_exec_query($query_log_det);
if($rs_log_det{status} != SPI_OK_INSERT)
{
elog(NOTICE,$query_log_det);
}
}
}
}
}
return;
END;
$$ LANGUAGE "plperl";
-- FUNCAO QUE OBTEM A CHAVE PRIMARIA DE UMA TABELA PELO OID DA MESMA
CREATE OR REPLACE FUNCTION tzrepl.tzr_get_pk_field_by_oid(tableoid oid)
RETURNS character varying AS
$BODY$
DECLARE
col VARCHAR;
rsCol RECORD;
BEGIN
SELECT pga.attname as column INTO rsCol FROM pg_class PGC
INNER JOIN pg_constraint PGCO ON PGCO.conrelid = PGC.oid AND PGC.oid =
tableOid
INNER JOIN pg_attribute PGA ON PGA.attnum IN
(array_to_string(PGCO.conkey,','))
AND PGA.attrelid = PGCO.conrelid;
col = rsCol.column;
return col;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
-- FIM DO CÓDIGO --
Bem, espero que isso ajude...
Assim que a replicação estiver estável, enviarei para que a lista
possa testar....
Att:
Thiago Risso
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral