PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgresql:come sfuggire alle virgolette singole nel trigger del database?

In generale singole, le virgolette vengono evitate raddoppiandole.

Per mettere concatenare le tue variabili in una stringa SQL, dovresti usare quote_literal() - quella funzione si occupa di eseguire correttamente l'escape della virgoletta singola, ad esempio:

quote_literal(temp_row.row_data)

Detto questo:la soluzione migliore (e più sicura) è utilizzare parametri combinati 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; 

Il %I placeholder di solito si occupa di eseguire correttamente l'escape di un identificatore, anche se in questo caso non funzionerebbe. Se vuoi essere sicuro al 100% che anche i nomi delle tabelle non standard funzionino correttamente, devi prima inserire il nome della tabella di destinazione in una variabile e usarla per il format() funzione:

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

Questa parte:

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

fallirà anche dopo la prima riga. execute .. into ... si aspetta che la query restituisca un single . L'istruzione che stai utilizzando restituirà tutto righe dalla tabella della cronologia.

Inoltre non capisco perché lo fai in primo luogo.

Non è necessario selezionare affatto dalla tabella della cronologia.

Qualcosa del genere dovrebbe essere sufficiente (non testato! ):

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;

Infine:i trigger di audit sono stati scritti in precedenza e ci sono molte soluzioni già pronte per questo: