2012-01-06 11 views
0

我有一個審計實現通過pltcl在Django應用程序PostgreSQL數據庫觸發器,我想跟蹤表上的每一個數據的變化,Django的審計日誌不不夠,因爲我們需要跟蹤通過SQL直接更改過,在psql裏我可以插入,更新,刪除和一切都很好,但在Django當應用程序與同一個數據庫用戶運行,以下錯誤被拋出:在pltcl觸發沒有這樣的變量使用Django時,審計表

DatabaseError at /recolecta/nuevo 
can't read "tgname_act": no such variable 
CONTEXT: can't read "tgname_act": no such variable 
    while executing 
"spi_exec "SELECT a.attname AS pk_name 
      FROM pg_class c, pg_attribute a, pg_index i 
      WHERE c.relname = '$tgname_act' AND c.oid = i.in..." 
    (procedure "__PLTcl_proc_71035_trigger" line 23) 
    invoked from within 
"__PLTcl_proc_71035_trigger tgrt_informationgathering_restitutionrequeststate 53594 informationgathering_restitutionrequeststate public {{} id restitut..." 
in PL/Tcl function "rtaudit_function" 
Request Method: POST 
Request URL: http://192.168.1.108:8001/recolecta/nuevo 
Django Version: 1.3.1 
Exception Type: DatabaseError 
Exception Value: 
can't read "tgname_act": no such variable 
CONTEXT: can't read "tgname_act": no such variable 
    while executing 
"spi_exec "SELECT a.attname AS pk_name 
      FROM pg_class c, pg_attribute a, pg_index i 
      WHERE c.relname = '$tgname_act' AND c.oid = i.in..." 
    (procedure "__PLTcl_proc_71035_trigger" line 23) 
    invoked from within 
"__PLTcl_proc_71035_trigger tgrt_informationgathering_restitutionrequeststate 53594 informationgathering_restitutionrequeststate public {{} id restitut..." 
in PL/Tcl function "rtaudit_function" 
Exception Location: /home/igor/.virtualenvs/registrotierras_app/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py in execute, line 44 
Python Executable: /home/igor/.virtualenvs/registrotierras_app/bin/python 
Python Version: 2.7.2 

觸發器的定義是

CREATE OR REPLACE FUNCTION rtaudit_function() RETURNS "trigger" AS 
$BODY$ 
set i 0 
set thecounter 1 
set pk_name "" 
set pk_value "" 
set theuser "registrotierras" 

# user 
spi_exec "SELECT CURRENT_USER AS tguser" 
# tablename | table_rtaudit 
spi_exec "SELECT relname AS tgname, relname || '_rtaudit' AS tgname_act FROM pg_class WHERE relfilenode = $TG_relid" 
spi_exec "SELECT a.attname AS pk_name 
      FROM pg_class c, pg_attribute a, pg_index i 
      WHERE c.relname = '$tgname_act' AND c.oid = i.indrelid AND a.attnum > 0 AND a.attrelid = i.indexrelid AND i.indisprimary='t'" 


# Make sure the audit table exists, if not, we create it 
spi_exec "SELECT COUNT(*) AS cols FROM information_schema.tables WHERE table_name = '$tgname_act' AND table_schema = 'rtaudit'" 
if {$cols == 0} { 
    spi_exec "CREATE TABLE rtaudit.$tgname_act AS SELECT text('1') AS theuser_rtaudit, current_timestamp AS thetime_rtaudit, text('I') AS theactivity_rtaudit, * FROM $tgname WHERE 1 = 0" 
    spi_exec "GRANT ALL ON rtaudit.$tgname_act TO $theuser" 
} 

set uni [concat "INSERT INTO rtaudit.$tgname_act" "(theuser_rtaudit, thetime_rtaudit, theactivity_rtaudit, "] 
set uni1 "" 

switch $TG_op { 
    INSERT { 
    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get NEW $field] 0] $pk_name] == 0} { 
     incr i 
     } 
    } 

    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get NEW $field] 0] $pk_name] == 0} { 
     if {$thecounter < $i} { 
      set uni [concat "$uni" "$field,"] 
     } else { 
      set uni [concat "$uni" "$field"] 
     } 
     incr thecounter 
     } 
    } 
    set uni [concat "$uni" ") VALUES ('$tguser', now(), '$TG_op', "] 
    set thecounter 1; 

    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get NEW $field] 0] $pk_name] == 0} { 
     set current_value [quote [lindex [array get NEW $field] 1]] 
     if {$current_value == ""} { 
      set current_value "NULL" 
     } else { 
      set current_value "'$current_value'" 
     } 

     if {$thecounter < $i} { 
      set uni [concat "$uni" "$current_value,"] 
     } else { 
      set uni [concat "$uni" "$current_value"] 
     } 
     incr thecounter 
     } 
    } 

    set uni [concat "$uni" ")"] 
    } 
    UPDATE { 
    set thesize [llength $TG_relatts] 
    set thesize [expr $thesize - 1] 

    for {set i 1} {$i <= $thesize} {incr i} { 
     set field [lindex $TG_relatts $i] 
     if {$i < $thesize} { 
     set uni [concat "$uni" "$field,"] 
     } else { 
     set uni [concat "$uni" "$field"] 
     } 
    } 
    set uni1 $uni 
    set uni [concat "$uni" ") VALUES ('$tguser', now(), '$TG_op', "] 
    set uni1 [concat "$uni1" ") VALUES ('$tguser', now(), 'PREVIOUS', "] 

    for {set i 1} {$i <= $thesize} {incr i} { 
     set field [lindex $TG_relatts $i] 
     set current_value [quote [lindex [array get NEW $field] 1]] 

     if {$current_value == ""} { 
     set current_value "NULL" 
     } else { 
     set current_value "'$current_value'" 
     } 

     if {$i < $thesize} { 
     set uni [concat "$uni" "$current_value,"] 
     } else { 
     set uni [concat "$uni" "$current_value"] 
     } 
    } 

    for {set i 1} {$i <= $thesize} {incr i} { 
     set field [lindex $TG_relatts $i] 
     set previous_value [quote [lindex [array get OLD $field] 1]] 

     if {$previous_value == ""} { 
     set previous_value "NULL" 
     } else { 
     set previous_value "'$previous_value'" 
     } 

     if {$i < $thesize} { 
     set uni1 [concat "$uni1" "$previous_value,"] 
     } else { 
     set uni1 [concat "$uni1" "$previous_value"] 
     } 
    } 

    set uni [concat "$uni" ")"] 
    set uni1 [concat "$uni1" ")"] 
    } 
    DELETE { 
    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get OLD $field] 0] $pk_name] == 0} { 
     incr i 
     } 
    } 

    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get OLD $field] 0] $pk_name] == 0} { 
     if {$thecounter < $i} { 
      set uni [concat "$uni" "$field,"] 
     } else { 
      set uni [concat "$uni" "$field"] 
     } 
     incr thecounter 
     } 
    } 
    set uni [concat "$uni" ") VALUES ('$tguser', now(), '$TG_op', "] 
    set thecounter 1; 

    foreach field $TG_relatts { 
     if {[string equal -nocase [lindex [array get OLD $field] 0] $pk_name] == 0} { 
     set current_value [quote [lindex [array get OLD $field] 1]] 

     if {$current_value == ""} { 
      set current_value "NULL" 
     } else { 
      set current_value "'$current_value'" 
     } 

     if {$thecounter < $i} { 
      set uni [concat "$uni" "$current_value,"] 
     } else { 
      set uni [concat "$uni" "$current_value"] 
     } 
     incr thecounter 
     } 
    } 
    set uni [concat "$uni" ")"] 
    } 
} 

# Execute the query y error management 
if {[catch {spi_exec $uni} catchres]} { 
     set uni2 "INSERT INTO error_rtaudit (thetime, thetable, error, query) VALUES (NOW(), '$tgname_act', '$catchres', '$uni')" 
     if {[catch {spi_exec $uni2} catchres1]} { 
       set uni3 "INSERT INTO error_rtaudit (thetime, error) VALUES (NOW(), '$catchres')" 
       if {[catch {spi_exec $uni3} catchres]} { 
         set errormsg "ERROR 1" 
       } 
     } else { 
       set errormsg "ERROR 2" 
     } 
} else { 
     set errormsg "OK" 
} 

set thesize [string length $uni1] 
if { $thesize > 0 } { 
     if {[catch {spi_exec $uni1} catchres]} { 
       set uni2 "INSERT INTO error_rtaudit (thetime, thetable, error, query) VALUES (NOW(), '$tgname_act', '$catchres', '$uni1')" 
       if {[catch {spi_exec $uni2} catchres1]} { 
         set uni3 "INSERT INTO error_rtaudit (thetime, error) VALUES (NOW(), '$catchres')" 
         if {[catch {spi_exec $uni3} catchres]} { 
           set errormsg [concat "$errormsg" " | ERROR 1"] 
         } 
       } else { 
         set errormsg [concat "$errormsg" " | ERROR 2"] 
       } 
     } else { 
       set errormsg [concat "$errormsg" " | OK"] 
     } 
} 

return OK 
$BODY$ 
LANGUAGE 'pltcl' VOLATILE; 

爲了使它工作,在Django中需要做些什麼?或者是否有必要避免pltcl? PostgreSQL數據庫是9.1的Ubuntu的服務器上,但我想這是更關係到Django和PostgreSQL中的一些權限而是擔心自己的代碼的

+0

錯誤指向觸發,變量tgname_act似乎沒有在任何地方定義,是不是函數的簽名的一部分。我不知道pgtcl的範圍規則,但是如果沒有某種魔法,它就是未定義的。 你可以用一個簡單的'set tgname_act「東西來定義它'''但那可能不是正確的修復。 – schlenk 2012-01-06 19:01:01

+0

我改變了線路,以確保我在數組中截獲的spi_exec的結果,但再次pltcl抱怨,但是當通過Django的視圖稱爲像這樣就叫:'的spi_exec -array C「SELECT relname AS tgname,relname ||‘_rtaudit’AS tgname_act FROM的pg_class WHERE relfilenode = $ TG_RELID」 組tgname_act $ C(tgname_act) 組tgname $ C(tgname)' – ikks 2012-01-06 19:48:34

回答

0

,我的建議是使用tablelog:http://pgfoundry.org/projects/tablelog/

這就是我們在LedgerSMB中進行審計某些表。

你目前的問題雖然是可能是代替tgname_act,您可能意味着無論是TG_NAME或TG_table_name。

1

的問題是,這個查詢沒有找到任何東西:

spi_exec "SELECT relname AS tgname, relname || '_rtaudit' AS tgname_act 
      FROM pg_class WHERE relfilenode = $TG_relid" 

反正這導致了tgname_act沒有定義的事實。 您可以檢查變量是否存在info exists tgname_act並提供有用的默認值。

例子:

spi_exec "SELECT relname AS tgname, relname || '_rtaudit' AS tgname_act 
      FROM pg_class WHERE relfilenode = $TG_relid" 
if {![info exists tgname_act]} {set tgname_act "foo_rtaudit"} 

如果你不這樣做此類檢查在PL/TCL,那麼你的觸發將在一段時間內炸燬。

相關問題