postgresql pl/perlトリガー、null vsを差別化する
-
16-10-2019 - |
質問
しばらく前にPL/PGSQLで書いた一般的な監査トリガーをスピードアップしようとしています。更新では、更新されるテーブル内の列のリストを生成し、変更を記録する監査テーブルに行を挿入します(テーブル、列、データの前、データ後など)。同じトリガー関数が複数のテーブルで使用されます。
手元のタスクでははるかに高速であるように思われるPL/PERLをいじっていますが、データベースのnullと空の文字列( '')値を区別することに問題が発生したようです。
列がnullから空の文字列(またはその逆)に移動する場合、それは私が記録する必要がある変更です。ただし、利用可能な新しい/古い列参照($ _td-> {new/old} {$ columnname})を使用して、実際にnullの列と空の文字列を含む列を区別することはできないようです。私が知っている列は、空のチェックとUNDEFチェックの両方に捕まり、空の列と同様に、nullが捕らえられています。
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");
}
私はここで愚かなことをしているのではないかと疑っていますが、多分私は単にできないことをしようとしています。何かアドバイス?
編集 - それが価値があるものにpostgres8.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
}
}
空の文字列とヌルの違いをキャッチし、それらをすべて監査テーブルに適切にログに記録します。
解決
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" );
}