File Coverage

blib/lib/Class/DBI.pm
Criterion Covered Total %
statement 189 596 31.7
branch 40 220 18.1
condition 18 88 20.4
subroutine 49 137 35.7
pod 36 52 69.2
total 332 1093 30.3


line stmt bran cond sub pod time code
1             package Class::DBI::__::Base;
2              
3             require 5.006;
4              
5 4     4   115809 use Class::Trigger 0.07;
  4         6121  
  4         25  
6 4     4   205 use base qw(Class::Accessor Class::Data::Inheritable Ima::DBI);
  4         8  
  4         4181  
7              
8             package Class::DBI;
9              
10 4     4   168329 use version; $VERSION = qv('3.0.17');
  4         10035  
  4         25  
11              
12 4     4   434 use strict;
  4         7  
  4         234  
13 4     4   22 use warnings;
  4         7  
  4         148  
14              
15 4     4   21 use base "Class::DBI::__::Base";
  4         8  
  4         2552  
16              
17 4     4   2817 use Class::DBI::ColumnGrouper;
  4         16  
  4         386  
18 4     4   2764 use Class::DBI::Query;
  4         12  
  4         33  
19 4     4   131 use Carp ();
  4         7  
  4         375  
20 4     4   22 use List::Util;
  4         7  
  4         296  
21 4     4   3685 use Clone ();
  4         14908  
  4         106  
22 4     4   4468 use UNIVERSAL::moniker;
  4         41  
  4         130  
23              
24 4     4   67 use vars qw($Weaken_Is_Available);
  4         7  
  4         367  
25              
26             BEGIN {
27 4     4   7 $Weaken_Is_Available = 1;
28 4         9 eval {
29 4         22 require Scalar::Util;
30 4         341 import Scalar::Util qw(weaken);
31             };
32 4 50       266 if ($@) {
33 0         0 $Weaken_Is_Available = 0;
34             }
35             }
36              
37             use overload
38 0     0   0 '""' => sub { shift->stringify_self },
39 0     0   0 bool => sub { not shift->_undefined_primary },
40 4     4   23 fallback => 1;
  4         10  
  4         59  
41              
42             sub stringify_self {
43 0     0 0 0 my $self = shift;
44 0 0 0     0 return (ref $self || $self) unless $self; # empty PK
45 0         0 my @cols = $self->columns('Stringify');
46 0 0       0 @cols = $self->primary_columns unless @cols;
47 0         0 return join "/", $self->get(@cols);
48             }
49              
50             sub _undefined_primary {
51 0     0   0 my $self = shift;
52 0         0 return grep !defined, $self->_attrs($self->primary_columns);
53             }
54              
55             #----------------------------------------------------------------------
56             # Deprecations
57             #----------------------------------------------------------------------
58              
59             __PACKAGE__->mk_classdata('__hasa_rels' => {});
60              
61             {
62             my %deprecated = (
63             # accessor_name => 'accessor_name_for', # 3.0.7
64             # mutator_name => 'accessor_name_for', # 3.0.7
65             );
66              
67 4     4   912 no strict 'refs';
  4         8  
  4         10726  
68             while (my ($old, $new) = each %deprecated) {
69             *$old = sub {
70             my @caller = caller;
71             warn
72             "Use of '$old' is deprecated at $caller[1] line $caller[2]. Use '$new' instead\n";
73             goto &$new;
74             };
75             }
76             }
77              
78             #----------------------------------------------------------------------
79             # Our Class Data
80             #----------------------------------------------------------------------
81             __PACKAGE__->mk_classdata('__AutoCommit');
82             __PACKAGE__->mk_classdata('__hasa_list');
83             __PACKAGE__->mk_classdata('_table');
84             __PACKAGE__->mk_classdata('_table_alias');
85             __PACKAGE__->mk_classdata('sequence');
86             __PACKAGE__->mk_classdata('__grouper' => Class::DBI::ColumnGrouper->new());
87             __PACKAGE__->mk_classdata('__data_type' => {});
88             __PACKAGE__->mk_classdata('__driver');
89             __PACKAGE__->mk_classdata('iterator_class' => 'Class::DBI::Iterator');
90             __PACKAGE__->mk_classdata('purge_object_index_every' => 1000);
91             __PACKAGE__->add_searcher(search => "Class::DBI::Search::Basic",);
92              
93             __PACKAGE__->add_relationship_type(
94             has_a => "Class::DBI::Relationship::HasA",
95             has_many => "Class::DBI::Relationship::HasMany",
96             might_have => "Class::DBI::Relationship::MightHave",
97             );
98             __PACKAGE__->mk_classdata('__meta_info' => {});
99              
100             #----------------------------------------------------------------------
101             # SQL we'll need
102             #----------------------------------------------------------------------
103             __PACKAGE__->set_sql(MakeNewObj => <<'');
104             INSERT INTO __TABLE__ (%s)
105             VALUES (%s)
106              
107             __PACKAGE__->set_sql(update => <<"");
108             UPDATE __TABLE__
109             SET %s
110             WHERE __IDENTIFIER__
111              
112             __PACKAGE__->set_sql(Nextval => <<'');
113             SELECT NEXTVAL ('%s')
114              
115             __PACKAGE__->set_sql(SearchSQL => <<'');
116             SELECT %s
117             FROM %s
118             WHERE %s
119              
120             __PACKAGE__->set_sql(RetrieveAll => <<'');
121             SELECT __ESSENTIAL__
122             FROM __TABLE__
123              
124             __PACKAGE__->set_sql(Retrieve => <<'');
125             SELECT __ESSENTIAL__
126             FROM __TABLE__
127             WHERE %s
128              
129             __PACKAGE__->set_sql(Flesh => <<'');
130             SELECT %s
131             FROM __TABLE__
132             WHERE __IDENTIFIER__
133              
134             __PACKAGE__->set_sql(single => <<'');
135             SELECT %s
136             FROM __TABLE__
137              
138             __PACKAGE__->set_sql(DeleteMe => <<"");
139             DELETE
140             FROM __TABLE__
141             WHERE __IDENTIFIER__
142              
143              
144             __PACKAGE__->mk_classdata('sql_transformer_class');
145             __PACKAGE__->sql_transformer_class('Class::DBI::SQL::Transformer');
146              
147             # Override transform_sql from Ima::DBI to provide some extra
148             # transformations
149             sub transform_sql {
150 0     0 1 0 my ($self, $sql, @args) = @_;
151 0         0 my $tclass = $self->sql_transformer_class;
152 0         0 $self->_require_class($tclass);
153 0         0 my $T = $tclass->new($self, $sql, @args);
154 0         0 return $self->SUPER::transform_sql($T->sql => $T->args);
155             }
156              
157             #----------------------------------------------------------------------
158             # EXCEPTIONS
159             #----------------------------------------------------------------------
160              
161             sub _carp {
162 0     0   0 my ($self, $msg) = @_;
163 0   0     0 Carp::carp($msg || $self);
164 0         0 return;
165             }
166              
167             sub _croak {
168 1     1   2 my ($self, $msg) = @_;
169 1   33     281 Carp::croak($msg || $self);
170             }
171              
172             sub _db_error {
173 0     0   0 my ($self, %info) = @_;
174 0         0 my $msg = delete $info{msg};
175 0         0 return $self->_croak($msg, %info);
176             }
177              
178             #----------------------------------------------------------------------
179             # SET UP
180             #----------------------------------------------------------------------
181              
182             sub connection {
183 0     0 1 0 my $class = shift;
184 0         0 $class->set_db(Main => @_);
185             }
186              
187             {
188             my %Per_DB_Attr_Defaults = (
189             pg => { AutoCommit => 0 },
190             oracle => { AutoCommit => 0 },
191             );
192              
193             sub _default_attributes {
194 0     0   0 my $class = shift;
195             return (
196 0 0       0 $class->SUPER::_default_attributes,
197             FetchHashKeyName => 'NAME_lc',
198             ShowErrorStatement => 1,
199             AutoCommit => 1,
200             ChopBlanks => 1,
201 0         0 %{ $Per_DB_Attr_Defaults{ lc $class->__driver } || {} },
202             );
203             }
204             }
205              
206             sub set_db {
207 0     0 1 0 my ($class, $db_name, $data_source, $user, $password, $attr) = @_;
208              
209             # 'dbi:Pg:dbname=foo' we want 'Pg'. I think this is enough.
210 0         0 my ($driver) = $data_source =~ /^dbi:(\w+)/i;
211 0         0 $class->__driver($driver);
212 0         0 $class->SUPER::set_db('Main', $data_source, $user, $password, $attr);
213             }
214              
215             sub table {
216 6     6 1 69 my ($proto, $table, $alias) = @_;
217 6   33     36 my $class = ref $proto || $proto;
218 6 100       61 $class->_table($table) if $table;
219 6 50       207 $class->table_alias($alias) if $alias;
220 6   33     23 return $class->_table || $class->_table($class->table_alias);
221             }
222              
223             sub table_alias {
224 1     1 1 3 my ($proto, $alias) = @_;
225 1   33     7 my $class = ref $proto || $proto;
226 1 50       4 $class->_table_alias($alias) if $alias;
227 1   33     9 return $class->_table_alias || $class->_table_alias($class->moniker);
228             }
229              
230             sub columns {
231 34     34 1 6002 my $proto = shift;
232 34   33     145 my $class = ref $proto || $proto;
233 34   100     95 my $group = shift || "All";
234 34 100       147 return $class->_set_columns($group => @_) if @_;
235 19 100       88 return $class->all_columns if $group eq "All";
236 9 100       24 return $class->primary_column if $group eq "Primary";
237 5 100       29 return $class->_essential if $group eq "Essential";
238 1         6 return $class->__grouper->group_cols($group);
239             }
240              
241 31     31   574 sub _column_class { 'Class::DBI::Column' }
242              
243             sub _set_columns {
244 15     15   39 my ($class, $group, @columns) = @_;
245              
246 15 100       108 my @cols = map ref $_ ? $_ : $class->_column_class->new($_), @columns;
247              
248             # Careful to take copy
249 15         314 $class->__grouper(Class::DBI::ColumnGrouper->clone($class->__grouper)
250             ->add_group($group => @cols));
251 15         1496 $class->_mk_column_accessors(@cols);
252 15         93 return @columns;
253             }
254              
255 10     10 0 36 sub all_columns { shift->__grouper->all_columns }
256              
257             sub id {
258 0     0 1 0 my $self = shift;
259 0 0       0 my $class = ref($self)
260             or return $self->_croak("Can't call id() as a class method");
261              
262             # we don't use get() here because all objects should have
263             # exisitng values for PK columns, or else loop endlessly
264 0         0 my @pk_values = $self->_attrs($self->primary_columns);
265 0   0     0 UNIVERSAL::can($_ => 'id') and $_ = $_->id for @pk_values;
266 0 0       0 return @pk_values if wantarray;
267 0 0       0 $self->_croak(
268             "id called in scalar context for class with multiple primary key columns")
269             if @pk_values > 1;
270 0         0 return $pk_values[0];
271             }
272              
273             sub primary_column {
274 14     14 0 791 my $self = shift;
275 14         54 my @primary_columns = $self->__grouper->primary;
276 14 100       78 return @primary_columns if wantarray;
277 2 50       6 $self->_carp(
278             ref($self)
279             . " has multiple primary columns, but fetching in scalar context")
280             if @primary_columns > 1;
281 2         14 return $primary_columns[0];
282             }
283             *primary_columns = \&primary_column;
284              
285 4     4   15 sub _essential { shift->__grouper->essential }
286              
287             sub find_column {
288 6     6 1 1483 my ($class, $want) = @_;
289 6         22 return $class->__grouper->find_column($want);
290             }
291              
292             sub _find_columns {
293 1     1   539 my $class = shift;
294 1         4 my $cg = $class->__grouper;
295 1         11 return map $cg->find_column($_), @_;
296             }
297              
298             sub has_real_column { # is really in the database
299 0     0 0 0 my ($class, $want) = @_;
300 0   0     0 return ($class->find_column($want) || return)->in_database;
301             }
302              
303             sub data_type {
304 0     0 0 0 my $class = shift;
305 0         0 my %datatype = @_;
306 0         0 while (my ($col, $type) = each %datatype) {
307 0         0 $class->_add_data_type($col, $type);
308             }
309             }
310              
311             sub _add_data_type {
312 0     0   0 my ($class, $col, $type) = @_;
313 0         0 my $datatype = $class->__data_type;
314 0         0 $datatype->{$col} = $type;
315 0         0 $class->__data_type($datatype);
316             }
317              
318             # Make a set of accessors for each of a list of columns. We construct
319             # the method name by calling accessor_name_for() and mutator_name_for()
320             # with the normalized column name.
321              
322             # mutator name will be the same as accessor name unless you override it.
323              
324             # If both the accessor and mutator are to have the same method name,
325             # (which will always be true unless you override mutator_name_for), a
326             # read-write method is constructed for it. If they differ we create both
327             # a read-only accessor and a write-only mutator.
328              
329             sub _mk_column_accessors {
330 15     15   27 my $class = shift;
331 15         30 foreach my $col (@_) {
332              
333 32         297 my $default_accessor = $col->accessor;
334              
335 32         403 my $acc = $class->accessor_name_for($col);
336 32         223 my $mut = $class->mutator_name_for($col);
337              
338 32         172 my %method = ();
339              
340 32 100 66     109 if (
341             ($acc eq $mut) # if they are the same
342             or ($mut eq $default_accessor)
343             ) { # or only the accessor was customized
344 25         46 %method = ('_' => $acc); # make the accessor the mutator too
345 25         65 $col->accessor($acc);
346 25         154 $col->mutator($acc);
347             } else {
348 7         20 %method = (
349             _ro_ => $acc,
350             _wo_ => $mut,
351             );
352 7         22 $col->accessor($acc);
353 7         45 $col->mutator($mut);
354             }
355              
356 32         192 foreach my $type (keys %method) {
357 39         61 my $name = $method{$type};
358 39         69 my $acc_type = "make${type}accessor";
359 39         111 my $accessor = $class->$acc_type($col->name_lc);
360 39         645 $class->_make_method($_, $accessor) for ($name, "_${name}_accessor");
361             }
362             }
363             }
364              
365             sub _make_method {
366 180     180   439 my ($class, $name, $method) = @_;
367 180 100       177 return if defined &{"$class\::$name"};
  180         1075  
368 102 50 33     1012 $class->_carp("Column '$name' in $class clashes with built-in method")
      66        
369             if Class::DBI->can($name)
370             and not($name eq "id" and join(" ", $class->primary_columns) eq "id");
371 4     4   106 no strict 'refs';
  4         8  
  4         20910  
372 102         169 *{"$class\::$name"} = $method;
  102         428  
373 102         289 $class->_make_method(lc $name => $method);
374             }
375              
376             sub accessor_name_for {
377 32     32 1 48 my ($class, $column) = @_;
378 32 50       661 if ($class->can('accessor_name')) {
379 0         0 warn "Use of 'accessor_name' is deprecated. Use 'accessor_name_for' instead\n";
380 0         0 return $class->accessor_name($column)
381             }
382 32         90 return $column->accessor;
383             }
384              
385             sub mutator_name_for {
386 25     25 1 36 my ($class, $column) = @_;
387 25 50       192 if ($class->can('mutator_name')) {
388 0         0 warn "Use of 'mutator_name' is deprecated. Use 'mutator_name_for' instead\n";
389 0         0 return $class->mutator_name($column)
390             }
391 25         67 return $column->mutator;
392             }
393              
394             sub autoupdate {
395 0     0 1 0 my $proto = shift;
396 0 0       0 ref $proto ? $proto->_obj_autoupdate(@_) : $proto->_class_autoupdate(@_);
397             }
398              
399             sub _obj_autoupdate {
400 0     0   0 my ($self, $set) = @_;
401 0         0 my $class = ref $self;
402 0 0       0 $self->{__AutoCommit} = $set if defined $set;
403 0 0       0 defined $self->{__AutoCommit}
404             ? $self->{__AutoCommit}
405             : $class->_class_autoupdate;
406             }
407              
408             sub _class_autoupdate {
409 0     0   0 my ($class, $set) = @_;
410 0 0       0 $class->__AutoCommit($set) if defined $set;
411 0         0 return $class->__AutoCommit;
412             }
413              
414             sub make_read_only {
415 0     0 0 0 my $proto = shift;
416 0     0   0 $proto->add_trigger("before_$_" => sub { _croak "$proto is read only" })
417 0         0 foreach qw/create delete update/;
418 0         0 return $proto;
419             }
420              
421             sub find_or_create {
422 0     0 1 0 my $class = shift;
423 0 0       0 my $hash = ref $_[0] eq "HASH" ? shift: {@_};
424 0         0 my ($exists) = $class->search($hash);
425 0 0       0 return defined($exists) ? $exists : $class->insert($hash);
426             }
427              
428             sub insert {
429 0     0 1 0 my $class = shift;
430 0 0       0 return $class->_croak("insert needs a hashref") unless ref $_[0] eq 'HASH';
431 0         0 my $info = { %{ +shift } }; # make sure we take a copy
  0         0  
432              
433 0         0 my $data;
434 0         0 while (my ($k, $v) = each %$info) {
435             my $col = $class->find_column($k)
436 0     0   0 || (List::Util::first { $_->mutator eq $k } $class->columns)
437 0   0 0   0 || (List::Util::first { $_->accessor eq $k } $class->columns)
  0         0  
438             || $class->_croak("$k is not a column of $class");
439 0         0 $data->{$col} = $v;
440             }
441              
442 0         0 $class->normalize_column_values($data);
443 0         0 $class->validate_column_values($data);
444 0         0 return $class->_insert($data);
445             }
446              
447             *create = \&insert;
448              
449             #----------------------------------------------------------------------
450             # Low Level Data Access
451             #----------------------------------------------------------------------
452              
453             sub _attrs {
454 0     0   0 my ($self, @atts) = @_;
455 0         0 return @{$self}{@atts};
  0         0  
456             }
457             *_attr = \&_attrs;
458              
459             sub _attribute_store {
460 0     0   0 my $self = shift;
461 0 0       0 my $vals = @_ == 1 ? shift: {@_};
462 0         0 my (@cols) = keys %$vals;
463 0         0 @{$self}{@cols} = @{$vals}{@cols};
  0         0  
  0         0  
464             }
465              
466             # If you override this method, you must use the same mechanism to log changes
467             # for future updates, as other parts of Class::DBI depend on it.
468             sub _attribute_set {
469 0     0   0 my $self = shift;
470 0 0       0 my $vals = @_ == 1 ? shift: {@_};
471              
472             # We increment instead of setting to 1 because it might be useful to
473             # someone to know how many times a value has changed between updates.
474 0         0 for my $col (keys %$vals) { $self->{__Changed}{$col}++; }
  0         0  
475 0         0 $self->_attribute_store($vals);
476             }
477              
478             sub _attribute_delete {
479 0     0   0 my ($self, @attributes) = @_;
480 0         0 delete @{$self}{@attributes};
  0         0  
481             }
482              
483             sub _attribute_exists {
484 0     0   0 my ($self, $attribute) = @_;
485 0         0 exists $self->{$attribute};
486             }
487              
488             #----------------------------------------------------------------------
489             # Live Object Index (using weak refs if available)
490             #----------------------------------------------------------------------
491              
492             my %Live_Objects;
493             my $Init_Count = 0;
494              
495             sub _init {
496 0     0   0 my $class = shift;
497 0   0     0 my $data = shift || {};
498 0         0 my $key = $class->_live_object_key($data);
499 0   0     0 return $Live_Objects{$key} || $class->_fresh_init($key => $data);
500             }
501              
502             sub _fresh_init {
503 0     0   0 my ($class, $key, $data) = @_;
504 0         0 my $obj = bless {}, $class;
505 0         0 $obj->_attribute_store(%$data);
506              
507             # don't store it unless all keys are present
508 0 0 0     0 if ($key && $Weaken_Is_Available) {
509 0         0 weaken($Live_Objects{$key} = $obj);
510              
511             # time to clean up your room?
512 0 0       0 $class->purge_dead_from_object_index
513             if ++$Init_Count % $class->purge_object_index_every == 0;
514             }
515 0         0 return $obj;
516             }
517              
518             sub _live_object_key {
519 0     0   0 my ($me, $data) = @_;
520 0   0     0 my $class = ref($me) || $me;
521 0         0 my @primary = $class->primary_columns;
522              
523             # no key unless all PK columns are defined
524 0 0       0 return "" unless @primary == grep defined $data->{$_}, @primary;
525              
526             # create single unique key for this object
527 0         0 return join "\030", $class, map $_ . "\032" . $data->{$_}, sort @primary;
528             }
529              
530             sub purge_dead_from_object_index {
531 0     0 0 0 delete @Live_Objects{ grep !defined $Live_Objects{$_}, keys %Live_Objects };
532             }
533              
534             sub remove_from_object_index {
535 0     0 1 0 my $self = shift;
536 0         0 my $obj_key = $self->_live_object_key({ $self->_as_hash });
537 0         0 delete $Live_Objects{$obj_key};
538             }
539              
540             sub clear_object_index {
541 5     5 1 16 %Live_Objects = ();
542             }
543              
544             #----------------------------------------------------------------------
545              
546             sub _prepopulate_id {
547 0     0   0 my $self = shift;
548 0         0 my @primary_columns = $self->primary_columns;
549 0 0       0 return $self->_croak(
550             sprintf "Can't create %s object with null primary key columns (%s)",
551             ref $self, $self->_undefined_primary)
552             if @primary_columns > 1;
553 0 0       0 $self->_attribute_store($primary_columns[0] => $self->_next_in_sequence)
554             if $self->sequence;
555             }
556              
557             sub _insert {
558 0     0   0 my ($proto, $data) = @_;
559 0   0     0 my $class = ref $proto || $proto;
560              
561 0         0 my $self = $class->_init($data);
562 0         0 $self->call_trigger('before_create');
563 0         0 $self->call_trigger('deflate_for_create');
564              
565 0 0       0 $self->_prepopulate_id if $self->_undefined_primary;
566              
567             # Reinstate data
568 0         0 my ($real, $temp) = ({}, {});
569 0         0 foreach my $col (grep $self->_attribute_exists($_), $self->all_columns) {
570 0 0       0 ($class->has_real_column($col) ? $real : $temp)->{$col} =
571             $self->_attrs($col);
572             }
573 0         0 $self->_insert_row($real);
574              
575 0         0 my @primary_columns = $class->primary_columns;
576 0 0       0 $self->_attribute_store(
577             $primary_columns[0] => $real->{ $primary_columns[0] })
578             if @primary_columns == 1;
579              
580 0         0 delete $self->{__Changed};
581              
582 0         0 my %primary_columns;
583 0         0 @primary_columns{@primary_columns} = ();
584 0         0 my @discard_columns = grep !exists $primary_columns{$_}, keys %$real;
585 0         0 $self->call_trigger('create', discard_columns => \@discard_columns); # XXX
586              
587             # Empty everything back out again!
588 0         0 $self->_attribute_delete(@discard_columns);
589 0         0 $self->call_trigger('after_create');
590 0         0 return $self;
591             }
592              
593             sub _next_in_sequence {
594 0     0   0 my $self = shift;
595 0         0 return $self->sql_Nextval($self->sequence)->select_val;
596             }
597              
598             sub _auto_increment_value {
599 0     0   0 my $self = shift;
600 0         0 my $dbh = $self->db_Main;
601              
602             # Try to do this in a standard method. Fall back to MySQL/SQLite
603             # specific versions. TODO remove these when last_insert_id is more
604             # widespread.
605             # Note: I don't believe the last_insert_id can be zero. We need to
606             # switch to defined() checks if it can.
607             my $id = $dbh->last_insert_id(undef, undef, $self->table, undef) # std
608             || $dbh->{mysql_insertid} # mysql
609 0 0 0     0 || eval { $dbh->func('last_insert_rowid') }
610             or $self->_croak("Can't get last insert id");
611 0         0 return $id;
612             }
613              
614             sub _insert_row {
615 0     0   0 my $self = shift;
616 0         0 my $data = shift;
617 0         0 eval {
618 0         0 my @columns = keys %$data;
619 0         0 my $sth = $self->sql_MakeNewObj(
620             join(', ', @columns),
621             join(', ', map $self->_column_placeholder($_), @columns),
622             );
623 0         0 $self->_bind_param($sth, \@columns);
624 0         0 $sth->execute(values %$data);
625 0         0 my @primary_columns = $self->primary_columns;
626 0 0 0     0 $data->{ $primary_columns[0] } = $self->_auto_increment_value
627             if @primary_columns == 1
628             && !defined $data->{ $primary_columns[0] };
629             };
630 0 0       0 if ($@) {
631 0         0 my $class = ref $self;
632 0         0 return $self->_db_error(
633             msg => "Can't insert new $class: $@",
634             err => $@,
635             method => 'insert'
636             );
637             }
638 0         0 return 1;
639             }
640              
641             sub _bind_param {
642 0     0   0 my ($class, $sth, $keys) = @_;
643 0 0       0 my $datatype = $class->__data_type or return;
644 0         0 for my $i (0 .. $#$keys) {
645 0 0       0 if (my $type = $datatype->{ $keys->[$i] }) {
646 0         0 $sth->bind_param($i + 1, undef, $type);
647             }
648             }
649             }
650              
651             sub retrieve {
652 1     1 1 1533 my $class = shift;
653 1 50       6 my @primary_columns = $class->primary_columns
654             or return $class->_croak(
655             "Can't retrieve unless primary columns are defined");
656 0         0 my %key_value;
657 0 0 0     0 if (@_ == 1 && @primary_columns == 1) {
658 0         0 my $id = shift;
659 0 0       0 return unless defined $id;
660 0 0       0 return $class->_croak("Can't retrieve a reference") if ref($id);
661 0         0 $key_value{ $primary_columns[0] } = $id;
662             } else {
663 0         0 %key_value = @_;
664 0 0       0 $class->_croak(
665             "$class->retrieve(@_) parameters don't include values for all primary key columns (@primary_columns)"
666             )
667             if keys %key_value < @primary_columns;
668             }
669 0         0 my @rows = $class->search(%key_value);
670 0 0       0 $class->_carp("$class->retrieve(@_) selected " . @rows . " rows")
671             if @rows > 1;
672 0         0 return $rows[0];
673             }
674              
675             # Get the data, as a hash, but setting certain values to whatever
676             # we pass. Used by copy() and move().
677             # This can take either a primary key, or a hashref of all the columns
678             # to change.
679             sub _data_hash {
680 0     0   0 my $self = shift;
681 0         0 my %data = $self->_as_hash;
682 0         0 my @primary_columns = $self->primary_columns;
683 0         0 delete @data{@primary_columns};
684 0 0       0 if (@_) {
685 0         0 my $arg = shift;
686 0 0       0 unless (ref $arg) {
687 0 0       0 $self->_croak("Need hash-ref to edit copied column values")
688             unless @primary_columns == 1;
689 0         0 $arg = { $primary_columns[0] => $arg };
690             }
691 0         0 @data{ keys %$arg } = values %$arg;
692             }
693 0         0 return \%data;
694             }
695              
696             sub _as_hash {
697 0     0   0 my $self = shift;
698 0         0 my @columns = $self->all_columns;
699 0         0 my %data;
700 0         0 @data{@columns} = $self->get(@columns);
701 0         0 return %data;
702             }
703              
704             sub copy {
705 0     0 1 0 my $self = shift;
706 0         0 return $self->insert($self->_data_hash(@_));
707             }
708              
709             #----------------------------------------------------------------------
710             # CONSTRUCT
711             #----------------------------------------------------------------------
712              
713             sub construct {
714 0     0 0 0 my ($proto, $data) = @_;
715 0   0     0 my $class = ref $proto || $proto;
716 0         0 my $self = $class->_init($data);
717 0         0 $self->call_trigger('select');
718 0         0 return $self;
719             }
720              
721             sub move {
722 0     0 1 0 my ($class, $old_obj, @data) = @_;
723 0         0 $class->_carp("move() is deprecated. If you really need it, "
724             . "you should tell me quickly so I can abandon my plan to remove it.");
725 0 0 0     0 return $old_obj->_croak("Can't move to an unrelated class")
726             unless $class->isa(ref $old_obj)
727             or $old_obj->isa($class);
728 0         0 return $class->insert($old_obj->_data_hash(@data));
729             }
730              
731             sub delete {
732 0     0 1 0 my $self = shift;
733 0 0       0 return $self->_search_delete(@_) if not ref $self;
734 0         0 $self->remove_from_object_index;
735 0         0 $self->call_trigger('before_delete');
736              
737 0         0 eval { $self->sql_DeleteMe->execute($self->id) };
  0         0  
738 0 0       0 if ($@) {
739 0         0 return $self->_db_error(
740             msg => "Can't delete $self: $@",
741             err => $@,
742             method => 'delete'
743             );
744             }
745 0         0 $self->call_trigger('after_delete');
746 0         0 undef %$self;
747 0         0 bless $self, 'Class::DBI::Object::Has::Been::Deleted';
748 0         0 return 1;
749             }
750              
751             sub _search_delete {
752 0     0   0 my ($class, @args) = @_;
753 0         0 $class->_carp(
754             "Delete as class method is deprecated. Use search and delete_all instead."
755             );
756 0         0 my $it = $class->search_like(@args);
757 0         0 while (my $obj = $it->next) { $obj->delete }
  0         0  
758 0         0 return 1;
759             }
760              
761             # Return the placeholder to be used in UPDATE and INSERT queries.
762             # Overriding this is deprecated in favour of
763             # __PACKAGE__->find_column('entered')->placeholder('IF(1, CURDATE(), ?));
764              
765             sub _column_placeholder {
766 0     0   0 my ($self, $column) = @_;
767 0         0 return $self->find_column($column)->placeholder;
768             }
769              
770             sub update {
771 0     0 1 0 my $self = shift;
772 0 0       0 my $class = ref($self)
773             or return $self->_croak("Can't call update as a class method");
774              
775 0         0 $self->call_trigger('before_update');
776 0 0       0 return -1 unless my @changed_cols = $self->is_changed;
777 0         0 $self->call_trigger('deflate_for_update');
778 0         0 my @primary_columns = $self->primary_columns;
779 0         0 my $sth = $self->sql_update($self->_update_line);
780 0         0 $class->_bind_param($sth, \@changed_cols);
781 0         0 my $rows = eval { $sth->execute($self->_update_vals, $self->id); };
  0         0  
782 0 0       0 if ($@) {
783 0         0 return $self->_db_error(
784             msg => "Can't update $self: $@",
785             err => $@,
786             method => 'update'
787             );
788             }
789              
790             # enable this once new fixed DBD::SQLite is released:
791 0         0 if (0 and $rows != 1) { # should always only update one row
792             $self->_croak("Can't update $self: row not found") if $rows == 0;
793             $self->_croak("Can't update $self: updated more than one row");
794             }
795              
796 0         0 $self->call_trigger('after_update', discard_columns => \@changed_cols);
797              
798             # delete columns that changed (in case adding to DB modifies them again)
799 0         0 $self->_attribute_delete(@changed_cols);
800 0         0 delete $self->{__Changed};
801 0         0 return 1;
802             }
803              
804             sub _update_line {
805 0     0   0 my $self = shift;
806 0         0 join(', ', map "$_ = " . $self->_column_placeholder($_), $self->is_changed);
807             }
808              
809             sub _update_vals {
810 0     0   0 my $self = shift;
811 0         0 $self->_attrs($self->is_changed);
812             }
813              
814             sub DESTROY {
815 0     0   0 my ($self) = shift;
816 0 0       0 if (my @changed = $self->is_changed) {
817 0         0 my $class = ref $self;
818 0         0 $self->_carp("$class $self destroyed without saving changes to "
819             . join(', ', @changed));
820             }
821             }
822              
823             sub discard_changes {
824 0     0 1 0 my $self = shift;
825 0 0       0 return $self->_croak("Can't discard_changes while autoupdate is on")
826             if $self->autoupdate;
827 0         0 $self->_attribute_delete($self->is_changed);
828 0         0 delete $self->{__Changed};
829 0         0 return 1;
830             }
831              
832             # We override the get() method from Class::Accessor to fetch the data for
833             # the column (and associated) columns from the database, using the _flesh()
834             # method. We also allow get to be called with a list of keys, instead of
835             # just one.
836              
837             sub get {
838 0     0 1 0 my $self = shift;
839 0 0       0 return $self->_croak("Can't fetch data as class method") unless ref $self;
840              
841 0         0 my @cols = $self->_find_columns(@_);
842 0 0       0 return $self->_croak("Can't get() nothing!") unless @cols;
843              
844 0 0       0 if (my @fetch_cols = grep !$self->_attribute_exists($_), @cols) {
845 0         0 $self->_flesh($self->__grouper->groups_for(@fetch_cols));
846             }
847              
848 0         0 return $self->_attrs(@cols);
849             }
850              
851             sub _flesh {
852 0     0   0 my ($self, @groups) = @_;
853 0         0 my @real = grep $_ ne "TEMP", @groups;
854 0 0       0 if (my @want = grep !$self->_attribute_exists($_),
855             $self->__grouper->columns_in(@real)) {
856 0         0 my %row;
857 0         0 @row{@want} = $self->sql_Flesh(join ", ", @want)->select_row($self->id);
858 0         0 $self->_attribute_store(\%row);
859 0         0 $self->call_trigger('select');
860             }
861 0         0 return 1;
862             }
863              
864             # We also override set() from Class::Accessor so we can keep track of
865             # changes, and either write to the database now (if autoupdate is on),
866             # or when update() is called.
867             sub set {
868 0     0 1 0 my $self = shift;
869 0         0 my $column_values = {@_};
870              
871 0         0 $self->normalize_column_values($column_values);
872 0         0 $self->validate_column_values($column_values);
873              
874 0         0 while (my ($column, $value) = each %$column_values) {
875 0 0       0 my $col = $self->find_column($column) or die "No such column: $column\n";
876 0         0 $self->_attribute_set($col => $value);
877              
878             # $self->SUPER::set($column, $value);
879              
880 0         0 eval { $self->call_trigger("after_set_$column") }; # eg inflate
  0         0  
881 0 0       0 if ($@) {
882 0         0 $self->_attribute_delete($column);
883 0         0 return $self->_croak("after_set_$column trigger error: $@", err => $@);
884             }
885             }
886              
887 0 0       0 $self->update if $self->autoupdate;
888 0         0 return 1;
889             }
890              
891             sub is_changed {
892 0     0 1 0 my $self = shift;
893 0         0 grep $self->has_real_column($_), keys %{ $self->{__Changed} };
  0         0  
894             }
895              
896 0     0 0 0 sub any_changed { keys %{ shift->{__Changed} } }
  0         0  
897              
898             # By default do nothing. Subclasses should override if required.
899             #
900             # Given a hash ref of column names and proposed new values,
901             # edit the values in the hash if required.
902             # For insert $self is the class name (not an object ref).
903             sub normalize_column_values {
904 0     0 0 0 my ($self, $column_values) = @_;
905             }
906              
907             # Given a hash ref of column names and proposed new values
908             # validate that the whole set of new values in the hash
909             # is valid for the object in relation to its current values
910             # For insert $self is the class name (not an object ref).
911             sub validate_column_values {
912 0     0 0 0 my ($self, $column_values) = @_;
913 0         0 my @errors;
914 0         0 foreach my $column (keys %$column_values) {
915 0         0 eval {
916 0         0 $self->call_trigger("before_set_$column", $column_values->{$column},
917             $column_values);
918             };
919 0 0       0 push @errors, $column => $@ if $@;
920             }
921 0 0       0 return unless @errors;
922 0         0 $self->_croak(
923             "validate_column_values error: " . join(" ", @errors),
924             method => 'validate_column_values',
925             data => {@errors}
926             );
927             }
928              
929             # We override set_sql() from Ima::DBI so it has a default database connection.
930             sub set_sql {
931 36     36 1 78 my ($class, $name, $sql, $db, @others) = @_;
932 36   50     130 $db ||= 'Main';
933 36         167 $class->SUPER::set_sql($name, $sql, $db, @others);
934 36 100       1461 $class->_generate_search_sql($name) if $sql =~ /select/i;
935 36         54 return 1;
936             }
937              
938             sub _generate_search_sql {
939 24     24   41 my ($class, $name) = @_;
940 24         36 my $method = "search_$name";
941 24 50       25 defined &{"$class\::$method"}
  24         135  
942             and return $class->_carp("$method() already exists");
943 24         43 my $sql_method = "sql_$name";
944 4     4   50 no strict 'refs';
  4         14  
  4         4029  
945 24         134 *{"$class\::$method"} = sub {
946 0     0   0 my ($class, @args) = @_;
947 0         0 return $class->sth_to_objects($name, \@args);
948 24         205 };
949             }
950              
951 0     0 1 0 sub dbi_commit { my $proto = shift; $proto->SUPER::commit(@_); }
  0         0  
952 0     0 1 0 sub dbi_rollback { my $proto = shift; $proto->SUPER::rollback(@_); }
  0         0  
953              
954             #----------------------------------------------------------------------
955             # Constraints / Triggers
956             #----------------------------------------------------------------------
957              
958             sub constrain_column {
959 0     0 1 0 my $class = shift;
960 0 0       0 my $col = $class->find_column(+shift)
961             or return $class->_croak("constraint_column needs a valid column");
962 0 0       0 my $how = shift
963             or return $class->_croak("constrain_column needs a constraint");
964 0 0       0 if (ref $how eq "ARRAY") {
    0          
    0          
965 0         0 my %hash = map { $_ => 1 } @$how;
  0         0  
966 0     0   0 $class->add_constraint(list => $col => sub { exists $hash{ +shift } });
  0         0  
967             } elsif (ref $how eq "Regexp") {
968 0     0   0 $class->add_constraint(regexp => $col => sub { shift =~ $how });
  0         0  
969             } elsif (ref $how eq "CODE") {
970             $class->add_constraint(
971 0     0   0 code => $col => sub { local $_ = $_[0]; $how->($_) });
  0         0  
  0         0  
972             } else {
973 0         0 my $try_method = sprintf '_constrain_by_%s', $how->moniker;
974 0 0       0 if (my $dispatch = $class->can($try_method)) {
975 0         0 $class->$dispatch($col => ($how, @_));
976             } else {
977 0         0 $class->_croak("Don't know how to constrain $col with $how");
978             }
979             }
980             }
981              
982             sub add_constraint {
983 0     0 0 0 my $class = shift;
984 0 0       0 $class->_invalid_object_method('add_constraint()') if ref $class;
985 0 0       0 my $name = shift or return $class->_croak("Constraint needs a name");
986 0 0       0 my $column = $class->find_column(+shift)
987             or return $class->_croak("Constraint $name needs a valid column");
988 0 0       0 my $code = shift
989             or return $class->_croak("Constraint $name needs a code reference");
990 0 0       0 return $class->_croak("Constraint $name '$code' is not a code reference")
991             unless ref($code) eq "CODE";
992              
993 0         0 $column->is_constrained(1);
994             $class->add_trigger(
995             "before_set_$column" => sub {
996 0     0   0 my ($self, $value, $column_values) = @_;
997 0 0       0 $code->($value, $self, $column, $column_values)
998             or return $self->_croak(
999             "$class $column fails '$name' constraint with '$value'",
1000             method => "before_set_$column",
1001             exception_type => 'constraint_failure',
1002             data => {
1003             column => $column,
1004             value => $value,
1005             constraint_name => $name,
1006             }
1007             );
1008             }
1009 0         0 );
1010             }
1011              
1012             sub add_trigger {
1013 14     14 0 108 my ($self, $name, @args) = @_;
1014 14 50       36 return $self->_croak("on_setting trigger no longer exists")
1015             if $name eq "on_setting";
1016 14 50 33     75 $self->_carp(
1017             "$name trigger deprecated: use before_$name or after_$name instead")
1018             if ($name eq "create" or $name eq "delete");
1019 14         63 $self->SUPER::add_trigger($name => @args);
1020             }
1021              
1022             #----------------------------------------------------------------------
1023             # Inflation
1024             #----------------------------------------------------------------------
1025              
1026             sub add_relationship_type {
1027 4     4 1 21 my ($self, %rels) = @_;
1028 4         23 while (my ($name, $class) = each %rels) {
1029 12         49 $self->_require_class($class);
1030 4     4   29 no strict 'refs';
  4         152  
  4         3176  
1031 12         127 *{"$self\::$name"} = sub {
1032 5     5   46 my $proto = shift;
1033 5         59 $class->set_up($name => $proto => @_);
1034 12         77 };
1035             }
1036             }
1037              
1038             sub _extend_meta {
1039 5     5   89 my ($class, $type, $subtype, $val) = @_;
1040 5   50     8 my %hash = %{ Clone::clone($class->__meta_info || {}) };
  5         39  
1041 5         145 $hash{$type}->{$subtype} = $val;
1042 5         35 $class->__meta_info(\%hash);
1043             }
1044              
1045             sub meta_info {
1046 4     4 0 1067 my ($class, $type, $subtype) = @_;
1047 4         19 my $meta = $class->__meta_info;
1048 4 100       40 return $meta unless $type;
1049 3 50       16 return $meta->{$type} unless $subtype;
1050 0         0 return $meta->{$type}->{$subtype};
1051             }
1052              
1053             sub _simple_bless {
1054 0     0   0 my ($class, $pri) = @_;
1055 0         0 return $class->_init({ $class->primary_column => $pri });
1056             }
1057              
1058             sub _deflated_column {
1059 0     0   0 my ($self, $col, $val) = @_;
1060 0 0 0     0 $val ||= $self->_attrs($col) if ref $self;
1061 0 0       0 return $val unless ref $val;
1062 0 0       0 my $meta = $self->meta_info(has_a => $col) or return $val;
1063 0         0 my ($a_class, %meths) = ($meta->foreign_class, %{ $meta->args });
  0         0  
1064 0 0       0 if (my $deflate = $meths{'deflate'}) {
1065 0 0       0 $val = $val->$deflate(ref $deflate eq 'CODE' ? $self : ());
1066 0 0       0 return $val unless ref $val;
1067             }
1068 0 0       0 return $self->_croak("Can't deflate $col: $val is not a $a_class")
1069             unless UNIVERSAL::isa($val, $a_class);
1070 0 0       0 return $val->id if UNIVERSAL::isa($val => 'Class::DBI');
1071 0         0 return "$val";
1072             }
1073              
1074             #----------------------------------------------------------------------
1075             # SEARCH
1076             #----------------------------------------------------------------------
1077              
1078 0     0 1 0 sub retrieve_all { shift->sth_to_objects('RetrieveAll') }
1079              
1080             sub retrieve_from_sql {
1081 0     0 1 0 my ($class, $sql, @vals) = @_;
1082 0         0 $sql =~ s/^\s*(WHERE)\s*//i;
1083 0         0 return $class->sth_to_objects($class->sql_Retrieve($sql), \@vals);
1084             }
1085              
1086             sub add_searcher {
1087 4     4 0 13 my ($self, %rels) = @_;
1088 4         25 while (my ($name, $class) = each %rels) {
1089 4         13 $self->_require_class($class);
1090 4 50       46 $self->_croak("$class is not a valid Searcher")
1091             unless $class->can('run_search');
1092 4     4   26 no strict 'refs';
  4         7  
  4         911  
1093 4         36 *{"$self\::$name"} = sub {
1094 0     0   0 $class->new(@_)->run_search;
1095 4         16 };
1096             }
1097             }
1098              
1099             # This should really be its own Search subclass. But the _do_search
1100             # version has been publicised as the way to do this. We need to
1101             # deprecate this eventually.
1102              
1103 0     0 1 0 sub search_like { shift->_do_search(LIKE => @_) }
1104              
1105             sub _do_search {
1106 0     0   0 my ($class, $type, @args) = @_;
1107 0         0 $class->_require_class('Class::DBI::Search::Basic');
1108 0         0 my $search = Class::DBI::Search::Basic->new($class, @args);
1109 0         0 $search->type($type);
1110 0         0 $search->run_search;
1111             }
1112              
1113             #----------------------------------------------------------------------
1114             # CONSTRUCTORS
1115             #----------------------------------------------------------------------
1116              
1117             sub add_constructor {
1118 0     0 1 0 my ($class, $method, $fragment) = @_;
1119 0 0       0 return $class->_croak("constructors needs a name") unless $method;
1120 4     4   47 no strict 'refs';
  4         8  
  4         3604  
1121 0         0 my $meth = "$class\::$method";
1122 0 0       0 return $class->_carp("$method already exists in $class")
1123             if *$meth{CODE};
1124             *$meth = sub {
1125 0     0   0 my $self = shift;
1126 0         0 $self->sth_to_objects($self->sql_Retrieve($fragment), \@_);
1127 0         0 };
1128             }
1129              
1130             sub sth_to_objects {
1131 0     0 0 0 my ($class, $sth, $args) = @_;
1132 0 0       0 $class->_croak("sth_to_objects needs a statement handle") unless $sth;
1133 0 0       0 unless (UNIVERSAL::isa($sth => "DBI::st")) {
1134 0         0 my $meth = "sql_$sth";
1135 0         0 $sth = $class->$meth();
1136             }
1137 0         0 my (%data, @rows);
1138 0         0 eval {
1139 0 0       0 $sth->execute(@$args) unless $sth->{Active};
1140 0         0 $sth->bind_columns(\(@data{ @{ $sth->{NAME_lc} } }));
  0         0  
1141 0         0 push @rows, {%data} while $sth->fetch;
1142             };
1143 0 0       0 return $class->_croak("$class can't $sth->{Statement}: $@", err => $@)
1144             if $@;
1145 0         0 return $class->_ids_to_objects(\@rows);
1146             }
1147             *_sth_to_objects = \&sth_to_objects;
1148              
1149             sub _my_iterator {
1150 0     0   0 my $self = shift;
1151 0         0 my $class = $self->iterator_class;
1152 0         0 $self->_require_class($class);
1153 0         0 return $class;
1154             }
1155              
1156             sub _ids_to_objects {
1157 0     0   0 my ($class, $data) = @_;
1158 0 0       0 return $#$data + 1 unless defined wantarray;
1159 0 0       0 return map $class->construct($_), @$data if wantarray;
1160 0         0 return $class->_my_iterator->new($class => $data);
1161             }
1162              
1163             #----------------------------------------------------------------------
1164             # SINGLE VALUE SELECTS
1165             #----------------------------------------------------------------------
1166              
1167             sub _single_row_select {
1168 0     0   0 my ($self, $sth, @args) = @_;
1169 0         0 Carp::confess("_single_row_select is deprecated in favour of select_row");
1170 0         0 return $sth->select_row(@args);
1171             }
1172              
1173             sub _single_value_select {
1174 0     0   0 my ($self, $sth, @args) = @_;
1175 0         0 $self->_carp("_single_value_select is deprecated in favour of select_val");
1176 0         0 return $sth->select_val(@args);
1177             }
1178              
1179 0     0 1 0 sub count_all { shift->sql_single("COUNT(*)")->select_val }
1180              
1181             sub maximum_value_of {
1182 0     0 1 0 my ($class, $col) = @_;
1183 0         0 $class->sql_single("MAX($col)")->select_val;
1184             }
1185              
1186             sub minimum_value_of {
1187 0     0 1 0 my ($class, $col) = @_;
1188 0         0 $class->sql_single("MIN($col)")->select_val;
1189             }
1190              
1191             sub _unique_entries {
1192 0     0   0 my ($class, %tmp) = shift;
1193 0         0 return grep !$tmp{$_}++, @_;
1194             }
1195              
1196             sub _invalid_object_method {
1197 0     0   0 my ($self, $method) = @_;
1198 0         0 $self->_carp(
1199             "$method should be called as a class method not an object method");
1200             }
1201              
1202             #----------------------------------------------------------------------
1203             # misc stuff
1204             #----------------------------------------------------------------------
1205              
1206             sub _extend_class_data {
1207 5     5   94 my ($class, $struct, $key, $value) = @_;
1208 5 100       9 my %hash = %{ $class->$struct() || {} };
  5         33  
1209 5         62 $hash{$key} = $value;
1210 5         32 $class->$struct(\%hash);
1211             }
1212              
1213             my %required_classes; # { required_class => class_that_last_required_it, ... }
1214              
1215             sub _require_class {
1216 23     23   78 my ($self, $load_class) = @_;
1217 23   33     191 $required_classes{$load_class} ||= my $for_class = ref($self) || $self;
      33        
1218              
1219             # return quickly if class already exists
1220 4     4   32 no strict 'refs';
  4         7  
  4         1240  
1221 23 100       28 return if exists ${"$load_class\::"}{ISA};
  23         173  
1222 19         105 (my $load_module = $load_class) =~ s!::!/!g;
1223 19 50       33 return if eval { require "$load_module.pm" };
  19         13277  
1224              
1225             # Only ignore "Can't locate" errors for the specific module we're loading
1226 0 0         return if $@ =~ /^Can't locate \Q$load_module\E\.pm /;
1227              
1228             # Other fatal errors (syntax etc) must be reported (as per base.pm).
1229 0           chomp $@;
1230              
1231             # This error message prefix is especially handy when dealing with
1232             # classes that are being loaded by other classes recursively.
1233             # The final message shows the path, e.g.:
1234             # Foo can't load Bar: Bar can't load Baz: syntax error at line ...
1235 0           $self->_croak("$for_class can't load $load_class: $@");
1236             }
1237              
1238             sub _check_classes { # may automatically call from CHECK block in future
1239 0     0     while (my ($load_class, $by_class) = each %required_classes) {
1240 0 0         next if $load_class->isa("Class::DBI");
1241 0           $by_class->_croak(
1242             "Class $load_class used by $by_class has not been loaded");
1243             }
1244             }
1245              
1246             1;
1247              
1248             __END__