У меня есть реализация аудита с помощью триггеров pltcl в базе данных postgresql в приложении Django, я хочу отслеживать каждое изменение данных в таблицах, и django-audit-log недостаточно, потому что нам также нужно отслеживать изменения напрямую через sql, в psql я могу вставить, обновить, удалить, и все идет хорошо, но в 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;
Что необходимо сделать в Джанго, чтобы это работало? или нужно будет избегать pltcl? База данных postgresql - это 9.1 на сервере Ubuntu, но я думаю, что она больше связана с Django и некоторыми разрешениями в postgresql