CREATE OR REPLACE FUNCTION check_updates() RETURNS TRIGGER AS 
$$
	BEGIN { strict->import(); }
	
	use PLPerl::CheckTrigger;
	
	my $states = {
		assertion_present => 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');
	
	die "$_TD->{name} takes at least 2 argument"
	unless ($_TD->{argc} >= 2);
	
	my ($options_arg, $condition);
	my @deny_columns = ();
	my @condition_columns = ();
	my $state = $states->{assertion_present};
	my ($assertname, $assertmessage);
			
	foreach (@{$_TD->{args}}) {
		if ($state == $states->{assertion_present}) {
			# get the options for check_columns
			$options_arg = uc($_);
			# check whether we have ASSERT_MESSAGE option
			foreach my $option (split (/,\s*/, $options_arg)) {
				if ($option eq "ASSERT_MESSAGE") {
					$state = $states->{assertion_name};
					last;
				}
			}
			# skip assertion name and message parsing
			# if the corresponding option is not present
			$state = $states->{columns_list} if ($state == $states->{assertion_present});
			next;
		} elsif ($state == $states->{assertion_name})
		{
			$assertname = $_;
			$state = $states->{assertion_message};
			next;
		} elsif ($state == $states->{assertion_message})
		{
			$assertmessage = $_;
			$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, @condition_columns);
		}
	};
	die $@ if ($@);
	
	if (!$result) {
		$errmsg .= " when " . $ch->{errmsg};
		$errmsg =~ s/, UPDATE is not allowed//;
		if ($assertname ne "" and $assertmessage ne "")
		{
			$errmsg = "\nASSERTION $assertname: $assertmessage.\nDETAIL: ".$errmsg;
		}
		die $errmsg
	}

return;
$$ LANGUAGE plperlu;

-- vi: noexpandtab
