2011-08-18 2 views
6

Trong trình kích hoạt, tôi muốn xem truy vấn sql nào đã kích hoạt trình kích hoạt này. Tôi đã sử dụng hàm current_query() của postgresql (8.4).

Mọi thứ đều ổn, nhưng nếu trình kích hoạt được thực hiện bằng câu lệnh đã chuẩn bị, tôi sẽ nhận được phần giữ chỗ ($ 1) thay vì giá trị chính xác. ví dụ: (truy vấn đã đăng nhập):

delete from some_table where id=$1 

Có cách nào để nhận/có giá trị/thông số này không?

Edited (ví dụ bổ sung):

--table for saving query 
create table log_table (
query text 
) 

--table for trigger 
create table some_table (
id text 
) 
--function itself 
CREATE FUNCTION save_query() RETURNS trigger AS $$ 
    switch $TG_op { 
    DELETE { 
      spi_exec "INSERT INTO log_table (query) VALUES (current_query())" 
     } 
    default { 
      return OK 
     } 
    } 
    return OK 
$$ LANGUAGE pltcl; 

Tạo một trigger:

create trigger test_trigger before delete on some_table for each row execute procedure save_query(); 

tuyên bố đã chuẩn bị được thực hiện từ hibernate.

Sửa lại (java phần bổ sung)

import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.PreparedStatement; 

public class DeleteUsingPreparedStmt { 

    public static void main(String[] args) { 
     try { 
      String deleteString = "delete from floors where id = ? "; 
      final int idToDelte = 1; 

      Class.forName("org.postgresql.Driver"); 
      String url = "jdbc:postgresql://127.0.0.1:5432/YOUR_DATABASE"; 
      Connection conn = DriverManager.getConnection(url, "user", "password"); 

      PreparedStatement deleteStmt = conn.prepareStatement(deleteString); 
      deleteStmt.setInt(1, idToDelte); 
      deleteStmt.executeUpdate(); 
     } catch (Exception e) { 
      //hide me :) 
     } 
    } 
} 

Bạn cần một trình điều khiển JDBC - click.

+0

Ông có thể viết ra mã ví dụ cho điều này trong câu hỏi của bạn? –

+2

Câu hỏi đã chỉnh sửa. Tôi đơn giản hóa mã một chút, nhưng nó hoạt động theo cách tương tự. –

Trả lời

4

Dưới đây là một số mã làm việc (cho người dùng Debian: chỉ cần cài đặt postgresql-pltcl-8.4 gói và chạy CREATE LANGUAGE pltcl;)

CREATE TABLE log_table (
    id serial, 
    query text 
); 

CREATE TABLE floors (
    id serial, 
    value text 
); 

INSERT INTO floors(value) VALUES ('aaa'), ('bbb'); 

CREATE OR REPLACE FUNCTION save_query() RETURNS trigger AS $$ 
    switch $TG_op { 
     DELETE { 
      spi_exec "INSERT INTO log_table (query) VALUES (current_query())" 
     } 
     default { 
      return OK 
     } 
    } 
    return OK 
$$ LANGUAGE pltcl; 

CREATE TRIGGER test_trigger 
    BEFORE DELETE ON floors 
    FOR EACH ROW 
    EXECUTE PROCEDURE save_query(); 

Tuy nhiên tôi không thể nhận giữ chỗ trong tuyên bố chuẩn bị (nó trả EXECUTE deleteFromFloors(2);):

TABLE log_table; 
id | query 
----+------- 
(0 rows) 
DELETE FROM floors WHERE id = 1; 
DELETE 1 
TABLE log_table; 
id |    query    
----+---------------------------------- 
    1 | DELETE FROM floors WHERE id = 1; 
(1 row) 
PREPARE deleteFromFloors(integer) AS 
    DELETE FROM floors WHERE id = $1; 
PREPARE 
EXECUTE deleteFromFloors(2); 
DELETE 1 
TABLE log_table; 
id |    query    
----+---------------------------------- 
    1 | DELETE FROM floors WHERE id = 1; 
    2 | EXECUTE deleteFromFloors(2); 
(2 rows) 

CHỈNH SỬA:

Là cách sử dụng giải pháp OLD bản ghi (được biểu diễn dưới dạng mảng trong Tcl), tìm nạp cột id từ đó và sử dụng chức năng replace để đặt nó thay vì $1. Ở đây bạn có hai giải pháp: PL/pgSQL và PL/Tcl:

CREATE OR REPLACE FUNCTION save_query() RETURNS TRIGGER AS $$ 
BEGIN 
    INSERT INTO log_table (query) 
     VALUES (replace(current_query(), '$1', OLD.id::text)); 
    RETURN OLD; 
END; 
$$ LANGUAGE plpgsql; 

CREATE OR REPLACE FUNCTION save_query() RETURNS trigger AS $$ 
    switch $TG_op { 
     DELETE { 
      spi_exec "INSERT INTO log_table (query) 
       VALUES (replace(current_query(), '\$1', '$OLD(id)'))" 
     } 
     default { 
      return OK 
     } 
    } 
    return OK 
$$ LANGUAGE pltcl; 

Kết quả:

java -classpath '.:postgresql-8.4-702.jdbc4.jar' DeleteUsingPreparedStmt 

TABLE log_table; 
id |    query    
----+--------------------------------- 
    1 | delete from floors where id = 1 

(1 hàng)

+0

Điều bạn viết là hành vi đúng của trình kích hoạt này. Nó lưu một truy vấn hiện tại - vì vậy 'EXECUTE deleteFromFloors (2)'. Tuy nhiên từ java, mà gọi là 'xóa từ tầng nơi id =?' một truy vấn khác (với $ 1) được lưu. Hãy để tôi viết một đoạn mã trong java để hiển thị nó. –

+0

Đã thêm một phần java. Câu trả lời của bạn sẽ hữu ích cho người khác, nhưng tôi không thể bỏ phiếu do xếp hạng thấp. –

+1

@ Michał: Thêm giải pháp (nhận id từ bản ghi/mảng OLD hiện có) –