I allmänhet enstaka, citattecken undkomms genom att dubbla dem.
För att sätta samman dina variabler i en SQL-sträng bör du använda quote_literal()
- den funktionen tar hand om enstaka citattecken på rätt sätt, t.ex.:
quote_literal(temp_row.row_data)
Med det sagt:den bättre (och säkrare) lösningen är att använda parametrar kombinerade med 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;
%I
platshållaren tar vanligtvis hand om att flykta en identifierare på rätt sätt, även om det i det här fallet inte skulle fungera. Om du vill vara 100 % säker på att även icke-standardiserade tabellnamn fungerar korrekt, måste du först lägga in måltabellens namn i en variabel och använda det för format()
funktion:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
Denna del:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
kommer att misslyckas efter första raden också. execute .. into ...
förväntar sig att frågan returnerar en enkel . Uttrycket du använder returnerar alla rader från historiktabellen.
Jag förstår inte heller varför du gör det i första hand.
Du behöver inte alls välja från historiktabellen.
Något sådant här borde vara tillräckligt (otestat! ):
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;
Slutligen:revisionstriggers har skrivits tidigare, och det finns många färdiga lösningar för detta: