File Coverage

blib/lib/DBIx/DBO/Query.pm
Criterion Covered Total %
statement 473 487 97.1
branch 167 206 81.0
condition 93 130 71.5
subroutine 68 68 100.0
pod 38 40 95.0
total 839 931 90.1


line stmt bran cond sub pod time code
1             package DBIx::DBO::Query;
2              
3 14     14   275 use 5.014;
  14         50  
4 14     14   75 use warnings;
  14         22  
  14         881  
5 14     14   81 use DBIx::DBO;
  14         25  
  14         530  
6              
7 14     14   81 use Carp 'croak';
  14         37  
  14         1345  
8 14     14   23277 use Devel::Peek 'SvREFCNT';
  14         7455  
  14         100  
9 14     14   10081 use Hash::Util 'hv_store';
  14         60218  
  14         184  
10 14     14   1666 use Scalar::Util 'weaken';
  14         28  
  14         1099  
11              
12 14     14   86 use overload '**' => \&column, fallback => 1;
  14         24  
  14         124  
13              
14 13     13 1 154 sub table_class { $_[0]{DBO}->table_class }
15 21     21 1 100 sub row_class { $_[0]{DBO}->row_class }
16              
17             *_isa = \&DBIx::DBO::DBD::_isa;
18              
19             =head1 NAME
20              
21             DBIx::DBO::Query - An OO interface to SQL queries and results. Encapsulates an entire query in an object.
22              
23             =head1 SYNOPSIS
24              
25             # Create a Query object by JOINing 2 tables
26             my $query = $dbo->query('my_table', 'my_other_table');
27            
28             # Get the Table objects from the query
29             my($table1, $table2) = $query->tables;
30            
31             # Add a JOIN ON clause
32             $query->join_on($table1 ** 'login', '=', $table2 ** 'username');
33            
34             # Find our ancestors, and order by age (oldest first)
35             $query->where('name', '=', 'Adam');
36             $query->where('name', '=', 'Eve');
37             $query->order_by({ COL => 'age', ORDER => 'DESC' });
38            
39             # New Query using a LEFT JOIN
40             ($query, $table1) = $dbo->query('my_table');
41             $table2 = $query->join_table('another_table', 'LEFT');
42             $query->join_on($table1 ** 'parent_id', '=', $table2 ** 'child_id');
43            
44             # Find those not aged between 20 and 30.
45             $query->where($table1 ** 'age', '<', 20, FORCE => 'OR'); # Force OR so that we get: (age < 20 OR age > 30)
46             $query->where($table1 ** 'age', '>', 30, FORCE => 'OR'); # instead of the default: (age < 20 AND age > 30)
47              
48             =head1 DESCRIPTION
49              
50             A C object represents rows from a database (from one or more tables). This module makes it easy, not only to fetch and use the data in the returned rows, but also to modify the query to return a different result set.
51              
52             =head1 METHODS
53              
54             =head3 C
55              
56             DBIx::DBO::Query->new($dbo, $table1, ...);
57             # or
58             $dbo->query($table1, ...);
59              
60             Create a new C object from the tables specified.
61             In scalar context, just the C object will be returned.
62             In list context, the C object and L objects will be returned for each table specified.
63             Tables can be specified with the same arguments as L or another Query can be used as a subquery.
64              
65             my($query, $table1, $table2) = DBIx::DBO::Query->new($dbo, 'customers', ['history', 'transactions']);
66              
67             You can also pass in a Query instead of a Table to use that query as a subquery.
68              
69             my $subquery = DBIx::DBO::Query->new($dbo, 'history.transactions');
70             my $query = DBIx::DBO::Query->new($dbo, 'customers', $subquery);
71             # SELECT * FROM customers, (SELECT * FROM history.transactions) t1;
72              
73             =cut
74              
75             sub new {
76 29     29 1 129 my $proto = shift;
77 29 50       50 eval { $_[0]->isa('DBIx::DBO') } or croak 'Invalid DBO Object';
  29         206  
78 29   33     117 my $class = ref($proto) || $proto;
79 29         153 $class->_init(@_);
80             }
81              
82             sub _init {
83 29     29   64 my $class = shift;
84 29         125 my $me = { DBO => shift, sql => undef, Columns => [] };
85 29 100       88 croak 'No table specified in new Query' unless @_;
86 28         86 bless $me, $class;
87              
88 28         75 for my $table (@_) {
89 29         118 $me->join_table($table);
90             }
91 25         111 $me->reset;
92 25 100       124 return wantarray ? ($me, $me->tables) : $me;
93             }
94              
95             sub _build_data {
96 1030     1030   2042 $_[0]->{build_data};
97             }
98              
99             =head3 C
100              
101             $query->reset;
102              
103             Reset the query, start over with a clean slate.
104             Resets the columns to return, removes all the WHERE, DISTINCT, HAVING, LIMIT, GROUP BY & ORDER BY clauses.
105              
106             B: This will not remove the JOINs or JOIN ON clauses.
107              
108             =cut
109              
110             sub reset {
111 27     27 1 48 my $me = shift;
112 27         79 $me->_inactivate;
113 27         118 $me->unwhere;
114 27         114 $me->distinct(0);
115 27         97 $me->show;
116 27         102 $me->group_by;
117 27         102 $me->order_by;
118 27         91 $me->unhaving;
119 27         83 $me->limit;
120             }
121              
122             =head3 C
123              
124             Return a list of L or Query objects that appear in the C clause for this query.
125              
126             =cut
127              
128             sub tables {
129 682     682 1 956 @{$_[0]->{Tables}};
  682         2328  
130             }
131              
132             sub _table_idx {
133 41     41   119 my($me, $tbl) = @_;
134 41         69 for my $i (0 .. $#{$me->{Tables}}) {
  41         354  
135 34 100       177 return $i if $tbl == $me->{Tables}[$i];
136             }
137 24         92 return undef;
138             }
139              
140             sub _table_alias {
141 450     450   867 my($me, $tbl) = @_;
142              
143             # This means it's checking for an aliased column in this Query
144 450 100       1457 return undef if $me == $tbl;
145              
146             # Don't use aliases, when there's only 1 table unless its a subquery
147 438 100 66     1019 return undef if $me->tables == 1 and _isa($tbl, 'DBIx::DBO::Table');
148              
149 99   66     430 my $_from_alias = ($me->{build_data}{_super_query} // $me)->_build_data->{_from_alias} //= {};
      100        
150 99   66     511 return $_from_alias->{$tbl} //= 't'.scalar(keys %$_from_alias);
151             }
152              
153             sub _as_table {
154 39     39   42 my($me, $super_query) = @_;
155 39         72 local $me->{build_data}{_super_query} = $super_query;
156 39         90 return '('.$me->{DBO}{dbd_class}->_build_sql_select($me).')';
157             }
158              
159             =head3 C
160              
161             Return a list of column names that will be returned by L.
162              
163             =cut
164              
165             sub columns {
166 8     8 1 23 my($me) = @_;
167              
168 3         9 @{$me->{Columns}} = do {
169 3 100       5 if (@{$me->{build_data}{select}}) {
  3         12  
170             map {
171 2 100       7 _isa($_, 'DBIx::DBO::Table', 'DBIx::DBO::Query') ? ($_->columns) : $me->_build_col_val_name(@$_)
172 1         2 } @{$me->{build_data}{select}};
  1         4  
173             } else {
174 2         3 map { $_->columns } @{$me->{Tables}};
  3         10  
  2         7  
175             }
176 8 100       14 } unless @{$me->{Columns}};
  8         33  
177              
178 8         15 @{$me->{Columns}};
  8         72  
179             }
180              
181             sub _build_col_val_name {
182 26     26   65 my($me, $fld, $func, $opt) = @_;
183 26 100       99 return $opt->{AS} if exists $opt->{AS};
184              
185             my @ary = map {
186 15 50       35 if (not ref $_) {
  9 100       44  
    50          
    50          
187 0         0 $me->rdbh->quote($_);
188             } elsif (_isa($_, 'DBIx::DBO::Column')) {
189 8         29 $_->[1];
190             } elsif (ref $_ eq 'SCALAR') {
191 0         0 $$_;
192             } elsif (_isa($_, 'DBIx::DBO::Query')) {
193 1         3 $_->_as_table($me);
194             }
195             } @$fld;
196 15 100       65 return $ary[0] unless defined $func;
197 6         30 $func =~ s/$DBIx::DBO::DBD::placeholder/shift @ary/ego;
  0         0  
198 6         27 return $func;
199             }
200              
201             =head3 C
202              
203             $query->column($alias_or_column_name);
204             $query ** $column_name;
205              
206             Returns a reference to a column for use with other methods.
207             The C<**> method is a shortcut for the C method.
208              
209             =cut
210              
211             sub column {
212 6     6 1 23 my($me, $col) = @_;
213 6         10 my @show;
214 6 100       10 @show = @{$me->{build_data}{select}} or @show = @{$me->{Tables}};
  2         3  
  6         29  
215 6         31 for my $fld (@show) {
216             return $me->{Column}{$col} //= bless [$me, $col], 'DBIx::DBO::Column'
217             if (_isa($fld, 'DBIx::DBO::Table') and exists $fld->{Column_Idx}{$col})
218 1         5 or (_isa($fld, 'DBIx::DBO::Query') and eval { $fld->column($col) })
219 10 100 100     32 or (ref($fld) eq 'ARRAY' and exists $fld->[2]{AS} and $col eq $fld->[2]{AS});
      100        
      66        
      100        
      100        
      100        
      100        
220             }
221 1         14 croak 'No such column: '.$me->{DBO}{dbd_class}->_qi($me, $col);
222             }
223              
224             sub _inner_col {
225 51     51   142 my($me, $col, $_check_aliases) = @_;
226 51 50       129 $_check_aliases = $me->{DBO}{dbd_class}->_alias_preference($me, 'column') unless defined $_check_aliases;
227 51         77 my $column;
228 51 100 100     205 return $column if $_check_aliases == 1 and $column = $me->_check_alias($col);
229 45         133 for my $tbl ($me->tables) {
230 45 100       317 return $tbl->column($col) if exists $tbl->{Column_Idx}{$col};
231             }
232 1 50 33     10 return $column if $_check_aliases == 2 and $column = $me->_check_alias($col);
233 0 0       0 croak 'No such column'.($_check_aliases ? '/alias' : '').': '.$me->{DBO}{dbd_class}->_qi($me, $col);
234             }
235              
236             sub _check_alias {
237 35     35   85 my($me, $col) = @_;
238 35         95 for my $fld (@{$me->{build_data}{select}}) {
  35         207  
239             return $me->{Column}{$col} //= bless [$me, $col], 'DBIx::DBO::Column'
240 32 100 100     288 if ref($fld) eq 'ARRAY' and exists $fld->[2]{AS} and $col eq $fld->[2]{AS};
      100        
      100        
241             }
242             }
243              
244             =head3 C
245              
246             $query->show(@columns);
247             $query->show($table1, { COL => $table2 ** 'name', AS => 'name2' });
248             $query->show($table1 ** 'id', { FUNC => 'UCASE(?)', COL => 'name', AS => 'alias' }, ...
249              
250             List which columns to return when we L.
251             If called without arguments all columns will be shown, C
252             If you use a Table object, all the columns from that table will be shown, C
253             You can also add a subquery by passing that Query as the value with an alias, Eg.
254              
255             $query->show({ VAL => $subquery, AS => 'sq' }, ...);
256             # SELECT ($subquery_sql) AS sq ...
257              
258             =cut
259              
260             # TODO: Keep track of all aliases in use and die if a used alias is removed
261             sub show {
262 48     48 1 1809 my $me = shift;
263 48         124 $me->_inactivate;
264 48         71 undef @{$me->{build_data}{select}};
  48         131  
265 48         76 undef @{$me->{Columns}};
  48         113  
266 48         122 for my $fld (@_) {
267 30 100       98 if (_isa($fld, 'DBIx::DBO::Table', 'DBIx::DBO::Query')) {
268 7 100       59 croak 'Invalid table to show' unless defined $me->_table_idx($fld);
269 6         11 push @{$me->{build_data}{select}}, $fld;
  6         22  
270 6         10 push @{$me->{Columns}}, $fld->columns;
  6         26  
271 6         22 next;
272             }
273             # If the $fld is just a scalar use it as a column name not a value
274 23         155 my @col = $me->{DBO}{dbd_class}->_parse_col_val($me, $fld, Aliases => 0);
275 22         46 push @{$me->{build_data}{select}}, \@col;
  22         63  
276 22         36 push @{$me->{Columns}}, $me->_build_col_val_name(@col);
  22         78  
277             }
278             }
279              
280             =head3 C
281              
282             $query->distinct(1);
283              
284             Takes a boolean argument to add or remove the DISTINCT clause for the returned rows.
285              
286             =cut
287              
288             sub distinct {
289 29     29 1 49 my $me = shift;
290 29         103 $me->_inactivate;
291 29         58 my $distinct = $me->{build_data}{Show_Distinct};
292 29 100       144 $me->{build_data}{Show_Distinct} = shift() ? 1 : undef if @_;
    50          
293             }
294              
295             =head3 C
296              
297             $query->join_table($table, $join_type);
298              
299             Join a table onto the query, creating a L object if needed.
300             This will perform a comma (", ") join unless $join_type is specified.
301              
302             Tables can be specified with the same arguments as L or another Query can be used as a subquery.
303              
304             Valid join types are any accepted by the DB. Eg: C<'JOIN'>, C<'LEFT'>, C<'RIGHT'>, C (for comma join), C<'INNER'>, C<'OUTER'>, ...
305              
306             Returns the Table or Query object added.
307              
308             =cut
309              
310             sub join_table {
311 36     36 1 1280 my($me, $tbl, $type) = @_;
312 36 100       114 if (_isa($tbl, 'DBIx::DBO::Table')) {
    100          
313 21 100       72 croak 'This table is already in this query' if defined $me->_table_idx($tbl);
314 20 100       195 croak 'This table is from a different DBO connection' if $me->{DBO} != $tbl->{DBO};
315             } elsif (_isa($tbl, 'DBIx::DBO::Query')) {
316             # Subquery
317 2 50       7 croak 'This table is from a different DBO connection' if $me->{DBO} != $tbl->{DBO};
318 2         7 $tbl->_add_up_query($me);
319             } else {
320 13         58 $tbl = $me->table_class->new($me->{DBO}, $tbl);
321             }
322 31         155 $me->_inactivate;
323 31 100       69 if (defined $type) {
324 4         39 $type =~ s/^\s*/ /;
325 4         26 $type =~ s/\s*$/ /;
326 4         13 $type = uc $type;
327 4 100       26 $type .= 'JOIN ' if $type !~ /\bJOIN\b/;
328             } else {
329 27         59 $type = ', ';
330             }
331 31         42 push @{$me->{Tables}}, $tbl;
  31         127  
332 31         100 push @{$me->{build_data}{join_types}}, $type;
  31         111  
333 31         44 push @{$me->{Join_Bracket_Refs}}, [];
  31         80  
334 31         71 push @{$me->{Join_Brackets}}, [];
  31         89  
335 31         67 undef @{$me->{Columns}};
  31         63  
336 31         125 return $tbl;
337             }
338              
339             =head3 C
340              
341             $query->join_on($table_object, $expression1, $operator, $expression2);
342             $query->join_on($table2, $table1 ** 'id', '=', $table2 ** 'id');
343              
344             Join tables on a specific WHERE clause. The first argument is the table object being joined onto.
345             Then a JOIN ON condition follows, which uses the same arguments as L.
346              
347             =cut
348              
349             sub join_on {
350 9     9 1 1301 my $me = shift;
351 9         21 my $t2 = shift;
352 9 100       55 my $i = $me->_table_idx($t2) or croak 'Invalid table object to join onto';
353              
354 8         121 my($col1, $col1_func, $col1_opt) = $me->{DBO}{dbd_class}->_parse_col_val($me, shift);
355 7         19 my $op = shift;
356 7         29 my($col2, $col2_func, $col2_opt) = $me->{DBO}{dbd_class}->_parse_col_val($me, shift);
357              
358             # Validate the fields
359 7         40 $me->_validate_where_fields(@$col1, @$col2);
360              
361             # Force a new search
362 7         49 $me->_inactivate;
363              
364             # Find the current join reference
365 7   100     47 my $ref = $me->{build_data}{"join$i"} ||= [];
366 7         23 $ref = $ref->[$_] for (@{$me->{Join_Bracket_Refs}[$i]});
  7         27  
367              
368 7 100       29 $me->{build_data}{join_types}[$i] = ' JOIN ' if $me->{build_data}{join_types}[$i] eq ', ';
369 7         39 $me->_add_where($ref, $op, $col1, $col1_func, $col1_opt, $col2, $col2_func, $col2_opt, @_);
370             }
371              
372             =head3 C, C
373              
374             $query->open_join_on_bracket($table, 'OR');
375             $query->join_on(...
376             $query->close_join_on_bracket($table);
377              
378             Equivalent to L, but for the JOIN ON clause.
379             The first argument is the table being joined onto.
380              
381             =cut
382              
383             sub open_join_on_bracket {
384 3     3 1 1098 my $me = shift;
385 3 100       60 my $tbl = shift or croak 'Invalid table object for join on clause';
386 2 100       10 my $i = $me->_table_idx($tbl) or croak 'No such table object in the join';
387 1   50     12 $me->_open_bracket($me->{Join_Brackets}[$i], $me->{Join_Bracket_Refs}[$i], $me->{build_data}{"join$i"} ||= [], @_);
388             }
389              
390             sub close_join_on_bracket {
391 3     3 1 1141 my $me = shift;
392 3 100       29 my $tbl = shift or croak 'Invalid table object for join on clause';
393 2 100       8 my $i = $me->_table_idx($tbl) or croak 'No such table object in the join';
394 1         8 $me->_close_bracket($me->{Join_Brackets}[$i], $me->{Join_Bracket_Refs}[$i]);
395             }
396              
397             =head3 C
398              
399             Restrict the query with the condition specified (WHERE clause).
400              
401             $query->where($expression1, $operator, $expression2, %options);
402              
403             C<$operator> is one of: C<'=', '', '<', 'E', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'BETWEEN', 'NOT BETWEEN', ...>
404              
405             C<$expression>s can be any of the following:
406              
407             =over 4
408              
409             =item *
410              
411             A scalar value: C<123> or C<'hello'> (or for C<$expression1> a column name: C<'id'>)
412              
413             $query->where('name', '<>', 'John');
414              
415             =item *
416              
417             A scalar reference: C<\"22 * 3"> (These are passed unquoted in the SQL statement!)
418              
419             $query->where(\'CONCAT(id, name)', '=', \'"22John"');
420              
421             =item *
422              
423             An array reference: C<[1, 3, 5]> (Used with C and C etc)
424              
425             $query->where('id', 'NOT IN', [21, 22, 25, 39]);
426              
427             =item *
428              
429             A Column object: C<$table ** 'id'> or C<$table-Ecolumn('id')>
430              
431             $query->where($table1 ** 'id', '=', $table2 ** 'id');
432              
433             =item *
434              
435             A Query object, to be used as a subquery.
436              
437             $query->where('id', '>', $subquery);
438              
439             =item *
440              
441             A hash reference: see L
442              
443             =back
444              
445             Multiple C expressions are combined I using the preferred aggregator C<'AND'> (unless L was used to change this). So that when you add where expressions to the query, they will be Ced together. However some expressions that refer to the same column will automatically be Ced instead where this makes sense, currently: C<'='>, C<'IS NULL'>, C<'E=E'>, C<'IN'> and C<'BETWEEN'>. Similarly, when the preferred aggregator is C<'OR'> the following operators will be Ced together: C<'!='>, C<'IS NOT NULL'>, C<'EE'>, C<'NOT IN'> and C<'NOT BETWEEN'>.
446             The chosen aggregator can also be overriden by passing a C option with a string C<'AND'> or C<'OR'>.
447              
448             $query->where('id', '=', 5);
449             $query->where('name', '=', 'Bob');
450             $query->where('id', '=', 7);
451             $query->where('age', '<', 20, FORCE => 'OR');
452             $query->where('age', '>', 30, FORCE => 'OR');
453             $query->where(...
454             # Produces: WHERE ("id" = 5 OR "id" = 7) AND "name" = 'Bob' AND ("age" < 20 OR "age" > 30) AND ...
455              
456             =cut
457              
458             sub where {
459 22     22 1 2946 my $me = shift;
460              
461             # If the $fld is just a scalar use it as a column name not a value
462 22         139 my($fld, $fld_func, $fld_opt) = $me->{DBO}{dbd_class}->_parse_col_val($me, shift);
463 21         120 my $op = shift;
464 21         152 my($val, $val_func, $val_opt) = $me->{DBO}{dbd_class}->_parse_val($me, shift, Check => 'Auto');
465              
466             # Validate the fields
467 20         97 $me->_validate_where_fields(@$fld, @$val);
468              
469             # Force a new search
470 20         70 $me->_inactivate;
471              
472             # Find the current where reference
473 20   100     94 my $ref = $me->{build_data}{where} ||= [];
474 20         34 $ref = $ref->[$_] for (@{$me->{Where_Bracket_Refs}});
  20         63  
475              
476 20         76 $me->_add_where($ref, $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, @_);
477             }
478              
479             =head3 C
480              
481             $query->unwhere();
482             $query->unwhere($column);
483              
484             Removes all previously added L restrictions for a column.
485             If no column is provided, the I WHERE clause is removed.
486              
487             =cut
488              
489             sub unwhere {
490 29     29 1 54 my $me = shift;
491 29         117 $me->_del_where('where', @_);
492             }
493              
494             sub _validate_where_fields {
495 30     30   62 my $me = shift;
496 30         298 for my $f (@_) {
497 60 100       136 if (_isa($f, 'DBIx::DBO::Column')) {
    100          
498 32         133 $me->{DBO}{dbd_class}->_valid_col($me, $f);
499             } elsif (my $type = ref $f) {
500 3 50 66     17 croak 'Invalid value type: '.$type if $type ne 'SCALAR' and not _isa($f, 'DBIx::DBO::Query');
501             }
502             }
503             }
504              
505             sub _del_where {
506 58     58   81 my $me = shift;
507 58         106 my $clause = shift;
508              
509 58 100       124 if (@_) {
510 4         873 require Data::Dumper;
511 4         10375 my($fld, $fld_func, $fld_opt) = $me->{DBO}{dbd_class}->_parse_col_val($me, shift);
512             # TODO: Validate the fields?
513              
514 4 50       19 return unless exists $me->{build_data}{$clause};
515             # Find the current where reference
516 4         10 my $ref = $me->{build_data}{$clause};
517 4         14 $ref = $ref->[$_] for (@{$me->{"\u${clause}_Bracket_Refs"}});
  4         25  
518              
519 4         11 local $Data::Dumper::Indent = 0;
520 4         12 local $Data::Dumper::Maxdepth = 2;
521             my @match = grep {
522 4         17 Data::Dumper::Dumper($fld, $fld_func, $fld_opt) eq Data::Dumper::Dumper(@{$ref->[$_]}[1,2,3])
  11         473  
  11         847  
523             } 0 .. $#$ref;
524              
525 4 100       389 if (@_) {
526 1         3 my $op = shift;
527 1         7 my($val, $val_func, $val_opt) = $me->{DBO}{dbd_class}->_parse_val($me, shift, Check => 'Auto');
528              
529             @match = grep {
530 1         3 Data::Dumper::Dumper($op, $val, $val_func, $val_opt) eq Data::Dumper::Dumper(@{$ref->[$_]}[0,4,5,6])
  3         137  
  3         141  
531             } @match;
532             }
533 4         69 splice @$ref, $_, 1 for reverse @match;
534             } else {
535 54         183 delete $me->{build_data}{$clause};
536 54         238 $me->{"\u${clause}_Bracket_Refs"} = [];
537 54         165 $me->{"\u${clause}_Brackets"} = [];
538             }
539             # This forces a new search
540 58         150 $me->_inactivate;
541             }
542              
543             ##
544             # This will add an arrayref to the $ref given.
545             # The arrayref will contain 8 values:
546             # $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, $force
547             # $op is the operator (those supported differ by DBD)
548             # $fld_func is undef or a scalar of the form '? AND ?' or 'POSITION(? IN ?)'
549             # $fld is an arrayref of columns/values for use with $fld_func
550             # $val_func is similar to $fld_func
551             # $val is an arrayref of values for use with $val_func
552             # $force is one of undef / 'AND' / 'OR' which if defined, overrides the default aggregator
553             ##
554             sub _add_where {
555 30     30   61 my $me = shift;
556 30         103 my($ref, $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, %opt) = @_;
557              
558             croak 'Invalid option, FORCE must be AND or OR'
559 30 50 66     171 if defined $opt{FORCE} and $opt{FORCE} ne 'AND' and $opt{FORCE} ne 'OR';
      66        
560              
561             # Deal with NULL values
562 30 100       85 $op = '<>' if $op eq '!='; # Use the valid SQL op
563 30 100 100     155 if (@$val == 1 and !defined $val->[0] and !defined $val_func) {
      66        
564 2 100       10 if ($op eq '=') { $op = 'IS'; $val_func = 'NULL'; delete $val->[0]; }
  1 50       3  
  1         2  
  1         4  
565 1         2 elsif ($op eq '<>') { $op = 'IS NOT'; $val_func = 'NULL'; delete $val->[0]; }
  1         3  
  1         3  
566             }
567              
568             # Deal with array values: BETWEEN & IN
569 30 100       143 unless (defined $val_func) {
570 19 100 100     163 if ($op eq 'BETWEEN' or $op eq 'NOT BETWEEN') {
    100 100        
    100          
571 3 100 66     23 croak 'Invalid value argument, BETWEEN requires 2 values'
572             if ref $val ne 'ARRAY' or @$val != 2;
573 2         18 $val_func = $me->{DBO}{dbd_class}->PLACEHOLDER.' AND '.$me->{DBO}{dbd_class}->PLACEHOLDER;
574             } elsif ($op eq 'IN' or $op eq 'NOT IN') {
575 3 50       12 if (ref $val eq 'ARRAY') {
576 3 50       10 croak 'Invalid value argument, IN requires at least 1 value' if @$val == 0;
577             } else {
578 0         0 $val = [ $val ];
579             }
580             # Add to previous 'IN' and 'NOT IN' Where expressions
581 3         20 my $op_ag = $me->{DBO}{dbd_class}->_op_ag($op);
582 3 50 33     14 unless ($opt{FORCE} and $opt{FORCE} ne $op_ag) {
583 3         17 for my $lim (grep $$_[0] eq $op, @$ref) {
584             # $fld and $$lim[1] are always ARRAY refs
585 1 50       3 next if "@{$$lim[1]}" ne "@$fld";
  1         9  
586 1 50 33     36 last if $$lim[7] and $$lim[7] ne $op_ag;
587 1 50       5 last if $$lim[5] ne '('.join(',', ($me->{DBO}{dbd_class}->PLACEHOLDER) x @{$$lim[4]}).')';
  1         8  
588 1         3 push @{$$lim[4]}, @$val;
  1         4  
589 1         5 $$lim[5] = '('.join(',', ($me->{DBO}{dbd_class}->PLACEHOLDER) x @{$$lim[4]}).')';
  1         5  
590 1         6 return;
591             }
592             }
593 2         22 $val_func = '('.join(',', ($me->{DBO}{dbd_class}->PLACEHOLDER) x @$val).')';
594             } elsif (@$val != 1) {
595             # Check that there is only 1 placeholder
596 1         10 croak 'Wrong number of fields/values, called with '.@$val.' while needing 1';
597             }
598             }
599              
600 27         50 push @{$ref}, [ $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, $opt{FORCE} ];
  27         211  
601             }
602              
603             =head3 C, C
604              
605             $query->open_bracket('OR');
606             $query->where( ...
607             $query->where( ...
608             $query->close_bracket;
609              
610             Used to group C expressions together in parenthesis using either C<'AND'> or C<'OR'> as the preferred aggregator.
611             All the C calls made between C and C will be inside the parenthesis.
612              
613             Without any parenthesis C<'AND'> is the preferred aggregator.
614              
615             =cut
616              
617             sub open_bracket {
618 2     2 1 5 my $me = shift;
619 2   50     13 $me->_open_bracket($me->{Where_Brackets}, $me->{Where_Bracket_Refs}, $me->{build_data}{where} ||= [], @_);
620             }
621              
622             sub _open_bracket {
623 3     3   10 my($me, $brackets, $bracket_refs, $ref, $ag) = @_;
624 3 50 33     29 croak 'Invalid argument MUST be AND or OR' if !$ag or $ag !~ /^(AND|OR)$/;
625 3 100       11 my $last = @$brackets ? $brackets->[-1] : 'AND';
626 3 50       11 if ($ag ne $last) {
627             # Find the current data reference
628 3         9 $ref = $ref->[$_] for @$bracket_refs;
629              
630 3         7 push @$ref, [];
631 3         9 push @$bracket_refs, $#$ref;
632             }
633 3         16 push @$brackets, $ag;
634             }
635              
636             sub close_bracket {
637 2     2 1 6 my $me = shift;
638 2         9 $me->_close_bracket($me->{Where_Brackets}, $me->{Where_Bracket_Refs});
639             }
640              
641             sub _close_bracket {
642 3     3   9 my($me, $brackets, $bracket_refs) = @_;
643 3 50       5 my $ag = pop @{$brackets} or croak "Can't close bracket with no open bracket!";
  3         13  
644 3 100       12 my $last = @$brackets ? $brackets->[-1] : 'AND';
645 3 50       10 pop @$bracket_refs if $last ne $ag;
646 3         12 return $ag;
647             }
648              
649             =head3 C
650              
651             $query->group_by('column', ...);
652             $query->group_by($table ** 'column', ...);
653             $query->group_by({ COL => $table ** 'column', ORDER => 'DESC' }, ...);
654              
655             Group the results by the column(s) listed. This will replace the GROUP BY clause.
656             To remove the GROUP BY clause simply call C without any columns.
657              
658             =cut
659              
660             sub group_by {
661 30     30 1 48 my $me = shift;
662 30         1831 $me->_inactivate;
663 30         43 undef @{$me->{build_data}{group}};
  30         96  
664 30         75 for my $col (@_) {
665 3         17 my @group = $me->{DBO}{dbd_class}->_parse_col_val($me, $col);
666 3         8 push @{$me->{build_data}{group}}, \@group;
  3         20  
667             }
668             }
669              
670             =head3 C
671              
672             Restrict the query with the condition specified (HAVING clause). This takes the same arguments as L.
673              
674             $query->having($expression1, $operator, $expression2);
675              
676             =cut
677              
678             sub having {
679 3     3 1 6 my $me = shift;
680              
681             # If the $fld is just a scalar use it as a column name not a value
682 3         16 my($fld, $fld_func, $fld_opt) = $me->{DBO}{dbd_class}->_parse_col_val($me, shift);
683 3         9 my $op = shift;
684 3         15 my($val, $val_func, $val_opt) = $me->{DBO}{dbd_class}->_parse_val($me, shift, Check => 'Auto');
685              
686             # Validate the fields
687 3         15 $me->_validate_where_fields(@$fld, @$val);
688              
689             # Force a new search
690 3         10 $me->_inactivate;
691              
692             # Find the current having reference
693 3   100     15 my $ref = $me->{build_data}{having} ||= [];
694 3         7 $ref = $ref->[$_] for (@{$me->{Having_Bracket_Refs}});
  3         9  
695              
696 3         12 $me->_add_where($ref, $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, @_);
697             }
698              
699             =head3 C
700              
701             $query->unhaving();
702             $query->unhaving($column);
703              
704             Removes all previously added L restrictions for a column.
705             If no column is provided, the I HAVING clause is removed.
706              
707             =cut
708              
709             sub unhaving {
710 29     29 1 81 my $me = shift;
711 29         98 $me->_del_where('having', @_);
712             }
713              
714             =head3 C
715              
716             $query->order_by('column', ...);
717             $query->order_by($table ** 'column', ...);
718             $query->order_by({ COL => $table ** 'column', ORDER => 'DESC' }, ...);
719              
720             Order the results by the column(s) listed. This will replace the ORDER BY clause.
721             To remove the ORDER BY clause simply call C without any columns.
722              
723             =cut
724              
725             sub order_by {
726 38     38 1 69 my $me = shift;
727 38         117 $me->_inactivate;
728 38         78 undef @{$me->{build_data}{order}};
  38         102  
729 38         90 for my $col (@_) {
730 10         78 my @order = $me->{DBO}{dbd_class}->_parse_col_val($me, $col);
731 10         26 push @{$me->{build_data}{order}}, \@order;
  10         55  
732             }
733             }
734              
735             =head3 C
736              
737             $query->limit;
738             $query->limit($rows);
739             $query->limit($rows, $offset);
740              
741             Limit the maximum number of rows returned to C<$rows>, optionally skipping the first C<$offset> rows.
742             When called without arguments or if C<$rows> is undefined, the limit is removed.
743              
744             NB. Oracle does not support pagging prior to version 12c, so this has been implemented in software,
745             , but if an offset is given, an extra column "_DBO_ROWNUM_" is added to the Query to achieve this.
746             TODO: Implement the new "FIRST n / NEXT n" clause if connected to a 12c database.
747              
748             =cut
749              
750             sub limit {
751 31     31 1 93 my($me, $rows, $offset) = @_;
752 31         83 $me->_inactivate;
753 31 100       155 return undef $me->{build_data}{limit} unless defined $rows;
754 4   33     52 /^\d+$/ or croak "Invalid argument '$_' in limit" for grep defined, $rows, $offset;
755 4         11 @{$me->{build_data}{limit}} = ($rows, $offset);
  4         22  
756             }
757              
758             =head3 C
759              
760             $query->arrayref;
761             $query->arrayref(\%attr);
762              
763             Run the query using Lselectall_arrayref|DBI/"selectall_arrayref"> which returns the result as an arrayref.
764             You can specify a slice by including a 'Slice' or 'Columns' attribute in C<%attr> - See Lselectall_arrayref|DBI/"selectall_arrayref">.
765              
766             =cut
767              
768             sub arrayref {
769 3     3 1 10 my($me, $attr) = @_;
770             $me->{DBO}{dbd_class}->_selectall_arrayref($me, $me->sql, $attr,
771 3         81 $me->{DBO}{dbd_class}->_bind_params_select($me));
772             }
773              
774             =head3 C
775              
776             $query->hashref($key_field);
777             $query->hashref($key_field, \%attr);
778              
779             Run the query using Lselectall_hashref|DBI/"selectall_hashref"> which returns the result as an hashref.
780             C<$key_field> defines which column, or columns, are used as keys in the returned hash.
781              
782             =cut
783              
784             sub hashref {
785 1     1 1 4 my($me, $key, $attr) = @_;
786             $me->{DBO}{dbd_class}->_selectall_hashref($me, $me->sql, $key, $attr,
787 1         6 $me->{DBO}{dbd_class}->_bind_params_select($me));
788             }
789              
790             =head3 C
791              
792             $query->col_arrayref;
793             $query->col_arrayref(\%attr);
794              
795             Run the query using Lselectcol_arrayref|DBI/"selectcol_arrayref"> which returns the result as an arrayref of the values of each row in one array. By default it pushes all the columns requested by the L method onto the result array (this differs from the C). Or to specify which columns to include in the result use the 'Columns' attribute in C<%attr> - see Lselectcol_arrayref|DBI/"selectcol_arrayref">.
796              
797             =cut
798              
799             sub col_arrayref {
800 3     3 1 9 my($me, $attr) = @_;
801 3         12 my($sql, @bind) = ($me->sql, $me->{DBO}{dbd_class}->_bind_params_select($me));
802 3         19 $me->{DBO}{dbd_class}->_sql($me, $sql, @bind);
803 3 50       12 my $sth = $me->rdbh->prepare($sql, $attr) or return;
804 3 100       637 unless (defined $attr->{Columns}) {
805             # Some drivers don't provide $sth->{NUM_OF_FIELDS} until after execute is called
806 1 50       17 if ($sth->{NUM_OF_FIELDS}) {
807 1         10 $attr->{Columns} = [1 .. $sth->{NUM_OF_FIELDS}];
808             } else {
809 0 0       0 $sth->execute(@bind) or return;
810 0         0 my @col;
811 0 0       0 if (my $max = $attr->{MaxRows}) {
812 0   0     0 push @col, @$_ while 0 < $max-- and $_ = $sth->fetch;
813             } else {
814 0         0 push @col, @$_ while $_ = $sth->fetch;
815             }
816 0         0 return \@col;
817             }
818             }
819 3         13 return $me->rdbh->selectcol_arrayref($sth, $attr, @bind);
820             }
821              
822             =head3 C
823              
824             my $row = $query->fetch;
825              
826             Fetch the next row from the query. This will run/rerun the query if needed.
827              
828             Returns a L object or undefined if there are no more rows.
829              
830             =cut
831              
832             sub fetch {
833 31     31 1 34907 my $me = $_[0];
834             # Prepare and/or execute the query if needed
835 31 50 66     231 exists $me->{cache} or $me->{Active} or $me->run
      66        
836             or croak $me->rdbh->errstr;
837             # Detach the old row if there is still another reference to it
838 31 100 100     118 if (defined $me->{Row} and SvREFCNT(${$me->{Row}}) > 1) {
  23         110  
839 8         31 $me->{Row}->_detach;
840             }
841              
842 31         100 my $row = $me->row;
843 31 100       95 if (exists $me->{cache}) {
844 1 50       4 if ($me->{cache}{idx} < @{$me->{cache}{data}}) {
  1         2  
845 1         5 @{$me->{cache}{array}}[0..$#{$me->{cache}{array}}] = @{$me->{cache}{data}[$me->{cache}{idx}++]};
  1         3  
  1         3  
  1         3  
846 1         2 $$row->{array} = $me->{cache}{array};
847 1         3 $$row->{hash} = $me->{hash};
848 1         5 return $row;
849             }
850 0         0 undef $$row->{array};
851 0         0 $me->{cache}{idx} = 0;
852             } else {
853             # Fetch and store the data then return the Row on success and undef on failure or no more rows
854 30 100       405 if ($$row->{array} = $me->{sth}->fetch) {
855 26         126 $$row->{hash} = $me->{hash};
856 26         159 return $row;
857             }
858 4         14 $me->{Active} = 0;
859             }
860 4         14 $$row->{hash} = {};
861 4         27 return undef;
862             }
863              
864             =head3 C
865              
866             my $row = $query->row;
867              
868             Returns the L object for the current row from the query or an empty L object if there is no current row.
869              
870             =cut
871              
872             sub row {
873 39     39 1 83 my $me = $_[0];
874 39         132 $me->sql; # Build the SQL and detach the Row if needed
875 39   66     253 $me->{Row} //= $me->row_class->new($me->{DBO}, $me);
876             }
877              
878             =head3 C
879              
880             $query->run;
881              
882             Run/rerun the query.
883             This is called automatically before fetching the first row.
884              
885             =cut
886              
887             sub run {
888 20     20 1 5552 my $me = shift;
889              
890 20 100       74 if (defined $me->{Row}) {
891 12         20 undef ${$me->{Row}}->{array};
  12         46  
892 12         26 ${$me->{Row}}->{hash} = {};
  12         35  
893             }
894              
895 20         47 undef $me->{Found_Rows};
896              
897             # Prepare and execute the statement
898 20 50       68 my $rv = $me->_execute
899             or return $me->_inactivate; # Don't leave a failed sth behind
900              
901 20         184 $me->_bind_cols_to_hash;
902 20 100       57 if ($me->config('CacheQuery')) {
903 1         10 $me->{cache}{data} = $me->{sth}->fetchall_arrayref;
904 1         46 $me->{cache}{idx} = 0;
905             } else {
906 19         45 $me->{Active} = 1;
907 19         38 delete $me->{cache};
908             }
909 20         130 return $rv;
910             }
911              
912             sub _execute {
913 20     20   36 my $me = shift;
914              
915 20 100       104 if ($me->{sth}) {
916 2         9 $me->{DBO}{dbd_class}->_sql($me, $me->{sql}, @{ $me->{bind} });
  2         14  
917             } else {
918 18         144 $me->{sql} = $me->{DBO}{dbd_class}->_build_sql_select($me);
919 18         81 $me->{bind} = [ $me->{DBO}{dbd_class}->_bind_params_select($me) ];
920 18         47 $me->{DBO}{dbd_class}->_sql($me, $me->{sql}, @{ $me->{bind} });
  18         93  
921 18         55 $me->{sth} = $me->rdbh->prepare($me->{sql});
922             }
923 20   33     2421 return $me->{sth} && $me->{sth}->execute(@{ $me->{bind} });
924             }
925              
926             sub _bind_cols_to_hash {
927 20     20   46 my $me = shift;
928 20 100       75 unless ($me->{hash}) {
929             # Bind only to the first column of the same name
930 18         29 @{$me->{Columns}} = @{$me->{sth}{NAME}};
  18         83  
  18         230  
931 18 100       103 if ($me->config('CacheQuery')) {
932 1         1 @{$me->{cache}{array}} = (undef) x @{$me->{Columns}};
  1         4  
  1         3  
933 1         2 $me->{hash} = \my %hash;
934 1         1 my $i = 0;
935 1         1 for (@{$me->{Columns}}) {
  1         2  
936 7 100       16 hv_store(%hash, $_, $me->{cache}{array}[$i]) unless exists $hash{$_};
937 7         8 $i++;
938             }
939             } else {
940 17         30 my $i;
941 17         28 for (@{$me->{Columns}}) {
  17         49  
942 44         70 $i++;
943 44 100       272 $me->{sth}->bind_col($i, \$me->{hash}{$_}) unless exists $me->{hash}{$_};
944             }
945             }
946             }
947             }
948              
949             =head3 C
950              
951             my $row_count = $query->rows;
952              
953             Count the number of rows returned.
954             Returns undefined if the number is unknown.
955             This uses the DBI C method which is unreliable in some situations (See Lrows|DBI/"rows">).
956              
957             =cut
958              
959             sub rows {
960 1     1 1 3 my $me = shift;
961 1 50       18 $me->{DBO}{dbd_class}->_rows($me) unless defined $me->{Row_Count};
962 1         6 $me->{Row_Count};
963             }
964              
965             =head3 C
966              
967             my $row_count = $query->count_rows;
968              
969             Count the number of rows that would be returned.
970             Returns undefined if there is an error.
971              
972             =cut
973              
974             sub count_rows {
975 2     2 1 5 my $me = shift;
976 2         7 local $me->{Config}{CalcFoundRows} = 0;
977 2         9 local $me->{build_data}{select} = [[[], 1]];
978 2         5 my $old_sb = delete $me->{build_data}{Show_Bind};
979              
980 2         13 my $sql = 'SELECT COUNT(*) FROM ('.$me->{DBO}{dbd_class}->_build_sql_select($me).') t';
981             my($count) = $me->{DBO}{dbd_class}->_selectrow_array($me, $sql, undef,
982 2         12 $me->{DBO}{dbd_class}->_bind_params_select($me));
983              
984 2 50       302 $me->{build_data}{Show_Bind} = $old_sb if $old_sb;
985 2         22 return $count;
986             }
987              
988             =head3 C
989              
990             $query->config(CalcFoundRows => 1); # Only applicable to MySQL
991             my $total_rows = $query->found_rows;
992              
993             Return the number of rows that would have been returned if there was no limit clause. Before runnning the query the C config option can be enabled for improved performance on supported databases.
994              
995             Returns undefined if there is an error or is unable to determine the number of found rows.
996              
997             =cut
998              
999             sub found_rows {
1000 1     1 1 3 my $me = shift;
1001 1   33     14 return $me->{Found_Rows} // $me->{DBO}{dbd_class}->_calc_found_rows($me);
1002             }
1003              
1004             =head3 C
1005              
1006             $query->update(department => 'Tech');
1007             $query->update(salary => { FUNC => '? * 1.10', COL => 'salary' }); # 10% raise
1008              
1009             Updates every row in the query with the new values specified.
1010             Returns the number of rows updated or C<'0E0'> for no rows to ensure the value is true,
1011             and returns false if there was an error.
1012              
1013             =cut
1014              
1015             sub update {
1016 2     2 1 608 my $me = shift;
1017 2         23 my @update = $me->{DBO}{dbd_class}->_parse_set($me, @_);
1018 2         19 my $sql = $me->{DBO}{dbd_class}->_build_sql_update($me, @update);
1019 2         14 $me->{DBO}{dbd_class}->_do($me, $sql, undef, $me->{DBO}{dbd_class}->_bind_params_update($me));
1020             }
1021              
1022             =head3 C
1023              
1024             my $sql = $query->sql;
1025              
1026             Returns the SQL statement string.
1027              
1028             =cut
1029              
1030             sub _recursion_check {
1031 12     12   17 my($me, @upquery) = @_;
1032              
1033 12         11 state @_recursion_check;
1034 12         15 push @_recursion_check, $me;
1035              
1036 12         15 for my $upquery (@upquery) {
1037 12 100       46 if (grep $upquery eq $_, @_recursion_check) {
1038 4         9 undef @_recursion_check;
1039 4         11 croak 'Recursive subquery found';
1040             }
1041             exists $upquery->{up_queries}
1042 8 100       17 and $upquery->_recursion_check(grep defined($_), @{ $upquery->{up_queries} });
  3         10  
1043             }
1044              
1045 5         8 pop @_recursion_check;
1046             }
1047              
1048             sub _add_up_query {
1049 9     9   12 my($me, $upquery) = @_;
1050              
1051 9         19 $me->_recursion_check($upquery);
1052              
1053 5   100     18 my $uq = $me->{up_queries} //= [];
1054 5         8 push @$uq, $upquery;
1055 5         11 weaken $uq->[-1];
1056             }
1057              
1058             sub sql {
1059 64     64 1 188 my $me = shift;
1060 64         380 return $me->{DBO}{dbd_class}->_build_sql_select($me);
1061             }
1062              
1063             sub _inactivate {
1064 331     331   517 my $me = shift;
1065 331         771 $me->_empty_row;
1066             # Also inactivate super queries
1067 331 100       743 if (exists $me->{up_queries}) {
1068 8   33     7 defined $_ and $_->_inactivate for @{ $me->{up_queries} };
  8         24  
1069             }
1070             # Reset the query
1071 331         498 delete $me->{cache};
1072 331         718 undef $me->{sth};
1073 331         585 undef $me->{sql};
1074 331         509 undef $me->{bind};
1075 331         504 undef $me->{hash};
1076 331         528 undef $me->{Active};
1077 331         465 undef $me->{Row_Count};
1078 331         501 undef $me->{Found_Rows};
1079 331         485 undef @{$me->{Columns}};
  331         704  
1080             }
1081              
1082             =head3 C
1083              
1084             $query->finish;
1085              
1086             Calls Lfinish|DBI/"finish"> on the statement handle, if it's active.
1087             Restarts cached queries from the first row (if created using the C config).
1088             This ensures that the next call to L will return the first row from the query.
1089              
1090             =cut
1091              
1092             sub finish {
1093 4     4 1 13 my $me = shift;
1094 4         18 $me->_empty_row;
1095             # Restart the query
1096 4 50       45 if (exists $me->{cache}) {
1097 0         0 $me->{cache}{idx} = 0;
1098             } else {
1099 4 100 66     136 $me->{sth}->finish if $me->{sth} and $me->{sth}{Active};
1100 4         29 $me->{Active} = 0;
1101             }
1102             }
1103              
1104             sub _empty_row {
1105 335     335   474 my $me = shift;
1106             # Detach or empty the Row
1107 335 100       813 if (defined $me->{Row}) {
1108 57 100       104 if (SvREFCNT(${$me->{Row}}) > 1) {
  57         248  
1109 4         25 $me->{Row}->_detach;
1110             } else {
1111 53         95 undef ${$me->{Row}}->{array};
  53         129  
1112 53         106 ${$me->{Row}}->{hash} = {};
  53         147  
1113             }
1114             }
1115             }
1116              
1117             =head2 Common Methods
1118              
1119             These methods are accessible from all DBIx::DBO* objects.
1120              
1121             =head3 C
1122              
1123             The C object.
1124              
1125             =head3 C
1126              
1127             The I C handle.
1128              
1129             =head3 C
1130              
1131             The I C handle, or if there is no I connection, the I C handle.
1132              
1133             =cut
1134              
1135 5     5 1 538 sub dbo { $_[0]{DBO} }
1136 2     2 1 10 sub dbh { $_[0]{DBO}->dbh }
1137 342     342 1 1180 sub rdbh { $_[0]{DBO}->rdbh }
1138              
1139             =head3 C
1140              
1141             $query_setting = $query->config($option);
1142             $query->config($option => $query_setting);
1143              
1144             Get or set this C object's config settings. When setting an option, the previous value is returned. When getting an option's value, if the value is undefined, the L's value is returned.
1145              
1146             See: L.
1147              
1148             =cut
1149              
1150             sub config {
1151 484     484 1 852 my $me = shift;
1152 484         730 my $opt = shift;
1153 484 100 100     1316 return $me->{DBO}{dbd_class}->_set_config($me->{Config} //= {}, $opt, shift) if @_;
1154 451   100     2445 $me->{DBO}{dbd_class}->_get_config($opt, $me->{Config} //= {}, $me->{DBO}{Config}, \%DBIx::DBO::Config);
1155             }
1156              
1157             sub STORABLE_freeze {
1158 5     5 0 10379 my($me, $cloning) = @_;
1159 5 100       127 return unless defined $me->{sth};
1160              
1161 2         5 local $me->{sth};
1162 2         4 local $me->{Row};
1163 2         3 local $me->{attached_rows};
1164 2 50       6 local $me->{hash} unless exists $me->{cache};
1165 2 50       7 local $me->{Active} = 0 unless exists $me->{cache};
1166 2 50       4 local $me->{cache}{idx} = 0 if exists $me->{cache};
1167 2         5 return Storable::nfreeze($me);
1168             }
1169              
1170             sub STORABLE_thaw {
1171 2     2 0 600 my($me, $cloning, @frozen) = @_;
1172 2         3 %$me = %{ Storable::thaw(@frozen) };
  2         5  
1173             }
1174              
1175             sub DESTROY {
1176             # Detach any attached Rows
1177 25 100 66 25   1490 if (my $attached_rows = delete $_[0]->{attached_rows} and ${^GLOBAL_PHASE} ne 'DESTRUCT') {
1178 13         36 for my $row (@$attached_rows) {
1179 14 100       88 $row->_detach if defined $row;
1180             }
1181             }
1182 25         44 undef %{$_[0]};
  25         735  
1183             }
1184              
1185             1;
1186              
1187             __END__