2011-08-18 2 views
6

In un trigger voglio vedere quale query sql ha attivato questo trigger. Ho usato la funzione current_query() di postgresql (8.4).

Tutto va bene, ma se il trigger viene eseguito dall'istruzione preparata ottengo segnaposto ($ 1) anziché valori corretti. per esempio (query registrata):

delete from some_table where id=$1 

C'è un modo per ottenere/avere questi valori/parametri?

cura (ad esempio aggiunta):

--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; 

Creazione di un trigger:

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

istruzione preparata viene eseguito da Hibernate.

Edit di nuovo (parte java aggiunto)

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 :) 
     } 
    } 
} 

Hai bisogno di un driver JDBC - click.

+0

Potrebbe scrivere codice di esempio per questo nella tua domanda? –

+2

Domanda modificata. Ho semplificato un po 'il codice, ma funziona allo stesso modo. –

risposta

4

Ecco alcuni codice di lavoro (per gli utenti Debian: basta installare postgresql-pltcl-8.4 pacchetto ed eseguire 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(); 

Tuttavia non posso ottenere segnaposto in dichiarazione preparata (restituisce 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) 

MODIFICA:

Come soluzione temporanea utilizzare 01 Record(rappresentato come array in Tcl), recuperare la colonna id da lì e utilizzare la funzione replace per inserirla al posto di $1. Qui ci sono due soluzioni: PL/pgSQL e 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; 

Risultato:

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

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

(1 fila)

+0

Ciò che hai scritto è un comportamento corretto di questo trigger. Salva una query corrente, quindi 'ESEGUI deleteFromFloors (2)'. Comunque da java, che chiama un 'delete from floors dove id =?' una query diversa (con $ 1) viene salvata. Lascia che scriva un pezzo di codice in java per mostrarlo. –

+0

Aggiunta una parte java. La tua risposta sarà utile per gli altri, ma non posso votare a causa della bassa classifica. –

+1

@ Michał: aggiunta soluzione (ottenendo id da record/array OLD disponibili) –