Em geral simples, as aspas são escapadas ao duplicá-las.
Para colocar suas variáveis em uma string SQL, você deve usar
quote_literal()
- essa função cuida de escapar corretamente aspas simples, por exemplo:quote_literal(temp_row.row_data)
Dito isto:a melhor (e mais segura) solução é usar parâmetros combinados com
format()
:EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', tg_table_name)
using temp_row.action_tstamp_tx, temp_row.action, temp_row.row_data;
O
%I
placeholder geralmente cuida de escapar adequadamente um identificador, embora neste caso não funcione. Se você quer ter 100% de certeza de que mesmo nomes de tabelas não padrão funcionam corretamente, você precisa primeiro colocar o nome da tabela de destino em uma variável e usá-la para o format()
função:l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
Esta parte:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
vai falhar após a primeira linha também.
execute .. into ...
espera que a consulta retorne um único . A instrução que você está usando retornará todos linhas da tabela de histórico. Eu também não entendo por que você faz isso em primeiro lugar.
Você não precisa selecionar na tabela de histórico.
Algo assim deve ser suficiente (não testado! ):
IF (TG_OP = 'UPDATE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'DELETE' AND TG_LEVEL = 'ROW') THEN
temp_row := OLD;
ELSIF (TG_OP = 'INSERT' AND TG_LEVEL = 'ROW') THEN
temp_row := NEW;
ELSE
RAISE EXCEPTION '[audit.if_modified] - Trigger func added as trigger for unhandled case: %, %',TG_OP, TG_LEVEL;
RETURN NULL;
END IF;
execute format ('insert ... values ($1, $2, $3')
using now(), SUBSTRING(TG_OP,1,1), temp_row;
Finalmente:os gatilhos de auditoria foram escritos antes e existem muitas soluções prontas para isso: