我有一個審計實現通過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中的一些權限而是擔心自己的代碼的
錯誤指向觸發,變量tgname_act似乎沒有在任何地方定義,是不是函數的簽名的一部分。我不知道pgtcl的範圍規則,但是如果沒有某種魔法,它就是未定義的。 你可以用一個簡單的'set tgname_act「東西來定義它'''但那可能不是正確的修復。 – schlenk 2012-01-06 19:01:01
我改變了線路,以確保我在數組中截獲的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