En general, las comillas simples se escapan duplicándolas.
Para poner concatenar sus variables en una cadena SQL, debe usar quote_literal()
- esa función se encarga de escapar correctamente las comillas simples, por ejemplo:
quote_literal(temp_row.row_data)
Habiendo dicho eso:la mejor (y más segura) solución es usar parámetros combinados con 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;
El %I
El marcador de posición generalmente se encarga de escapar correctamente un identificador, aunque en este caso no funcionaría. Si desea estar 100% seguro de que incluso los nombres de tablas no estándar funcionan correctamente, primero debe colocar el nombre de la tabla de destino en una variable y usar eso para el format()
función:
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;
va a fallar después de la primera fila también. execute .. into ...
espera que la consulta devuelva un único . La declaración que está utilizando devolverá todos filas de la tabla de historial.
Tampoco entiendo por qué haces eso en primer lugar.
No necesita seleccionar nada de la tabla de historial.
Algo como esto debería ser suficiente (¡no probado! ):
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:los disparadores de auditoría se han escrito antes, y hay muchas soluciones preparadas para esto: