PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Postgresql :Comment échapper aux guillemets simples dans le déclencheur de la base de données ?

En général, les guillemets simples sont échappés en les doublant.

Pour concaténer vos variables dans une chaîne SQL, vous devez utiliser quote_literal() - cette fonction s'occupe d'échapper correctement les guillemets simples, par exemple :

quote_literal(temp_row.row_data)

Cela dit :la meilleure solution (et la plus sûre) consiste à utiliser des paramètres combinés avec 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; 

Le %I placeholder s'occupe généralement d'échapper correctement un identifiant, bien que dans ce cas cela ne fonctionnerait pas. Si vous voulez être sûr à 100 % que même les noms de table non standard fonctionnent correctement, vous devez d'abord mettre le nom de la table cible dans une variable et l'utiliser pour le format() fonction :

l_tablename := TG_TABLE_NAME || '_history';
EXECUTE 
   format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
   using ....

Cette partie :

v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;

va également échouer après la première rangée. execute .. into ... s'attend à ce que la requête renvoie un single . L'instruction que vous utilisez renverra tous lignes de la table d'historique.

Je ne comprends pas non plus pourquoi vous faites cela en premier lieu.

Vous n'avez pas du tout besoin de sélectionner dans la table d'historique.

Quelque chose comme ça devrait suffire (non testé ! ):

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;

Enfin :les déclencheurs d'audit ont déjà été écrits, et il existe de nombreuses solutions toutes faites pour cela :