Over het algemeen worden enkele aanhalingstekens ontsnapt door ze te verdubbelen.
Om uw variabelen samen te voegen in een SQL-tekenreeks, moet u quote_literal()
gebruiken - die functie zorgt voor het correct ontsnappen van enkele aanhalingstekens, bijvoorbeeld:
quote_literal(temp_row.row_data)
Dat gezegd hebbende:de betere (en veiligere) oplossing is om parameters te gebruiken in combinatie met 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;
De %I
placeholder zorgt er meestal voor dat een identifier correct ontsnapt, hoewel het in dit geval niet zou werken. Als je er 100% zeker van wilt zijn dat zelfs niet-standaard tabelnamen goed werken, moet je eerst de doeltabelnaam in een variabele zetten en die gebruiken voor het format()
functie:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
Dit deel:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
gaat ook mis na de eerste rij. execute .. into ...
verwacht dat de zoekopdracht een enkele . retourneert . De instructie die u gebruikt, retourneert alles rijen uit de geschiedenistabel.
Ik begrijp ook niet waarom je dat in de eerste plaats doet.
U hoeft helemaal niet te selecteren uit de geschiedenistabel.
Zoiets zou voldoende moeten zijn (niet getest! ):
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;
Tot slot:er zijn al eerder audit triggers geschreven en daar zijn veel kant-en-klare oplossingen voor: