Postgresql
PostgreSQL pl/perl 觸發器,區分 null 與空
我一直在嘗試加速我以前用 pl/pgsql 編寫的通用審計觸發器。更新時,它會在正在更新的表中生成列列表,並在審計表中插入記錄任何更改的行(按表、列、之前的數據、之後的數據等)。跨多個表使用相同的觸發器函式。
我正在玩弄 pl/perl,因為它對於手頭的任務似乎要快得多,但我似乎在區分數據庫中的 NULL 和空字元串 (’’) 值時遇到了問題。
在我看來,如果一列從 NULL 變為空字元串(反之亦然),這就是我需要記錄的更改。但是,使用可用的新/舊列引用 ($_TD->{new/old}{$columnName}),我似乎無法區分實際為空的列和包含空字元串的列。我知道為空的列被空檢查和 undef 檢查擷取,我知道為空的列也是如此。
if($_TD->{new}{$column} eq '') { elog(NOTICE, "New value in column $column is empty"); } if($_TD->{old}{$column} eq '') { elog(NOTICE, "Old value in column $column is empty"); } if($_TD->{new}{$column} eq undef) { elog(NOTICE, "New value in column $column is not defined"); } if($_TD->{old}{$column} eq undef) { elog(NOTICE, "Old value in column $column is not defined"); }
我懷疑我在這裡做了一些愚蠢的事情,但也許我正在嘗試做一些我根本做不到的事情。有什麼建議嗎?
編輯 - 使用 Postgres 8.4.4 物有所值
編輯 - 在查看下面 filiprem 的文章(以及更多測試)之後,我最終得到了這個,這似乎正在工作:
my %newrow = %{$_TD->{new}}; my %oldrow = %{$_TD->{old}}; my $valChanged; while (($column,$value) = each %newrow) { $valChanged = 0; if($newrow{$column} ne $oldrow{$column}) { $valChanged = 1; elog(NOTICE, "Values in column $column differ. New: $_TD->{new}{$column}, Old: $_TD->{old}{$column}"); } elsif(!defined($newrow{$column}) && defined($oldrow{$column})) { elog(NOTICE, "New row contains nulled out field"); $valChanged = 1; } elsif(defined($newrow{$column}) && !defined($oldrow{$column})) { elog(NOTICE, "New row contains newly populated field"); $valChanged = 1; } if($valChanged) { ### Update audit table } }
它擷取空字元串和 NULL 之間的差異,並將它們都適當地記錄在審計表中。
您沒有指定 PostgreSQL 版本。在 9.0.5 上,我觀察到了相同的行為(不確定這是否是錯誤,請參閱下面的評論)。
這很容易解決 - 您可以首先測試定義是否擷取 NULL,如果它通過,則測試空字元串。
if ( not defined $_TD->{ new }{ $column } ) { elog( NOTICE, "New value in column $column is not defined" ); } elsif ( $_TD->{ new }{ $column } eq '' ) { elog( NOTICE, "New value in column $column is empty" ); } if ( not defined $_TD->{ old }{ $column } ) { elog( NOTICE, "Old value in column $column is not defined" ); } elsif ( $_TD->{ old }{ $column } eq '' ) { elog( NOTICE, "Old value in column $column is empty" ); }