Nói chung, các dấu ngoặc kép được thoát ra bằng cách nhân đôi chúng.
Để nối các biến của bạn thành một chuỗi SQL, bạn nên sử dụng quote_literal()
- chức năng đó xử lý việc thoát đúng cách một dấu ngoặc kép, ví dụ:
quote_literal(temp_row.row_data)
Đã nói rằng:giải pháp tốt hơn (và an toàn hơn) là sử dụng các tham số kết hợp với 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
trình giữ chỗ thường đảm nhận việc thoát đúng cách một số nhận dạng, mặc dù trong trường hợp này, nó sẽ không hoạt động. Nếu bạn muốn chắc chắn 100% rằng ngay cả những tên bảng không chuẩn cũng hoạt động bình thường, trước tiên bạn cần đặt tên bảng đích vào một biến và sử dụng tên đó cho format()
chức năng:
l_tablename := TG_TABLE_NAME || '_history';
EXECUTE
format('INSERT INTO audit.%I_history values ($1, $2, $3)', l_tablename)
using ....
Phần này:
v_sql = 'select * from ' || TG_TABLE_NAME::regclass || '_history';
execute v_sql into temp_row;
cũng sẽ thất bại sau hàng đầu tiên. execute .. into ...
mong đợi truy vấn trả về một đơn lẻ . Câu lệnh bạn đang sử dụng sẽ trả về tất cả hàng từ bảng lịch sử.
Tôi cũng không hiểu tại sao bạn lại làm như vậy ngay từ đầu.
Bạn không cần phải chọn từ bảng lịch sử.
Một cái gì đó như thế này là đủ ( chưa được kiểm tra! ):
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;
Cuối cùng:các trình kích hoạt kiểm tra đã được viết trước đây và có rất nhiều giải pháp sẵn sàng cho việc này: