File Coverage

blib/lib/DBIx/DBO/DBD.pm
Criterion Covered Total %
statement 412 452 91.1
branch 182 246 73.9
condition 71 97 73.2
subroutine 59 63 93.6
pod n/a
total 724 858 84.3


line stmt bran cond sub pod time code
1             package # hide from PAUSE
2             DBIx::DBO::DBD;
3              
4 14     14   313 use 5.014;
  14         54  
5 14     14   639 use mro;
  14         863  
  14         110  
6 14     14   438 use warnings;
  14         63  
  14         1303  
7 14     14   86 use Carp 'croak';
  14         55  
  14         1020  
8 14     14   196 use Scalar::Util 'blessed';
  14         57  
  14         1238  
9 14     14   85 use constant PLACEHOLDER => "\x{b1}\x{a4}\x{221e}";
  14         23  
  14         68454  
10              
11             our @CARP_NOT = qw(DBIx::DBO DBIx::DBO::DBD DBIx::DBO::Table DBIx::DBO::Query DBIx::DBO::Row);
12             *DBIx::DBO::CARP_NOT = \@CARP_NOT;
13             *DBIx::DBO::Table::CARP_NOT = \@CARP_NOT;
14             *DBIx::DBO::Query::CARP_NOT = \@CARP_NOT;
15             *DBIx::DBO::Row::CARP_NOT = \@CARP_NOT;
16              
17             our $placeholder = PLACEHOLDER;
18             $placeholder = qr/\Q$placeholder/;
19              
20             sub _isa {
21 1599     1599   3534 my($me, @class) = @_;
22 1599 100       5360 if (blessed $me) {
23 938   100     6815 $me->isa($_) and return 1 for @class;
24             }
25             }
26              
27             sub _init_dbo {
28 14     14   35 my($class, $me) = @_;
29 14         97 return $me;
30             }
31              
32             sub _get_table_schema {
33 0     0   0 my($class, $me, $table) = @_;
34              
35 0         0 my $q_table = $table =~ s/([\\_%])/\\$1/gr;
36              
37             # First try just these types
38 0         0 my $info = $me->rdbh->table_info(undef, undef, $q_table,
39             'TABLE,VIEW,GLOBAL TEMPORARY,LOCAL TEMPORARY,SYSTEM TABLE')->fetchall_arrayref;
40             # Then if we found nothing, try any type
41 0 0 0     0 $info = $me->rdbh->table_info(undef, undef, $q_table)->fetchall_arrayref if $info and @$info == 0;
42 0 0 0     0 croak 'Invalid table: '.$class->_qi($me, $table) unless $info and @$info == 1 and $info->[0][2] eq $table;
      0        
43 0         0 return $info->[0][1];
44             }
45              
46             sub _get_column_info {
47 4     4   13 my($class, $me, $schema, $table) = @_;
48              
49 4         17 my $cols = $me->rdbh->column_info(undef, $schema, $table, '%');
50 4   100     400 $cols = $cols && $cols->fetchall_arrayref({}) || [];
51 4 100       525 croak 'Invalid table: '.$class->_qi($me, $schema, $table) unless @$cols;
52              
53 2         53 return map { $_->{COLUMN_NAME} => $_->{ORDINAL_POSITION} } @$cols;
  5         46  
54             }
55              
56             sub _get_table_info {
57 4     4   17 my($class, $me, $schema, $table) = @_;
58              
59 4         11 my %h;
60 4         25 $h{Column_Idx} = { $class->_get_column_info($me, $schema, $table) };
61 2         7 $h{Columns} = [ sort { $h{Column_Idx}{$a} <=> $h{Column_Idx}{$b} } keys %{$h{Column_Idx}} ];
  3         15  
  2         15  
62              
63 2         6 $h{PrimaryKeys} = [];
64 2         24 $class->_set_table_key_info($me, $schema, $table, \%h);
65              
66 2   50     388 return $me->{TableInfo}{$schema // ''}{$table} = \%h;
67             }
68              
69             sub _set_table_key_info {
70 2     2   7 my($class, $me, $schema, $table, $h) = @_;
71              
72 2 50       9 if (my $sth = $me->rdbh->primary_key_info(undef, $schema, $table)) {
73 2         241 $h->{PrimaryKeys}[$_->{KEY_SEQ} - 1] = $_->{COLUMN_NAME} for @{$sth->fetchall_arrayref({})};
  2         13  
74             }
75             }
76              
77             sub _unquote_table {
78 25     25   63 my($class, $me, $table) = @_;
79             # TODO: Better splitting of: schema.table or `schema`.`table` or "schema"."table"@"catalog" or ...
80 25 50       266 $table =~ /^(?:("|)(.+)\1\.|)("|)(.+)\3$/ or croak "Invalid table: \"$table\"";
81 25         192 return ($2, $4);
82             }
83              
84             sub _selectrow_array {
85 3     3   10 my($class, $me, $sql, $attr, @bind) = @_;
86 3         16 $class->_sql($me, $sql, @bind);
87 3         12 $me->rdbh->selectrow_array($sql, $attr, @bind);
88             }
89              
90             sub _selectrow_arrayref {
91 2     2   10 my($class, $me, $sql, $attr, @bind) = @_;
92 2         10 $class->_sql($me, $sql, @bind);
93 2         9 $me->rdbh->selectrow_arrayref($sql, $attr, @bind);
94             }
95              
96             sub _selectrow_hashref {
97 0     0   0 my($class, $me, $sql, $attr, @bind) = @_;
98 0         0 $class->_sql($me, $sql, @bind);
99 0         0 $me->rdbh->selectrow_hashref($sql, $attr, @bind);
100             }
101              
102             sub _selectall_arrayref {
103 9     9   35 my($class, $me, $sql, $attr, @bind) = @_;
104 9         37 $class->_sql($me, $sql, @bind);
105 9         34 $me->rdbh->selectall_arrayref($sql, $attr, @bind);
106             }
107              
108             sub _selectall_hashref {
109 1     1   7 my($class, $me, $sql, $key, $attr, @bind) = @_;
110 1         7 $class->_sql($me, $sql, @bind);
111 1         5 $me->rdbh->selectall_hashref($sql, $key, $attr, @bind);
112             }
113              
114             sub _qi {
115 446     446   1276 my($class, $me, @id) = @_;
116 446 100       1269 return $me->rdbh->quote_identifier(@id) if $me->config('QuoteIdentifier');
117             # Strip off any null/undef elements (ie schema)
118 48   100     139 shift(@id) while @id and not length $id[0];
119 48         107 return join '.', @id;
120             }
121              
122             sub _sql {
123 90     90   217 my $class = shift;
124 90         142 my $me = shift;
125 90 50       291 if (my $hook = $me->config('HookSQL')) {
126 90         349 $hook->($me, @_);
127             }
128 90 50       261 my $dbg = $me->config('DebugSQL') or return;
129 0         0 my($sql, @bind) = @_;
130              
131 0         0 my $loc = Carp::short_error_loc();
132 0         0 my %i = Carp::caller_info($loc);
133 0         0 my $trace;
134 0 0       0 if ($dbg > 1) {
135 0         0 $trace = "\t$i{sub_name} called at $i{file} line $i{line}\n";
136 0         0 $trace .= "\t$i{sub_name} called at $i{file} line $i{line}\n" while %i = Carp::caller_info(++$loc);
137             } else {
138 0         0 $trace = "\t$i{sub} called at $i{file} line $i{line}\n";
139             }
140 0         0 warn $sql."\n(".join(', ', map $me->rdbh->quote($_), @bind).")\n".$trace;
141             }
142              
143             sub _do {
144 20     20   77 my($class, $me, $sql, $attr, @bind) = @_;
145 20         93 $class->_sql($me, $sql, @bind);
146 20         71 $me->dbh->do($sql, $attr, @bind);
147             }
148              
149             sub _build_sql_select {
150 132     132   286 my($class, $me) = @_;
151 132         334 my $sql = 'SELECT '.$class->_build_show($me);
152 132         351 $sql .= ' FROM '.$class->_build_from($me);
153 132         200 my $clause;
154 132 100       352 $sql .= ' WHERE '.$clause if $clause = $class->_build_where($me);
155 132 100       406 $sql .= ' GROUP BY '.$clause if $clause = $class->_build_group($me);
156 132 100       318 $sql .= ' HAVING '.$clause if $clause = $class->_build_having($me);
157 132 100       307 $sql .= ' ORDER BY '.$clause if $clause = $class->_build_order($me);
158 132 100       428 $sql .= ' '.$clause if $clause = $class->_build_limit($me);
159 132         499 return $sql;
160             }
161              
162             sub _bind_params_select {
163 36     36   117 my($class, $me) = @_;
164 36         87 my $h = $me->_build_data;
165             map {
166 36 50       87 exists $h->{$_} ? @{$h->{$_}} : ()
  216         451  
  216         538  
167             } qw(Show_Bind From_Bind Where_Bind Group_Bind Having_Bind Order_Bind);
168             }
169              
170             sub _build_sql_update {
171 6     6   21 my($class, $me, @arg) = @_;
172 6 50       26 croak 'Update is not valid with a GROUP BY clause' if $class->_build_group($me);
173 6 50       21 croak 'Update is not valid with a HAVING clause' if $class->_build_having($me);
174 6         20 my $sql = 'UPDATE '.$class->_build_from($me);
175 6         30 $sql .= ' SET '.$class->_build_set($me, @arg);
176 6         12 my $clause;
177 6 100       25 $sql .= ' WHERE '.$clause if $clause = $class->_build_where($me);
178 6 50       32 $sql .= ' ORDER BY '.$clause if $clause = $class->_build_order($me);
179 6 50       31 $sql .= ' '.$clause if $clause = $class->_build_limit($me);
180 6         23 $sql;
181             }
182              
183             sub _bind_params_update {
184 6     6   15 my($class, $me) = @_;
185 6         19 my $h = $me->_build_data;
186             map {
187 6 50       16 exists $h->{$_} ? @{$h->{$_}} : ()
  24         54  
  24         67  
188             } qw(From_Bind Set_Bind Where_Bind Order_Bind);
189             }
190              
191             sub _build_sql_delete {
192 1     1   3 my($class, $me) = @_;
193 1 50       4 croak 'Delete is not valid with a GROUP BY clause' if $class->_build_group($me);
194 1         5 my $sql = 'DELETE FROM '.$class->_build_from($me);
195 1         3 my $clause;
196 1 50       4 $sql .= ' WHERE '.$clause if $clause = $class->_build_where($me);
197 1 50       4 $sql .= ' ORDER BY '.$clause if $clause = $class->_build_order($me);
198 1 50       5 $sql .= ' '.$clause if $clause = $class->_build_limit($me);
199 1         4 $sql;
200             }
201              
202             sub _bind_params_delete {
203 1     1   4 my($class, $me) = @_;
204 1         4 my $h = $me->_build_data;
205             map {
206 1 50       4 exists $h->{$_} ? @{$h->{$_}} : ()
  3         8  
  3         10  
207             } qw(From_Bind Where_Bind Order_Bind);
208             }
209              
210             sub _build_table {
211 179     179   363 my($class, $me, $t) = @_;
212 179         586 my $from = $t->_as_table($me);
213 179         1088 my $alias = $me->_table_alias($t);
214 179 100       412 $alias = defined $alias ? ' '.$class->_qi($me, $alias) : '';
215 179         1446 return $from.$alias;
216             }
217              
218             sub _build_show {
219 132     132   214 my($class, $me) = @_;
220 132         328 my $h = $me->_build_data;
221 132 100       342 my $distinct = $h->{Show_Distinct} ? 'DISTINCT ' : '';
222 132         168 undef @{$h->{Show_Bind}};
  132         299  
223 132 100       226 return $distinct.'*' unless @{$h->{select}};
  132         405  
224              
225             # Parse a list of columns & tables into fields
226             my @flds = map {
227             _isa($_, 'DBIx::DBO::Table', 'DBIx::DBO::Query')
228             ? $class->_qi($me, $me->_table_alias($_) || $_->{Name}).'.*'
229 126 100 66     485 : $class->_build_val($me, $h->{Show_Bind}, @$_)
230 86         135 } @{$h->{select}};
  86         163  
231 86         613 return $distinct.join(', ', @flds);
232             }
233              
234             sub _build_from {
235 167     167   324 my($class, $me) = @_;
236 167         477 my $h = $me->_build_data;
237              
238             # Row objects have cached the SQL and bind values
239 167 100       430 return $h->{from_sql} if exists $h->{from_sql};
240              
241 152         191 undef @{$h->{From_Bind}};
  152         302  
242 152         333 my @tables = $me->tables;
243 152         522 my $from = $class->_build_table($me, $tables[0]);
244 152         441 for (my $i = 1; $i < @tables; $i++) {
245 27         85 $from .= $h->{join_types}[$i].$class->_build_table($me, $tables[$i]);
246             $from .= ' ON '.join(' AND ', $class->_build_where_chunk($me, $h->{From_Bind}, 'OR', $h->{"join$i"}))
247 27 100       160 if $h->{"join$i"};
248             }
249 152         498 return $from;
250             }
251              
252             sub _parse_col_val {
253 80     80   259 my($class, $me, $col, %c) = @_;
254 80   66     325 $c{Aliases} //= do {
255 57         787 my($method) = (caller(1))[3] =~ /(\w+)$/;
256 57         261 $class->_alias_preference($me, $method);
257             };
258 80 100       315 return $class->_parse_val($me, $col, Check => 'Column', %c) if ref $col;
259 38         135 return [ $class->_parse_col($me, $col, $c{Aliases}) ];
260             }
261              
262             # In some cases column aliases can be used, but this differs by DB and where in the statement it's used.
263             # The $method is the method we were called from: (join_on|column|where|having|_del_where|order_by|group_by)
264             # This method provides a way for DBs to override the default which is always 1 except for join_on.
265             # Return values: 0 = Don't use aliases, 1 = Check aliases then columns, 2 = Check columns then aliases
266             sub _alias_preference {
267             # my($class, $me, $method) = @_;
268 58 100   58   299 return $_[2] eq 'join_on' ? 0 : 1;
269             }
270              
271             sub _valid_col {
272 59     59   160 my($class, $me, $col) = @_;
273             # Check if the object is an alias
274 59 100       245 return $col if $col->[0] == $me;
275             # TODO: Sub-queries
276             # Check if the column is from one of our tables
277 51         175 for my $tbl ($me->tables) {
278 62 100       354 return $col if $col->[0] == $tbl;
279             }
280 1         212 croak 'Invalid column, the column is from a table not included in this query';
281             }
282              
283             sub _parse_col {
284 95     95   1146 my($class, $me, $col, $_check_aliases) = @_;
285 95 100       226 if (ref $col) {
286 14 50       55 return $class->_valid_col($me, $col) if _isa($col, 'DBIx::DBO::Column');
287 0         0 croak 'Invalid column: '.$col;
288             }
289             # If $_check_aliases is not defined dont accept an alias
290 81   100     501 $me->_inner_col($col, $_check_aliases || 0);
291             }
292              
293             sub _build_col {
294 307     307   798 my($class, $me, $col) = @_;
295 307         1020 $class->_qi($me, $me->_table_alias($col->[0]), $col->[1]);
296             }
297              
298             sub _parse_val {
299 140     140   458 my($class, $me, $val, %c) = @_;
300 140   100     591 $c{Check} //= '';
301              
302 140         348 my @fld;
303             my $func;
304 140         0 my $opt;
305 140 100       690 if (ref $val eq 'SCALAR') {
    100          
    100          
    100          
306 20 0       59 croak 'Invalid '.($c{Check} eq 'Column' ? 'column' : 'field').' reference (scalar ref to undef)'
    50          
307             unless defined $$val;
308 20         36 $func = $$val;
309             } elsif (ref $val eq 'HASH') {
310 22 100       88 $func = $val->{FUNC} if exists $val->{FUNC};
311 22 100       82 $opt->{AS} = $val->{AS} if exists $val->{AS};
312 22 100       63 if (exists $val->{ORDER}) {
313 3 50       26 croak 'Invalid ORDER, must be ASC or DESC' if $val->{ORDER} !~ /^(A|DE)SC$/i;
314 3         15 $opt->{ORDER} = uc $val->{ORDER};
315             }
316 22 100       61 $opt->{COLLATE} = $val->{COLLATE} if exists $val->{COLLATE};
317 22 100       78 if (exists $val->{COL}) {
    100          
318 12 50       43 croak 'Invalid HASH containing both COL and VAL' if exists $val->{VAL};
319 12 100       61 my @cols = ref $val->{COL} eq 'ARRAY' ? @{$val->{COL}} : ($val->{COL});
  1         6  
320 12         70 @fld = map $class->_parse_col($me, $_, $c{Aliases}), @cols;
321             } elsif (exists $val->{VAL}) {
322 8 100       32 @fld = ref $val->{VAL} eq 'ARRAY' ? @{$val->{VAL}} : ($val->{VAL});
  3         13  
323             }
324             } elsif (ref $val eq 'ARRAY') {
325 6         22 @fld = @$val;
326             } elsif (_isa($val, 'DBIx::DBO::Column')) {
327 13         49 return [ $class->_valid_col($me, $val) ];
328             } else {
329 79         212 @fld = ($val);
330             }
331              
332             # Swap placeholders
333 127         248 my $with = @fld;
334 127 100 66     512 if (defined $func) {
    50          
335 32         122 my $need = $class->_substitute_placeholders($me, $func);
336 32 100       318 croak "The number of params ($with) does not match the number of placeholders ($need)" if $need != $with;
337             } elsif ($with != 1 and $c{Check} ne 'Auto') {
338 0 0       0 croak 'Invalid '.($c{Check} eq 'Column' ? 'column' : 'field')." reference (passed $with params instead of 1)";
339             }
340             # Check for subqueries
341 126         358 for my $subquery (grep _isa($_, 'DBIx::DBO::Query'), @fld) {
342 7         17 $subquery->_add_up_query($me);
343             }
344 123         611 return (\@fld, $func, $opt);
345             }
346              
347             sub _substitute_placeholders {
348             #my($class, $me, $func) = @_;
349 32     32   56 my $num_placeholders = 0;
350 32 100       332 $_[2] =~ s/((?
  20         176  
351 32         75 return $num_placeholders;
352             }
353              
354             sub _build_val {
355 515     515   1248 my($class, $me, $bind, $fld, $func, $opt) = @_;
356 515         856 my $extra = '';
357 515 100       1117 $extra .= ' COLLATE '.$me->rdbh->quote($opt->{COLLATE}) if exists $opt->{COLLATE};
358 515 100       1070 $extra .= ' AS '.$class->_qi($me, $opt->{AS}) if exists $opt->{AS};
359 515 100       1780 $extra .= " $opt->{ORDER}" if exists $opt->{ORDER};
360              
361             my @ary = map {
362 515 100       1070 if (!ref $_) {
  462 100       1401  
    100          
    50          
363 162         354 push @$bind, $_;
364 162         412 '?';
365             } elsif (_isa($_, 'DBIx::DBO::Column')) {
366 263         904 $class->_build_col($me, $_);
367             } elsif (ref $_ eq 'SCALAR') {
368 8         25 $$_;
369             } elsif (_isa($_, 'DBIx::DBO::Query')) {
370 29         48 $_->_as_table($me);
371             } else {
372 0         0 croak 'Invalid field: '.$_;
373             }
374             } @$fld;
375 515 100       11181 unless (defined $func) {
376 362 50       823 die "Number of placeholders and values don't match!" if @ary != 1;
377 362         2145 return $ary[0].$extra;
378             }
379             # Add one value to @ary to make sure the number of placeholders & values match
380 153         312 push @ary, 'Error';
381 153         530 $func =~ s/$placeholder/shift @ary/ego;
  100         294  
382             # At this point all the values should have been used and @ary must only have 1 item!
383 153 50       375 die "Number of placeholders and values don't match!" if @ary != 1;
384 153         768 return $func.$extra;
385             }
386              
387             # Construct the WHERE clause
388             sub _build_where {
389 139     139   223 my($class, $me) = @_;
390 139         284 my $h = $me->_build_data;
391 139         192 undef @{$h->{Where_Bind}};
  139         292  
392 139         243 my @where;
393 139 100       333 push @where, $class->_build_quick_where($me, $h->{Where_Bind}, @{$h->{Quick_Where}}) if exists $h->{Quick_Where};
  14         63  
394 139 100       409 push @where, $class->_build_where_chunk($me, $h->{Where_Bind}, 'OR', $h->{where}) if exists $h->{where};
395 139         589 return join ' AND ', @where;
396             }
397              
398             # Construct the WHERE contents of one set of parentheses
399             sub _build_where_chunk {
400 72     72   211 my($class, $me, $bind, $ag, $whs) = @_;
401 72         107 my @str;
402             # Make a copy so we can hack at it
403 72         156 my @whs = @$whs;
404 72         204 while (my $wh = shift @whs) {
405 141         229 my @ary;
406 141 100       306 if (ref $wh->[0]) {
407 17 100       75 @ary = $class->_build_where_chunk($me, $bind, $ag eq 'OR' ? 'AND' : 'OR', $wh);
408             } else {
409 124         425 @ary = $class->_build_where_piece($me, $bind, @$wh);
410 124         358 my($op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt, $force) = @$wh;
411             # Group AND/OR'ed for same fld if $force or $op requires it
412 124 100 100     411 if ($ag eq ($force || _op_ag($op))) {
413 59         207 for (my $i = $#whs; $i >= 0; $i--) {
414             # Right now this starts with the last @whs and works backwards
415             # It splices when the ag is the correct AND/OR and the funcs match and all flds match
416 38 100 100     185 next if ref $whs[$i][0] or $ag ne ($whs[$i][7] || _op_ag($whs[$i][0]));
      100        
417 14     14   156 no warnings 'uninitialized';
  14         29  
  14         1137  
418 18 50       67 next if $whs[$i][2] ne $fld_func;
419 14     14   89 use warnings 'uninitialized';
  14         22  
  14         56108  
420             # next unless $fld_func ~~ $whs[$i][2];
421 18         36 my $l = $whs[$i][1];
422 18 50       145 next if ((ref $l eq 'ARRAY' ? "@$l" : $l) ne (ref $fld eq 'ARRAY' ? "@$fld" : $fld));
    50          
    100          
423             # next unless $fld ~~ $whs[$i][1];
424 10         24 push @ary, $class->_build_where_piece($me, $bind, @{splice @whs, $i, 1});
  10         42  
425             }
426             }
427             }
428 141 100       669 push @str, @ary == 1 ? $ary[0] : '('.join(' '.$ag.' ', @ary).')';
429             }
430 72         252 return @str;
431             }
432              
433             sub _op_ag {
434 149 100 100 149   1171 return 'OR' if $_[0] eq '=' or $_[0] eq 'IS' or $_[0] eq '<=>' or $_[0] eq 'IN' or $_[0] eq 'BETWEEN';
      66        
      100        
      100        
435 65 100 100     529 return 'AND' if $_[0] eq '<>' or $_[0] eq 'IS NOT' or $_[0] eq 'NOT IN' or $_[0] eq 'NOT BETWEEN';
      100        
      100        
436             }
437              
438             # Construct one WHERE expression
439             sub _build_where_piece {
440 134     134   493 my($class, $me, $bind, $op, $fld, $fld_func, $fld_opt, $val, $val_func, $val_opt) = @_;
441 134         335 $class->_build_val($me, $bind, $fld, $fld_func, $fld_opt)." $op ".$class->_build_val($me, $bind, $val, $val_func, $val_opt);
442             }
443              
444             # Construct one WHERE expression (simple)
445             sub _build_quick_where {
446 22 50   22   87 croak 'Wrong number of arguments' unless @_ & 1;
447 22         79 my($class, $me, $bind) = splice @_, 0, 3;
448 22         39 my @where;
449 22         89 while (my($col, $val) = splice @_, 0, 2) {
450             # FIXME: What about aliases in quick_where?
451 20         81 push @where, $class->_build_col($me, $class->_parse_col($me, $col)) . do {
452 19 100 66     771 if (ref $val eq 'SCALAR' and $$val =~ /^\s*(?:NOT\s+)NULL\s*$/is) {
    100          
    100          
453 1         6 ' IS ';
454             } elsif (ref $val eq 'ARRAY') {
455 2 50       9 croak 'Invalid value argument, IN requires at least 1 value' unless @$val;
456 2         18 $val = { FUNC => '('.join(',', ('?') x @$val).')', VAL => $val };
457 2         14 ' IN ';
458             } elsif (defined $val) {
459 15         72 ' = ';
460             } else {
461 1         3 $val = \'NULL';
462 1         4 ' IS ';
463             }
464             } . $class->_build_val($me, $bind, $class->_parse_val($me, $val));
465             }
466 21         98 return join ' AND ', @where;
467             }
468              
469             sub _parse_set {
470 6 50   6   27 croak 'Wrong number of arguments' if @_ & 1;
471 6         24 my($class, $me, @arg) = @_;
472 6         15 my @update;
473             my %remove_duplicates;
474 6         19 while (@arg) {
475 8         31 my @val = $class->_parse_val($me, pop @arg);
476 8         52 my $col = $class->_parse_col($me, pop @arg);
477 8 100       65 unshift @update, $col, \@val unless $remove_duplicates{$col}++;
478             }
479 6         26 return @update;
480             }
481              
482             sub _build_set {
483 6     6   22 my($class, $me, @arg) = @_;
484 6         22 my $h = $me->_build_data;
485 6         13 undef @{$h->{Set_Bind}};
  6         18  
486 6         13 my @set;
487 6         17 while (@arg) {
488 7         31 push @set, $class->_build_col($me, shift @arg).' = '.$class->_build_val($me, $h->{Set_Bind}, @{shift @arg});
  7         293  
489             }
490 6         29 return join ', ', @set;
491             }
492              
493             sub _build_group {
494 139     139   226 my($class, $me) = @_;
495 139         309 my $h = $me->_build_data;
496 139         197 undef @{$h->{Group_Bind}};
  139         308  
497 139         209 return join ', ', map $class->_build_val($me, $h->{Group_Bind}, @$_), @{$h->{group}};
  139         503  
498             }
499              
500             # Construct the HAVING clause
501             sub _build_having {
502 138     138   292 my($class, $me) = @_;
503 138         296 my $h = $me->_build_data;
504 138         244 undef @{$h->{Having_Bind}};
  138         296  
505 138         206 my @having;
506 138 100       297 push @having, $class->_build_where_chunk($me, $h->{Having_Bind}, 'OR', $h->{having}) if exists $h->{having};
507 138         409 return join ' AND ', @having;
508             }
509              
510             sub _build_order {
511 139     139   235 my($class, $me) = @_;
512 139         277 my $h = $me->_build_data;
513 139         252 undef @{$h->{Order_Bind}};
  139         292  
514 139         213 return join ', ', map $class->_build_val($me, $h->{Order_Bind}, @$_), @{$h->{order}};
  139         470  
515             }
516              
517             sub _build_limit {
518 64     64   92 my($class, $me) = @_;
519 64         90 my $h = $me->_build_data;
520 64 50       158 return '' unless defined $h->{limit};
521 0         0 my $sql = 'LIMIT ';
522 0 0       0 $sql .= $h->{limit}[0] >= 0 ? $h->{limit}[0] : 18446744073709551615;
523 0 0       0 $sql .= ' OFFSET '.$h->{limit}[1] if $h->{limit}[1];
524 0         0 return $sql;
525             }
526              
527             sub _get_config {
528 1197     1197   3099 my($class, $opt, @confs) = @_;
529 1197   100     7834 defined $_->{$opt} and return $_->{$opt} for @confs;
530 502         2789 return;
531             }
532              
533             sub _set_config {
534 131     131   585 my($class, $ref, $opt, $val) = @_;
535 131 50 66     453 croak "Invalid value for the 'OnRowUpdate' setting"
      66        
      33        
      33        
536             if $opt eq 'OnRowUpdate' and $val and $val ne 'empty' and $val ne 'simple' and $val ne 'reload';
537 131 100 100     756 croak "Invalid value for the 'UseHandle' setting"
      100        
      100        
538             if $opt eq 'UseHandle' and $val and $val ne 'read-only' and $val ne 'read-write';
539 130         335 my $old = $ref->{$opt};
540 130         305 $ref->{$opt} = $val;
541 130         536 return $old;
542             }
543              
544              
545             # Query methods
546             sub _rows {
547 1     1   4 my($class, $me) = @_;
548 1 50       5 if (exists $me->{cache}) {
549 0         0 return $me->{Row_Count} = @{ $me->{cache}{data} };
  0         0  
550             }
551 1 50 33     12 $me->{sth} or $me->run
552             or croak $me->rdbh->errstr;
553 1         11 my $rows = $me->{sth}->rows;
554 1 50       6 $me->{Row_Count} = $rows == -1 ? undef : $rows;
555             }
556              
557             sub _calc_found_rows {
558 1     1   5 my($class, $me) = @_;
559 1         4 local $me->{build_data}{limit};
560 1         5 $me->{Found_Rows} = $me->count_rows;
561             }
562              
563              
564             # Table methods
565       0     sub _save_last_insert_id {
566             #my($class, $me, $sth) = @_;
567             # Should be provided in a DBD specific method
568             # It is called after insert and must return the autogenerated ID
569             #return $sth->{Database}->last_insert_id(undef, @$me{qw(Schema Name)}, undef);
570             }
571              
572             sub _fast_bulk_insert {
573 0     0   0 my($class, $me, $sql, $cols, %opt) = @_;
574              
575 0         0 my @vals;
576             my @bind;
577 0 0       0 if (ref $opt{rows}[0] eq 'ARRAY') {
578 0         0 for my $row (@{$opt{rows}}) {
  0         0  
579 0         0 push @vals, '('.join(', ', map $class->_build_val($me, \@bind, $class->_parse_val($me, $_)), @$row).')';
580             }
581             } else {
582 0         0 for my $row (@{$opt{rows}}) {
  0         0  
583 0         0 push @vals, '('.join(', ', map $class->_build_val($me, \@bind, $class->_parse_val($me, $_)), @$row{@$cols}).')';
584             }
585             }
586              
587 0         0 $sql .= join(",\n", @vals);
588 0         0 $class->_do($me, $sql, undef, @bind);
589             }
590              
591             sub _safe_bulk_insert {
592 4     4   15 my($class, $me, $sql, $cols, %opt) = @_;
593              
594             # TODO: Wrap in a transaction
595 4         8 my $rv;
596             my $sth;
597 4         9 my $prev_vals = '';
598 4 100       18 if (ref $opt{rows}[0] eq 'ARRAY') {
599 2         21 for my $row (@{$opt{rows}}) {
  2         7  
600 8         67 my @bind;
601 8         49 my $vals = '('.join(', ', map $class->_build_val($me, \@bind, $class->_parse_val($me, $_)), @$row).')';
602 8         45 $class->_sql($me, $sql.$vals, @bind);
603 8 100       27 if ($prev_vals ne $vals) {
604 2 50       8 $sth = $me->dbh->prepare($sql.$vals) or return undef;
605 2         182 $prev_vals = $vals;
606             }
607 8 50       340 $rv += $sth->execute(@bind) or return undef;
608             }
609             } else {
610 2         5 for my $row (@{$opt{rows}}) {
  2         7  
611 8         19 my @bind;
612 8         53 my $vals = '('.join(', ', map $class->_build_val($me, \@bind, $class->_parse_val($me, $_)), @$row{@$cols}).')';
613 8         44 $class->_sql($me, $sql.$vals, @bind);
614 8 100       42 if ($prev_vals ne $vals) {
615 2 50       7 $sth = $me->dbh->prepare($sql.$vals) or return undef;
616 2         182 $prev_vals = $vals;
617             }
618 8 50       360 $rv += $sth->execute(@bind) or return undef;
619             }
620             }
621              
622 4   50     96 return $rv || '0E0';
623             }
624             *_bulk_insert = \&_safe_bulk_insert;
625              
626              
627             # Row methods
628             sub _reset_row_on_update {
629 4     4   18 my($class, $me, @update) = @_;
630 4   50     12 my $on_row_update = $me->config('OnRowUpdate') || 'simple';
631              
632 4 50       13 if ($on_row_update ne 'empty') {
633             # Set the row values if they are simple expressions
634 4         7 my @cant_update;
635 4         15 for (my $i = 0; $i < @update; $i += 2) {
636             # Keep a list of columns we can't update, and skip them
637             next if $cant_update[ $me->_column_idx($update[0]) ] = (
638 5 100 66     20 defined $update[1][1] or @{$update[1][0]} != 1 or (
639             ref $update[1][0][0] and (
640             not _isa($update[1][0][0], 'DBIx::DBO::Column')
641             or $cant_update[ $me->_column_idx($update[1][0][0]) ]
642             )
643             )
644             );
645 4         14 my($col, $val) = splice @update, $i, 2;
646 4         9 $val = $val->[0][0];
647 4 50       12 $val = $$me->{array}[ $me->_column_idx($val) ] if ref $val;
648 4         16 $$me->{array}[ $me->_column_idx($col) ] = $val;
649 4         15 $i -= 2;
650             }
651             # If we were able to update all the columns then return
652 4 100       25 grep $_, @cant_update or return;
653              
654 1 50       5 if ($on_row_update eq 'reload') {
655             # Attempt reload
656 1         3 my @cols = map $$me->{build_data}{Quick_Where}[$_ << 1], 0 .. $#{$$me->{build_data}{Quick_Where}} >> 1;
  1         9  
657 1         5 my @cidx = map $me->_column_idx($_), @cols;
658 1 50       7 unless (grep $cant_update[$_], @cidx) {
659 1         2 my %bd = %{$$me->{build_data}};
  1         10  
660 1         4 delete $bd{where};
661 1         4 $bd{Quick_Where} = [map { $cols[$_] => $$me->{array}[ $cidx[$_] ] } 0 .. $#cols];
  1         6  
662 1         3 my($sql, @bind) = do {
663 1         4 local $$me->{build_data} = \%bd;
664 1         4 ($class->_build_sql_select($me), $class->_bind_params_select($me));
665             };
666 1         5 return $me->_load($sql, @bind);
667             }
668             }
669             }
670             # If we can't update or reload then empty the Row
671 0         0 undef $$me->{array};
672 0         0 $$me->{hash} = {};
673             }
674              
675             sub _build_data_matching_this_row {
676 5     5   14 my($class, $me) = @_;
677             # Identify the row by the PrimaryKeys if any, otherwise by all Columns
678 5         11 my @quick_where;
679 5         14 for my $tbl ($me->tables) {
680 5 50       8 for my $col (map $tbl ** $_, @{$tbl->{ @{$tbl->{PrimaryKeys}} ? 'PrimaryKeys' : 'Columns' }}) {
  5         11  
  5         32  
681 5         17 my $i = $me->_column_idx($col);
682 5 50       15 defined $i or croak 'The '.$class->_qi($me, $tbl->{Name}, $col->[1]).' field needed to identify this row, was not included in this query';
683 5         26 push @quick_where, $col => $$me->{array}[$i];
684             }
685             }
686 5         14 my $bd = $me->_build_data;
687             my %h = (
688             select => $bd->{select},
689             from_sql => exists $$me->{Parent} ? $class->_build_from($$me->{Parent}) : $bd->{from_sql},
690 5 50       36 Quick_Where => \@quick_where
691             );
692 5 50       20 $h{From_Bind} = $bd->{From_Bind} if exists $bd->{From_Bind};
693 5         21 return \%h;
694             }
695              
696              
697             # require the DBD module if it exists
698             my %inheritance;
699             sub _require_dbd_class {
700 24     24   85 my($class, $dbd) = @_;
701 24         59 my $dbd_class = $class.'::'.$dbd;
702              
703 24         56 my $rv;
704             my @warn;
705             {
706 24     1   44 local $SIG{__WARN__} = sub { push @warn, join '', @_ };
  24         230  
  1         6  
707 24         2429 $rv = eval "require $dbd_class";
708             }
709 24 100       184 if ($rv) {
710 3 50       13 warn @warn if @warn;
711             } else {
712 21         139 my $file = $dbd_class =~ s|::|/|gr;
713 21 100       443 if ("$@" !~ / \Q$file.pm\E in \@INC /) {
714 1         6 my $err = $@ =~ s/\n.*$//r; # Remove the last line
715 1         3 chomp @warn;
716 1         2 chomp $err;
717 1         320 croak join "\n", @warn, $err, "Can't load $dbd driver";
718             }
719              
720 20         49 $@ = '';
721 20         53 delete $INC{$file};
722 20         58 $INC{$file} = 1;
723             }
724              
725             # Set the derived DBD class' inheritance
726 23 100       101 unless (exists $inheritance{$class}{$dbd}) {
727 14     14   159 no strict 'refs';
  14         42  
  14         3659  
728 11 50       41 unless (@{$dbd_class.'::ISA'}) {
  11         106  
729 11         60 my @isa = map $_->_require_dbd_class($dbd), grep $_->isa(__PACKAGE__), @{$class.'::ISA'};
  11         74  
730 11         27 @{$dbd_class.'::ISA'} = ($class, @isa);
  11         207  
731 11 100       72 mro::set_mro($dbd_class, 'c3') if @isa;
732             }
733 11         45 push @CARP_NOT, $dbd_class;
734 11         40 $inheritance{$class}{$dbd} = $dbd_class;
735             }
736              
737 23         130 return $inheritance{$class}{$dbd};
738             }
739              
740             1;