Autovivified column data after before_create trigger

[prev] [thread] [next] [Date index for 2004/10/09]

From: Christopher L. Everett
Subject: Autovivified column data after before_create trigger
Date: 23:15 on 09 Oct 2004
This is a multi-part message in MIME format.
--------------030606020308050606020501
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

As far as I can tell, for every column you set a constraint on, a null entry in the instance data gets created for every column you don't explicitly set.

For example, a table having DDL like this:

CREATE TABLE bar(
  bar_id integer unsigned auto_increment primary key,
  baz integer unsigned NOT NULL,
  quux integer unsigned NOT NULL
);

(note the NOT NULLs) with a class like

package Foo:Bar;
use base 'Foo::Base';

__PACKAGE__->table('foo.bar');
__PACKAGE__->columns(All => qw/bar_id baz quux/);

__PACKAGE__->add_constraint($_ => &is_def) foreach qw/baz quux/;

sub is_def { return defined($_[0]); }

1;

doing this:

my $bar = Foo::Bar->create({baz => 1});

leaves your object data like this after the before_create trigger runs:

bless({baz => 1, 
       quux => undef}, Foo::Bar);

I expected it to look like this:

bless({baz => 1}, Foo::Bar);

Note that the is_def constraint for `quux` won't get triggered, though 
the value violates the constraint.  Instead, the error happens at the 
database level.

In addition to a very unexpected outcome, now I have to work harder:

  -- providing a defined value upfront for every single column
  -- parsing and handling a wider variety of possible errors

I've posted about this before.  Given the much nicer code base we now 
have (thanks guys for all the good work!), my kludgey patch to solve the
problem in a hurry (damn that blind upgrading on production servers) at 
least looks a bit cleaner.

IMO, the proble with the included patch is that I shouldn't have to do 
this work at all -- oughtn't the constraint checking be run against a local copy of the object?  In the limited time that I have, I couldn't 
find out how the constraint checking happens in before_create, but if 
helps me out  bit, I will be more than happyto produce a permanent fix 
and a set of tests, because forgetting to check for this problem will 
cost me a lot more than the time it takes me to fix it for good.

PS.  Is this why the undocumented deflate_before_create trigger exists?

        -- 
        Christopher L. Everett

Chief Technology Officer                               www.medbanner.com
MedBanner, Inc.                                          www.physemp.com


--------------030606020308050606020501
Content-Type: text/x-patch;
 name="DBI.pm.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="DBI.pm.patch"

--- DBI.pm.orig	2004-10-08 04:45:24.000000000 -0500
+++ DBI.pm	2004-10-08 03:59:08.000000000 -0500
@@ -578,6 +578,9 @@
 	my $self = $class->_init($data);
 
 	$self->call_trigger('before_create');
+	delete $self->{$_} 
+	  foreach grep { not exists $self->{__Changed}{$_} and not exists $data->{$_} }
+	               $self->all_columns;
 	$self->call_trigger('deflate_for_create');
 
 	$self->_prepopulate_id if $self->_undefined_primary;

--------------030606020308050606020501--

(message missing)

Autovivified column data after before_create trigger
Christopher L. Everett 23:15 on 09 Oct 2004

Autovivified column data after before_create trigger
Christopher L. Everett 21:41 on 11 Oct 2004

Re: Autovivified column data after before_create trigger
Christopher L. Everett 19:56 on 12 Oct 2004

Generated at 11:34 on 01 Dec 2004 by mariachi v0.52