Re: before_create trigger problems

[prev] [thread] [next] [Date index for 2004/12/21]

From: Charles Bailey
Subject: Re: before_create trigger problems
Date: 19:01 on 21 Dec 2004
--On Tuesday, December 21, 2004 10:35:50 AM EST -0800 Emile Aben 
<emileaben@xxxxx.xxx> wrote:

>
> --- Emile Aben <emileaben@xxxxx.xxx> wrote:
>
>>
>> --- Tony Bowden <tony-cdbitalk@xxxxx.xxx> wrote:
>>
>> > On Mon, Dec 20, 2004 at 05:39:11PM -0800, Emile
>> Aben
>> > wrote:
>
> Cheered too early. Now I'm genuinly confused. In my
> triggered routine I fetch information from the
> database, and I seem to have to use the low-level
> access sometimes, but not at other times:
>
> sub _fixup_exclusive {
> 	my ($this) = @_;
> 	# need to use low-level accessors(_attrs) and not
> set/get here because we're in a trigger!
> 	# shouldn't be too many @attrs that match
> 	my @mondata_list = __PACKAGE__->search (
> 		{
> 			monitor => $this->_attrs("monitor"),
> 			attribute => $this->_attrs("attribute"),
> 		}
> 	);
>
> 	my $new_start = $this->_attrs("start_date");
> 	my $new_end   = $this->_attrs("end_date");
> 	foreach my $old (@mondata_list) {
> 		next if ( $this->_attrs("id")
> 			&& $this->_attrs("id") eq $old->_attrs("id") );
> 		my $old_start = $old->start_date();
> 		my $old_end   = $old->end_date();
>
> 		next if ($old_end && ( $old_end < $new_start ));
> 		print STDERR "NEW: $new_start -> $new_end \n";
> 		print STDERR "OLD: $old_start -> $old_end \n";
> 		use Data::Dumper; print Dumper($old);
>
>
> $old is an object created from a search in the
> database, but to be able to access anything other than
> the primary key, I have to use the accessor
> 'start_date', otherwise the data for this object won't
> actually be fetched from the database (checked that
> with Data::Dumper).

That's as designed, though I agree it seems a surprise sometimes.  The 
philosophy is this (with the hope that more informed readers will correct 
any errors I may make):

- "low-level" accessors retrieve or modify the relevant property of the 
object in core, without triggering any side effects, including 
inflation/deflation, lazy loading, or other triggers.  The intent is to 
allow code which may itself be in a trigger to make modifications without 
setting up infinite recursion, or doing unnecessary work.  Since the intent 
was for these to be "internal" routines, they don't do extra work for the 
caller (e.g. looking up column names, though that'd be easy enough to add). 
This also makes them somewhat more efficient than the "regular" accessors 
for simple operations, though speed isn't a major goal of CDBI.

- "regular" accessors retrieve or modify the relevant property of the 
object as modelled by the CDBI class, with all of the class's side effects 
(typically via triggers, though possibly via a custom get() or set() 
function), including inflation/deflation, lazy loading, etc.  This should 
be the usual way to access object attributes, but for the reasons mentioned 
above can cause problems when used in triggers.  The before_create case is 
special in another way: even if one can guarantee that a trigger won't 
cause infinite recursion or a similar problem, there's no guarantee that 
the object which is about to be created will be sufficiently assembled for 
a "regular" accessor (or its side effects) to function properly.  As a 
consequence, before_create triggers should only use the low-level 
accessors, and will need to account for any preprocessing needed to insure 
that the value supplied by the caller is in the proper format to be written 
to the database (modulo stringification, though I think that's more a 
detail of the current implementation than a documented behavior).

This should become much cleaner when we have smarter attributes which can 
handle interconversions on their own.  Back to the tuit search . . .


> Further on in the triggered sub I sometimes have to
> create a new object in the database, and I'm currently
> unable to get this working. My best try is:
>
>                if ($new_end && $new_start >=
> $old_start && (!$old_end || $new_end <= $old_end ) ) {
> 			# case:     nnnn
>                         #        ooooooooo(...)
> 			# solution: cut old in 2
> 			print STDERR "     nnnn\n";
> 			print STDERR "   ooooooooo(...)\n";
> 			my $old2 = $old->copy();
> 			$old2->_attribute_set("start_date", $new_end + 1 );
> 			$old2->update();
> 			$old->_attribute_set("end_date", $new_start - 1 );
> 			$old->update();
> 		}
>
> This get's stuck on line 51 in Trigger.pm again:
> Can't retrieve a reference at
> /usr/local/perl-5.6.0/lib/site_perl/5.6.0/Class/Trigger.pm
> line 51

Hmm.  Do you happen to know whether the copy() or the update() triggers 
this error?


--
Regards,
Charles Bailey  < bailey _at_ newman _dot_ upenn _dot_ edu >
Newman Center at the University of Pennsylvania

(message missing)

before_create trigger problems
Emile Aben 01:39 on 21 Dec 2004

Re: before_create trigger problems
Tony Bowden 09:09 on 21 Dec 2004

Re: before_create trigger problems
Drew Taylor 16:21 on 21 Dec 2004

Re: before_create trigger problems
Emile Aben 17:13 on 21 Dec 2004

Re: before_create trigger problems
Emile Aben 18:35 on 21 Dec 2004

Re: before_create trigger problems
Charles Bailey 19:01 on 21 Dec 2004

Re: before_create trigger problems
Emile Aben 19:28 on 21 Dec 2004

Re: before_create trigger problems
Charles Bailey 15:56 on 22 Dec 2004

Re: before_create trigger problems
Emile Aben 17:24 on 22 Dec 2004

Generated at 12:15 on 16 Jan 2005 by mariachi v0.52