CREATE OR REPLACE FUNCTION check_updates() RETURNS TRIGGER AS $$ BEGIN { strict->import(); } use lib '/contrib'; use lib '/extensions'; use CheckTrigger; my $states = { read_options => 0, assertion_name => 1, assertion_message => 2, columns_list => 3, condition => 4, condition_columns => 5 }; # This should be a row level trigger die 'should be called as a row level trigger' unless ($_TD->{level} eq 'ROW'); # Do nothing if event is not UPDATE return if ($_TD->{event} ne 'UPDATE'); my $minargc = 2; # $minargc += 2; die "$_TD->{name} takes at least $minargc argument" unless ($_TD->{argc} >= $minargc); my ($options_arg, $condition); my @deny_columns = (); my @condition_columns = (); my $state = $states->{read_options}; # $state = $states->{assertion_name}; my ($assertname, $assertmessage); foreach (@{$_TD->{args}}) { if ($state == $states->{assertion_name}) { $assertname = PLPerl::CheckTrigger::pg_quote_nullable($_); $state = $states->{assertion_message}; next; } elsif ($state == $states->{assertion_message}) { $assertmessage = PLPerl::CheckTrigger::pg_quote_nullable($_); $state = $states->{read_options}; next; } elsif ($state == $states->{read_options}) { # read options $options_arg = uc($_); $state = $states->{columns_list}; next; } elsif ($state == $states->{columns_list}) { # get the list of columns for check_columns. # Read the values until they are valid column names. if (defined $_TD->{new}{$_}) { push @deny_columns, $_; next; } else { $state = $states->{condition}; } } if ($state == $states->{condition}) { # get the condition to check $condition = $_; $state = $states->{condition_columns}; } elsif ($state == $states->{condition_columns}) { # get the columns for check_condition push @condition_columns, $_; } else { # shouldn't be there die "Invalid state: $state"; } } # create a new instance of the 'helper' class. my $ch = new PLPerl::CheckTrigger($_TD); my $result; my $errmsg = ""; eval { # check whether this update touches columns that shouldn't change $result = $ch->check_columns($options_arg, @deny_columns); if ($result == 0) { # this update should be denied, however, we allow it if the # condition passed will be satisfied. $errmsg = $ch->{errmsg}; $result = $ch->check_condition($condition, 0, @condition_columns); } }; die $@ if ($@); if (!$result) { $errmsg .= " when " . $ch->{errmsg}; $errmsg =~ s/, UPDATE is not allowed//; # $assertmessage = PLPerl::CheckTrigger::pg_quote_nullable($errmsg) if (($assertmessage eq '') || ($assertmessage eq 'NULL')); # my $query = "SELECT tools.assert($assertname, false, $assertmessage)"; # my $rv = spi_exec_query($query); die $errmsg; } return; $$ LANGUAGE plperlu;