Secara umum, kutipan diloloskan dengan menggandakannya.
Untuk menggabungkan variabel Anda ke dalam string SQL, Anda harus menggunakan quote_literal()
- fungsi itu menangani pelepasan tanda kutip tunggal dengan benar, mis:
quote_literal(temp_row.row_data)
Karena itu:solusi yang lebih baik (dan lebih aman) adalah menggunakan parameter yang dikombinasikan dengan 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
placeholder biasanya menangani pelepasan pengenal dengan benar, meskipun dalam kasus ini tidak akan berfungsi. Jika Anda ingin 100% yakin bahwa bahkan nama tabel non-standar berfungsi dengan baik, Anda harus terlebih dahulu memasukkan nama tabel target ke dalam variabel dan menggunakannya untuk format()
fungsi:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
Bagian ini:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
akan gagal setelah baris pertama juga. execute .. into ...
mengharapkan kueri untuk mengembalikan tunggal . Pernyataan yang Anda gunakan akan mengembalikan semua baris dari tabel sejarah.
Saya juga tidak mengerti mengapa Anda melakukan itu sejak awal.
Anda tidak perlu memilih dari tabel riwayat sama sekali.
Sesuatu seperti ini seharusnya sudah cukup (belum diuji! ):
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;
Terakhir:pemicu audit telah ditulis sebelumnya, dan ada banyak solusi siap pakai untuk ini: