File Coverage

blib/lib/Rose/DB/Object.pm
Criterion Covered Total %
statement 68 710 9.5
branch 1 372 0.2
condition 2 100 2.0
subroutine 24 34 70.5
pod 10 10 100.0
total 105 1226 8.5


line stmt bran cond sub pod time code
1             package Rose::DB::Object;
2              
3 61     61   27264298 use strict;
  61         409  
  61         1858  
4              
5 61     61   365 use Carp();
  61         136  
  61         958  
6              
7 61     61   2245 use Rose::DB;
  61         1327174  
  61         1294  
8 61     61   76991 use Rose::DB::Object::Metadata;
  61         214  
  61         2587  
9              
10 61     61   454 use Rose::Object;
  61         153  
  61         2359  
11             our @ISA = qw(Rose::Object);
12              
13 61     61   379 use Rose::DB::Object::Manager;
  61         140  
  61         1612  
14 61     61   353 use Rose::DB::Object::Constants qw(:all);
  61         131  
  61         12369  
15 61     61   476 use Rose::DB::Constants qw(IN_TRANSACTION);
  61         173  
  61         2894  
16 61     61   400 use Rose::DB::Object::Exception;
  61         159  
  61         1303  
17 61     61   333 use Rose::DB::Object::Util();
  61         137  
  61         3813  
18              
19             our $VERSION = '0.820';
20              
21             our $Debug = 0;
22              
23             #
24             # Object data
25             #
26              
27             use Rose::Object::MakeMethods::Generic
28             (
29 61         575 'scalar' => [ 'error', 'not_found' ],
30             'boolean' =>
31             [
32             #FLAG_DB_IS_PRIVATE,
33             STATE_IN_DB,
34             STATE_LOADING,
35             STATE_SAVING,
36             ],
37 61     61   377 );
  61         133  
38              
39             #
40             # Class methods
41             #
42              
43 96     96 1 534 sub meta_class { 'Rose::DB::Object::Metadata' }
44              
45             sub meta
46             {
47 5946     5946 1 114378 my($self) = shift;
48              
49 5946 50       8493 if(ref $self)
50             {
51 0   0     0 return $self->{META_ATTR_NAME()} ||= $self->meta_class->for_class(ref $self);
52             }
53              
54 5946   66     14543 return $Rose::DB::Object::Metadata::Objects{$self} ||
55             $self->meta_class->for_class($self);
56             }
57              
58             #
59             # Object methods
60             #
61              
62             sub db
63             {
64 0     0 1 0 my($self) = shift;
65              
66 0 0       0 if(@_)
67             {
68             #$self->{FLAG_DB_IS_PRIVATE()} = 0;
69              
70 0         0 my $new_db = shift;
71              
72             # If potentially migrating across db types, "suck through" the
73             # driver-formatted values using the old db before swapping it
74             # with the new one.
75 0 0 0     0 if($self->{LOADED_FROM_DRIVER()} &&
76             $self->{LOADED_FROM_DRIVER()} ne $new_db->{'driver'})
77             {
78 0         0 foreach my $method ($self->meta->column_accessor_method_names)
79             {
80             # Need to catch return to avoid clever methods that
81             # skip work when called in void context.
82 0         0 my $val = $self->$method();
83             }
84             }
85              
86 0         0 $self->{'db'} = $new_db;
87              
88 0         0 return $new_db;
89             }
90              
91 0   0     0 return $self->{'db'} ||= $self->_init_db;
92             }
93              
94 14     14 1 54 sub init_db { Rose::DB->new() }
95              
96             sub _init_db
97             {
98 0     0     my($self) = shift;
99              
100 0           my($db, $error);
101              
102             TRY:
103             {
104 0           local $@;
  0            
105 0           eval { $db = $self->init_db };
  0            
106 0           $error = $@;
107             }
108              
109 0 0         unless($error)
110             {
111             #$self->{FLAG_DB_IS_PRIVATE()} = 1;
112 0           return $db;
113             }
114              
115 0 0         if(ref $error)
116             {
117 0           $self->error($error);
118             }
119             else
120             {
121 0 0         $self->error("Could not init_db() - $error - " . ($db ? $db->error : ''));
122             }
123              
124 0           $self->meta->handle_error($self);
125 0           return undef;
126             }
127              
128             sub dbh
129             {
130 0     0 1   my($self) = shift;
131              
132 0 0         my $db = $self->db or return undef;
133              
134 0 0         if(my $dbh = $db->dbh(@_))
135             {
136 0           return $dbh;
137             }
138             else
139             {
140 0           $self->error($db->error);
141 0           $self->meta->handle_error($self);
142 0           return undef;
143             }
144             }
145              
146 61         293 use constant LAZY_LOADED_KEY =>
147 61     61   84186 Rose::DB::Object::Util::lazy_column_values_loaded_key();
  61         204  
148              
149             sub load
150             {
151 0     0 1   my($self) = $_[0]; # XXX: Must maintain alias to actual "self" object arg
152              
153 0           my %args = (self => @_); # faster than @_[1 .. $#_];
154              
155 0 0         my $db = $self->db or return 0;
156 0 0         my $dbh = $self->dbh or return 0;
157              
158 0           my $meta = $self->meta;
159              
160             my $prepare_cached =
161 0 0         exists $args{'prepare_cached'} ? $args{'prepare_cached'} :
162             $meta->dbi_prepare_cached;
163              
164 0           local $self->{STATE_SAVING()} = 1;
165 0           local $self->{SAVING_FOR_LOAD()} = 1;
166              
167 0           my(@key_columns, @key_methods, @key_values);
168              
169 0           my $null_key = 0;
170 0           my $found_key = 0;
171              
172 0 0         if(my $key = delete $args{'use_key'})
173             {
174 0           my @uk = grep { $_->name eq $key } $meta->unique_keys;
  0            
175              
176 0 0         if(@uk == 1)
177             {
178 0           my $defined = 0;
179 0           @key_columns = $uk[0]->column_names;
180 0           @key_methods = map { $meta->column_accessor_method_name($_) } @key_columns;
  0            
181 0 0         @key_values = map { $defined++ if(defined $_); $_ }
  0            
182 0           map { $self->$_() } @key_methods;
  0            
183              
184 0 0         unless($defined)
185             {
186 0           $self->error("Could not load() based on key '$key' - column(s) have undefined values");
187 0           $meta->handle_error($self);
188 0           return undef;
189             }
190              
191 0 0         if(@key_values != $defined)
192             {
193 0           $null_key = 1;
194             }
195             }
196 0           else { Carp::croak "No unique key named '$key' is defined in ", ref($self) }
197             }
198             else
199             {
200 0           @key_columns = $meta->primary_key_column_names;
201 0           @key_methods = $meta->primary_key_column_accessor_names;
202 0           @key_values = grep { defined } map { $self->$_() } @key_methods;
  0            
  0            
203              
204 0 0         unless(@key_values == @key_columns)
205             {
206 0           my $alt_columns;
207              
208             # Prefer unique keys where we have defined values for all
209             # key columns, but fall back to the first unique key found
210             # where we have at least one defined value.
211 0           foreach my $cols ($meta->unique_keys_column_names)
212             {
213 0           my $defined = 0;
214 0           @key_columns = @$cols;
215 0           @key_methods = map { $meta->column_accessor_method_name($_) } @key_columns;
  0            
216 0 0         @key_values = map { $defined++ if(defined $_); $_ }
  0            
217 0           map { $self->$_() } @key_methods;
  0            
218              
219 0 0         if($defined == @key_columns)
220             {
221 0           $found_key = 1;
222 0           last;
223             }
224              
225 0 0 0       $alt_columns ||= $cols if($defined);
226             }
227              
228 0 0 0       if(!$found_key && $alt_columns)
229             {
230 0           @key_columns = @$alt_columns;
231 0           @key_methods = map { $meta->column_accessor_method_name($_) } @key_columns;
  0            
232 0           @key_values = map { $self->$_() } @key_methods;
  0            
233 0           $null_key = 1;
234 0           $found_key = 1;
235             }
236              
237 0 0         unless($found_key)
238             {
239 0           @key_columns = $meta->primary_key_column_names;
240              
241 0 0         my $e =
242             Rose::DB::Object::Exception->new(
243             message => "Cannot load " . ref($self) . " without a primary key (" .
244             join(', ', @key_columns) . ') with ' .
245             (@key_columns > 1 ? 'non-null values in all columns' :
246             'a non-null value') .
247             ' or another unique key with at least one non-null value.',
248             code => EXCEPTION_CODE_NO_KEY);
249              
250 0           $self->error($e);
251              
252 0           $meta->handle_error($self);
253 0           return 0;
254             }
255             }
256             }
257              
258 0 0         my $has_lazy_columns = $args{'nonlazy'} ? 0 : $meta->has_lazy_columns;
259 0           my $column_names;
260              
261 0 0         if($has_lazy_columns)
262             {
263 0           $column_names = $meta->nonlazy_column_names;
264 0           $self->{LAZY_LOADED_KEY()} = {};
265             }
266             else
267             {
268 0           $column_names = $meta->column_names;
269             }
270              
271             # Coerce for_update boolean alias into lock argument
272 0 0         if(delete $args{'for_update'})
273             {
274 0   0       $args{'lock'}{'type'} ||= 'for update';
275             }
276              
277             #
278             # Handle sub-object load in separate code path
279             #
280              
281 0 0         if(my $with = $args{'with'})
282             {
283 0   0       my $mgr_class = $args{'manager_class'} || 'Rose::DB::Object::Manager';
284 0           my %query;
285              
286 0           @query{map { "t1.$_" } @key_columns} = @key_values;
  0            
287              
288 0           my($objects, $error);
289              
290             TRY:
291             {
292 0           local $@;
  0            
293              
294             eval
295 0           {
296             $objects =
297             $mgr_class->get_objects(object_class => ref $self,
298             db => $db,
299             query => [ %query ],
300             with_objects => $with,
301             multi_many_ok => 1,
302             nonlazy => $args{'nonlazy'},
303             inject_results => $args{'inject_results'},
304             lock => $args{'lock'},
305             (exists $args{'prepare_cached'} ?
306 0 0         (prepare_cached => $args{'prepare_cached'}) :
    0          
307             ()))
308             or Carp::confess $mgr_class->error;
309              
310 0 0         if(@$objects > 1)
311             {
312 0           die "Found ", @$objects, " objects instead of one";
313             }
314             };
315              
316 0           $error = $@;
317             }
318              
319 0 0         if($error)
320             {
321 0 0         $self->error(ref $error ? $error : "load(with => ...) - $error");
322 0           $meta->handle_error($self);
323 0           return undef;
324             }
325              
326 0 0         if(@$objects > 0)
327             {
328             # Sneaky init by object replacement
329 0           $self = $_[0] = $objects->[0];
330              
331             # Init by copying attributes (broken; need to do fks and relationships too)
332             #my $methods = $meta->column_mutator_method_names;
333             #my $object = $objects->[0];
334             #
335             #local $self->{STATE_LOADING()} = 1;
336             #local $object->{STATE_SAVING()} = 1;
337             #
338             #foreach my $method (@$methods)
339             #{
340             # $self->$method($object->$method());
341             #}
342             }
343             else
344             {
345 61     61   579 no warnings;
  61         182  
  61         31226  
346 0           $self->error("No such " . ref($self) . ' where ' .
347             join(', ', @key_columns) . ' = ' . join(', ', @key_values));
348 0           $self->{'not_found'} = 1;
349              
350 0           $self->{STATE_IN_DB()} = 0;
351              
352             my $speculative =
353 0 0         exists $args{'speculative'} ? $args{'speculative'} :
354             $meta->default_load_speculative;
355              
356 0 0         unless($speculative)
357             {
358 0           $meta->handle_error($self);
359             }
360              
361 0           return 0;
362             }
363              
364 0           $self->{STATE_IN_DB()} = 1;
365 0           $self->{LOADED_FROM_DRIVER()} = $db->{'driver'};
366 0           $self->{MODIFIED_COLUMNS()} = {};
367 0   0       return $self || 1;
368             }
369              
370             #
371             # Handle normal load
372             #
373              
374 0           my($loaded_ok, $error);
375              
376 0           $self->{'not_found'} = 0;
377              
378             TRY:
379             {
380 0           local $@;
  0            
381              
382             eval
383 0           {
384 0           local $self->{STATE_LOADING()} = 1;
385 0           local $dbh->{'RaiseError'} = 1;
386              
387 0           my($sql, $sth);
388              
389 0 0         if($null_key)
390             {
391 0 0         if($has_lazy_columns)
392             {
393 0           $sql = $meta->load_sql_with_null_key(\@key_columns, \@key_values, $db);
394             }
395             else
396             {
397 0           $sql = $meta->load_all_sql_with_null_key(\@key_columns, \@key_values, $db);
398             }
399             }
400             else
401             {
402 0 0         if($has_lazy_columns)
403             {
404 0           $sql = $meta->load_sql(\@key_columns, $db);
405             }
406             else
407             {
408 0           $sql = $meta->load_all_sql(\@key_columns, $db);
409             }
410             }
411              
412 0 0         if(my $lock = $args{'lock'})
413             {
414 0           $sql .= ' ' . $db->format_select_lock($self, $lock);
415             }
416              
417             # $meta->prepare_select_options (defunct)
418 0 0         $sth = $prepare_cached ? $dbh->prepare_cached($sql, undef, 3) :
419             $dbh->prepare($sql);
420              
421 0 0         $Debug && warn "$sql - bind params: ", join(', ', grep { defined } @key_values), "\n";
  0            
422 0           $sth->execute(grep { defined } @key_values);
  0            
423              
424 0           my %row;
425              
426 0           $sth->bind_columns(undef, \@row{@$column_names});
427              
428 0           $loaded_ok = defined $sth->fetch;
429              
430             # The load() query shouldn't find more than one row anyway,
431             # but DBD::SQLite demands this :-/
432             # XXX: Recent versions of DBD::SQLite seem to have cured this.
433             # XXX: Safe to remove?
434 0           $sth->finish;
435              
436 0 0         if($loaded_ok)
437             {
438 0           my $methods = $meta->column_mutator_method_names_hash;
439              
440             # Empty existing object?
441             #%$self = (db => $self->db, meta => $meta, STATE_LOADING() => 1);
442              
443 0           foreach my $name (@$column_names)
444             {
445 0           my $method = $methods->{$name};
446 0           $self->$method($row{$name});
447             }
448              
449             # Sneaky init by object replacement
450             #my $object = (ref $self)->new(db => $self->db);
451             #
452             #foreach my $name (@$column_names)
453             #{
454             # my $method = $methods->{$name};
455             # $object->$method($row{$name});
456             #}
457             #
458             #$self = $_[0] = $object;
459             }
460             else
461             {
462 61     61   544 no warnings;
  61         158  
  61         103237  
463 0           $self->error("No such " . ref($self) . ' where ' .
464             join(', ', @key_columns) . ' = ' . join(', ', @key_values));
465 0           $self->{'not_found'} = 1;
466 0           $self->{STATE_IN_DB()} = 0;
467             }
468             };
469              
470 0           $error = $@;
471             }
472              
473 0 0         if($error)
474             {
475 0 0         $self->error(ref $error ? $error : "load() - $error");
476 0           $meta->handle_error($self);
477 0           return undef;
478             }
479              
480 0 0         unless($loaded_ok)
481             {
482             my $speculative =
483 0 0         exists $args{'speculative'} ? $args{'speculative'} :
484             $meta->default_load_speculative;
485              
486 0 0         unless($speculative)
487             {
488 0           $meta->handle_error($self);
489             }
490              
491 0           return 0;
492             }
493              
494 0           $self->{STATE_IN_DB()} = 1;
495 0           $self->{LOADED_FROM_DRIVER()} = $db->{'driver'};
496 0           $self->{MODIFIED_COLUMNS()} = {};
497 0   0       return $self || 1;
498             }
499              
500             sub save
501             {
502 0     0 1   my($self, %args) = @_;
503              
504 0           my $meta = $self->meta;
505              
506             my $cascade =
507 0 0         exists $args{'cascade'} ? $args{'cascade'} :
508             $meta->default_cascade_save;
509              
510             # Keep trigger-encumbered and cascade code in separate code path
511 0 0 0       if($self->{ON_SAVE_ATTR_NAME()} || $cascade)
512             {
513 0   0       my $db = $args{'db'} || $self->db || return 0;
514 0           my $ret = $db->begin_work;
515              
516 0   0       $args{'db'} ||= $db;
517              
518 0 0         unless($ret)
519             {
520 0           my $error = $db->error;
521 0 0         $self->error(ref $error ? $error : "Could not begin transaction before saving - $error");
522 0           $self->meta->handle_error($self);
523 0           return undef;
524             }
525              
526 0 0         my $started_new_tx = ($ret == IN_TRANSACTION) ? 0 : 1;
527              
528 0           my $error;
529              
530             TRY:
531             {
532 0           local $@;
  0            
533              
534             eval
535 0           {
536 0           my %did_set;
537              
538             my %code_args =
539 0           map { ($_ => $args{$_}) } grep { exists $args{$_} }
  0            
  0            
540             qw(changes_only prepare_cached cascade);
541              
542             #
543             # Do pre-save stuff
544             #
545              
546 0           my $todo = $self->{ON_SAVE_ATTR_NAME()}{'pre'};
547              
548 0           foreach my $fk_name (keys %{$todo->{'fk'}})
  0            
549             {
550 0 0         my $code = $todo->{'fk'}{$fk_name}{'set'} or next;
551 0           my $object = $code->($self, \%code_args);
552              
553             # Account for objects that evaluate to false to due overloading
554 0 0 0       unless($object || ref $object)
555             {
556 0           die $self->error;
557             }
558              
559             # Track which rows were set so we can avoid deleting
560             # them later in the "delete on save" code
561 0           $did_set{'fk'}{$fk_name}{Rose::DB::Object::Util::row_id($object)} = 1;
562             }
563              
564             #
565             # Do the actual save
566             #
567              
568 0 0 0       if(!$args{'insert'} && ($args{'update'} || $self->{STATE_IN_DB()}))
      0        
569             {
570 0           $ret = shift->update(@_);
571             }
572             else
573             {
574 0           $ret = shift->insert(@_);
575             }
576              
577             #
578             # Do post-save stuff
579             #
580              
581 0           $todo = $self->{ON_SAVE_ATTR_NAME()}{'post'};
582              
583             # Foreign keys (and some fk-like relationships)
584 0           foreach my $fk_name (keys %{$todo->{'fk'}})
  0            
585             {
586 0 0         foreach my $item (@{$todo->{'fk'}{$fk_name}{'delete'} || []})
  0            
587             {
588 0           my $code = $item->{'code'};
589 0           my $object = $item->{'object'};
590              
591             # Don't run the code to delete this object if we just set it above
592 0 0         next if($did_set{'fk'}{$fk_name}{Rose::DB::Object::Util::row_id($object)});
593              
594 0 0         $code->($self, \%code_args) or die $self->error;
595             }
596             }
597              
598 0 0         if($cascade)
599             {
600 0           foreach my $fk ($meta->foreign_keys)
601             {
602             # If this object was just set above, just save changes (there
603             # should be none) as a way to continue the cascade
604 0 0         local $args{'changes_only'} = 1 if($todo->{'fk'}{$fk->name}{'set'});
605              
606 0   0       my $foreign_object = $fk->object_has_foreign_object($self) || next;
607              
608 0 0 0       if(Rose::DB::Object::Util::has_modified_columns($foreign_object) ||
609             Rose::DB::Object::Util::has_modified_children($foreign_object))
610             {
611 0 0         $Debug && warn "$self - save foreign ", $fk->name, " - $foreign_object\n";
612 0           $foreign_object->save(%args);
613             }
614             }
615             }
616              
617             # Relationships
618 0           foreach my $rel_name (keys %{$todo->{'rel'}})
  0            
619             {
620 0           my $code;
621              
622             # Set value(s)
623 0 0         if($code = $todo->{'rel'}{$rel_name}{'set'})
624             {
625 0 0         $code->($self, \%code_args) or die $self->error;
626             }
627              
628             # Delete value(s)
629 0 0         if($code = $todo->{'rel'}{$rel_name}{'delete'})
630             {
631 0 0         $code->($self, \%code_args) or die $self->error;
632             }
633              
634             # Add value(s)
635 0 0         if($code = $todo->{'rel'}{$rel_name}{'add'}{'code'})
636             {
637 0 0         $code->($self, \%code_args) or die $self->error;
638             }
639             }
640              
641 0 0         if($cascade)
642             {
643 0           foreach my $rel ($meta->relationships)
644             {
645             # If this object was just set above, just save changes (there
646             # should be none) as a way to continue the cascade
647 0 0         local $args{'changes_only'} = 1 if($todo->{'rel'}{$rel->name}{'set'});
648              
649 0   0       my $related_objects = $rel->object_has_related_objects($self) || next;
650              
651 0           foreach my $related_object (@$related_objects)
652             {
653 0 0 0       if(Rose::DB::Object::Util::has_modified_columns($related_object) ||
654             Rose::DB::Object::Util::has_modified_children($related_object))
655             {
656 0 0         $Debug && warn "$self - save related ", $rel->name, " - $related_object\n";
657 0           $related_object->save(%args);
658             }
659             }
660             }
661             }
662              
663 0 0         if($started_new_tx)
664             {
665 0 0         $db->commit or die $db->error;
666             }
667             };
668              
669 0           $error = $@;
670             }
671              
672 0           delete $self->{ON_SAVE_ATTR_NAME()};
673              
674 0 0         if($error)
675             {
676 0           $self->error($error);
677 0 0 0       $db->rollback or warn $db->error if($started_new_tx);
678 0           $self->meta->handle_error($self);
679 0           return 0;
680             }
681              
682 0           $self->{MODIFIED_COLUMNS()} = {};
683              
684 0           return $ret;
685             }
686             else
687             {
688 0 0 0       if(!$args{'insert'} && ($args{'update'} || $self->{STATE_IN_DB()}))
      0        
689             {
690 0           return shift->update(@_);
691             }
692              
693 0           return shift->insert(@_);
694             }
695             }
696              
697             sub update
698             {
699 0     0 1   my($self, %args) = @_;
700              
701 0 0         my $db = $self->db or return 0;
702 0 0         my $dbh = $self->dbh or return 0;
703              
704 0           my $meta = $self->meta;
705              
706             my $prepare_cached =
707 0 0         exists $args{'prepare_cached'} ? $args{'prepare_cached'} :
708             $meta->dbi_prepare_cached;
709              
710             my $changes_only =
711 0 0         exists $args{'changes_only'} ? $args{'changes_only'} :
712             $meta->default_update_changes_only;
713              
714 0           local $self->{STATE_SAVING()} = 1;
715              
716 0           my @key_columns = $meta->primary_key_column_names;
717 0           my @key_methods = $meta->primary_key_column_accessor_names;
718 0           my @key_values = grep { defined } map { $self->$_() } @key_methods;
  0            
  0            
719              
720             # Special case for tables where all columns are part of the primary key
721 0 0 0       return $self || 1 if(@key_columns == $meta->num_columns);
722              
723             # See comment below
724             #my $null_key = 0;
725             #my $found_key = 0;
726              
727 0 0         unless(@key_values == @key_columns)
728             {
729 0 0         $self->error("Cannot update " . ref($self) . " without a primary key (" .
730             join(', ', @key_columns) . ') with ' .
731             (@key_columns > 1 ? 'non-null values in all columns' :
732             'a non-null value'));
733 0           $self->meta->handle_error($self);
734 0           return undef;
735             }
736              
737             #my $ret = $db->begin_work;
738             #
739             #unless($ret)
740             #{
741             # my $error = $db->error;
742             # $self->error(ref $error ? $error : "Could not begin transaction before updating - $error");
743             # return undef;
744             #}
745             #
746             #my $started_new_tx = ($ret == Rose::DB::Constants::IN_TRANSACTION) ? 0 : 1;
747              
748 0           my $error;
749              
750             TRY:
751             {
752 0           local $@;
  0            
753              
754             eval
755 0           {
756             #local $self->{STATE_SAVING()} = 1;
757 0           local $dbh->{'RaiseError'} = 1;
758              
759 0           my $sth;
760              
761 0 0         if($meta->allow_inline_column_values)
762             {
763             # This versions of update_sql_with_inlining is not needed (see comments
764             # in Rose/DB/Object/Metadata.pm for more information)
765             #my($sql, $bind) =
766             # $meta->update_sql_with_inlining($self, \@key_columns, \@key_values);
767              
768 0           my($sql, $bind, $bind_params);
769              
770 0 0         if($changes_only)
771             {
772             # No changes to save...
773 0 0 0       return $self || 1 unless(%{$self->{MODIFIED_COLUMNS()} || {}});
  0 0          
774 0           ($sql, $bind, $bind_params) =
775             $meta->update_changes_only_sql_with_inlining($self, \@key_columns);
776              
777 0 0         unless($sql) # skip key-only updates
778             {
779 0           $self->{MODIFIED_COLUMNS()} = {};
780 0   0       return $self || 1;
781             }
782             }
783             else
784             {
785 0           ($sql, $bind, $bind_params) = $meta->update_sql_with_inlining($self, \@key_columns);
786             }
787              
788 0 0         if($Debug)
789             {
790 61     61   614 no warnings;
  61         184  
  61         15833  
791 0           warn "$sql - bind params: ", join(', ', @$bind, @key_values), "\n";
792             }
793              
794 0           $sth = $dbh->prepare($sql); #, $meta->prepare_update_options);
795              
796 0 0         if($bind_params)
797             {
798 0           my $i = 1;
799              
800 0           foreach my $value (@$bind)
801             {
802 0           $sth->bind_param($i, $value, $bind_params->[$i - 1]);
803 0           $i++;
804             }
805              
806 0           my $kv_idx = 0;
807              
808 0           foreach my $column_name (@key_columns)
809             {
810 0           my $column = $meta->column($column_name);
811 0           $sth->bind_param($i++, $key_values[$kv_idx++], $column->dbi_bind_param_attrs($db));
812             }
813              
814 0           $sth->execute;
815             }
816             else
817             {
818 0           $sth->execute(@$bind, @key_values);
819             }
820             }
821             else
822             {
823 0 0         if($changes_only)
    0          
824             {
825             # No changes to save...
826 0 0 0       return $self || 1 unless(%{$self->{MODIFIED_COLUMNS()} || {}});
  0 0          
827              
828 0           my($sql, $bind, $columns) = $meta->update_changes_only_sql($self, \@key_columns, $db);
829              
830 0 0         unless($sql) # skip key-only updates
831             {
832 0           $self->{MODIFIED_COLUMNS()} = {};
833 0   0       return $self || 1;
834             }
835              
836             # $meta->prepare_update_options (defunct)
837 0 0         my $sth = $prepare_cached ? $dbh->prepare_cached($sql, undef, 3) :
838             $dbh->prepare($sql);
839              
840 0 0         if($Debug)
841             {
842 61     61   768 no warnings;
  61         310  
  61         12901  
843 0           warn "$sql - bind params: ", join(', ', @$bind, @key_values), "\n";
844             }
845              
846 0 0         if($meta->dbi_requires_bind_param($db))
847             {
848 0           my $i = 1;
849              
850 0           foreach my $column (@$columns)
851             {
852 0           my $method = $column->accessor_method_name;
853 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
854             }
855              
856 0           my $kv_idx = 0;
857              
858 0           foreach my $column_name (@key_columns)
859             {
860 0           my $column = $meta->column($column_name);
861 0           $sth->bind_param($i++, $key_values[$kv_idx++], $column->dbi_bind_param_attrs($db));
862             }
863              
864 0           $sth->execute;
865             }
866             else
867             {
868 0           $sth->execute(@$bind, @key_values);
869             }
870             }
871             elsif($meta->has_lazy_columns)
872             {
873 0           my($sql, $bind, $columns) = $meta->update_sql($self, \@key_columns, $db);
874              
875             # $meta->prepare_update_options (defunct)
876 0 0         my $sth = $prepare_cached ? $dbh->prepare_cached($sql, undef, 3) :
877             $dbh->prepare($sql);
878              
879 0 0         if($Debug)
880             {
881 61     61   527 no warnings;
  61         191  
  61         15475  
882 0           warn "$sql - bind params: ", join(', ', @$bind, @key_values), "\n";
883             }
884              
885 0 0         if($meta->dbi_requires_bind_param($db))
886             {
887 0           my $i = 1;
888              
889 0           foreach my $column (@$columns)
890             {
891 0           my $method = $column->accessor_method_name;
892 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
893             }
894              
895 0           my $kv_idx = 0;
896              
897 0           foreach my $column_name (@key_columns)
898             {
899 0           my $column = $meta->column($column_name);
900 0           $sth->bind_param($i++, $key_values[$kv_idx++], $column->dbi_bind_param_attrs($db));
901             }
902              
903 0           $sth->execute;
904             }
905             else
906             {
907 0           $sth->execute(@$bind, @key_values);
908             }
909             }
910             else
911             {
912 0           my $sql = $meta->update_all_sql(\@key_columns, $db);
913              
914             # $meta->prepare_update_options (defunct)
915 0 0         my $sth = $prepare_cached ? $dbh->prepare_cached($sql, undef, 3) :
916             $dbh->prepare($sql);
917              
918 0           my %key = map { ($_ => 1) } @key_methods;
  0            
919              
920 0           my $method_names = $meta->column_accessor_method_names;
921              
922 0 0         if($Debug)
923             {
924 61     61   3346 no warnings;
  61         200  
  61         50575  
925             warn "$sql - bind params: ",
926 0           join(', ', (map { $self->$_() } grep { !$key{$_} } @$method_names),
  0            
927 0           grep { defined } @key_values), "\n";
  0            
928             }
929              
930 0 0         if($meta->dbi_requires_bind_param($db))
931             {
932 0           my $i = 1;
933              
934 0           foreach my $column (grep { !$key{$_->name} } $meta->columns_ordered)
  0            
935             {
936 0           my $method = $column->accessor_method_name;
937 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
938             }
939              
940 0           foreach my $column_name (@key_columns)
941             {
942 0           my $column = $meta->column($column_name);
943 0           my $method = $column->accessor_method_name;
944 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
945             }
946              
947 0           $sth->execute;
948             }
949             else
950             {
951             $sth->execute(
952 0           (map { $self->$_() } grep { !$key{$_} } @$method_names),
  0            
  0            
953             @key_values);
954             }
955             }
956             }
957             #if($started_new_tx)
958             #{
959             # $db->commit or die $db->error;
960             #}
961             };
962              
963 0           $error = $@;
964             }
965              
966 0 0         if($error)
967             {
968 0 0         $self->error(ref $error ? $error : "update() - $error");
969             #$db->rollback or warn $db->error if($started_new_tx);
970 0           $self->meta->handle_error($self);
971 0           return 0;
972             }
973              
974 0           $self->{STATE_IN_DB()} = 1;
975 0           $self->{MODIFIED_COLUMNS()} = {};
976              
977 0   0       return $self || 1;
978             }
979              
980             sub insert
981             {
982 0     0 1   my($self, %args) = @_;
983              
984 0 0         my $db = $self->db or return 0;
985 0 0         my $dbh = $self->dbh or return 0;
986              
987 0           my $meta = $self->meta;
988              
989             my $prepare_cached =
990 0 0         exists $args{'prepare_cached'} ? $args{'prepare_cached'} :
991             $meta->dbi_prepare_cached;
992              
993             my $changes_only =
994 0 0         exists $args{'changes_only'} ? $args{'changes_only'} :
995             $meta->default_insert_changes_only;
996              
997 0           local $self->{STATE_SAVING()} = 1;
998              
999 0           my @pk_methods = $meta->primary_key_column_accessor_names;
1000 0           my @pk_values = grep { defined } map { $self->$_() } @pk_methods;
  0            
  0            
1001              
1002             #my $ret = $db->begin_work;
1003             #
1004             #unless($ret)
1005             #{
1006             # my $error = $db->error;
1007             # $self->error(ref $error ? $error : "Could not begin transaction before inserting - $error");
1008             # return undef;
1009             #}
1010             #
1011             #my $started_new_tx = ($ret > 0) ? 1 : 0;
1012              
1013 0           my $using_pk_placeholders = 0;
1014              
1015 0 0 0       unless(@pk_values == @pk_methods || $args{'on_duplicate_key_update'})
1016             {
1017 0           my @generated_pk_values = $meta->generate_primary_key_values($db);
1018              
1019 0 0         unless(@generated_pk_values)
1020             {
1021 0           @generated_pk_values = $meta->generate_primary_key_placeholders($db);
1022 0           $using_pk_placeholders = 1;
1023             }
1024              
1025 0 0         unless(@generated_pk_values == @pk_methods)
1026             {
1027 0 0         my $s = (@pk_values == 1 ? '' : 's');
1028 0           $self->error("Could not generate primary key$s for column$s " .
1029             join(', ', @pk_methods));
1030 0           $self->meta->handle_error($self);
1031 0           return undef;
1032             }
1033              
1034 0           my @pk_set_methods = map { $meta->column_mutator_method_name($_) }
  0            
1035             $meta->primary_key_column_names;
1036              
1037 0           my $i = 0;
1038              
1039 0           foreach my $name (@pk_set_methods)
1040             {
1041 0           my $pk_value = shift @generated_pk_values;
1042 0 0         next unless(defined $pk_value);
1043 0           $self->$name($pk_value);
1044             }
1045             }
1046              
1047 0           my $error;
1048              
1049             TRY:
1050             {
1051 0           local $@;
  0            
1052              
1053             eval
1054 0           {
1055             #local $self->{STATE_SAVING()} = 1;
1056 0           local $dbh->{'RaiseError'} = 1;
1057              
1058             #my $options = $meta->prepare_insert_options;
1059              
1060 0           my $sth;
1061              
1062 0 0         if($meta->allow_inline_column_values)
1063             {
1064 0           my($sql, $bind, $bind_params);
1065              
1066 0 0         if($args{'on_duplicate_key_update'})
    0          
1067             {
1068 0           ($sql, $bind, $bind_params) =
1069             $meta->insert_and_on_duplicate_key_update_with_inlining_sql(
1070             $self, $db, $changes_only);
1071             }
1072             elsif($changes_only)
1073             {
1074 0           ($sql, $bind, $bind_params) = $meta->insert_changes_only_sql_with_inlining($self);
1075             }
1076             else
1077             {
1078 0           ($sql, $bind, $bind_params) = $meta->insert_sql_with_inlining($self);
1079             }
1080              
1081 0 0         if($Debug)
1082             {
1083 61     61   747 no warnings;
  61         250  
  61         13307  
1084 0           warn "$sql - bind params: ", join(', ', @$bind), "\n";
1085             }
1086              
1087 0           $sth = $dbh->prepare($sql); #, $options);
1088              
1089 0 0         if($bind_params)
1090             {
1091 0           my $i = 1;
1092              
1093 0           foreach my $value (@$bind)
1094             {
1095 0           $sth->bind_param($i, $value, $bind_params->[$i - 1]);
1096 0           $i++;
1097             }
1098              
1099 0           $sth->execute;
1100             }
1101             else
1102             {
1103 0           $sth->execute(@$bind);
1104             }
1105             }
1106             else
1107             {
1108 0           my $column_names = $meta->column_names;
1109              
1110 0 0 0       if($args{'on_duplicate_key_update'} || $changes_only)
1111             {
1112 0           my($sql, $bind, $columns);
1113              
1114 0 0         if($args{'on_duplicate_key_update'})
1115             {
1116 0           ($sql, $bind, $columns) =
1117             $meta->insert_and_on_duplicate_key_update_sql(
1118             $self, $db, $changes_only);
1119             }
1120             else
1121             {
1122 0           ($sql, $bind, $columns) = $meta->insert_changes_only_sql($self, $db);
1123             }
1124              
1125 0 0         if($Debug)
1126             {
1127 61     61   614 no warnings;
  61         185  
  61         10169  
1128 0           warn $sql, " - bind params: @$bind\n";
1129             }
1130              
1131 0 0         $sth = $prepare_cached ?
1132             $dbh->prepare_cached($sql, undef, 3) :
1133             $dbh->prepare($sql);
1134              
1135 0 0         if($meta->dbi_requires_bind_param($db))
1136             {
1137 0           my $i = 1;
1138              
1139 0           foreach my $column (@$columns)
1140             {
1141 0           my $method = $column->accessor_method_name;
1142 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
1143             }
1144              
1145 0           $sth->execute;
1146             }
1147             else
1148             {
1149 0           $sth->execute(@$bind);
1150             }
1151             }
1152             else
1153             {
1154 0 0         $sth = $prepare_cached ?
1155             $dbh->prepare_cached($meta->insert_sql($db), undef, 3) :
1156             $dbh->prepare($meta->insert_sql($db));
1157              
1158 0 0         if($Debug)
1159             {
1160 61     61   2358 no warnings;
  61         255  
  61         156647  
1161             warn $meta->insert_sql($db), " - bind params: ",
1162 0           join(', ', (map {$self->$_()} $meta->column_accessor_method_names)),
  0            
1163             "\n";
1164             }
1165              
1166             #$sth->execute(map { $self->$_() } $meta->column_accessor_method_names);
1167              
1168 0 0         if($meta->dbi_requires_bind_param($db))
1169             {
1170 0           my $i = 1;
1171              
1172 0           foreach my $column ($meta->columns_ordered)
1173             {
1174 0           my $method = $column->accessor_method_name;
1175 0           $sth->bind_param($i++, $self->$method(), $column->dbi_bind_param_attrs($db));
1176             }
1177              
1178 0           $sth->execute;
1179             }
1180             else
1181             {
1182 0           $sth->execute(map { $self->$_() } $meta->column_accessor_method_names);
  0            
1183             }
1184             }
1185             }
1186              
1187 0 0         if(@pk_methods == 1)
    0          
    0          
1188             {
1189 0           my $get_pk = $pk_methods[0];
1190              
1191 0 0 0       if($using_pk_placeholders || !defined $self->$get_pk())
    0 0        
1192             {
1193 0           local $self->{STATE_LOADING()} = 1;
1194 0           my $set_pk = $meta->column_mutator_method_name($meta->primary_key_column_names);
1195             #$self->$set_pk($db->last_insertid_from_sth($sth, $self));
1196 0           $self->$set_pk($db->last_insertid_from_sth($sth));
1197 0           $self->{STATE_IN_DB()} = 1;
1198             }
1199             elsif(!$using_pk_placeholders && defined $self->$get_pk())
1200             {
1201 0           $self->{STATE_IN_DB()} = 1;
1202             }
1203             }
1204             elsif(@pk_values == @pk_methods)
1205             {
1206 0           $self->{STATE_IN_DB()} = 1;
1207             }
1208             elsif(!$using_pk_placeholders)
1209             {
1210 0           my $have_pk = 1;
1211              
1212 0           my @pk_set_methods = $meta->primary_key_column_mutator_names;
1213              
1214 0           my $i = 0;
1215 0           my $got_last_insert_id = 0;
1216              
1217 0           foreach my $pk (@pk_methods)
1218             {
1219 0 0         unless(defined $self->$pk())
1220             {
1221             # XXX: This clause assumes that any db that uses last_insert_id
1222             # XXX: can only have one such id per table. This is currently
1223             # XXX: true for the supported dbs: MySQL, Pg, SQLite, Informix.
1224 0 0         if($got_last_insert_id)
    0          
1225             {
1226 0           $have_pk = 0;
1227 0           last;
1228             }
1229             elsif(my $pk_val = $db->last_insertid_from_sth($sth))
1230             {
1231 0           my $set_pk = $pk_set_methods[$i];
1232 0           $self->$set_pk($pk_val);
1233 0           $got_last_insert_id = 1;
1234             }
1235             else
1236             {
1237 0           $have_pk = 0;
1238 0           last;
1239             }
1240             }
1241              
1242 0           $i++;
1243             }
1244              
1245 0           $self->{STATE_IN_DB()} = $have_pk;
1246             }
1247              
1248             #if($started_new_tx)
1249             #{
1250             # $db->commit or die $db->error;
1251             #}
1252             };
1253              
1254 0           $error = $@;
1255             }
1256              
1257 0 0         if($error)
1258             {
1259 0 0         $self->error(ref $error ? $error : "insert() - $error");
1260             #$db->rollback or warn $db->error if($started_new_tx);
1261 0           $self->meta->handle_error($self);
1262 0           return 0;
1263             }
1264              
1265 0           $self->{MODIFIED_COLUMNS()} = {};
1266              
1267 0   0       return $self || 1;
1268             }
1269              
1270             my %CASCADE_VALUES = (delete => 'delete', null => 'null', 1 => 'delete');
1271              
1272             sub delete
1273             {
1274 0     0 1   my($self, %args) = @_;
1275              
1276 0           my $meta = $self->meta;
1277              
1278             my $prepare_cached =
1279 0 0         exists $args{'prepare_cached'} ? $args{'prepare_cached'} :
1280             $meta->dbi_prepare_cached;
1281              
1282 0           local $self->{STATE_SAVING()} = 1;
1283              
1284 0           my @pk_methods = $meta->primary_key_column_accessor_names;
1285 0           my @pk_values = grep { defined } map { $self->$_() } @pk_methods;
  0            
  0            
1286              
1287 0 0         unless(@pk_values == @pk_methods)
1288             {
1289 0           $self->error("Cannot delete " . ref($self) . " without a primary key (" .
1290             join(', ', @pk_methods) . ')');
1291 0           $self->meta->handle_error($self);
1292 0           return 0;
1293             }
1294              
1295             # Totally separate code path for cascaded delete
1296 0 0         if(my $cascade = $args{'cascade'})
1297             {
1298 0 0         unless(exists $CASCADE_VALUES{$cascade})
1299             {
1300 0           Carp::croak "Illegal value for 'cascade' parameter: '$cascade'. ",
1301             "Valid values are 'delete', 'null', and '1'";
1302             }
1303              
1304 0           $cascade = $CASCADE_VALUES{$cascade};
1305              
1306 0           my $mgr_error_mode = Rose::DB::Object::Manager->error_mode;
1307              
1308 0           my($db, $started_new_tx, $error);
1309              
1310             TRY:
1311             {
1312 0           local $@;
  0            
1313              
1314             eval
1315 0           {
1316 0           $db = $self->db;
1317 0           my $meta = $self->meta;
1318              
1319 0           my $ret = $db->begin_work;
1320              
1321 0 0         unless(defined $ret)
1322             {
1323 0           die 'Could not begin transaction before deleting with cascade - ',
1324             $db->error;
1325             }
1326              
1327 0 0         $started_new_tx = ($ret == IN_TRANSACTION) ? 0 : 1;
1328              
1329 0 0         unless($self->{STATE_IN_DB()})
1330             {
1331 0 0         $self->load
1332             or die "Could not load in preparation for cascading delete: ",
1333             $self->error;
1334             }
1335              
1336 0           Rose::DB::Object::Manager->error_mode('fatal');
1337              
1338 0           my @one_to_one_rels;
1339              
1340             # Process all the rows for each "... to many" relationship
1341 0           REL: foreach my $relationship ($meta->relationships)
1342             {
1343 0           my $rel_type = $relationship->type;
1344              
1345 0 0         if($rel_type eq 'one to many')
    0          
    0          
1346             {
1347 0           my $column_map = $relationship->column_map;
1348 0           my @query;
1349              
1350 0           foreach my $local_column (keys %$column_map)
1351             {
1352 0           my $foreign_column = $column_map->{$local_column};
1353              
1354 0           my $method = $meta->column_accessor_method_name($local_column);
1355 0           my $value = $self->$method();
1356              
1357             # XXX: Comment this out to allow null keys
1358 0 0         next REL unless(defined $value);
1359              
1360 0           push(@query, $foreign_column => $value);
1361             }
1362              
1363 0 0         if($cascade eq 'delete')
    0          
1364             {
1365 0           Rose::DB::Object::Manager->delete_objects(
1366             db => $db,
1367             object_class => $relationship->class,
1368             where => \@query);
1369             }
1370             elsif($cascade eq 'null')
1371             {
1372 0           my %set = map { $_ => undef } values(%$column_map);
  0            
1373              
1374 0           Rose::DB::Object::Manager->update_objects(
1375             db => $db,
1376             object_class => $relationship->class,
1377             set => \%set,
1378             where => \@query);
1379             }
1380 0           else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
1381             }
1382             elsif($rel_type eq 'many to many')
1383             {
1384 0           my $map_class = $relationship->map_class;
1385 0           my $map_from = $relationship->map_from;
1386              
1387 0   0       my $map_from_relationship =
1388             $map_class->meta->foreign_key($map_from) ||
1389             $map_class->meta->relationship($map_from) ||
1390             Carp::confess "No foreign key or 'many to one' relationship ",
1391             "named '$map_from' in class $map_class";
1392              
1393 0           my $key_columns = $map_from_relationship->key_columns;
1394 0           my @query;
1395              
1396             # "Local" here means "local to the mapping table"
1397 0           foreach my $local_column (keys %$key_columns)
1398             {
1399 0           my $foreign_column = $key_columns->{$local_column};
1400              
1401 0           my $method = $meta->column_accessor_method_name($foreign_column);
1402 0           my $value = $self->$method();
1403              
1404             # XXX: Comment this out to allow null keys
1405 0 0         next REL unless(defined $value);
1406              
1407 0           push(@query, $local_column => $value);
1408             }
1409              
1410 0 0         if($cascade eq 'delete')
    0          
1411             {
1412 0           Rose::DB::Object::Manager->delete_objects(
1413             db => $db,
1414             object_class => $map_class,
1415             where => \@query);
1416             }
1417             elsif($cascade eq 'null')
1418             {
1419 0           my %set = map { $_ => undef } keys(%$key_columns);
  0            
1420              
1421 0           Rose::DB::Object::Manager->update_objects(
1422             db => $db,
1423             object_class => $map_class,
1424             set => \%set,
1425             where => \@query);
1426             }
1427 0           else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
1428             }
1429             elsif($rel_type eq 'one to one')
1430             {
1431 0           push(@one_to_one_rels, $relationship);
1432             }
1433             }
1434              
1435             # Delete the object itself
1436 0 0         my $dbh = $db->dbh or die "Could not get dbh: ", $self->error;
1437             #local $self->{STATE_SAVING()} = 1;
1438 0           local $dbh->{'RaiseError'} = 1;
1439              
1440             # $meta->prepare_delete_options (defunct)
1441 0 0         my $sth = $prepare_cached ? $dbh->prepare_cached($meta->delete_sql($db), undef, 3) :
1442             $dbh->prepare($meta->delete_sql($db));
1443              
1444 0 0         $Debug && warn $meta->delete_sql($db), " - bind params: ", join(', ', @pk_values), "\n";
1445 0           $sth->execute(@pk_values);
1446              
1447 0 0         unless($sth->rows > 0)
1448             {
1449 0           $self->error("Did not delete " . ref($self) . ' where ' .
1450             join(', ', @pk_methods) . ' = ' . join(', ', @pk_values));
1451             }
1452              
1453             # Process all rows referred to by "one to one" foreign keys
1454 0           FK: foreach my $fk ($meta->foreign_keys)
1455             {
1456 0 0         next unless($fk->relationship_type eq 'one to one');
1457              
1458 0           my $key_columns = $fk->key_columns;
1459 0           my @query;
1460              
1461 0           foreach my $local_column (keys %$key_columns)
1462             {
1463 0           my $foreign_column = $key_columns->{$local_column};
1464              
1465 0           my $method = $meta->column_accessor_method_name($local_column);
1466 0           my $value = $self->$method();
1467              
1468             # XXX: Comment this out to allow null keys
1469 0 0         next FK unless(defined $value);
1470              
1471 0           push(@query, $foreign_column => $value);
1472             }
1473              
1474 0 0         if($cascade eq 'delete')
    0          
1475             {
1476 0           Rose::DB::Object::Manager->delete_objects(
1477             db => $db,
1478             object_class => $fk->class,
1479             where => \@query);
1480             }
1481             elsif($cascade eq 'null')
1482             {
1483 0           my %set = map { $_ => undef } values(%$key_columns);
  0            
1484              
1485 0           Rose::DB::Object::Manager->update_objects(
1486             db => $db,
1487             object_class => $fk->class,
1488             set => \%set,
1489             where => \@query);
1490             }
1491 0           else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
1492             }
1493              
1494             # Process all the rows for each "one to one" relationship
1495 0           REL: foreach my $relationship (@one_to_one_rels)
1496             {
1497 0           my $column_map = $relationship->column_map;
1498 0           my @query;
1499              
1500 0           foreach my $local_column (keys %$column_map)
1501             {
1502 0           my $foreign_column = $column_map->{$local_column};
1503              
1504 0           my $method = $meta->column_accessor_method_name($local_column);
1505 0           my $value = $self->$method();
1506              
1507             # XXX: Comment this out to allow null keys
1508 0 0         next REL unless(defined $value);
1509              
1510 0           push(@query, $foreign_column => $value);
1511             }
1512              
1513 0 0         if($cascade eq 'delete')
    0          
1514             {
1515 0           Rose::DB::Object::Manager->delete_objects(
1516             db => $db,
1517             object_class => $relationship->class,
1518             where => \@query);
1519             }
1520             elsif($cascade eq 'null')
1521             {
1522 0           my %set = map { $_ => undef } values(%$column_map);
  0            
1523              
1524 0           Rose::DB::Object::Manager->update_objects(
1525             db => $db,
1526             object_class => $relationship->class,
1527             set => \%set,
1528             where => \@query);
1529             }
1530 0           else { Carp::confess "Illegal cascade value '$cascade' snuck through" }
1531             }
1532              
1533 0 0         if($started_new_tx)
1534             {
1535 0 0         $db->commit or die $db->error;
1536             }
1537             };
1538              
1539 0           $error = $@;
1540             }
1541              
1542 0 0         if($error)
1543             {
1544 0           Rose::DB::Object::Manager->error_mode($mgr_error_mode);
1545 0 0         $self->error(ref $error ? $error : "delete() with cascade - $error");
1546 0 0 0       $db->rollback if($db && $started_new_tx);
1547 0           $self->meta->handle_error($self);
1548 0           return 0;
1549             }
1550              
1551 0           Rose::DB::Object::Manager->error_mode($mgr_error_mode);
1552 0           $self->{STATE_IN_DB()} = 0;
1553 0           return 1;
1554             }
1555             else
1556             {
1557 0 0         my $db = $self->db or return 0;
1558 0 0         my $dbh = $db->dbh or return 0;
1559              
1560 0           my $error;
1561              
1562             TRY:
1563             {
1564 0           local $@;
  0            
1565              
1566             eval
1567 0           {
1568             #local $self->{STATE_SAVING()} = 1;
1569 0           local $dbh->{'RaiseError'} = 1;
1570              
1571             # $meta->prepare_delete_options (defunct)
1572 0 0         my $sth = $prepare_cached ? $dbh->prepare_cached($meta->delete_sql($db), undef, 3) :
1573             $dbh->prepare($meta->delete_sql($db));
1574              
1575 0 0         $Debug && warn $meta->delete_sql($db), " - bind params: ", join(', ', @pk_values), "\n";
1576 0           $sth->execute(@pk_values);
1577              
1578 0 0         unless($sth->rows > 0)
1579             {
1580 0           $self->error("Did not delete " . ref($self) . ' where ' .
1581             join(', ', @pk_methods) . ' = ' . join(', ', @pk_values));
1582             }
1583             };
1584              
1585 0           $error = $@;
1586             }
1587              
1588 0 0         if($error)
1589             {
1590 0 0         $self->error(ref $error ? $error : "delete() - $error");
1591 0           $self->meta->handle_error($self);
1592 0           return 0;
1593             }
1594              
1595 0           $self->{STATE_IN_DB()} = 0;
1596 0           return 1;
1597             }
1598             }
1599              
1600             our $AUTOLOAD;
1601              
1602             sub AUTOLOAD
1603             {
1604 0     0     my $self = shift;
1605              
1606 0           my $msg = '';
1607              
1608             TRY:
1609             {
1610 0           local $@;
  0            
1611              
1612             # Not sure if this will ever be used, but just in case...
1613             eval
1614 0           {
1615 0           my @fks = $self->meta->deferred_foreign_keys;
1616 0           my @rels = $self->meta->deferred_relationships;
1617              
1618 0 0 0       if(@fks || @rels)
1619             {
1620 0           my $class = ref $self;
1621              
1622 0           my $tmp_msg =<<"EOF";
1623             Methods for the following relationships and foreign keys were deferred and
1624             then never actually created in the class $class.
1625              
1626             TYPE NAME
1627             ---- ----
1628             EOF
1629              
1630 0           my $found = 0;
1631              
1632 0           foreach my $thing (@fks, @rels)
1633             {
1634 0 0         next unless($thing->parent->class eq $class);
1635              
1636 0           $found++;
1637              
1638 0 0         my $type =
    0          
1639             $thing->isa('Rose::DB::Object::Metadata::Relationship') ? 'Relationship' :
1640             $thing->isa('Rose::DB::Object::Metadata::ForeignKey') ? 'Foreign Key' :
1641             '???';
1642              
1643 0           $tmp_msg .= sprintf("%-15s %s\n", $type, $thing->name);
1644             }
1645              
1646 0 0 0       $msg = "\n\n$tmp_msg\n" if($tmp_msg && $found);
1647             }
1648             };
1649              
1650             # XXX: Ignoring errors
1651             }
1652              
1653 0 0         my $method_type = ref $self ? 'object' : 'class';
1654              
1655 0 0         if($AUTOLOAD =~ /^(.+)::(.+)$/)
1656             {
1657 0           Carp::confess qq(Can't locate $method_type method "$2" via package "$1"$msg);
1658             }
1659             else # not reached?
1660             {
1661 0           Carp::confess qq(Can't locate $method_type method $AUTOLOAD$msg);
1662             }
1663             }
1664              
1665       0     sub DESTROY { }
1666             # {
1667             # my($self) = shift;
1668             #
1669             # if($self->{FLAG_DB_IS_PRIVATE()})
1670             # {
1671             # if(my $db = $self->{'db'})
1672             # {
1673             # #$Debug && warn "$self DISCONNECT\n";
1674             # $db->disconnect;
1675             # }
1676             # }
1677             # }
1678              
1679             1;
1680              
1681             __END__
1682              
1683             =head1 NAME
1684              
1685             Rose::DB::Object - Extensible, high performance object-relational mapper (ORM).
1686              
1687             =head1 SYNOPSIS
1688              
1689             ## For an informal overview of Rose::DB::Object, please
1690             ## see the Rose::DB::Object::Tutorial documentation. The
1691             ## reference documentation follows.
1692              
1693             ## First, set up your Rose::DB data sources, otherwise you
1694             ## won't be able to connect to the database at all. See
1695             ## the Rose::DB documentation for more information. For
1696             ## a quick start, see the Rose::DB::Tutorial documentation.
1697              
1698             ##
1699             ## Create classes - two possible approaches:
1700             ##
1701              
1702             #
1703             # 1. Automatic configuration
1704             #
1705              
1706             package Category;
1707             use base qw(Rose::DB::Object);
1708             __PACKAGE__->meta->setup
1709             (
1710             table => 'categories',
1711             auto => 1,
1712             );
1713              
1714             ...
1715              
1716             package Price;
1717             use base qw(Rose::DB::Object);
1718             __PACKAGE__->meta->setup
1719             (
1720             table => 'prices',
1721             auto => 1,
1722             );
1723              
1724             ...
1725              
1726             package Product;
1727             use base qw(Rose::DB::Object);
1728             __PACKAGE__->meta->setup
1729             (
1730             table => 'products',
1731             auto => 1,
1732             );
1733              
1734             #
1735             # 2. Manual configuration
1736             #
1737              
1738             package Category;
1739              
1740             use base qw(Rose::DB::Object);
1741              
1742             __PACKAGE__->meta->setup
1743             (
1744             table => 'categories',
1745              
1746             columns =>
1747             [
1748             id => { type => 'int', primary_key => 1 },
1749             name => { type => 'varchar', length => 255 },
1750             description => { type => 'text' },
1751             ],
1752              
1753             unique_key => 'name',
1754             );
1755              
1756             ...
1757              
1758             package Price;
1759              
1760             use base qw(Rose::DB::Object);
1761              
1762             __PACKAGE__->meta->setup
1763             (
1764             table => 'prices',
1765              
1766             columns =>
1767             [
1768             id => { type => 'int', primary_key => 1 },
1769             price => { type => 'decimal' },
1770             region => { type => 'char', length => 3 },
1771             product_id => { type => 'int' }
1772             ],
1773              
1774             unique_key => [ 'product_id', 'region' ],
1775             );
1776              
1777             ...
1778              
1779             package Product;
1780              
1781             use base qw(Rose::DB::Object);
1782              
1783             __PACKAGE__->meta->setup
1784             (
1785             table => 'products',
1786              
1787             columns =>
1788             [
1789             id => { type => 'int', primary_key => 1 },
1790             name => { type => 'varchar', length => 255 },
1791             description => { type => 'text' },
1792             category_id => { type => 'int' },
1793              
1794             status =>
1795             {
1796             type => 'varchar',
1797             check_in => [ 'active', 'inactive' ],
1798             default => 'inactive',
1799             },
1800              
1801             start_date => { type => 'datetime' },
1802             end_date => { type => 'datetime' },
1803              
1804             date_created => { type => 'timestamp', default => 'now' },
1805             last_modified => { type => 'timestamp', default => 'now' },
1806             ],
1807              
1808             unique_key => 'name',
1809              
1810             foreign_keys =>
1811             [
1812             category =>
1813             {
1814             class => 'Category',
1815             key_columns => { category_id => 'id' },
1816             },
1817             ],
1818              
1819             relationships =>
1820             [
1821             prices =>
1822             {
1823             type => 'one to many',
1824             class => 'Price',
1825             column_map => { id => 'product_id' },
1826             },
1827             ],
1828             );
1829              
1830             ...
1831              
1832             #
1833             # Example usage
1834             #
1835              
1836             $product = Product->new(id => 123,
1837             name => 'GameCube',
1838             status => 'active',
1839             start_date => '11/5/2001',
1840             end_date => '12/1/2007',
1841             category_id => 5);
1842              
1843             $product->save;
1844              
1845             ...
1846              
1847             $product = Product->new(id => 123);
1848             $product->load;
1849              
1850             # Load foreign object via "one to one" relationship
1851             print $product->category->name;
1852              
1853             $product->end_date->add(days => 45);
1854              
1855             $product->save;
1856              
1857             ...
1858              
1859             $product = Product->new(id => 456);
1860             $product->load;
1861              
1862             # Load foreign objects via "one to many" relationship
1863             print join ' ', $product->prices;
1864              
1865             ...
1866              
1867             =head1 DESCRIPTION
1868              
1869             L<Rose::DB::Object> is a base class for objects that encapsulate a single row in a database table. L<Rose::DB::Object>-derived objects are sometimes simply called "L<Rose::DB::Object> objects" in this documentation for the sake of brevity, but be assured that derivation is the only reasonable way to use this class.
1870              
1871             L<Rose::DB::Object> inherits from, and follows the conventions of, L<Rose::Object>. See the L<Rose::Object> documentation for more information.
1872              
1873             For an informal overview of this module distribution, consult the L<Rose::DB::Object::Tutorial>.
1874              
1875             =head2 Restrictions
1876              
1877             L<Rose::DB::Object> objects can represent rows in almost any database table, subject to the following constraints.
1878              
1879             =over 4
1880              
1881             =item * The database server must be supported by L<Rose::DB>.
1882              
1883             =item * The database table must have a primary key.
1884              
1885             =item * The primary key must not allow null values in any of its columns.
1886              
1887             =back
1888              
1889             Although the list above contains the only hard and fast rules, there may be other realities that you'll need to work around.
1890              
1891             The most common example is the existence of a column name in the database table that conflicts with the name of a method in the L<Rose::DB::Object> API. There are two possible workarounds: either explicitly alias the column, or define a L<mapping function|Rose::DB::Object::Metadata/column_name_to_method_name_mapper>. See the L<alias_column|Rose::DB::Object::Metadata/alias_column> and L<column_name_to_method_name_mapper|Rose::DB::Object::Metadata/column_name_to_method_name_mapper> methods in the L<Rose::DB::Object::Metadata> documentation for more details.
1892              
1893             There are also varying degrees of support for data types in each database server supported by L<Rose::DB>. If you have a table that uses a data type not supported by an existing L<Rose::DB::Object::Metadata::Column>-derived class, you will have to write your own column class and then map it to a type name using L<Rose::DB::Object::Metadata>'s L<column_type_class|Rose::DB::Object::Metadata/column_type_class> method, yada yada. (Or, of course, you can map the new type to an existing column class.)
1894              
1895             The entire framework is extensible. This module distribution contains straight-forward implementations of the most common column types, but there's certainly more that can be done. Submissions are welcome.
1896              
1897             =head2 Features
1898              
1899             L<Rose::DB::Object> provides the following functions:
1900              
1901             =over 4
1902              
1903             =item * Create a row in the database by saving a newly constructed object.
1904              
1905             =item * Initialize an object by loading a row from the database.
1906              
1907             =item * Update a row by saving a modified object back to the database.
1908              
1909             =item * Delete a row from the database.
1910              
1911             =item * Fetch an object referred to by a foreign key in the current object. (i.e., "one to one" and "many to one" relationships.)
1912              
1913             =item * Fetch multiple objects that refer to the current object, either directly through foreign keys or indirectly through a mapping table. (i.e., "one to many" and "many to many" relationships.)
1914              
1915             =item * Load an object along with "foreign objects" that are related through any of the supported relationship types.
1916              
1917             =back
1918              
1919             Objects can be loaded based on either a primary key or a unique key. Since all tables fronted by L<Rose::DB::Object>s must have non-null primary keys, insert, update, and delete operations are done based on the primary key.
1920              
1921             In addition, its sibling class, L<Rose::DB::Object::Manager>, can do the following:
1922              
1923             =over 4
1924              
1925             =item * Fetch multiple objects from the database using arbitrary query conditions, limits, and offsets.
1926              
1927             =item * Iterate over a list of objects, fetching from the database in response to each step of the iterator.
1928              
1929             =item * Fetch objects along with "foreign objects" (related through any of the supported relationship types) in a single query by automatically generating the appropriate SQL join(s).
1930              
1931             =item * Count the number of objects that match a complex query.
1932              
1933             =item * Update objects that match a complex query.
1934              
1935             =item * Delete objects that match a complex query.
1936              
1937             =back
1938              
1939             L<Rose::DB::Object::Manager> can be subclassed and used separately (the recommended approach), or it can create object manager methods within a L<Rose::DB::Object> subclass. See the L<Rose::DB::Object::Manager> documentation for more information.
1940              
1941             L<Rose::DB::Object> can parse, coerce, inflate, and deflate column values on your behalf, providing the most convenient possible data representations on the Perl side of the fence, while allowing the programmer to completely forget about the ugly details of the data formats required by the database. Default implementations are included for most common column types, and the framework is completely extensible.
1942              
1943             Finally, the L<Rose::DB::Object::Loader> can be used to automatically create a suite of L<Rose::DB::Object> and L<Rose::DB::Object::Manager> subclasses based on the contents of the database.
1944              
1945             =head2 Configuration
1946              
1947             Before L<Rose::DB::Object> can do any useful work, you must register at least one L<Rose::DB> data source. By default, L<Rose::DB::Object> instantiates a L<Rose::DB> object by passing no arguments to its constructor. (See the L<db|/db> method.) If you register a L<Rose::DB> data source using the default type and domain, this will work fine. Otherwise, you must override the L<meta|/meta> method in your L<Rose::DB::Object> subclass and have it return the appropriate L<Rose::DB>-derived object.
1948              
1949             To define your own L<Rose::DB::Object>-derived class, you must describe the table that your class will act as a front-end for. This is done through the L<Rose::DB::Object::Metadata> object associated with each L<Rose::DB::Object>-derived class. The metadata object is accessible via L<Rose::DB::Object>'s L<meta|/meta> method.
1950              
1951             Metadata objects can be populated manually or automatically. Both techniques are shown in the L<synopsis|/SYNOPSIS> above. The automatic mode works by asking the database itself for the information. There are some caveats to this approach. See the L<auto-initialization|Rose::DB::Object::Metadata/"AUTO-INITIALIZATION"> section of the L<Rose::DB::Object::Metadata> documentation for more information.
1952              
1953             =head2 Serial and Auto-Incremented Columns
1954              
1955             Most databases provide a way to use a series of arbitrary integers as primary key column values. Some support a native C<SERIAL> column data type. Others use a special auto-increment column attribute.
1956              
1957             L<Rose::DB::Object> supports at least one such serial or auto-incremented column type in each supported database. In all cases, the L<Rose::DB::Object>-derived class setup is the same:
1958              
1959             package My::DB::Object;
1960             ...
1961             __PACKAGE__->meta->setup
1962             (
1963             columns =>
1964             [
1965             id => { type => 'serial', primary_key => 1, not_null => 1 },
1966             ...
1967             ],
1968             ...
1969             );
1970              
1971             (Note that the column doesn't have to be named "id"; it can be named anything.)
1972              
1973             If the database column uses big integers, use "L<bigserial|Rose::DB::Object::Metadata::Column::BigSerial>" column C<type> instead.
1974              
1975             Given the column metadata definition above, L<Rose::DB::Object> will automatically generate and/or retrieve the primary key column value when an object is L<save()|/save>d. Example:
1976              
1977             $o = My::DB::Object->new(name => 'bud'); # no id specified
1978             $o->save; # new id value generated here
1979              
1980             print "Generated new id value: ", $o->id;
1981              
1982             This will only work, however, if the corresponding column definition in the database is set up correctly. The exact technique varies from vendor to vendor. Below are examples of primary key column definitions that provide auto-generated values. There's one example for each of the databases supported by L<Rose::DB>.
1983              
1984             =over
1985              
1986             =item * PostgreSQL
1987              
1988             CREATE TABLE mytable
1989             (
1990             id SERIAL PRIMARY KEY,
1991             ...
1992             );
1993              
1994             =item * MySQL
1995              
1996             CREATE TABLE mytable
1997             (
1998             id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
1999             ...
2000             );
2001              
2002             =item * SQLite
2003              
2004             CREATE TABLE mytable
2005             (
2006             id INTEGER PRIMARY KEY AUTOINCREMENT,
2007             ...
2008             );
2009              
2010             =item * Informix
2011              
2012             CREATE TABLE mytable
2013             (
2014             id SERIAL NOT NULL PRIMARY KEY,
2015             ...
2016             );
2017              
2018             =item * Oracle
2019              
2020             Since Oracle does not natively support a serial or auto-incremented column data type, an explicit sequence and trigger must be created to simulate the behavior. The sequence should be named according to this convention: C<E<lt>tableE<gt>_E<lt>columnE<gt>_seq>. For example, if the table is named C<mytable> and the column is named C<id>, then the sequence should be named C<mytable_id_seq>. Here's an example database setup.
2021              
2022             CREATE TABLE mytable
2023             (
2024             id INT NOT NULL PRIMARY KEY,
2025             ...
2026             );
2027              
2028             CREATE SEQUENCE mytable_id_seq;
2029              
2030             CREATE TRIGGER mytable_insert BEFORE INSERT ON mytable
2031             FOR EACH ROW
2032             BEGIN
2033             IF :new.id IS NULL THEN
2034             :new.id := mytable_id_seq.nextval;
2035             END IF;
2036             END;
2037              
2038             Note the conditional that checks if C<:new.id> is null, which allows the value of the C<id> column to be set explicitly. If a non-NULL value for the C<id> column is provided, then a new value is not pulled from the sequence.
2039              
2040             If the sequence is not named according to the C<E<lt>tableE<gt>_E<lt>columnE<gt>_seq> convention, you can specify the sequence name explicitly in the column metadata. Example:
2041              
2042             columns =>
2043             [
2044             id => { type => 'serial', primary_key => 1, not_null => 1,
2045             sequence => 'some_other_seq' },
2046             ...
2047              
2048             =back
2049              
2050             If the table has a multi-column primary key or does not use a column type that supports auto-generated values, you can define a custom primary key generator function using the L<primary_key_generator|Rose::DB::Object::Metadata/primary_key_generator> method of the L<Rose::DB::Object::Metadata>-derived object that contains the metadata for this class. Example:
2051              
2052             package MyDBObject;
2053              
2054             use base qw(Rose::DB::Object);
2055              
2056             __PACKAGE__->meta->setup
2057             (
2058             table => 'mytable',
2059              
2060             columns =>
2061             [
2062             k1 => { type => 'int', not_null => 1 },
2063             k2 => { type => 'int', not_null => 1 },
2064             name => { type => 'varchar', length => 255 },
2065             ...
2066             ],
2067              
2068             primary_key_columns => [ 'k1', 'k2' ],
2069              
2070             primary_key_generator => sub
2071             {
2072             my($meta, $db) = @_;
2073              
2074             # Generate primary key values somehow
2075             my $k1 = ...;
2076             my $k2 = ...;
2077              
2078             return $k1, $k2;
2079             },
2080             );
2081              
2082             See the L<Rose::DB::Object::Metadata> documentation for more information on custom primary key generators.
2083              
2084             =head2 Inheritance
2085              
2086             Simple, single inheritance between L<Rose::DB::Object>-derived classes is supported. (Multiple inheritance is not currently supported.) The first time the L<metadata object|/meta> for a given class is accessed, it is created by making a one-time "deep copy" of the base class's metadata object (as long that the base class has one or more L<columns|Rose::DB::Object::Metadata/columns> set). This includes all columns, relationships, foreign keys, and other metadata from the base class. From that point on, the subclass may add to or modify its metadata without affecting any other class.
2087              
2088             B<Tip:> When using perl 5.8.0 or later, the L<Scalar::Util::Clone> module is highly recommended. If it's installed, it will be used to more efficiently clone base-class metadata objects.
2089              
2090             If the base class has already been L<initialized|Rose::DB::Object::Metadata/initialize>, the subclass must explicitly specify whether it wants to create a new set of column and relationship methods, or merely inherit the methods from the base class. If the subclass contains any metadata modifications that affect method creation, then it must create a new set of methods to reflect those changes.
2091              
2092             Finally, note that column types cannot be changed "in-place." To change a column type, delete the old column and add a new one with the same name. This can be done in one step with the L<replace_column|Rose::DB::Object::Metadata/replace_column> method.
2093              
2094             Example:
2095              
2096             package BaseClass;
2097             use base 'Rose::DB::Object';
2098              
2099             __PACKAGE__->meta->setup
2100             (
2101             table => 'objects',
2102              
2103             columns =>
2104             [
2105             id => { type => 'int', primary_key => 1 },
2106             start => { type => 'scalar' },
2107             ],
2108             );
2109              
2110             ...
2111              
2112             package SubClass;
2113             use base 'BaseClass';
2114              
2115             # Set a default value for this column.
2116             __PACKAGE__->meta->column('id')->default(123);
2117              
2118             # Change the "start" column into a datetime column.
2119             __PACKAGE__->meta->replace_column(start => { type => 'datetime' });
2120              
2121             # Initialize, replacing any inherited methods with newly created ones
2122             __PACKAGE__->meta->initialize(replace_existing => 1);
2123              
2124             ...
2125              
2126             $b = BaseClass->new;
2127              
2128             $id = $b->id; # undef
2129              
2130             $b->start('1/2/2003');
2131             print $b->start; # '1/2/2003' (plain string)
2132              
2133              
2134             $s = SubClass->new;
2135              
2136             $id = $s->id; # 123
2137              
2138             $b->start('1/2/2003'); # Value is converted to a DateTime object
2139             print $b->start->strftime('%B'); # 'January'
2140              
2141             To preserve all inherited methods in a subclass, do this instead:
2142              
2143             package SubClass;
2144             use base 'BaseClass';
2145             __PACKAGE__->meta->initialize(preserve_existing => 1);
2146              
2147             =head2 Error Handling
2148              
2149             Error handling for L<Rose::DB::Object>-derived objects is controlled by the L<error_mode|Rose::DB::Object::Metadata/error_mode> method of the L<Rose::DB::Object::Metadata> object associated with the class (accessible via the L<meta|/meta> method). The default setting is "fatal", which means that L<Rose::DB::Object> methods will L<croak|Carp/croak> if they encounter an error.
2150              
2151             B<PLEASE NOTE:> The error return values described in the L<object method|/"OBJECT METHODS"> documentation are only relevant when the error mode is set to something "non-fatal." In other words, if an error occurs, you'll never see any of those return values if the selected error mode L<die|perlfunc/die>s or L<croak|Carp/croak>s or otherwise throws an exception when an error occurs.
2152              
2153             =head1 CONSTRUCTOR
2154              
2155             =over 4
2156              
2157             =item B<new PARAMS>
2158              
2159             Returns a new L<Rose::DB::Object> constructed according to PARAMS, where PARAMS are name/value pairs. Any object method is a valid parameter name.
2160              
2161             =back
2162              
2163             =head1 CLASS METHODS
2164              
2165             =over 4
2166              
2167             =item B<init_db>
2168              
2169             Returns the L<Rose::DB>-derived object used to access the database in the absence of an explicit L<db|/db> value. The default implementation simply calls L<Rose::DB-E<gt>new()|Rose::DB/new> with no arguments.
2170              
2171             Override this method in your subclass in order to use a different default data source. B<Note:> This method must be callable as both an object method and a class method.
2172              
2173             =item B<meta>
2174              
2175             Returns the L<Rose::DB::Object::Metadata>-derived object associated with this class. This object describes the database table whose rows are fronted by this class: the name of the table, its columns, unique keys, foreign keys, etc.
2176              
2177             See the L<Rose::DB::Object::Metadata> documentation for more information.
2178              
2179             =item B<meta_class>
2180              
2181             Return the name of the L<Rose::DB::Object::Metadata>-derived class used to store this object's metadata. Subclasses should override this method if they want to use a custom L<Rose::DB::Object::Metadata> subclass. (See the source code for L<Rose::DB::Object::Std> for an example of this.)
2182              
2183             =back
2184              
2185             =head1 OBJECT METHODS
2186              
2187             =over 4
2188              
2189             =item B<db [DB]>
2190              
2191             Get or set the L<Rose::DB> object used to access the database that contains the table whose rows are fronted by the L<Rose::DB::Object>-derived class.
2192              
2193             If it does not already exist, this object is created with a simple, argument-less call to C<Rose::DB-E<gt>new()>. To override this default in a subclass, override the L<init_db|/init_db> method and return the L<Rose::DB> to be used as the new default.
2194              
2195             =item B<init_db>
2196              
2197             Returns the L<Rose::DB>-derived object used to access the database in the absence of an explicit L<db|/db> value. The default implementation simply calls L<Rose::DB-E<gt>new()|Rose::DB/new> with no arguments.
2198              
2199             Override this method in your subclass in order to use a different default data source. B<Note:> This method must be callable as both an object method and a class method.
2200              
2201             =item B<dbh [DBH]>
2202              
2203             Get or set the L<DBI> database handle contained in L<db|/db>.
2204              
2205             =item B<delete [PARAMS]>
2206              
2207             Delete the row represented by the current object. The object must have been previously loaded from the database (or must otherwise have a defined primary key value) in order to be deleted. Returns true if the row was deleted or did not exist, false otherwise.
2208              
2209             PARAMS are optional name/value pairs. Valid PARAMS are:
2210              
2211             =over 4
2212              
2213             =item B<cascade TYPE>
2214              
2215             Also process related rows. TYPE must be "delete", "null", or "1". The value "1" is an alias for "delete". Passing an illegal TYPE value will cause a fatal error.
2216              
2217             For each "one to many" relationship, all of the rows in the foreign ("many") table that reference the current object ("one") will be deleted in "delete" mode, or will have the column(s) that reference the current object set to NULL in "null" mode.
2218              
2219             For each "many to many" relationship, all of the rows in the "mapping table" that reference the current object will deleted in "delete" mode, or will have the columns that reference the two tables that the mapping table maps between set to NULL in "null" mode.
2220              
2221             For each "one to one" relationship or foreign key with a "one to one" L<relationship type|Rose::DB::Object::Metadata::ForeignKey/relationship_type>, all of the rows in the foreign table that reference the current object will deleted in "delete" mode, or will have the column(s) that reference the current object set to NULL in "null" mode.
2222              
2223             In all modes, if the L<db|/db> is not currently in a transaction, a new transaction is started. If any part of the cascaded delete fails, the transaction is rolled back.
2224              
2225             =item B<prepare_cached BOOL>
2226              
2227             If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will delete the object. If omitted, the default value is determined by the L<metadata object|/meta>'s L<dbi_prepare_cached|Rose::DB::Object::Metadata/dbi_prepare_cached> class method.
2228              
2229             =back
2230              
2231             The cascaded delete feature described above plays it safe by only deleting rows that are not referenced by any other rows (according to the metadata provided by each L<Rose::DB::Object>-derived class). I B<strongly recommend> that you implement "cascaded delete" in the database itself, rather than using this feature. It will undoubtedly be faster and more robust than doing it "client-side." You may also want to cascade only to certain tables, or otherwise deviate from the "safe" plan. If your database supports automatic cascaded delete and/or triggers, please consider using these features.
2232              
2233             =item B<error>
2234              
2235             Returns the text message associated with the last error that occurred.
2236              
2237             =item B<insert [PARAMS]>
2238              
2239             Insert the current object to the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be inserted, rather than updated. It is recommended that you use the L<save|/save> method instead of this one in most circumstances. The L<save|/save> method will "do the right thing," executing an insert or update as appropriate for the current situation.
2240              
2241             PARAMS are optional name/value pairs. Valid PARAMS are:
2242              
2243             =over 4
2244              
2245             =item B<changes_only BOOL>
2246              
2247             If true, then only the columns whose values have been modified will be included in the insert query. Otherwise, all columns will be included. Note that any column that has a L<default|Rose::DB::Object::Metadata::Column/default> value set in its L<column metadata|Rose::DB::Object::Metadata::Column> is considered "modified" during an insert operation.
2248              
2249             If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_insert_changes_only|Rose::DB::Object::Metadata/default_insert_changes_only> class method, which returns false by default.
2250              
2251             =item B<prepare_cached BOOL>
2252              
2253             If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will insert the object. If omitted, the default value is determined by the L<metadata object|/meta>'s L<dbi_prepare_cached|Rose::DB::Object::Metadata/dbi_prepare_cached> class method.
2254              
2255             =back
2256              
2257             Returns true if the row was inserted successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of the object itself.
2258              
2259             =item B<load [PARAMS]>
2260              
2261             Load a row from the database table, initializing the object with the values from that row. An object can be loaded based on either a primary key or a unique key.
2262              
2263             Returns true if the row was loaded successfully, undef if the row could not be loaded due to an error, or zero (0) if the row does not exist. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of the object itself.
2264              
2265             When loading based on a unique key, unique keys are considered in the order in which they were defined in the L<metadata|/meta> for this class. If the object has defined values for every column in a unique key, then that key is used. If no such key is found, then the first key for which the object has at least one defined value is used.
2266              
2267             PARAMS are optional name/value pairs. Valid PARAMS are:
2268              
2269             =over 4
2270              
2271             =item B<for_update BOOL>
2272              
2273             If true, this parameter is translated to be the equivalent of passing the L<lock|/lock> parameter and setting the C<type> to C<for update>. For example, these are both equivalent:
2274              
2275             $object->load(for_update => 1);
2276             $object->load(lock => { type => 'for update' });
2277              
2278             See the L<lock|/lock> parameter below for more information.
2279              
2280             =item B<lock [ TYPE | HASHREF ]>
2281              
2282             Load the object using some form of locking. These lock directives have database-specific behavior and not all directives are supported by all databases. The value should be a reference to a hash or a TYPE string, which is equivalent to setting the value of the C<type> key in the hash reference form. For example, these are both equivalent:
2283              
2284             $object->load(lock => 'for update');
2285             $object->load(lock => { type => 'for update' });
2286              
2287             Valid hash keys are:
2288              
2289             =over 4
2290              
2291             =item B<columns ARRAYREF>
2292              
2293             A reference to an array of column names to lock. References to scalars will be de-referenced and used as-is, included literally in the SQL locking clause.
2294              
2295             =item C<nowait BOOL>
2296              
2297             If true, do not wait to acquire the lock. If supported, this is usually by adding a C<NOWAIT> directive to the SQL.
2298              
2299             =item C<type TYPE>
2300              
2301             The lock type. Valid values for TYPE are C<for update> and C<shared>. This parameter is required unless the L<for_update|/for_update> parameter was passed with a true value.
2302              
2303             =item C<wait TIME>
2304              
2305             Wait for the specified TIME (generally seconds) before giving up acquiring the lock. If supported, this is usually by adding a C<WAIT ...> clause to the SQL.
2306              
2307             =back
2308              
2309             =item B<nonlazy BOOL>
2310              
2311             If true, then all columns will be fetched from the database, even L<lazy|Rose::DB::Object::Metadata::Column/load_on_demand> columns. If omitted, the default is false.
2312              
2313             =item B<prepare_cached BOOL>
2314              
2315             If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL query that will load the object. If omitted, the default value is determined by the L<metadata object|/meta>'s L<dbi_prepare_cached|Rose::DB::Object::Metadata/dbi_prepare_cached> class method.
2316              
2317             =item B<speculative BOOL>
2318              
2319             If this parameter is passed with a true value, and if the load failed because the row was L<not found|/not_found>, then the L<error_mode|Rose::DB::Object::Metadata/error_mode> setting is ignored and zero (0) is returned. In the absence of an explicitly set value, this parameter defaults to the value returned my the L<metadata object|/meta>'s L<default_load_speculative|Rose::DB::Object::Metadata/default_load_speculative> method.
2320              
2321             =item B<use_key KEY>
2322              
2323             Use the unique key L<name|Rose::DB::Object::Metadata::UniqueKey/name>d KEY to load the object. This overrides the unique key selection process described above. The key must have a defined value in at least one of its L<columns|Rose::DB::Object::Metadata::UniqueKey/columns>.
2324              
2325             =item B<with OBJECTS>
2326              
2327             Load the object and the specified "foreign objects" simultaneously. OBJECTS should be a reference to an array of L<foreign key|Rose::DB::Object::Metadata/foreign_keys> or L<relationship|Rose::DB::Object::Metadata/relationships> names.
2328              
2329             =back
2330              
2331             B<SUBCLASS NOTE:> If you are going to override the L<load|/load> method in your subclass, you I<must> pass an I<alias to the actual object> as the first argument to the method, rather than passing a copy of the object reference. Example:
2332              
2333             # This is the CORRECT way to override load() while still
2334             # calling the base class version of the method.
2335             sub load
2336             {
2337             my $self = $_[0]; # Copy, not shift
2338              
2339             ... # Do your stuff
2340              
2341             shift->SUPER::load(@_); # Call superclass
2342             }
2343              
2344             Now here's the wrong way:
2345              
2346             # This is the WRONG way to override load() while still
2347             # calling the base class version of the method.
2348             sub load
2349             {
2350             my $self = shift; # WRONG! The alias to the object is now lost!
2351              
2352             ... # Do your stuff
2353              
2354             $self->SUPER::load(@_); # This won't work right!
2355             }
2356              
2357             This requirement exists in order to preserve some sneaky object-replacement optimizations in the base class implementation of L<load|/load>. At some point, those optimizations may change or go away. But if you follow these guidelines, your code will continue to work no matter what.
2358              
2359             =item B<not_found>
2360              
2361             Returns true if the previous call to L<load|/load> failed because a row in the database table with the specified primary or unique key did not exist, false otherwise.
2362              
2363             =item B<meta>
2364              
2365             Returns the L<Rose::DB::Object::Metadata> object associated with this class. This object describes the database table whose rows are fronted by this class: the name of the table, its columns, unique keys, foreign keys, etc.
2366              
2367             See the L<Rose::DB::Object::Metadata> documentation for more information.
2368              
2369             =item B<save [PARAMS]>
2370              
2371             Save the current object to the database table. In the absence of PARAMS, if the object was previously L<load|/load>ed from the database, the row will be L<update|/update>d. Otherwise, a new row will be L<insert|/insert>ed. PARAMS are name/value pairs. Valid PARAMS are listed below.
2372              
2373             Actions associated with sub-objects that were added or deleted using one of the "*_on_save" relationship or foreign key method types are also performed when this method is called. If there are any such actions to perform, a new transaction is started if the L<db|/db> is not already in one, and L<rollback()|Rose::DB/rollback> is called if any of the actions fail during the L<save()|/save>. Example:
2374              
2375             $product = Product->new(name => 'Sled');
2376             $vendor = Vendor->new(name => 'Acme');
2377              
2378             $product->vendor($vendor);
2379              
2380             # Product and vendor records created and linked together,
2381             # all within a single transaction.
2382             $product->save;
2383              
2384             See the "making methods" sections of the L<Rose::DB::Object::Metadata::Relationship|Rose::DB::Object::Metadata::Relationship/"MAKING METHODS"> and L<Rose::DB::Object::Metadata::ForeignKey|Rose::DB::Object::Metadata::ForeignKey/"MAKING METHODS"> documentation for a description of the "method map" associated with each relationship and foreign key. Only the actions initiated through one of the "*_on_save" method types are handled when L<save()|/save> is called. See the documentation for each individual "*_on_save" method type for more specific information.
2385              
2386             Valid parameters to L<save()|/save> are:
2387              
2388             =over 4
2389              
2390             =item B<cascade BOOL>
2391              
2392             If true, then sub-objects related to this object through a foreign key or relationship that have been previously loaded using methods called on this object and that contain unsaved changes will be L<saved|/save> after the parent object is saved. This proceeds recursively through all sub-objects. (All other parameters to the original call to L<save|/save> are also passed on when saving sub-objects.)
2393              
2394             All database operations are done within a single transaction. If the L<db|/db> is not currently in a transaction, a new transaction is started. If any part of the cascaded save fails, the transaction is rolled back.
2395              
2396             If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_cascade_save|Rose::DB::Object::Metadata/default_cascade_save> class method, which returns false by default.
2397              
2398             Example:
2399              
2400             $p = Product->new(id => 123)->load;
2401              
2402             print join(', ', $p->colors); # related Color objects loaded
2403             $p->colors->[0]->code('zzz'); # one Color object is modified
2404              
2405             # The Product object and the modified Color object are saved
2406             $p->save(cascade => 1);
2407              
2408             =item B<changes_only BOOL>
2409              
2410             If true, then only the columns whose values have been modified will be included in the insert or update query. Otherwise, all eligible columns will be included. Note that any column that has a L<default|Rose::DB::Object::Metadata::Column/default> value set in its L<column metadata|Rose::DB::Object::Metadata::Column> is considered "modified" during an insert operation.
2411              
2412             If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_update_changes_only|Rose::DB::Object::Metadata/default_update_changes_only> class method on update, and the L<default_insert_changes_only|Rose::DB::Object::Metadata/default_insert_changes_only> class method on insert, both of which return false by default.
2413              
2414             =item B<insert BOOL>
2415              
2416             If set to a true value, then an L<insert|/insert> is attempted, regardless of whether or not the object was previously L<load|/load>ed from the database.
2417              
2418             =item B<prepare_cached BOOL>
2419              
2420             If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will save the object. If omitted, the default value is determined by the L<metadata object|/meta>'s L<dbi_prepare_cached|Rose::DB::Object::Metadata/dbi_prepare_cached> class method.
2421              
2422             =item B<update BOOL>
2423              
2424             If set to a true value, then an L<update|/update> is attempted, regardless of whether or not the object was previously L<load|/load>ed from the database.
2425              
2426             =back
2427              
2428             It is an error to pass both the C<insert> and C<update> parameters in a single call.
2429              
2430             Returns true if the row was inserted or updated successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of the object itself.
2431              
2432             If an insert was performed and the primary key is a single column that supports auto-generated values, then the object accessor for the primary key column will contain the auto-generated value. See the L<Serial and Auto-Incremented Columns|/"Serial and Auto-Incremented Columns"> section for more information.
2433              
2434             =item B<update [PARAMS]>
2435              
2436             Update the current object in the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be updated, rather than inserted. It is recommended that you use the L<save|/save> method instead of this one in most circumstances. The L<save|/save> method will "do the right thing," executing an insert or update as appropriate for the current situation.
2437              
2438             PARAMS are optional name/value pairs. Valid PARAMS are:
2439              
2440             =over 4
2441              
2442             =item B<changes_only BOOL>
2443              
2444             If true, then only the columns whose values have been modified will be updated. Otherwise, all columns whose values have been loaded from the database will be updated. If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<default_update_changes_only|Rose::DB::Object::Metadata/default_update_changes_only> class method, which returns false by default.
2445              
2446             =item B<prepare_cached BOOL>
2447              
2448             If true, then L<DBI>'s L<prepare_cached|DBI/prepare_cached> method will be used (instead of the L<prepare|DBI/prepare> method) when preparing the SQL statement that will insert the object. If omitted, the default value of this parameter is determined by the L<metadata object|/meta>'s L<dbi_prepare_cached|Rose::DB::Object::Metadata/dbi_prepare_cached> class method.
2449              
2450             =back
2451              
2452             Returns true if the row was updated successfully, false otherwise. The true value returned on success will be the object itself. If the object L<overload>s its boolean value such that it is not true, then a true value will be returned instead of the object itself.
2453              
2454             =back
2455              
2456             =head1 RESERVED METHODS
2457              
2458             As described in the L<Rose::DB::Object::Metadata> documentation, each column in the database table has an associated get/set accessor method in the L<Rose::DB::Object>. Since the L<Rose::DB::Object> API already defines many methods (L<load|/load>, L<save|/save>, L<meta|/meta>, etc.), accessor methods for columns that share the name of an existing method pose a problem. The solution is to alias such columns using L<Rose::DB::Object::Metadata>'s L<alias_column|Rose::DB::Object::Metadata/alias_column> method.
2459              
2460             Here is a list of method names reserved by the L<Rose::DB::Object> API. If you have a column with one of these names, you must alias it.
2461              
2462             db
2463             dbh
2464             delete
2465             DESTROY
2466             error
2467             init_db
2468             _init_db
2469             insert
2470             load
2471             meta
2472             meta_class
2473             not_found
2474             save
2475             update
2476              
2477             Note that not all of these methods are public. These methods do not suddenly become public just because you now know their names! Remember the stated policy of the L<Rose> web application framework: if a method is not documented, it does not exist. (And no, the list of method names above does not constitute "documentation.")
2478              
2479             =head1 DEVELOPMENT POLICY
2480              
2481             The L<Rose development policy|Rose/"DEVELOPMENT POLICY"> applies to this, and all C<Rose::*> modules. Please install L<Rose> from CPAN and then run "C<perldoc Rose>" for more information.
2482              
2483             =head1 SUPPORT
2484              
2485             For an informal overview of L<Rose::DB::Object>, consult the L<Rose::DB::Object::Tutorial>.
2486              
2487             perldoc Rose::DB::Object::Tutorial
2488              
2489             Any L<Rose::DB::Object> questions or problems can be posted to the L<Rose::DB::Object> mailing list. To subscribe to the list or view the archives, go here:
2490              
2491             L<http://groups.google.com/group/rose-db-object>
2492              
2493             Although the mailing list is the preferred support mechanism, you can also email the author (see below) or file bugs using the CPAN bug tracking system:
2494              
2495             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-DB-Object>
2496              
2497             There's also a wiki and other resources linked from the Rose project home page:
2498              
2499             L<http://rosecode.org>
2500              
2501             =head1 CONTRIBUTORS
2502              
2503             Bradley C Bailey, Graham Barr, Kostas Chatzikokolakis, David Christensen, Lucian Dragus, Justin Ellison, Perrin Harkins, Cees Hek, Benjamin Hitz, Dave Howorth, Peter Karman, Ed Loehr, Adam Mackler, Michael Reece, Thomas Whaples, Douglas Wilson, Teodor Zlatanov
2504              
2505             =head1 AUTHOR
2506              
2507             John C. Siracusa (siracusa@gmail.com)
2508              
2509             =head1 LICENSE
2510              
2511             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is
2512             free software; you can redistribute it and/or modify it under the same terms
2513             as Perl itself.