File Coverage

blib/lib/DBIx/Wrapper.pm
Criterion Covered Total %
statement 53 1503 3.5
branch 0 620 0.0
condition 0 177 0.0
subroutine 18 200 9.0
pod 66 88 75.0
total 137 2588 5.2


line stmt bran cond sub pod time code
1             # -*-perl-*-
2             # Creation date: 2003-03-30 12:17:42
3             # Authors: Don
4             # Change log:
5             # $Revision: 2043 $
6             #
7             # Copyright (c) 2003-2012 Don Owens (don@regexguy.com)
8             #
9             # All rights reserved. This program is free software; you can
10             # redistribute it and/or modify it under the same terms as Perl
11             # itself.
12             #
13             # This program is distributed in the hope that it will be
14             # useful, but WITHOUT ANY WARRANTY; without even the implied
15             # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16             # PURPOSE.
17              
18             # TODO:
19             # $db->not(); e.g., $db->select_from_hash($table, { val => $db->not(undef) });
20             # $db->in(); e.g., $db->update($table, { val => $db->in([ 4, 5, 6]) })
21             #
22             # * Take care of error caused by using DBD-mysql-2.1026
23             # - It either gives the wrong quote for quoting
24             # identifiers, or doesn't allow identifiers to be quoted
25              
26             =pod
27              
28             =head1 NAME
29              
30             DBIx::Wrapper - A wrapper around the DBI
31              
32             =head1 SYNOPSIS
33              
34             use DBIx::Wrapper;
35            
36             my $db = DBIx::Wrapper->connect($dsn, $user, $auth, \%attr);
37            
38             my $db = DBIx::Wrapper->connect($dsn, $user, $auth, \%attr,
39             { error_handler => sub { print $DBI::errstr },
40             debug_handler => sub { print $DBI::errstr },
41             });
42            
43             my $db = DBIx::Wrapper->connect_from_config($db_key, $config_file,
44             { error_handler => sub { print $DBI::errstr },
45             debug_handler => sub { print $DBI::errstr },
46             });
47            
48            
49             my $dbi_obj = DBI->connect(...)
50             my $db = DBIx::Wrapper->newFromDBI($dbi_obj);
51            
52             my $dbi_obj = $db->getDBI;
53            
54             my $rv = $db->insert($table, { id => 5, val => "myval",
55             the_date => \"NOW()",
56             });
57             my $rv = $db->insert($table, { id => 5, val => "myval",
58             the_date => $db->command("NOW()"),
59             });
60            
61             my $rv = $db->replace($table, \%data);
62             my $rv = $db->smartReplace($table, \%data)
63             my $rv = $db->delete($table, \%keys);
64             my $rv = $db->update($table, \%keys, \%data);
65             my $rv = $db->smartUpdate($table, \%keys, \%data);
66            
67             my $row = $db->selectFromHash($table, \%keys, \@cols);
68             my $row = $db->selectFromHashMulti($table, \%keys, \@cols);
69             my $val = $db->selectValueFromHash($table, \%keys, $col);
70             my $vals = $db->selectValueFromHashMulti($table, \%keys, \@cols);
71             my $rows = $db->selectAll($table, \@cols);
72            
73             my $row = $db->nativeSelect($query, \@exec_args);
74            
75             my $loop = $db->nativeSelectExecLoop($query);
76             foreach my $val (@vals) {
77             my $row = $loop->next([ $val ]);
78             }
79            
80             my $row = $db->nativeSelectWithArrayRef($query, \@exec_args);
81            
82             my $rows = $db->nativeSelectMulti($query, \@exec_args);
83             my $rows = $db->nativeSelectMultiOrOne($query, \@exec_args);
84            
85             my $loop = $db->nativeSelectMultiExecLoop($query)
86             foreach my $val (@vals) {
87             my $rows = $loop->next([ $val ]);
88             }
89            
90             my $rows = $db->nativeSelectMultiWithArrayRef($query, \@exec_args);
91            
92             my $hash = $db->nativeSelectMapping($query, \@exec_args);
93             my $hash = $db->nativeSelectDynaMapping($query, \@cols, \@exec_args);
94            
95             my $hash = $db->nativeSelectRecordMapping($query, \@exec_args);
96             my $hash = $db->nativeSelectRecordDynaMapping($query, $col, \@exec_args);
97            
98             my $val = $db->nativeSelectValue($query, \@exec_args);
99             my $vals = $db->nativeSelectValuesArray($query, \@exec_args);
100            
101             my $row = $db->abstractSelect($table, \@fields, \%where, \@order);
102             my $rows = $db->abstractSelectMulti($table, \@fields, \%where, \@order);
103            
104             my $loop = $db->nativeSelectLoop($query, \@exec_args);
105             while (my $row = $loop->next) {
106             my $id = $$row{id};
107             }
108            
109             my $rv = $db->nativeQuery($query, \@exec_args);
110            
111             my $loop = $db->nativeQueryLoop("UPDATE my_table SET value=? WHERE id=?");
112             $loop->next([ 'one', 1]);
113             $loop->next([ 'two', 2]);
114            
115             my $id = $db->getLastInsertId;
116            
117             $db->debugOn(\*FILE_HANDLE);
118            
119             $db->setNameArg($arg)
120            
121             $db->commit();
122             $db->ping();
123             $db->err();
124            
125             my $str = $db->to_csv($rows);
126             my $xml = $db->to_xml($rows);
127             my $bencoded = $db->bencode($rows);
128              
129              
130             =head2 Attributes
131              
132             Attributes accessed in C object via hash access are
133             passed on or retrieved from the underlying DBI object, e.g.,
134              
135             $dbi_obj->{RaiseError} = 1
136              
137             =head2 Named Placeholders
138              
139             All native* methods (except for C) support
140             named placeholders. That is, instead of using ? as a
141             placeholder, you can use :name, where name is the name of a key
142             in the hash passed to the method. To use named placeholders,
143             pass a hash reference containing the values in place of the
144             C<@exec_args> argument. E.g.,
145              
146             my $row = $db->nativeSelect("SELECT * FROM test_table WHERE id=:id", { id => 1 });
147              
148             :: in the query string gets converted to : so you can include
149             literal colons in the query. :"var name" and :'var name' are
150             also supported so you can use variable names containing spaces.
151              
152             The implementation uses ? as placeholders under the hood so that
153             quoting is done properly. So if your database driver does not
154             support placeholders, named placeholders will not help you.
155              
156             =head1 DESCRIPTION
157              
158             C provides a wrapper around the DBI that makes it a
159             bit easier on the programmer. This module allows you to execute
160             a query with a single method call as well as make inserts easier,
161             etc. It also supports running hooks at various stages of
162             processing a query (see the section on L).
163              
164             =cut
165              
166             # =over
167              
168             # =item * tries to maintain database independence
169              
170             # =item * inserts, updates, and deletes using native Perl datastructures
171              
172             # =item * combines prepare, execute, fetch of DBIx::Wrapper into a single call
173              
174             # =item * convenience methods such as to_csv, to_xml, to_bencode, etc.
175              
176             # =back
177              
178             =pod
179              
180             =head1 METHODS
181              
182             Following are C methods. Any undocumented methods
183             should be considered private.
184              
185             =cut
186              
187 2     2   55274 use strict;
  2         6  
  2         85  
188 2     2   2492 use Data::Dumper ();
  2         14550  
  2         67  
189              
190             package DBIx::Wrapper;
191              
192 2     2   69 use 5.006_00; # should have at least Perl 5.6.0
  2         7  
  2         74  
193              
194 2     2   12 use warnings;
  2         3  
  2         83  
195 2     2   9 no warnings 'once';
  2         5  
  2         73  
196              
197 2     2   10 use Carp ();
  2         3  
  2         87  
198              
199             our $AUTOLOAD;
200             our $Heavy = 0;
201              
202             our $VERSION = '0.29'; # update below in POD as well
203              
204 2     2   2190 use DBI;
  2         28608  
  2         224  
205 2     2   1902 use DBIx::Wrapper::Request;
  2         5  
  2         58  
206 2     2   1103 use DBIx::Wrapper::SQLCommand;
  2         4  
  2         51  
207 2     2   1267 use DBIx::Wrapper::Statement;
  2         5  
  2         55  
208 2     2   1412 use DBIx::Wrapper::SelectLoop;
  2         6  
  2         58  
209 2     2   1247 use DBIx::Wrapper::SelectExecLoop;
  2         5  
  2         64  
210 2     2   1305 use DBIx::Wrapper::StatementLoop;
  2         7  
  2         54  
211 2     2   1239 use DBIx::Wrapper::Delegator;
  2         5  
  2         152  
212 2     2   1150 use DBIx::Wrapper::DBIDelegator;
  2         6  
  2         2542  
213              
214             my %i_data;
215             my $have_config_general;
216              
217             # adapted from refaddr in Scalar::Util
218             sub refaddr($) {
219 0     0 0 0 my $obj = shift;
220 0 0       0 my $pkg = ref($obj) or return undef;
221            
222 0         0 bless $obj, 'DBIx::Wrapper::Fake';
223            
224 0         0 my $i = int($obj);
225            
226 0         0 bless $obj, $pkg;
227            
228 0         0 return $i;
229             }
230              
231             # taken verbatim from Scalar::Util
232             sub reftype ($) {
233 0     0 0 0 local($@, $SIG{__DIE__}, $SIG{__WARN__});
234 0         0 my $r = shift;
235 0         0 my $t;
236              
237 0 0       0 length($t = ref($r)) or return undef;
238              
239             # This eval will fail if the reference is not blessed
240 0         0 eval { $r->a_sub_not_likely_to_be_here; 1 }
  0         0  
241 0 0       0 ? do {
242             $t = eval {
243             # we have a GLOB or an IO. Stringify a GLOB gives it's name
244 0         0 my $q = *$r;
245 0 0       0 $q =~ /^\*/ ? "GLOB" : "IO";
246             }
247 0 0       0 or do {
248             # OK, if we don't have a GLOB what parts of
249             # a glob will it populate.
250             # NOTE: A glob always has a SCALAR
251 0         0 local *glob = $r;
252 0         0 defined *glob{ARRAY} && "ARRAY"
253             or defined *glob{HASH} && "HASH"
254             or defined *glob{CODE} && "CODE"
255 0 0 0     0 or length(ref(${$r})) ? "REF" : "SCALAR";
    0 0        
      0        
      0        
      0        
256             }
257             }
258             : $t
259             }
260              
261             sub _new {
262 0     0   0 my ($proto) = @_;
263 0   0     0 my $self = bless {}, ref($proto) || $proto;
264 0         0 $i_data{ refaddr($self) } = {};
265              
266 0         0 tie %$self, 'DBIx::Wrapper::DBIDelegator', $self;
267              
268 0         0 return $self;
269             }
270              
271             sub _get_i_data {
272 0     0   0 my $self = shift;
273 0         0 return $i_data{ refaddr($self) };
274             }
275              
276             sub _get_i_val {
277 0     0   0 my $self = shift;
278            
279 0         0 return $self->_get_i_data()->{ shift() };
280             }
281              
282             sub _set_i_val {
283 0     0   0 my $self = shift;
284 0         0 my $name = shift;
285 0         0 my $val = shift;
286              
287 0         0 $self->_get_i_data()->{$name} = $val;
288             }
289              
290             sub _delete_i_val {
291 0     0   0 my $self = shift;
292 0         0 my $name = shift;
293 0         0 delete $self->_get_i_data()->{$name};
294             }
295              
296             sub import {
297 1     1   11 my $class = shift;
298              
299 1         4513 foreach my $e (@_) {
300 0 0         if ($e eq ':heavy') {
301 0           $Heavy = 1;
302             }
303             }
304             }
305              
306             =pod
307              
308             =head2 C
309              
310             Connects to the given database. The first four parameters are
311             the same parameters you would pass to the connect call when
312             using DBI directly. If $data_source is a hash, it will generate
313             the dsn for DBI using the values for the keys driver, database,
314             host, port.
315              
316             The C<%params> hash is optional and contains extra parameters to
317             control the behaviour of C itself. Following are
318             the valid parameters.
319              
320             =over 4
321              
322             =item error_handler and debug_handler
323              
324             These values should either be a reference to a subroutine, or a
325             reference to an array whose first element is an object and whose
326             second element is a method name to call on that object. The
327             parameters passed to the error_handler callback are the current
328             C object and an error string, usually the query if
329             appropriate. The parameters passed to the debug_handler
330             callback are the current C object, an error string,
331             and the filehandle passed to the C method (defaults to
332             C). E.g.,
333              
334             sub do_error {
335             my ($db, $str) = @_;
336             print $DBI::errstr;
337             }
338             sub do_debug {
339             my ($db, $str, $fh) = @_;
340             print $fh "query was: $str\n";
341             }
342            
343             my $db = DBIx::Wrapper->connect($ds, $un, $auth, \%attr,
344             { error_handler => \&do_error,
345             debug_handler => \&do_debug,
346             });
347              
348              
349             =item db_style
350              
351             Used to control some database specific logic. The default value
352             is 'mysql'. Currently, this is only used for the
353             C method. MSSQL is supported with a value of
354             mssql for this parameter.
355              
356             =item heavy
357              
358             If set to a true value, any hashes returned will actually be
359             objects on which you can call methods to get the values back.
360             E.g.,
361              
362             my $row = $db->nativeSelect($query);
363             my $id = $row->id;
364             # or
365             my $id = $row->{id};
366              
367             =item no_placeholders
368              
369             If you are unfortunate enough to be using a database that does
370             not support placeholders, you can set no_placeholders to a true
371             value here. For non native* methods that generate SQL on their
372             own, placeholders are normally used to ensure proper quoting of
373             values. If you set no_placeholders to a true value, DBI's
374             C method will be used to quote the values instead of using
375             placeholders.
376              
377             =back
378              
379             =head2 C
380              
381             An alias for connect().
382              
383             =cut
384              
385             sub connect {
386 0     0 1   my ($proto, $data_source, $username, $auth, $attr, $params) = @_;
387 0           my $self = $proto->_new;
388              
389 0           $self->_set_i_val('_pre_prepare_hooks', []);
390 0           $self->_set_i_val('_post_prepare_hooks', []);
391 0           $self->_set_i_val('_pre_exec_hooks', []);
392 0           $self->_set_i_val('_post_exec_hooks', []);
393 0           $self->_set_i_val('_pre_fetch_hooks', []);
394 0           $self->_set_i_val('_post_fetch_hooks', []);
395              
396              
397 0           my $dsn = $data_source;
398 0 0         $dsn = $self->_getDsnFromHash($data_source) if ref($data_source) eq 'HASH';
399              
400 0           my $dbh = DBI->connect($dsn, $username, $auth, $attr);
401 0 0 0       unless (ref($attr) eq 'HASH' and defined($$attr{PrintError}) and not $$attr{PrintError}) {
      0        
402             # FIXME: make a way to set debug level here
403             # $self->addDebugLevel(2); # print on error
404             }
405 0 0         unless ($dbh) {
406 0 0         if ($self->_isDebugOn) {
407 0           $self->_printDebug(Carp::longmess($DBI::errstr));
408             } else {
409 0 0 0       $self->_printDbiError
410             if not defined($$attr{PrintError}) or $$attr{PrintError};
411             }
412 0           return undef;
413             }
414              
415 0 0         $params = {} unless UNIVERSAL::isa($params, 'HASH');
416            
417 0           $self->_setDatabaseHandle($dbh);
418 0           $self->_setDataSource($data_source);
419 0           $self->_setDataSourceStr($dsn);
420 0           $self->_setUsername($username);
421 0           $self->_setAuth($auth);
422 0           $self->_setAttr($attr);
423 0           $self->_setDisconnect(1);
424              
425 0 0         $self->_setErrorHandler($params->{error_handler}) if $params->{error_handler};
426 0 0         $self->_setDebugHandler($params->{debug_handler}) if $params->{debug_handler};
427 0 0         $self->_setDbStyle($params->{db_style}) if CORE::exists($params->{db_style});
428 0 0         $self->_setHeavy(1) if $params->{heavy};
429 0 0         $self->_setNoPlaceholders($params->{no_placeholders}) if CORE::exists($params->{no_placeholders});
430            
431 0           my ($junk, $dbd_driver, @rest) = split /:/, $dsn;
432 0           $self->_setDbdDriver(lc($dbd_driver));
433              
434 0           return $self;
435             }
436 2     2   24 { no warnings;
  2         4  
  2         40843  
437             *new = \&connect;
438             }
439              
440              
441             =pod
442              
443             =head2 C
444              
445             Like C, but the parameters used to connect are taken
446             from the given configuration file. The L module
447             must be present for this method to work (it is loaded as
448             needed). C<$config_file> should be the path to a configuration
449             file in an Apache-style format. C<$db_key> is the name of the
450             container with the database connection information you wish to
451             use. The C<%params> hash is optional and contains extra parameters
452             to control the behaviour of C itself.
453              
454             Following is an example configuration file. Note that the dsn
455             can be specified either as a container with each piece named
456             separately, or as an option whose value is the full dsn that
457             should be based to the underlying DBI object. Each db container
458             specifies one database connection. Note that, unlike Apache,
459             the containers and option names are case-sensitive.
460              
461             =for pod2rst next-code-block: apache
462              
463            
464            
465             driver mysql
466             database test_db
467             host example.com
468             port 3306
469            
470            
471             user test_user
472             password test_pwd
473            
474            
475             RaiseError 0
476             PrintError 1
477            
478            
479            
480            
481             dsn "dbi:mysql:database=test_db;host=example.com;port=3306"
482            
483             user test_user
484             password test_pwd
485            
486              
487              
488             Configuration features from L supported:
489              
490             =over 4
491              
492             =item * Perl style comments
493              
494             =item * C-style comments
495              
496             =item * Here-documents
497              
498             =item * Apache style Include directive
499              
500             =item * Variable interpolation (see docs for L)
501              
502             =back
503              
504             =cut
505             sub connect_from_config {
506 0     0 1   my ($self, $db_key, $conf_path, $wrapper_attrs) = @_;
507              
508 0           my $config = $self->_read_config_file($conf_path);
509              
510             # FIXME: need to set $DBI::errstr here or something
511 0 0         unless ($config) {
512 0           return;
513             }
514              
515 0           my $dbs = $config->{db};
516 0           my $this_db = $dbs->{$db_key};
517              
518             # FIXME: need to set $DBI::errstr here or something
519 0 0         unless ($this_db) {
520             # $DBI::errstr = "no entry for database key $db_key in $conf_path";
521 0           return;
522             }
523              
524 0           my $dsn = $this_db->{dsn};
525 0           my $user = $this_db->{user};
526 0           my $pwd = $this_db->{password};
527              
528 0 0         if (ref($dsn) eq 'HASH') {
529 0           my @keys = grep { $_ ne 'driver' } sort keys %$dsn;
  0            
530 0           $dsn = "dbi:$dsn->{driver}:" . join(';', map { "$_=$dsn->{$_}" } @keys);
  0            
531             }
532              
533 0           my $attr_container = $this_db->{attributes};
534 0           my $attrs = {};
535 0 0 0       if ($attr_container and UNIVERSAL::isa($attr_container, 'HASH')) {
536 0           $attrs = { %$attr_container };
537             }
538              
539 0           return DBIx::Wrapper->connect($dsn, $user, $pwd, $attrs, $wrapper_attrs);
540             }
541              
542             sub _read_config_file {
543 0     0     my $self = shift;
544 0           my $config_file = shift;
545              
546 0 0         unless ($self->_load_config_general) {
547 0           warn "cannot load config file '$config_file' -- Config::General not present";
548 0           return;
549             }
550            
551 0           my $config_obj = Config::General->new(-ConfigFile => $config_file,
552             # -LowerCaseNames => 1,
553             -UseApacheInclude => 1,
554             -IncludeRelative => 1,
555             -MergeDuplicateBlocks => 1,
556             -AllowMultiOptions => 'yes',
557             -SplitPolicy => 'whitespace',
558             -InterPolateVars => 1,
559             # -SplitPolicy => 'guess',
560             );
561              
562 0 0         unless ($config_obj) {
563 0           return;
564             }
565            
566 0           my %config = $config_obj->getall;
567 0           return \%config;
568             }
569              
570             sub _load_config_general {
571 0 0   0     if (defined($have_config_general)) {
572 0           return $have_config_general;
573             }
574              
575 0           local($SIG{__DIE__});
576 0           eval 'use Config::General';
577 0 0         if ($@) {
578 0           $have_config_general = 0;
579             }
580             else {
581 0           $have_config_general = 1;
582             }
583             }
584              
585             =pod
586              
587             =head2 C
588              
589             Reconnect to the database using the same parameters that were
590             given to the C method. It does not try to disconnect
591             before attempting to connect again.
592              
593             =cut
594             sub reconnect {
595 0     0 1   my $self = shift;
596              
597 0           my $dsn = $self->_getDataSourceStr;
598              
599 0           my $dbh = DBI->connect($dsn, $self->_getUsername, $self->_getAuth,
600             $self->_getAttr);
601 0 0         if ($dbh) {
602 0           $self->_setDatabaseHandle($dbh);
603 0           return $self;
604             } else {
605 0           return undef;
606             }
607             }
608              
609             =pod
610              
611             =head2 C
612              
613             Disconnect from the database. This disconnects and frees up the
614             underlying C object.
615              
616             =cut
617             sub disconnect {
618 0     0 1   my $self = shift;
619 0           my $dbi_obj = $self->_getDatabaseHandle;
620 0 0         $dbi_obj->disconnect if $dbi_obj;
621 0           $self->_deleteDatabaseHandle;
622              
623 0           return 1;
624             }
625              
626             =pod
627              
628             =head2 C
629              
630             Connects to a random database out of the list. This is useful
631             for connecting to a slave database out of a group for read-only
632             access. Ths list should look similar to the following:
633              
634             my $cfg_list = [ { driver => 'mysql',
635             host => 'db0.example.com',
636             port => 3306,
637             database => 'MyDB',
638             user => 'dbuser',
639             auth => 'dbpwd',
640             attr => { RaiseError => 1 },
641             weight => 1,
642             },
643             { driver => 'mysql',
644             host => 'db1.example.com',
645             port => 3306,
646             database => 'MyDB',
647             user => 'dbuser',
648             auth => 'dbpwd',
649             attr => { RaiseError => 1 },
650             weight => 2,
651             },
652             ];
653              
654             where the weight fields are optional (defaulting to 1). The
655             attr field is also optional and corresponds to the 4th argument
656             to DBI's C method. The C<\%attr> passed to this method is
657             an optional parameter specifying the defaults for C<\%attr> to be
658             passed to the C method. The attr field in the config
659             for each database in the list overrides any in the C<\%attr>
660             parameter passed into the method.
661              
662             You may also pass the DSN string for the connect() method as the
663             'dsn' field in each config instead of the separate driver, host,
664             port, and database fields, e.g.,
665              
666             my $cfg_list = [ { dsn => 'dbi:mysql:host=db0.example.com;database=MyDB;port=3306',
667             user => 'dbuser',
668             auth => 'dbpwd',
669             attr => { RaiseError => 1 },
670             weight => 1,
671             },
672             ];
673              
674             Aliases: connect_one
675              
676             =cut
677             sub connect_one {
678 0     0 0   my $proto = shift;
679 0           my $cfg_list = shift;
680 0   0       my $attr = shift || {};
681              
682 0 0 0       return undef unless $cfg_list and @$cfg_list;
683              
684             # make copy so we don't distrub the original datastructure
685 0           $cfg_list = [ @$cfg_list ];
686              
687 0           my $db = 0;
688 0   0       while (not $db and scalar(@$cfg_list) > 0) {
689 0           my ($cfg, $index) = $proto->_pick_one($cfg_list);
690 0   0       my $this_attr = $cfg->{attr} || {};
691 0           $this_attr = { %$attr, %$this_attr };
692              
693 0           eval {
694 0           local($SIG{__DIE__});
695 0   0       $db = $proto->connect($cfg->{dsn} || $cfg, $cfg->{user}, $cfg->{auth}, $this_attr);
696             };
697              
698 0 0         splice(@$cfg_list, $index, 1) unless $db;
699             }
700              
701 0           return $db;
702             }
703             *connectOne = \&connect_one;
704              
705             sub _pick_one {
706 0     0     my $proto = shift;
707 0           my $cfg_list = shift;
708 0 0 0       return undef unless $cfg_list and @$cfg_list;
709              
710 0 0         $cfg_list = [ grep { not defined($_->{weight}) or $_->{weight} != 0 } @$cfg_list ];
  0            
711 0           my $total_weight = 0;
712 0           foreach my $cfg (@$cfg_list) {
713 0   0       $total_weight += $cfg->{weight} || 1;
714             }
715              
716 0           my $target = rand($total_weight);
717            
718 0           my $accumulated = 0;
719 0           my $pick;
720 0           my $index = 0;
721 0           foreach my $cfg (@$cfg_list) {
722 0   0       $accumulated += $cfg->{weight} || 1;
723 0 0         if ($target < $accumulated) {
724 0           $pick = $cfg;
725 0           last;
726             }
727 0           $index++;
728             }
729              
730 0 0         return wantarray ? ($pick, $index) : $pick;
731             }
732            
733             sub _getDsnFromHash {
734 0     0     my $self = shift;
735 0           my $data_source = shift;
736 0           my @dsn;
737            
738 0 0         push @dsn, "database=$$data_source{database}" if $data_source->{database};
739 0 0         push @dsn, "host=$$data_source{host}" if $data_source->{host};
740 0 0         push @dsn, "port=$$data_source{port}" if $data_source->{port};
741              
742 0 0         push @dsn, "mysql_connect_timeout=$$data_source{mysql_connect_timeout}"
743             if $data_source->{mysql_connect_timeout};
744              
745 0   0       my $driver = $data_source->{driver} || $data_source->{type};
746              
747 0 0         if ($data_source->{timeout}) {
748 0 0         if ($driver eq 'mysql') {
749 0           push @dsn, "mysql_connect_timeout=$$data_source{timeout}";
750             }
751             }
752            
753 0           return "dbi:$driver:" . join(';', @dsn);
754             }
755              
756             sub addDebugLevel {
757 0     0 0   my $self = shift;
758 0           my $level = shift;
759 0           my $cur_level = $self->_get_i_val('_debug_level');
760 0           $cur_level |= $level;
761 0           $self->_set_i_val('_debug_level', $cur_level);
762             }
763              
764             sub getDebugLevel {
765 0     0 0   return shift()->_get_i_data('_debug_level');
766             }
767              
768             =pod
769              
770             =head2 C
771              
772             Returns a new DBIx::Wrapper object from a DBI object that has
773             already been created. Note that when created this way,
774             disconnect() will not be called automatically on the underlying
775             DBI object when the DBIx::Wrapper object goes out of scope.
776              
777             Aliases: new_from_dbi
778              
779             =cut
780             sub newFromDBI {
781 0     0 1   my ($proto, $dbh) = @_;
782 0 0         return unless $dbh;
783 0           my $self = $proto->_new;
784 0           $self->_setDatabaseHandle($dbh);
785 0           return $self;
786             }
787              
788             *new_from_dbi = \&newFromDBI;
789              
790             =pod
791              
792             =head2 C
793              
794             Return the underlying DBI object used to query the database.
795              
796             Aliases: get_dbi, getDbi
797              
798             =cut
799             sub getDBI {
800 0     0 1   my ($self) = @_;
801 0           return $self->_getDatabaseHandle;
802             }
803              
804             *get_dbi = \&getDBI;
805             *getDbi = \&getDBI;
806              
807             sub _insert_replace {
808 0     0     my ($self, $operation, $table, $data) = @_;
809              
810 0           my @values;
811             my @fields;
812 0           my @place_holders;
813              
814 0           my $dbh = $self->_getDatabaseHandle;
815              
816 0           while (my ($field, $value) = each %$data) {
817 0           push @fields, $field;
818              
819 0 0         if (UNIVERSAL::isa($value, 'DBIx::Wrapper::SQLCommand')) {
    0          
820 0           push @place_holders, $value->asString;
821             } elsif (ref($value) eq 'SCALAR') {
822 0           push @place_holders, $$value;
823             } else {
824 0 0         if ($self->_getNoPlaceholders) {
825 0 0         if (defined($value)) {
826 0           push @place_holders, $dbh->quote($value);
827             }
828             else {
829 0           push @place_holders, 'NULL';
830             }
831             }
832             else {
833 0           push @place_holders, '?';
834 0           push @values, $value;
835             }
836             }
837             }
838              
839 0           my $fields = join(",", map { $self->_quote_field_name($_) } @fields);
  0            
840 0           my $place_holders = join(",", @place_holders);
841 0           my $sf_table = $self->_quote_table($table);
842 0           my $query = qq{$operation INTO $sf_table ($fields) values ($place_holders)};
843 0           my ($sth, $rv) = $self->_getStatementHandleForQuery($query, \@values);
844 0 0         return $sth unless $sth;
845 0           $sth->finish;
846              
847 0           return $rv;
848             }
849              
850             # FIXME: finish
851             sub _insert_replace_multi {
852 0     0     my ($self, $operation, $table, $data_rows) = @_;
853              
854 0           my @values;
855             my @fields;
856 0           my @all_place_holders;
857              
858 0           my $dbh = $self->_getDatabaseHandle;
859              
860 0           foreach my $data (@$data_rows) {
861 0           my @these_fields;
862             my @place_holders;
863              
864 0           foreach my $field (keys %$data) {
865 0           my $value = $data->{$field};
866              
867 0           push @these_fields, $field;
868              
869 0 0         if (UNIVERSAL::isa($value, 'DBIx::Wrapper::SQLCommand')) {
    0          
870 0           push @place_holders, $value->asString;
871             } elsif (ref($value) eq 'SCALAR') {
872 0           push @place_holders, $$value;
873             } else {
874 0 0         if ($self->_getNoPlaceholders) {
875 0 0         if (defined($value)) {
876 0           push @place_holders, $dbh->quote($value);
877             } else {
878 0           push @place_holders, 'NULL';
879             }
880             } else {
881 0           push @place_holders, '?';
882 0           push @values, $value;
883             }
884             }
885             }
886              
887 0           push @all_place_holders, \@place_holders;
888              
889 0 0         if (@fields) {
890             # FIXME: check that number of fields is same as @these_fields
891 0 0         unless (scalar(@fields) == scalar(@these_fields)) {
892            
893             }
894             }
895             else {
896 0           @fields = @these_fields;
897             }
898             }
899              
900 0           my $fields = join(",", map { $self->_quote_field_name($_) } @fields);
  0            
901             # my $place_holders = join(",", @place_holders);
902 0           my $groups = join(',', map { '(' . join(",", @$_) . ')' } @all_place_holders);
  0            
903 0           my $sf_table = $self->_quote_table($table);
904 0           my $query = qq{$operation INTO $sf_table ($fields) values $groups};
905 0           my ($sth, $rv) = $self->_getStatementHandleForQuery($query, \@values);
906 0 0         return $sth unless $sth;
907 0           $sth->finish;
908            
909 0           return $rv;
910             }
911              
912             =pod
913              
914             =head2 C
915              
916             Insert the provided row into the database. $table is the name
917             of the table you want to insert into. %data is the data you
918             want to insert -- a hash with key/value pairs representing a row
919             to be insert into the database.
920              
921             =cut
922             sub insert {
923 0     0 1   my ($self, $table, $data) = @_;
924 0           return $self->_insert_replace('INSERT', $table, $data);
925             }
926              
927             =pod
928              
929             =head2 C
930              
931             Same as C, except does a C instead of an C for
932             databases which support it.
933              
934             =cut
935             sub replace {
936 0     0 1   my ($self, $table, $data) = @_;
937 0           my $style = lc($self->_getDbStyle);
938 0 0         if ($style eq 'mssql') {
939             # mssql doesn't support replace, so do an insert instead
940 0           return $self->_insert_replace('INSERT', $table, $data);
941             } else {
942 0           return $self->_insert_replace('REPLACE', $table, $data);
943             }
944             }
945              
946             =pod
947              
948             =head2 C
949              
950             This method is MySQL specific. If $table has an auto_increment
951             column, the return value will be the value of the auto_increment
952             column. So if that column was specified in C<\%data>, that value
953             will be returned, otherwise, an insert will be performed and the
954             value of C will be returned. If there is no
955             auto_increment column, but primary keys are provided, the row
956             containing the primary keys will be returned. Otherwise, a true
957             value will be returned upon success.
958              
959             Aliases: smart_replace
960              
961             =cut
962             sub smartReplace {
963 0     0 1   my ($self, $table, $data, $keys) = @_;
964              
965 0           if (0 and $keys) {
966             # ignore $keys for now
967            
968             } else {
969 0           my $dbh = $self->_getDatabaseHandle;
970 0           my $query = qq{DESCRIBE $table};
971 0           my $sth = $self->_getStatementHandleForQuery($query);
972 0 0         return $sth unless $sth;
973 0           my $auto_incr = undef;
974 0           my $key_list = [];
975 0           my $info_list = [];
976 0           while (my $info = $sth->fetchrow_hashref('NAME_lc')) {
977 0           push @$info_list, $info;
978 0 0         push @$key_list, $$info{field} if lc($$info{key}) eq 'pri';
979 0 0         if ($$info{extra} =~ /auto_increment/i) {
980 0           $auto_incr = $$info{field};
981             }
982             }
983              
984 0           my $orig_auto_incr = $auto_incr;
985 0           $auto_incr = lc($auto_incr);
986 0           my $keys_provided = [];
987 0           my $key_hash = { map { (lc($_) => 1) } @$key_list };
  0            
988 0           my $auto_incr_provided = 0;
989 0           foreach my $key (keys %$data) {
990 0 0         push @$keys_provided, $key if CORE::exists($$key_hash{lc($key)});
991 0 0         if (lc($key) eq $auto_incr) {
992 0           $auto_incr_provided = 1;
993 0           last;
994             }
995             }
996              
997 0 0         if (@$keys_provided) {
998             # do replace and return the value of this field
999 0           my $rv = $self->replace($table, $data);
1000 0 0         return $rv unless $rv;
1001 0 0 0       if (not defined($orig_auto_incr) or $orig_auto_incr eq '') {
1002 0           my %hash = map { ($_ => $$data{$_}) } @$keys_provided;
  0            
1003 0           my $row = $self->selectFromHash($table, \%hash);
1004 0 0 0       return $row if $row and %$row;
1005 0           return undef;
1006             } else {
1007 0           return $$data{$orig_auto_incr};
1008             }
1009             } else {
1010             # do insert and return last insert id
1011 0           my $rv = $self->insert($table, $data);
1012 0 0         return $rv unless $rv;
1013 0 0 0       if (not defined($orig_auto_incr) or $orig_auto_incr eq '') {
1014             # FIXME: what do we do here?
1015 0           return 1;
1016             } else {
1017 0           my $id = $self->getLastInsertId(undef, undef, $table, $orig_auto_incr);
1018 0           return $id;
1019             }
1020             }
1021             }
1022             }
1023              
1024             *smart_replace = \&smartReplace;
1025              
1026             =pod
1027              
1028             =head2 C
1029              
1030             Delete rows from table C<$table> using the key/value pairs in C<%keys>
1031             to specify the C clause of the query. Multiple key/value
1032             pairs are joined with C in the C clause. The C
1033             parameter can optionally be an array ref instead of a hashref.
1034             E.g.
1035              
1036             $db->delete($table, [ key1 => $val1, key2 => $val2 ])
1037              
1038             This is so that the order of the parameters in the C clause
1039             are kept in the same order. This is required to use the correct
1040             multi field indexes in some databases.
1041              
1042             =cut
1043             sub delete {
1044 0     0 1   my ($self, $table, $keys) = @_;
1045              
1046 0 0 0       unless ($keys and (UNIVERSAL::isa($keys, 'HASH') or UNIVERSAL::isa($keys, 'ARRAY'))) {
      0        
1047 0           return $self->setErr(-1, 'DBIx::Wrapper: No keys passed to update()');
1048             }
1049              
1050 0           my @keys;
1051             my @values;
1052 0 0         if (ref($keys) eq 'ARRAY') {
1053             # allow this to maintain order in the WHERE clause in
1054             # order to use the right indexes
1055 0           my @copy = @$keys;
1056 0           while (my $key = shift @copy) {
1057 0           push @keys, $key;
1058 0           my $val = shift @copy; # shift off the value
1059             }
1060 0           $keys = { @$keys };
1061             } else {
1062 0           @keys = keys %$keys;
1063             }
1064              
1065 0           my $sf_table = $self->_quote_table($table);
1066              
1067 0           my @where;
1068 0           my $dbh = $self->_getDatabaseHandle;
1069 0           foreach my $key (@keys) {
1070 0           my $sf_key = $self->_quote_field_name($key);
1071 0           my $val = $keys->{$key};
1072              
1073 0 0         if ($self->_getNoPlaceholders) {
1074 0 0         if (defined($val)) {
1075 0           push @where, "$sf_key=" . $dbh->quote($val);
1076             }
1077             else {
1078 0           push @where, "$sf_key IS NULL";
1079             }
1080             }
1081             else {
1082 0 0         if (defined($val)) {
1083 0           push @where, "$sf_key=?";
1084 0           push @values, $val;
1085             }
1086             else {
1087 0           push @where, "$sf_key IS NULL";
1088             }
1089             }
1090             }
1091            
1092             # my $where = join(" AND ", map { "$_=?" } map { $self->_quote_field_name($_) } @keys);
1093            
1094 0           my $where = join(" AND ", @where);
1095 0           my $query = qq{DELETE FROM $sf_table WHERE $where};
1096              
1097 0           my ($sth, $rv) = $self->_getStatementHandleForQuery($query, \@values);
1098 0 0         return $sth unless $sth;
1099 0           $sth->finish;
1100            
1101 0           return $rv;
1102             }
1103              
1104             sub _get_quote_chars {
1105 0     0     my $self = shift;
1106 0           my $quote_cache = $self->_get_i_val('_quote_cache');
1107 0 0         unless ($quote_cache) {
1108 0           my $dbi = $self->_getDatabaseHandle;
1109 0   0       $quote_cache = [ $dbi->get_info(29) || '"', # identifier quot char
      0        
      0        
1110             $dbi->get_info(41) || '.', # catalog name separator
1111             $dbi->get_info(114) || 1, # catalog location
1112             ];
1113 0           $self->_set_i_val('_quote_cache', $quote_cache);
1114             }
1115              
1116 0           return $quote_cache;
1117             }
1118              
1119             sub _get_identifier_quote_char {
1120 0     0     return shift()->_get_quote_chars()->[0];
1121             }
1122              
1123             sub _get_catalog_separator {
1124 0     0     return shift()->_get_quote_chars()->[1];
1125             }
1126              
1127             # don't quote if is a reference to a scalar
1128             sub _maybe_quote_field_name {
1129 0     0     my ($self, $field) = @_;
1130              
1131 0           my $ref = ref($field);
1132 0 0 0       if ($ref and $ref eq 'SCALAR') {
1133 0           return $$field;
1134             }
1135             else {
1136 0           return $self->_quote_field_name($field);
1137             }
1138             }
1139              
1140             sub _quote_field_name {
1141 0     0     my $self = shift;
1142 0           my $field = shift;
1143              
1144 0           my $sep = $self->_get_catalog_separator;
1145 0           my $sf_sep = quotemeta($sep);
1146 0           my @parts = split(/$sf_sep/, $field);
1147              
1148 0           my $quote_char = $self->_get_identifier_quote_char;
1149 0           my $sf_quote_char = quotemeta($quote_char);
1150              
1151 0           foreach my $part (@parts) {
1152 0           $part =~ s/$sf_quote_char/$quote_char$quote_char/g;
1153 0           $part = $quote_char . $part . $quote_char;
1154             }
1155              
1156 0           return join($sep, @parts);
1157             }
1158              
1159             # E.g., turn test_db.test_table into `test_db`.`test_table`
1160             sub _quote_table {
1161 0     0     my $self = shift;
1162 0           my $table = shift;
1163              
1164 0           my $sep = $self->_get_catalog_separator;
1165              
1166 0           my $parts;
1167 0 0         if (ref($table) eq 'ARRAY') {
1168 0           $parts = $table;
1169             }
1170             else {
1171 0           my $sf_sep = quotemeta($sep);
1172 0           $parts = [ split(/$sf_sep/, $table) ];
1173             }
1174            
1175 0           return join($sep, map { $self->_quote_field_name($_) } @$parts);
  0            
1176             }
1177              
1178             =pod
1179              
1180             =head2 C
1181              
1182             Update the table using the key/value pairs in C<%keys> to specify
1183             the C clause of the query. C<%data> contains the new values
1184             for the row(s) in the database. The keys parameter can
1185             optionally be an array ref instead of a hashref. E.g.,
1186              
1187             $db->update($table, [ key1 => $val1, key2 => $val2 ], \%data);
1188              
1189             This is so that the order of the parameters in the C clause
1190             are kept in the same order. This is required to use the correct
1191             multi field indexes in some databases.
1192              
1193             =cut
1194             sub update {
1195 0     0 1   my ($self, $table, $keys, $data) = @_;
1196              
1197 0 0         if (defined($keys)) {
1198 0 0 0       unless ((UNIVERSAL::isa($keys, 'HASH') or UNIVERSAL::isa($keys, 'ARRAY'))) {
1199 0           return $self->setErr(-1, 'DBIx::Wrapper: No keys passed to update()');
1200             }
1201            
1202             }
1203              
1204 0 0 0       unless ($data and UNIVERSAL::isa($data, 'HASH')) {
1205 0           return $self->setErr(-1, 'DBIx::Wrapper: No values passed to update()');
1206             }
1207              
1208 0 0         unless (%$data) {
1209 0           return "0E";
1210             }
1211            
1212             # my @fields;
1213 0           my @values;
1214             my @set;
1215              
1216 0           my $dbh = $self->_getDatabaseHandle;
1217 0           while (my ($field, $value) = each %$data) {
1218             # push @fields, $field;
1219 0           my $sf_field = $self->_quote_field_name($field);
1220 0 0         if (UNIVERSAL::isa($value, 'DBIx::Wrapper::SQLCommand')) {
    0          
1221 0           push @set, "$sf_field=" . $value->asString;
1222             } elsif (ref($value) eq 'SCALAR') {
1223 0           push @set, "$sf_field=" . $$value;
1224             } else {
1225 0 0         if ($self->_getNoPlaceholders) {
1226 0 0         if (defined($value)) {
1227 0           push @set, "$sf_field=" . $dbh->quote($value);
1228             }
1229             else {
1230 0           push @set, "$sf_field=NULL";
1231             }
1232             }
1233             else {
1234 0           push @set, "$sf_field=?";
1235 0           push @values, $value;
1236             }
1237             }
1238             }
1239              
1240 0           my @keys;
1241 0 0         if (ref($keys) eq 'ARRAY') {
    0          
1242             # allow this to maintain order in the WHERE clause in
1243             # order to use the right indexes
1244 0           my @copy = @$keys;
1245 0           while (my $key = shift @copy) {
1246 0           push @keys, $key;
1247 0           my $val = shift @copy; # shift off the value
1248             }
1249 0           $keys = { @$keys };
1250             }
1251             elsif (not defined($keys)) {
1252             # do nothing
1253             }
1254             else {
1255 0           @keys = keys %$keys;
1256             }
1257              
1258             # unless ($self->_getNoPlaceholders) {
1259             # if (defined($keys)) {
1260             # push @values, @$keys{@keys};
1261             # }
1262             # }
1263              
1264 0           my $set = join(",", @set);
1265 0           my $where;
1266 0 0         if (defined($keys)) {
1267 0 0         if ($self->_getNoPlaceholders) {
1268 0           my @where;
1269 0           foreach my $key (@keys) {
1270 0           my $val = $keys->{$key};
1271 0 0         if (UNIVERSAL::isa($val, 'DBIx::Wrapper::SQLCommand')) {
1272 0           my $sf_field = $self->_quote_field_name($key);
1273              
1274 0 0         if ($val->has_condition) {
1275 0           my ($cond, $r_val) = $val->get_condition(not $self->_getNoPlaceholders);
1276              
1277 0 0         if (defined($r_val)) {
1278 0           push @where, "$sf_field $cond $r_val";
1279             } else {
1280 0           push @where, "$sf_field $cond";
1281             }
1282             }
1283            
1284             }
1285             else {
1286 0           push @where, $self->_equals_or_is_null($key, $val);
1287             }
1288             }
1289 0           $where = join(" AND ", @where);
1290             # $where = join(" AND ", map { $self->_equals_or_is_null($_, $keys->{$_}) } @keys);
1291             }
1292             else {
1293 0           my @where;
1294 0           foreach my $key (@keys) {
1295 0           my $sf_field = $self->_quote_field_name($key);
1296 0           my $val = $keys->{$key};
1297 0 0         if (defined($val)) {
1298 0 0         if (UNIVERSAL::isa($val, 'DBIx::Wrapper::SQLCommand')) {
1299 0 0         if ($val->has_condition) {
1300 0           my ($cond, $r_val) = $val->get_condition(not $self->_getNoPlaceholders);
1301 0 0         if (defined($r_val)) {
1302 0           push @where, "$sf_field $cond $r_val";
1303 0           push @values, $val->get_val;
1304             } else {
1305 0           push @where, "$sf_field $cond";
1306             }
1307             }
1308              
1309             }
1310             else {
1311 0           push @values, $val;
1312 0           push @where, "$sf_field=?";
1313             }
1314            
1315             }
1316             else {
1317 0           push @where, "$sf_field IS NULL";
1318             }
1319             }
1320            
1321             # $where = join(" AND ", map { "$_=?" } map { $self->_quote_field_name($_) } @keys);
1322 0           $where = join(" AND ", @where);
1323             }
1324             }
1325            
1326             # quote_identifier() method added to DBI in version 1.21 (Feb 2002)
1327            
1328 0           my $sf_table = $self->_quote_table($table);
1329 0           my $query;
1330 0 0         if (defined($where)) {
1331 0           $query = qq{UPDATE $sf_table SET $set WHERE $where};
1332             }
1333             else {
1334 0           $query = qq{UPDATE $sf_table SET $set};
1335             }
1336            
1337 0           my ($sth, $rv) = $self->_getStatementHandleForQuery($query, \@values);
1338 0 0         return $sth unless $sth;
1339 0           $sth->finish;
1340            
1341 0           return $rv;
1342             }
1343              
1344             sub _equals_or_is_null {
1345 0     0     my ($self, $field_name, $value, $dont_quote_val) = @_;
1346              
1347 0           my $str = '';
1348 0 0         if (defined($value)) {
1349 0           $str = $self->_quote_field_name($field_name) . '=';
1350 0 0         if ($dont_quote_val) {
1351 0           $str .= $value;
1352             }
1353             else {
1354 0           $str .= $self->_getDatabaseHandle()->quote($value);
1355             }
1356             }
1357             else {
1358 0           $str = $self->_quote_field_name($field_name) . ' IS NULL';
1359             }
1360              
1361 0           return $str;
1362             }
1363              
1364             =pod
1365              
1366             =head2 C
1367              
1368             Returns true if one or more records exist with the given column
1369             values in C<%keys>. C<%keys> can be recursive as in the
1370             C method.
1371              
1372             =cut
1373             sub exists {
1374 0     0 1   my $self = shift;
1375 0           my $table = shift;
1376 0           my $keys = shift;
1377              
1378 0           my $row = $self->select_from_hash($table, $keys, [ [ keys %$keys ]->[0] ]);
1379             # my $row = $self->select_from_hash($table, $keys);
1380             # print STDERR "\n\n=====> exists: " . Data::Dumper->Dump([ $row ], [ 'row' ]) . "\n\n";
1381              
1382 0 0 0       if ($row and %$row) {
1383 0           return 1;
1384             }
1385 0           return;
1386             }
1387              
1388             =pod
1389              
1390             =head2 C
1391              
1392             Select from table C<$table> using the key/value pairs in C<%keys> to
1393             specify the C clause of the query. Multiple key/value pairs
1394             are joined with C in the C clause. Returns a single row
1395             as a hashref. If C<%keys> is empty or not passed, it is treated as
1396             C<"SELECT * FROM $table"> with no C clause. C<@cols> is a list of
1397             columns you want back. If nothing is passed in C<@cols>, all
1398             columns will be returned.
1399              
1400             If a value in the C<%keys> hash is an array ref, the resulting
1401             query will search for records with any of those values. E.g.,
1402              
1403             my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ] });
1404              
1405             will result in a query like
1406              
1407             =for pod2rst next-code-block: sql
1408              
1409             SELECT * FROM the_table WHERE (id=5 OR id=6 OR id=7)
1410              
1411             The call
1412              
1413             my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ], the_val => 'ten' });
1414              
1415             will result in a query like
1416              
1417             =for pod2rst next-code-block: sql
1418              
1419             SELECT * FROM the_table WHERE (id=5 OR id=6 OR id=7) AND the_val="ten"
1420              
1421             or, if a value was passed in for C<\@cols>, e.g.,
1422              
1423             my $row = $db->selectFromHash('the_table', { id => [ 5, 6, 7 ], the_val => 'ten' }, [ 'id' ]);
1424              
1425             the resulting query would be
1426              
1427             =for pod2rst next-code-block: sql
1428              
1429             SELECT id FROM the_table WHERE (id=5 OR id=6 OR id=7) AND the_val="ten"
1430              
1431              
1432             Aliases: select_from_hash, sfh
1433              
1434             =cut
1435             sub selectFromHash {
1436 0     0 1   my ($self, $table, $keys, $cols) = @_;
1437 0           my $sth = $self->_get_statement_handle_for_select_from_hash($table, $keys, $cols);
1438 0 0         return $sth unless $sth;
1439 0           my $info = $sth->fetchrow_hashref;
1440 0           my $rv;
1441 0 0 0       if ($info and %$info) {
1442 0           $rv = $info;
1443             } else {
1444 0 0         $rv = wantarray ? () : undef;
1445             }
1446 0           $sth->finish;
1447 0           return $rv;
1448             }
1449              
1450             *select_from_hash = \&selectFromHash;
1451             *sfh = \&selectFromHash;
1452              
1453             sub _get_statement_handle_for_select_from_hash {
1454 0     0     my ($self, $table, $keys, $cols) = @_;
1455              
1456 0           my ($query, $exec_args) = $self->_get_query_for_select_from_hash($table, $keys, $cols);
1457              
1458 0 0         if ($exec_args) {
1459 0           return $self->_getStatementHandleForQuery($query, $exec_args);
1460             }
1461             else {
1462 0           return $self->_getStatementHandleForQuery($query);
1463             }
1464             }
1465              
1466             sub _get_query_for_select_from_hash {
1467 0     0     my ($self, $table, $keys, $cols) = @_;
1468 0           my $query;
1469              
1470 0           my $col_list = '*';
1471 0 0 0       if (ref($cols) eq 'ARRAY') {
    0          
1472 0 0         if (@$cols) {
1473 0           $col_list = join(',', map { $self->_maybe_quote_field_name($_) } @$cols);
  0            
1474             }
1475             } elsif (defined($cols) and $cols ne '') {
1476 0           $col_list = $self->_quote_field_name($cols);
1477             }
1478              
1479 0           my $sf_table = $self->_quote_table($table);
1480 0 0 0       if ($keys and ((ref($keys) eq 'HASH' and %$keys) or (ref($keys) eq 'ARRAY' and @$keys))) {
      0        
1481 0           my ($where, $exec_args) = $self->_get_clause_for_select_from_hash($keys);
1482 0           return (qq{SELECT $col_list FROM $sf_table WHERE $where}, $exec_args);
1483             } else {
1484 0           return (qq{SELECT $col_list FROM $sf_table});
1485             }
1486             }
1487              
1488             sub _get_clause_for_select_from_hash {
1489 0     0     my $self = shift;
1490 0           my $data = shift;
1491 0           my $parent_key = shift;
1492 0           my @values;
1493             my @where;
1494              
1495 0           my $dbh = $self->_getDatabaseHandle;
1496 0 0         if (ref($data) eq 'HASH') {
    0          
1497 0           my @keys = sort keys %$data;
1498 0           foreach my $key (@keys) {
1499 0           my $val = $data->{$key};
1500 0 0         if (ref($val)) {
1501 0           my ($clause, $exec_args) = $self->_get_clause_for_select_from_hash($val, $key);
1502 0           push @where, "($clause)";
1503 0 0         push @values, @$exec_args if $exec_args;
1504             } else {
1505 0           my $sf_key = $self->_quote_field_name($key);
1506 0 0         if ($self->_getNoPlaceholders) {
1507 0 0         if (defined($val)) {
1508 0           push @where, "$sf_key=" . $dbh->quote($val);
1509             }
1510             else {
1511 0           push @where, "$sf_key IS NULL";
1512             }
1513             }
1514             else {
1515 0 0         if (defined($val)) {
1516 0           push @where, "$sf_key=?";
1517 0           push @values, $val;
1518             }
1519             else {
1520 0           push @where, "$sf_key IS NULL";
1521             }
1522             }
1523             }
1524             }
1525 0           my $where = join(" AND ", @where);
1526 0 0         return wantarray ? ($where, \@values) : $where;
1527             } elsif (ref($data) eq 'ARRAY') {
1528 0           foreach my $val (@$data) {
1529 0 0         if (ref($val)) {
1530 0           my ($clause, $exec_args) =
1531             $self->_get_clause_for_select_from_hash($val, $parent_key);
1532 0           push @where, "($clause)";
1533 0 0         push @values, @$exec_args if $exec_args;
1534             } else {
1535 0           my $sf_parent_key = $self->_quote_field_name($parent_key);
1536 0 0         if ($self->_getNoPlaceholders) {
1537 0 0         if (defined($val)) {
1538 0           push @where, "$sf_parent_key=" . $dbh->quote($val);
1539             }
1540             else {
1541 0           push @where, "$sf_parent_key IS NULL";
1542             }
1543             }
1544             else {
1545 0 0         if (defined($val)) {
1546 0           push @where, "$sf_parent_key=?";
1547 0           push @values, $val;
1548             }
1549             else {
1550 0           push @where, "$sf_parent_key IS NULL";
1551             }
1552             }
1553             }
1554             }
1555 0           my $where = join(" OR ", @where);
1556 0 0         return wantarray ? ($where, \@values) : $where;
1557             } else {
1558 0 0         return wantarray ? ($data, []) : $data;
1559             }
1560             }
1561            
1562              
1563             =pod
1564              
1565             =head2 C
1566              
1567             Like C, but returns all rows in the result.
1568             Returns a reference to an array of hashrefs.
1569              
1570             Aliases: select_from_hash_multi, sfhm
1571              
1572             =cut
1573             sub selectFromHashMulti {
1574 0     0 1   my ($self, $table, $keys, $cols) = @_;
1575 0           my $sth = $self->_get_statement_handle_for_select_from_hash($table, $keys, $cols);
1576 0 0         return $sth unless $sth;
1577 0           my $results = [];
1578 0           while (my $info = $sth->fetchrow_hashref) {
1579 0           push @$results, $info;
1580             }
1581 0           $sth->finish;
1582 0           return $results;
1583             }
1584              
1585             *select_from_hash_multi = \&selectFromHashMulti;
1586             *sfhm = \&selectFromHashMulti;
1587              
1588             =pod
1589              
1590             =head2 C
1591              
1592             Selects every row in the given table. Equivalent to leaving out
1593             C<%keys> when calling C, e.g.,
1594             C<$dbh-EselectFromHashMulti($table, undef, \@cols)>. The simplest
1595             case of C<$dbh-EselectAll($table)> gets turned into something like
1596             C
1597              
1598             Aliases: select_from_all
1599              
1600             =cut
1601             # version 0.22
1602             sub selectAll {
1603 0     0 1   my $self = shift;
1604 0           my $table = shift;
1605 0           my $cols = shift;
1606              
1607 0           return $self->select_from_hash_multi($table, undef, $cols);
1608             }
1609              
1610             *select_all = \&selectAll;
1611              
1612             =pod
1613              
1614             =head2 C
1615              
1616             Combination of C and C.
1617             Returns the first column from the result of a query given by
1618             C<$table> and C<%keys>, as in C. C<$col> is the column to
1619             return.
1620              
1621             Aliases: select_value_from_hash, svfh
1622              
1623             =cut
1624             sub selectValueFromHash {
1625 0     0 1   my ($self, $table, $keys, $col) = @_;
1626              
1627 0           my $sth = $self->_get_statement_handle_for_select_from_hash($table, $keys, $col);
1628 0 0         return $sth unless $sth;
1629 0           my $info = $sth->fetchrow_arrayref;
1630 0           $sth->finish;
1631              
1632 0           my $rv;
1633 0 0 0       if ($info and @$info) {
1634 0           return $info->[0];
1635             } else {
1636 0 0         return wantarray ? () : undef;
1637             }
1638             }
1639              
1640             *select_value_from_hash = \&selectValueFromHash;
1641             *svfh = \&selectValueFromHash;
1642              
1643             =pod
1644              
1645             =head2 C
1646              
1647             Like C, but returns the first column of all
1648             rows in the result.
1649              
1650             Aliases: select_value_from_hash_multi, svfhm
1651              
1652             =cut
1653              
1654             sub selectValueFromHashMulti {
1655 0     0 1   my ($self, $table, $keys, $col) = @_;
1656              
1657 0           my $sth = $self->_get_statement_handle_for_select_from_hash($table, $keys, $col);
1658 0 0         return $sth unless $sth;
1659 0           my $results = [];
1660 0           while (my $info = $sth->fetchrow_arrayref) {
1661 0           push @$results, $info->[0];
1662             }
1663 0           $sth->finish;
1664 0           return $results;
1665             }
1666              
1667             *select_value_from_hash_multi = \&selectValueFromHashMulti;
1668             *svfhm = \&selectValueFromHashMulti;
1669              
1670             =pod
1671              
1672             =head2 C
1673              
1674             Same as C, except that a check is first made to see if
1675             there are any rows matching the data in C<%keys>. If so, C
1676             is called, otherwise, C is called.
1677              
1678             Aliases: smart_update
1679              
1680             =cut
1681             sub smartUpdate {
1682 0     0 1   my ($self, $table, $keys, $data) = @_;
1683 0 0 0       unless (ref($data) eq 'HASH' and %$data) {
1684 0           return "0E";
1685             }
1686              
1687             # print STDERR "\n\n=====> calling exists: " . Data::Dumper->Dump([ $keys ], [ 'keys' ]) . "\n\n";
1688              
1689 0 0         if ($self->exists($table, $keys)) {
1690             # print STDERR "\n\n====> calling update()\n\n";
1691 0           return $self->update($table, $keys, $data);
1692             } else {
1693 0           my %new_data = %$data;
1694 0           while (my ($key, $value) = each %$keys) {
1695 0 0         $new_data{$key} = $value unless CORE::exists $new_data{$key};
1696             }
1697 0           return $self->insert($table, \%new_data);
1698             }
1699            
1700             }
1701              
1702             *smart_update = \&smartUpdate;
1703              
1704             sub _runHandler {
1705 0     0     my ($self, $handler_info, @args) = @_;
1706 0 0         return undef unless ref($handler_info);
1707              
1708 0           my ($handler, $custom_args) = @$handler_info;
1709 0 0         $custom_args = [] unless $custom_args;
1710            
1711 0           unshift @args, $self;
1712 0 0         if (ref($handler) eq 'ARRAY') {
1713 0           my $method = $handler->[1];
1714 0           $handler->[0]->$method(@args, @$custom_args);
1715             } else {
1716 0           $handler->(@args, @$custom_args);
1717             }
1718              
1719 0           return 1;
1720             }
1721              
1722             sub _runHandlers {
1723 0     0     my ($self, $handlers, $r) = @_;
1724 0 0         return undef unless $handlers;
1725              
1726 0           my $rv = $r->OK;
1727 0           foreach my $handler_info (reverse @$handlers) {
1728 0           my ($handler, $custom_args) = @$handler_info;
1729 0 0         $custom_args = [] unless $custom_args;
1730            
1731 0 0         if (ref($handler) eq 'ARRAY') {
1732 0           my $method = $handler->[1];
1733 0           $rv = $handler->[0]->$method($r);
1734             } else {
1735 0           $rv = $handler->($r);
1736             }
1737 0 0         last unless $rv == $r->DECLINED;
1738             }
1739              
1740 0           return $rv;
1741             }
1742              
1743              
1744              
1745             sub _defaultPrePrepareHandler {
1746 0     0     my $r = shift;
1747 0           return $r->OK;
1748             }
1749              
1750             sub _defaultPostPrepareHandler {
1751 0     0     my $r = shift;
1752 0           return $r->OK;
1753             }
1754              
1755             sub _defaultPreExecHandler {
1756 0     0     my $r = shift;
1757 0           return $r->OK;
1758             }
1759              
1760             sub _defaultPostExecHandler {
1761 0     0     my $r = shift;
1762 0           return $r->OK;
1763             }
1764              
1765             sub _defaultPreFetchHandler {
1766 0     0     my $r = shift;
1767 0           return $r->OK;
1768             }
1769            
1770             sub _defaultPostFetchHandler {
1771 0     0     my $r = shift;
1772 0           return $r->OK;
1773             }
1774              
1775             sub _runGenericHook {
1776 0     0     my ($self, $r, $default_handler, $custom_handler_field) = @_;
1777 0           my $handlers = [ $default_handler ];
1778            
1779 0 0         if ($self->shouldBeHeavy) {
1780 0 0         if ($custom_handler_field eq '_post_fetch_hooks') {
1781 0           push @$handlers, [ \&_heavyPostFetchHook ];
1782             }
1783             }
1784            
1785 0           my $custom_handlers = $self->_get_i_val($custom_handler_field);
1786 0 0         push @$handlers, @$custom_handlers if $custom_handlers;
1787              
1788 0           return $self->_runHandlers($handlers, $r);
1789             }
1790              
1791             sub _runPrePrepareHook {
1792 0     0     my $self = shift;
1793 0           my $r = shift;
1794 0           my $handlers = [ [ \&_defaultPrePrepareHandler ] ];
1795 0           my $custom_handlers = $self->_get_i_val('_pre_prepare_hooks');
1796 0 0         push @$handlers, @$custom_handlers if $custom_handlers;
1797            
1798 0           return $self->_runHandlers($handlers, $r);
1799             }
1800              
1801             sub _runPostPrepareHook {
1802 0     0     my $self = shift;
1803 0           my $r = shift;
1804 0           my $handlers = [ [ \&_defaultPostPrepareHandler ] ];
1805 0           my $custom_handlers = $self->_get_i_val('_post_prepare_hooks');
1806 0 0         push @$handlers, @$custom_handlers if $custom_handlers;
1807            
1808 0           return $self->_runHandlers($handlers, $r);
1809             }
1810              
1811             sub _runPreExecHook {
1812 0     0     my $self = shift;
1813 0           my $r = shift;
1814 0           my $handlers = [ [ \&_defaultPreExecHandler ] ];
1815 0           my $custom_handlers = $self->_get_i_val('_pre_exec_hooks');
1816 0 0         push @$handlers, @$custom_handlers if $custom_handlers;
1817            
1818 0           return $self->_runHandlers($handlers, $r);
1819             }
1820              
1821             sub _runPostExecHook {
1822 0     0     my $self = shift;
1823 0           my $r = shift;
1824 0           return $self->_runGenericHook($r, [ \&_defaultPostExecHandler ], '_post_exec_hooks');
1825             }
1826              
1827             sub _runPreFetchHook {
1828 0     0     my $self = shift;
1829 0           my $r = shift;
1830 0           return $self->_runGenericHook($r, [ \&_defaultPreFetchHandler ], '_pre_fetch_hooks');
1831             }
1832              
1833             sub _runPostFetchHook {
1834 0     0     my $self = shift;
1835 0           my $r = shift;
1836 0           return $self->_runGenericHook($r, [ \&_defaultPostFetchHandler ],
1837             '_post_fetch_hooks');
1838             }
1839              
1840             sub _heavyPostFetchHook {
1841 0     0     my $r = shift;
1842 0           my $row = $r->getReturnVal;
1843              
1844 0 0         if (ref($row) eq 'HASH') {
    0          
1845 0           $r->setReturnVal(bless($row, 'DBIx::Wrapper::Delegator'));
1846             } elsif (ref($row) eq 'ARRAY') {
1847             # do nothing for now
1848             }
1849             }
1850              
1851             sub _bind_named_place_holders {
1852 0     0     my $self = shift;
1853 0           my $query = shift;
1854 0           my $exec_args = shift;
1855              
1856 0           my $dbh = $self->_getDatabaseHandle;
1857            
1858             # $query =~ s/(?quote($exec_args->{$2})/eg;
1859             # return wantarray ? ($query, []) : $query;
1860              
1861 0           my @new_args;
1862             # $query =~ s/(?{$2}); '?'/eg;
1863              
1864             # Convert :: to : instead of treating it as a placeholder
1865 0           $query =~ s{(::)|:([\'\"]?)(\w+)\2}{
1866 0 0 0       if (defined($1) and $1 eq '::' ) {
1867 0 0         ':' . (defined $2 ? $2 : '') . (defined $3 ? $3 : '') . (defined $2 ? $2 : '')
    0          
    0          
1868             }
1869             else {
1870 0           my $val = '?';
1871 0 0         if ($self->_getNoPlaceholders) {
1872 0           $val = $dbh->quote($exec_args->{$3});
1873             } else {
1874 0           push(@new_args, $exec_args->{$3});
1875             }
1876 0           $val;
1877             }
1878             }eg;
1879            
1880 0 0         return wantarray ? ($query, \@new_args) : $query;
1881              
1882             }
1883              
1884             sub _getStatementHandleForQuery {
1885 0     0     my ($self, $query, $exec_args, $attr) = @_;
1886            
1887 0 0         if (scalar(@_) >= 3) {
1888 0           my $type = ref($exec_args);
1889 0 0         if ($type eq 'HASH') {
    0          
1890             # okay
1891 0           ($query, $exec_args) = $self->_bind_named_place_holders($query, $exec_args);
1892             }
1893             elsif ($type eq 'ARRAY') {
1894             # okay -- leave as is
1895             }
1896             else {
1897 0           $exec_args = [ $exec_args ];
1898             }
1899             }
1900            
1901 0 0         $exec_args = [] unless $exec_args;
1902              
1903 0           $self->_printDebug($query);
1904              
1905 0           my $r = DBIx::Wrapper::Request->new($self);
1906 0           $r->setQuery($query);
1907 0           $r->setExecArgs($exec_args);
1908            
1909 0           $self->_runPrePrepareHook($r);
1910 0           $query = $r->getQuery;
1911 0           $exec_args = $r->getExecArgs;
1912            
1913 0           my $dbh = $self->_getDatabaseHandle;
1914 0           my $sth;
1915              
1916 0 0         if (ref($attr) eq 'HASH') {
1917 0           $sth = $dbh->prepare($query, $attr);
1918             }
1919             else {
1920 0           $sth = $dbh->prepare($query);
1921             }
1922              
1923 0           $r->setStatementHandle($sth);
1924 0 0         $r->setErrorStr($sth ? $dbh->errstr : '');
1925 0           $self->_runPostPrepareHook($r);
1926            
1927 0 0         unless ($sth) {
1928 0 0         if ($self->_isDebugOn) {
1929 0           $self->_printDebug(Carp::longmess($dbh->errstr) . "\nQuery was '$query'\n");
1930             } else {
1931 0           $self->_printDbiError("\nQuery was '$query'\n");
1932             }
1933 0 0         return wantarray ? ($self->setErr(0, $dbh->errstr), undef)
1934             : $self->setErr(0, $dbh->errstr);
1935             }
1936              
1937 0           $r->setQuery($query);
1938 0           $r->setExecArgs($exec_args);
1939              
1940 0           $self->_runPreExecHook($r);
1941              
1942 0           $exec_args = $r->getExecArgs;
1943              
1944 0           my $rv = $sth->execute(@$exec_args);
1945            
1946 0           $r->setExecReturnValue($rv);
1947 0 0         $r->setErrorStr($rv ? '' : $dbh->errstr);
1948 0           $self->_runPostExecHook($r);
1949 0           $rv = $r->getExecReturnValue;
1950 0           $sth = $r->getStatementHandle;
1951            
1952 0 0         unless ($rv) {
1953 0 0         if ($self->_isDebugOn) {
1954 0           $self->_printDebug(Carp::longmess($dbh->errstr) . "\nQuery was '$query'\n");
1955             } else {
1956 0           $self->_printDbiError("\nQuery was '$query'\n");
1957             }
1958 0 0         return wantarray ? ($self->setErr(1, $dbh->errstr), undef)
1959             : $self->setErr(1, $dbh->errstr);
1960             }
1961              
1962 0 0         return wantarray ? ($sth, $rv, $r) : $sth;
1963             }
1964              
1965             sub prepare_no_hooks {
1966 0     0 0   my $self = shift;
1967 0           my $query = shift;
1968              
1969 0           my $dbi_obj = $self->getDBI;
1970 0           my $sth = $dbi_obj->prepare($query);
1971              
1972 0           return $sth;
1973             }
1974              
1975             *prepare_no_handlers = \&prepare_no_hooks;
1976              
1977              
1978             =pod
1979              
1980             =head2 C
1981              
1982             Executes the query in $query and returns a single row result (as
1983             a hash ref). If there are multiple rows in the result, the rest
1984             get silently dropped. C<@exec_args> are the same arguments you
1985             would pass to an C called on a DBI object. Returns
1986             undef on error.
1987              
1988             Aliases: native_select
1989              
1990             =cut
1991             sub nativeSelect {
1992 0     0 1   my ($self, $query, $exec_args) = @_;
1993              
1994 0           my ($sth, $rv, $r);
1995 0 0         if (scalar(@_) == 3) {
1996 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query, $exec_args);
1997             } else {
1998 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query);
1999             }
2000            
2001 0 0         return $sth unless $sth;
2002              
2003 0           $self->_runPreFetchHook($r);
2004 0           $sth = $r->getStatementHandle;
2005            
2006 0           my $result = $sth->fetchrow_hashref($self->getNameArg);
2007            
2008 0           $r->setReturnVal($result);
2009 0           $self->_runPostFetchHook($r);
2010 0           $result = $r->getReturnVal;
2011            
2012 0           $sth->finish;
2013              
2014 0           return $result;
2015             }
2016              
2017             *read = \&nativeSelect;
2018             *selectNative = \&nativeSelect;
2019             *native_select = \&nativeSelect;
2020             *select_native = \&nativeSelect;
2021              
2022             =pod
2023              
2024             =head2 C
2025              
2026             Like C, but returns a loop object that can be used
2027             to execute the same query over and over with different bind
2028             parameters. This does a single DBI C instead of a new
2029             C for select.
2030              
2031             E.g.,
2032              
2033             my $loop = $db->nativeSelectExecLoop("SELECT * FROM mytable WHERE id=?");
2034             foreach my $id (@ids) {
2035             my $row = $loop->next([ $id ]);
2036             }
2037              
2038             To get the column names in the order returned from your query:
2039              
2040             # returns the names with their character case the same as when
2041             # calling $loop->next, i.e., the case set with $db->setNameArg
2042             my $cols = $loop->get_field_names;
2043            
2044             # returns the names with their character case unmodified
2045             my $cols = $loop->get_names;
2046            
2047             # returns the names in all upper-case
2048             my $cols = $loop->get_names_uc;
2049            
2050             # returns the names in all lower-case
2051             my $cols = $loop->get_names_lc;
2052              
2053             Aliases: native_select_exec_loop
2054              
2055             =cut
2056             # added for v 0.08
2057             sub nativeSelectExecLoop {
2058 0     0 1   my ($self, $query) = @_;
2059 0           return DBIx::Wrapper::SelectExecLoop->new($self, $query);
2060             }
2061              
2062             *native_select_exec_loop = \&nativeSelectExecLoop;
2063             *select_native_exec_loop = \&nativeSelectExecLoop;
2064             *selectNativeExecLoop = \&nativeSelectExecLoop;
2065              
2066             =pod
2067              
2068             =head2 C
2069              
2070             Like C, but return a reference to an array instead
2071             of a hash. Returns undef on error. If there are no results
2072             from the query, a reference to an empty array is returned.
2073              
2074             Aliases: native_select_with_array_ref, nswar
2075              
2076             =cut
2077             sub nativeSelectWithArrayRef {
2078 0     0 1   my ($self, $query, $exec_args) = @_;
2079              
2080 0           my ($sth, $rv, $r);
2081 0 0         if (scalar(@_) == 3) {
2082 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query, $exec_args);
2083             } else {
2084 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query);
2085             }
2086            
2087 0 0         return $sth unless $sth;
2088              
2089 0           $self->_runPreFetchHook($r);
2090 0           $sth = $r->getStatementHandle;
2091              
2092 0           my $result = $sth->fetchrow_arrayref;
2093              
2094 0           $r->setReturnVal($result);
2095 0           $self->_runPostFetchHook($r);
2096              
2097 0           $result = $r->getReturnVal;
2098              
2099 0           $sth->finish;
2100              
2101 0 0 0       return [] unless $result and ref($result) =~ /ARRAY/;
2102            
2103             # have to make copy because recent version of DBI now
2104             # return the same array reference each time
2105 0           return [ @$result ];
2106             }
2107              
2108             *native_select_with_array_ref = \&nativeSelectArrayWithArrayRef;
2109             *select_native_with_array_ref = \&nativeSelectArrayWithArrayRef;
2110             *selectNativeArrayWithArrayRef = \&nativeSelectArrayWithArrayRef;
2111             *nswar = \&nativeSelectArrayWithArrayRef;
2112              
2113             =pod
2114              
2115             =head2 C
2116              
2117             Executes the query in C<$query> and returns an array of rows, where
2118             each row is a hash representing a row of the result. Returns
2119             C on error. If there are no results for the query, an empty
2120             array ref is returned.
2121              
2122             Aliases: native_select_multi
2123              
2124             =cut
2125             sub nativeSelectMulti {
2126 0     0 1   my ($self, $query, $exec_args) = @_;
2127              
2128 0           my ($sth, $rv, $r);
2129 0 0         if (scalar(@_) == 3) {
2130 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query, $exec_args);
2131             } else {
2132 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query);
2133             }
2134 0 0         return $sth unless $sth;
2135              
2136 0           $self->_runPreFetchHook($r);
2137 0           $sth = $r->getStatementHandle;
2138              
2139 0           my $rows = [];
2140 0           my $row = $sth->fetchrow_hashref($self->getNameArg);
2141 0           while ($row) {
2142 0           $r->setReturnVal($row);
2143 0           $self->_runPostFetchHook($r);
2144              
2145 0           $row = $r->getReturnVal;
2146 0           push @$rows, $row;
2147            
2148 0           $self->_runPreFetchHook($r);
2149 0           $sth = $r->getStatementHandle;
2150              
2151 0           $row = $sth->fetchrow_hashref($self->getNameArg)
2152             }
2153 0           my $col_names = $sth->{$self->getNameArg};
2154 0           $self->_set_i_val('_last_col_names', $col_names);
2155 0           $sth->finish;
2156              
2157 0           return $rows;
2158             }
2159              
2160             *readArray = \&nativeSelectMulti;
2161             *native_select_multi = \&nativeSelectMulti;
2162             *select_native_multi = \&nativeSelectMulti;
2163             *selectNativeMulti = \&nativeSelectMulti;
2164              
2165             =pod
2166              
2167             =head2 C
2168              
2169             Like C, but if there is only one row in the
2170             result, that row (a hash ref) is returned. If there are zero
2171             rows, undef is returned. Otherwise, an array ref is returned.
2172              
2173             Aliases: native_select_multi_or_one
2174              
2175             =cut
2176             # version 0.22
2177             sub nativeSelectMultiOrOne {
2178 0     0 1   my $self = shift;
2179              
2180 0           my $rows = $self->nativeSelectMulti(@_);
2181 0 0         if ($rows) {
2182 0 0         if (scalar(@$rows) == 0) {
    0          
2183 0           return;
2184             }
2185             elsif (scalar(@$rows) == 1) {
2186 0           return $rows->[0];
2187             }
2188             else {
2189 0           return $rows;
2190             }
2191             }
2192             else {
2193 0           return $rows;
2194             }
2195              
2196             }
2197             *native_select_multi_or_one = \&nativeSelectMultiOrOne;
2198              
2199             =pod
2200              
2201             =head2 C
2202              
2203             Like C, but returns an array of rows, where
2204             each row is a hash representing a row of the result.
2205              
2206             Aliases: native_select_multi_exec_loop
2207              
2208             =cut
2209             sub nativeSelectMultiExecLoop {
2210 0     0 1   my ($self, $query) = @_;
2211 0           return DBIx::Wrapper::SelectExecLoop->new($self, $query, 1);
2212             }
2213              
2214             *native_select_multi_exec_loop = \&nativeSelectMultiExecLoop;
2215             *select_native_multi_exec_loop = \&nativeSelectMultiExecLoop;
2216             *selectNativeMultiExecLoop = \&nativeSelectMultiExecLoop;
2217              
2218             =pod
2219              
2220             =head2 C
2221              
2222             Like C, but return a reference to an array of
2223             arrays instead of to an array of hashes. Returns undef on error.
2224              
2225             Aliases: native_select_multi_with_array_ref
2226              
2227             =cut
2228             sub nativeSelectMultiWithArrayRef {
2229 0     0 1   my ($self, $query, $exec_args, $attr) = @_;
2230              
2231 0           my ($sth, $rv, $r);
2232 0 0         if (scalar(@_) >= 3) {
2233 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query, $exec_args, $attr);
2234             } else {
2235 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query);
2236             }
2237            
2238 0 0         return $sth unless $sth;
2239              
2240 0           $self->_runPreFetchHook($r);
2241 0           $sth = $r->getStatementHandle;
2242              
2243 0           my $list = [];
2244              
2245 0           my $result = $sth->fetchrow_arrayref;
2246 0           while ($result) {
2247 0           $r->setReturnVal($result);
2248 0           $self->_runPostFetchHook($r);
2249 0           $result = $r->getReturnVal;
2250            
2251             # have to make copy because recent versions of DBI now
2252             # return the same array reference each time
2253 0           push @$list, [ @$result ];
2254 0           $result = $sth->fetchrow_arrayref;
2255             }
2256 0           $sth->finish;
2257              
2258 0           return $list;
2259             }
2260              
2261             *native_select_multi_with_array_ref = \&nativeSelectMultiWithArrayRef;
2262             *select_native_multi_with_array_ref = \&nativeSelectMultiWithArrayRef;
2263             *selectNativeMultiWithArrayRef = \&nativeSelectMultiWithArrayRef;
2264              
2265             =pod
2266              
2267             =head2 C
2268              
2269             Executes the given query and returns a reference to a hash
2270             containing the first and second columns of the results as
2271             key/value pairs.
2272              
2273             Aliases: native_select_mapping, nsm
2274              
2275             =cut
2276             sub nativeSelectMapping {
2277 0     0 1   my ($self, $query, $exec_args) = @_;
2278 0 0         if (scalar(@_) == 3) {
2279 0           $self->nativeSelectDynaMapping($query, [ 0, 1 ], $exec_args);
2280             } else {
2281 0           $self->nativeSelectDynaMapping($query, [ 0, 1 ]);
2282             }
2283             }
2284              
2285             *native_select_mapping = \&nativeSelectMapping;
2286             *select_native_mapping = \&nativeSelectMapping;
2287             *selectNativeMapping = \&nativeSelectMapping;
2288             *nsm = \&nativeSelectMapping;
2289              
2290             =pod
2291              
2292             =head2 C
2293              
2294             Similar to C except you specify which
2295             columns to use for the key/value pairs in the return hash. If
2296             the first element of C<@cols> starts with a digit, then C<@cols> is
2297             assumed to contain indexes for the two columns you wish to use.
2298             Otherwise, C<@cols> is assumed to contain the field names for the
2299             two columns you wish to use.
2300              
2301             For example,
2302              
2303             nativeSelectMapping($query, \@exec_args) is
2304              
2305             equivalent (and in fact calls) to
2306              
2307             nativeSelectDynaMapping($query, [ 0, 1 ], $exec_args).
2308              
2309             Aliases: native_select_dyna_mapping, nsdm
2310              
2311             =cut
2312             # FIXME: return undef on error
2313             sub nativeSelectDynaMapping {
2314 0     0 1   my ($self, $query, $cols, $exec_args) = @_;
2315              
2316 0           my ($first, $second) = @$cols;
2317 0           my $key;
2318 0           my $map = {};
2319 0 0         if ($first =~ /^\d/) {
2320 0           my $rows;
2321 0 0         if (scalar(@_) == 4) {
2322 0           $rows = $self->nativeSelectMultiWithArrayRef($query, $exec_args);
2323             } else {
2324 0           $rows = $self->nativeSelectMultiWithArrayRef($query);
2325             }
2326 0           foreach my $row (@$rows) {
2327 0           $key = $row->[$first];
2328 0 0         unless (defined($key)) {
2329 0           $key = '';
2330             }
2331 0           $map->{$key} = $row->[$second];
2332             }
2333              
2334             } else {
2335 0           my $rows;
2336 0 0         if (scalar(@_) == 4) {
2337 0           $rows = $self->nativeSelectMulti($query, $exec_args);
2338             } else {
2339 0           $rows = $self->nativeSelectMulti($query);
2340             }
2341 0           foreach my $row (@$rows) {
2342 0           $key = $row->{$first};
2343 0 0         unless (defined($key)) {
2344 0           $key = '';
2345             }
2346 0           $map->{$key} = $row->{$second};
2347             }
2348             }
2349            
2350 0           return $map;
2351             }
2352              
2353             *native_select_dyna_mapping = \&nativeSelectDynaMapping;
2354             *select_native_dyna_mapping = \&nativeSelectDynaMapping;
2355             *selectNativeDynaMapping = \&nativeSelectDynaMapping;
2356             *nsdm = \&nativeSelectDynaMapping;
2357              
2358             =pod
2359              
2360             =head2 C
2361              
2362             Similar to C, except the values in the hash
2363             are references to the corresponding record (as a hash).
2364              
2365             Aliases: native_select_record_mapping
2366              
2367             =cut
2368             sub nativeSelectRecordMapping {
2369 0     0 1   my ($self, $query, $exec_args) = @_;
2370              
2371 0 0         if (scalar(@_) == 3) {
2372 0           return $self->nativeSelectRecordDynaMapping($query, 0, $exec_args);
2373             } else {
2374 0           return $self->nativeSelectRecordDynaMapping($query, 0);
2375             }
2376             }
2377              
2378             *native_select_record_mapping = \&nativeSelectRecordMapping;
2379             *select_native_record_mapping = \&nativeSelectRecordMapping;
2380             *selectNativeRecordMapping = \&nativeSelectRecordMapping;
2381              
2382             =pod
2383              
2384             =head2 C
2385              
2386             Similar to C, except you specify
2387             which column is the key in each key/value pair in the hash. If
2388             C<$col> starts with a digit, then it is assumed to contain the
2389             index for the column you wish to use. Otherwise, C<$col> is
2390             assumed to contain the field name for the two columns you wish
2391             to use.
2392              
2393             =cut
2394             # FIXME: return undef on error
2395             sub nativeSelectRecordDynaMapping {
2396 0     0 1   my ($self, $query, $col, $exec_args) = @_;
2397              
2398 0           my $map = {};
2399 0 0         if ($col =~ /^\d/) {
2400 0           my $rows;
2401 0 0         if (scalar(@_) == 4) {
2402 0           $rows = $self->nativeSelectMulti($query, $exec_args);
2403             } else {
2404 0           $rows = $self->nativeSelectMulti($query);
2405             }
2406 0           my $names = $self->_get_i_val('_last_col_names');
2407 0           my $col_name = $$names[$col];
2408 0           foreach my $row (@$rows) {
2409 0           $$map{$$row{$col_name}} = $row;
2410             }
2411              
2412             } else {
2413 0           my $rows;
2414 0 0         if (scalar(@_) == 4) {
2415 0           $rows = $self->nativeSelectMulti($query, $exec_args);
2416             } else {
2417 0           $rows = $self->nativeSelectMulti($query);
2418             }
2419 0           foreach my $row (@$rows) {
2420 0           $$map{$$row{$col}} = $row;
2421             }
2422             }
2423              
2424 0           return $map;
2425             }
2426              
2427             *native_select_record_dyna_mapping = \&nativeSelectRecordDynaMapping;
2428             *select_native_record_dyna_mapping = \&nativeSelectRecordDynaMapping;
2429             *selectNativeRecordDynaMapping = \&nativeSelectRecordDynaMapping;
2430            
2431             sub _getSqlObj {
2432             # return SQL::Abstract->new(case => 'textbook', cmp => '=', logic => 'and');
2433 0     0     require SQL::Abstract;
2434 0           return SQL::Abstract->new(case => 'textbook', cmp => '=');
2435             }
2436              
2437             =pod
2438              
2439             =head2 C
2440              
2441             Returns a single value, the first column from the first row of
2442             the result. Returns undef on error or if there are no rows in
2443             the result. Note this may be the same value returned for a C
2444             value in the result.
2445              
2446             Aliases: native_select_value
2447              
2448             =cut
2449             sub nativeSelectValue {
2450 0     0 1   my ($self, $query, $exec_args) = @_;
2451 0           my $row;
2452            
2453 0 0         if (scalar(@_) == 3) {
2454 0           $row = $self->nativeSelectWithArrayRef($query, $exec_args);
2455             } else {
2456 0           $row = $self->nativeSelectWithArrayRef($query);
2457             }
2458 0 0 0       if ($row and @$row) {
2459 0           return $row->[0];
2460             }
2461              
2462 0           return undef;
2463             }
2464              
2465             *native_select_value = \&nativeSelectValue;
2466             *select_native_value = \&nativeSelectValue;
2467             *selectNativeValue = \&nativeSelectValue;
2468              
2469             =pod
2470              
2471             =head2 C
2472              
2473             Like C, but return multiple values, e.g.,
2474             return an array of ids for the query
2475              
2476             =for pod2rst next-code-block: sql
2477              
2478             SELECT id FROM WHERE color_pref='red'
2479              
2480             Aliases: native_select_values_array
2481              
2482             =cut
2483             sub nativeSelectValuesArray {
2484 0     0 1   my ($self, $query, $exec_args) = @_;
2485              
2486 0           my $rows;
2487 0 0         if (scalar(@_) == 3) {
2488 0           $rows = $self->nativeSelectMultiWithArrayRef($query, $exec_args);
2489             } else {
2490 0           $rows = $self->nativeSelectMultiWithArrayRef($query);
2491             }
2492              
2493 0 0         return undef unless $rows;
2494 0           return [ map { $_->[0] } @$rows ];
  0            
2495             }
2496              
2497             *native_select_values_array = \&nativeSelectValuesArray;
2498             *select_native_values_array = \&nativeSelectValuesArray;
2499             *selectNativeValuesArray = \&nativeSelectValuesArray;
2500              
2501             =pod
2502              
2503             =head2 C
2504              
2505             Same as C except uses L to generate the
2506             SQL. See the POD for L for usage. You must have L installed for this method to work.
2507              
2508             Aliases: abstract_select
2509              
2510             =cut
2511             sub abstractSelect {
2512 0     0 1   my ($self, $table, $fields, $where, $order) = @_;
2513 0           my $sql_obj = $self->_getSqlObj;
2514 0           my ($query, @bind) = $sql_obj->select($table, $fields, $where, $order);
2515              
2516 0 0         if (@bind) {
2517 0           return $self->nativeSelect($query, \@bind);
2518             } else {
2519 0           return $self->nativeSelect($query);
2520             }
2521             }
2522              
2523             *abstract_select = \&abstractSelect;
2524              
2525             =pod
2526              
2527             =head2 C
2528              
2529             Same as C except uses L to
2530             generate the SQL. See the POD for L for usage. You
2531             must have L installed for this method to work.
2532              
2533             Aliases: abstract_select_multi
2534              
2535             =cut
2536             sub abstractSelectMulti {
2537 0     0 1   my ($self, $table, $fields, $where, $order) = @_;
2538 0           my $sql_obj = $self->_getSqlObj;
2539 0           my ($query, @bind) = $sql_obj->select($table, $fields, $where, $order);
2540              
2541 0 0         if (@bind) {
2542 0           return $self->nativeSelectMulti($query, \@bind);
2543             } else {
2544 0           return $self->nativeSelectMulti($query);
2545             }
2546             }
2547              
2548             *abstract_select_multi = \&abstractSelectMulti;
2549              
2550             =pod
2551              
2552             =head2 C
2553              
2554             Executes the query in C<$query>, then returns an object that allows
2555             you to loop through one result at a time, e.g.,
2556              
2557             my $loop = $db->nativeSelectLoop("SELECT * FROM my_table");
2558             while (my $row = $loop->next) {
2559             my $id = $$row{id};
2560             }
2561              
2562             To get the number of rows selected, you can call the
2563             C method on the loop object, e.g.,
2564              
2565             my $loop = $db->nativeSelectLoop("SELECT * FROM my_table");
2566             my $rows_in_result = $loop->rowCountCurrent;
2567              
2568             The C method is an alias for C.
2569              
2570             To get the number of rows returned by C so far, use the
2571             C method.
2572              
2573             To get the column names in the order returned from your query:
2574              
2575             # returns the names with their character case the same as when
2576             # calling $loop->next, i.e., the case set with $db->setNameArg
2577             my $cols = $loop->get_field_names;
2578            
2579             # returns the names with their character case unmodified
2580             my $cols = $loop->get_names;
2581            
2582             # returns the names in all upper-case
2583             my $cols = $loop->get_names_uc;
2584            
2585             # returns the names in all lower-case
2586             my $cols = $loop->get_names_lc;
2587              
2588             Aliases: native_select_loop
2589              
2590             =cut
2591             sub nativeSelectLoop {
2592 0     0 1   my ($self, $query, $exec_args) = @_;
2593 0           $self->_printDebug($query);
2594              
2595 0 0         if (scalar(@_) == 3) {
2596 0           return DBIx::Wrapper::SelectLoop->new($self, $query, $exec_args);
2597             } else {
2598 0           return DBIx::Wrapper::SelectLoop->new($self, $query);
2599             }
2600             }
2601              
2602             *readLoop = \&nativeSelectLoop;
2603             *native_select_loop = \&nativeSelectLoop;
2604             *select_native_loop = \&nativeSelectLoop;
2605             *selectNativeLoop = \&nativeSelectLoop;
2606              
2607             =pod
2608              
2609             =head2 C
2610              
2611             Executes the query in $query and returns true if successful.
2612             This is typically used for deletes and is a catchall for
2613             anything the methods provided by this module don't take into
2614             account.
2615              
2616             Aliases: native_query
2617              
2618             =cut
2619             sub nativeQuery {
2620 0     0 1   my ($self, $query, $exec_args, $attr) = @_;
2621              
2622 0           my ($sth, $rv, $r);
2623 0 0         if (scalar(@_) >= 3) {
2624 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query, $exec_args, $attr);
2625             } else {
2626 0           ($sth, $rv, $r) = $self->_getStatementHandleForQuery($query);
2627             }
2628 0 0         return $sth unless $sth;
2629 0           return $rv;
2630             }
2631              
2632             *doQuery = \&nativeQuery;
2633             *native_query = \&nativeQuery;
2634              
2635             =pod
2636              
2637             =head2 C
2638              
2639             A loop on nativeQuery, where any placeholders you have put in
2640             your query are bound each time you call C. E.g.,
2641              
2642             my $loop = $db->nativeQueryLoop("UPDATE my_table SET value=? WHERE id=?");
2643             $loop->next([ 'one', 1]);
2644             $loop->next([ 'two', 2]);
2645              
2646             Aliases: native_query_loop
2647              
2648             =cut
2649             sub nativeQueryLoop {
2650 0     0 1   my ($self, $query) = @_;
2651 0           $self->_printDebug($query);
2652              
2653 0           return DBIx::Wrapper::StatementLoop->new($self, $query);
2654             }
2655              
2656             *native_query_loop = \&nativeQueryLoop;
2657              
2658             # =pod
2659              
2660             # =head2 newCommand($cmd)
2661              
2662             # This method is deprecated. Use $db->command($cmd_str) instead.
2663              
2664             # This creates a literal SQL command for use in insert(), update(),
2665             # and related methods, since if you simply put something like
2666             # "CUR_DATE()" as a value in the %data parameter passed to insert,
2667             # the function will get quoted, and so will not work as expected.
2668             # Instead, do something like this:
2669              
2670             # my $data = { file => 'my_document.txt',
2671             # the_date => $db->newCommand('CUR_DATE()')
2672             # };
2673             # $db->insert('my_doc_table', $data);
2674              
2675             # This can also be done by passing a reference to a string with the
2676             # SQL command, e.g.,
2677              
2678             # my $data = { file => 'my_document.txt',
2679             # the_date => \'CUR_DATE()'
2680             # };
2681             # $db->insert('my_doc_table', $data);
2682              
2683              
2684             # =cut
2685             sub newCommand {
2686 0     0 0   my ($self, $contents) = @_;
2687 0           return DBIx::Wrapper::SQLCommand->new($contents);
2688             }
2689              
2690             *new_command = \&newCommand;
2691              
2692             =pod
2693              
2694             =head2 C
2695              
2696             This creates a literal SQL command for use in C,
2697             C, and related methods, since if you simply put something
2698             like C<"CUR_DATE()"> as a value in the C<%data> parameter passed to
2699             insert, the function will get quoted, and so will not work as
2700             expected. Instead, do something like this:
2701              
2702             my $data = { file => 'my_document.txt',
2703             the_date => $db->command('CUR_DATE()')
2704             };
2705             $db->insert('my_doc_table', $data);
2706              
2707             This can also be done by passing a reference to a string with
2708             the SQL command, e.g.,
2709              
2710             my $data = { file => 'my_document.txt',
2711             the_date => \'CUR_DATE()'
2712             };
2713             $db->insert('my_doc_table', $data);
2714              
2715             This is currently how C is implemented.
2716              
2717             Aliases: literal, sql_literal
2718              
2719             =cut
2720             sub command {
2721 0     0 1   my ($self, $str) = @_;
2722 0           return \$str;
2723             }
2724              
2725             *sql_literal = \&command;
2726             *literal = \&command;
2727              
2728             sub not {
2729 0     0 0   my $self = shift;
2730 0           my $val = shift;
2731              
2732 0           return DBIx::Wrapper::SQLCommand->new_cond($self, 'not', $val);
2733             }
2734              
2735             =pod
2736              
2737             =head2 C
2738              
2739             Turns on debugging output. Debugging information will be printed
2740             to the given filehandle.
2741              
2742             =cut
2743             # expects a reference to a filehandle to print debug info to
2744             sub debugOn {
2745 0     0 1   my $self = shift;
2746 0           my $fh = shift;
2747 0           $self->_set_i_val('_debug', 1);
2748 0           $self->_set_i_val('_debug_fh', $fh);
2749              
2750 0           return 1;
2751             }
2752              
2753             *debug_on = \&debugOn;
2754              
2755             =pod
2756              
2757             =head2 C
2758              
2759             Turns off debugging output.
2760              
2761             =cut
2762             sub debugOff {
2763 0     0 1   my $self = shift;
2764 0           $self->_delete_i_val('_debug');
2765 0           $self->_delete_i_val('_debug_fh');
2766              
2767 0           return 1;
2768             }
2769              
2770             *debug_off = \&debugOff;
2771              
2772             sub _isDebugOn {
2773 0     0     my ($self) = @_;
2774 0 0 0       if (($self->_get_i_val('_debug') and $self->_get_i_val('_debug_fh'))
      0        
2775             or $ENV{'DBIX_WRAPPER_DEBUG'}) {
2776 0           return 1;
2777             }
2778 0           return undef;
2779             }
2780              
2781             sub _printDbiError {
2782 0     0     my ($self, $extra) = @_;
2783              
2784 0           my $handler = $self->_getErrorHandler;
2785 0 0         $handler = [ $self, \&_default_error_handler ] unless $handler;
2786 0 0         if ($handler) {
2787 0 0         if (UNIVERSAL::isa($handler, 'ARRAY')) {
2788 0           my ($obj, $meth) = @$handler;
2789 0           return $obj->$meth($self, $extra);
2790             } else {
2791 0           return $handler->($self, $extra);
2792             }
2793             }
2794              
2795 0           return undef;
2796             }
2797              
2798             sub _default_error_handler {
2799 0     0     my ($self, $db, $extra) = @_;
2800              
2801 0           my $dbi_obj = $self->getDBI;
2802 0 0         return undef unless $dbi_obj->{PrintError};
2803            
2804 0 0         return undef unless ($self->getDebugLevel | 2);
2805            
2806 0           my $fh = $self->_get_i_val('_debug_fh');
2807 0 0         $fh = \*STDERR unless $fh;
2808            
2809 0           my $time = $self->_getCurDateTime;
2810              
2811 0           my ($package, $filename, $line, $subroutine, $hasargs,
2812             $wantarray, $evaltext, $is_require, $hints, $bitmask);
2813              
2814 0           my $frame = 1;
2815 0           my $this_pkg = __PACKAGE__;
2816              
2817 0           ($package, $filename, $line, $subroutine, $hasargs,
2818             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($frame);
2819 0           while ($package eq $this_pkg) {
2820 0           $frame++;
2821 0           ($package, $filename, $line, $subroutine, $hasargs,
2822             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($frame);
2823              
2824             # if we get more than 10 something must be wrong
2825 0 0         last if $frame >= 10;
2826             }
2827              
2828 0           local($Carp::CarpLevel) = $frame;
2829 0           my $str = Carp::longmess($DBI::errstr);
2830              
2831 0 0         $str .= $extra if defined($extra);
2832              
2833 0           my @one_more = caller($frame + 1);
2834 0           $subroutine = $one_more[3];
2835 0 0         $subroutine = '' unless defined($subroutine);
2836 0 0         $subroutine .= '()' if $subroutine ne '';
2837            
2838 0           print $fh '*' x 60, "\n", "$time:$filename:$line:$subroutine\n", $str, "\n";
2839             }
2840              
2841             sub _default_debug_handler {
2842 0     0     my ($self, $db, $str, $fh) = @_;
2843              
2844 0           my $time = $self->_getCurDateTime;
2845              
2846 0           my ($package, $filename, $line, $subroutine, $hasargs,
2847             $wantarray, $evaltext, $is_require, $hints, $bitmask);
2848              
2849 0           my $frame = 1;
2850 0           my $this_pkg = __PACKAGE__;
2851              
2852 0           ($package, $filename, $line, $subroutine, $hasargs,
2853             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($frame);
2854 0           while ($package eq $this_pkg) {
2855 0           $frame++;
2856 0           ($package, $filename, $line, $subroutine, $hasargs,
2857             $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($frame);
2858              
2859             # if we get more than 10 something must be wrong
2860 0 0         last if $frame >= 10;
2861             }
2862              
2863 0           my @one_more = caller($frame + 1);
2864 0           $subroutine = $one_more[3];
2865 0 0         $subroutine = '' unless defined($subroutine);
2866 0 0         $subroutine .= '()' if $subroutine ne '';
2867            
2868 0           print $fh '*' x 60, "\n", "$time:$filename:$line:$subroutine\n", $str, "\n";
2869             }
2870            
2871             sub _printDebug {
2872 0     0     my ($self, $str) = @_;
2873 0 0         unless ($self->_isDebugOn) {
2874 0           return undef;
2875             }
2876              
2877             # FIXME: check perl version to see if should use \*STDERR or *STDERR
2878 0           my $fh = $self->_get_i_val('_debug_fh');
2879 0 0         $fh = \*STDERR unless $fh;
2880              
2881 0           my $handler = $self->_getDebugHandler;
2882 0 0         $handler = [ $self, \&_default_debug_handler ] unless $handler;
2883 0 0         if ($handler) {
2884 0 0         if (UNIVERSAL::isa($handler, 'ARRAY')) {
2885 0           my ($obj, $meth) = @$handler;
2886 0           return $obj->$meth($self, $str, $fh);
2887             } else {
2888 0           return $handler->($self, $str, $fh);
2889             }
2890             }
2891              
2892 0           return undef;
2893             }
2894              
2895             sub _getCurDateTime {
2896 0     0     my ($self) = @_;
2897            
2898 0           my $time = time();
2899 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
2900 0           $mon += 1;
2901 0           $year += 1900;
2902 0           my $date = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday,
2903             $hour, $min, $sec;
2904            
2905 0           return $date;
2906             }
2907              
2908            
2909             sub escapeString {
2910 0     0 0   my ($self, $value) = @_;
2911            
2912 0 0         $value = "" unless defined($value);
2913 0           $value =~ s|\\|\\\\|g;
2914 0           $value =~ s|\'|''|g;
2915 0           $value =~ s|\?|\\\?|g;
2916 0           $value =~ s|\000|\\0|g;
2917 0           $value =~ s|\"|""|g;
2918 0           $value =~ s|\n|\\n|g;
2919 0           $value =~ s|\r|\\r|g;
2920 0           $value =~ s|\t|\\t|g;
2921              
2922 0           return $value;
2923             }
2924              
2925             *escape_string = \&escapeString;
2926              
2927             sub _moduleHasSub {
2928 0     0     my ($self, $module, $sub_name) = @_;
2929             }
2930            
2931             sub DESTROY {
2932 0     0     my ($self) = @_;
2933 0 0         return undef unless $self->_getDisconnect;
2934 0           my $dbh = $self->_getDatabaseHandle;
2935 0 0         $dbh->disconnect if $dbh;
2936 0           delete $i_data{ refaddr($self) }; # free up private data
2937             }
2938              
2939             #################
2940             # getters/setters
2941              
2942             sub getNameArg {
2943 0     0 0   my ($self) = @_;
2944 0           my $arg = $self->_get_i_val('_name_arg');
2945 0 0 0       $arg = 'NAME_lc' unless defined($arg) and $arg ne '';
2946              
2947 0           return $arg;
2948             }
2949              
2950             =pod
2951              
2952             =head2 C
2953              
2954             This is the argument to pass to the C call on
2955             the underlying DBI object. By default, this is 'NAME_lc', so
2956             that all field names returned are all lowercase to provide for
2957             portable code. If you want to make all the field names return
2958             be uppercase, call C<$db-EsetNameArg('NAME_uc')> after the
2959             C call. And if you really want the case of the field
2960             names to be what the underlying database driver returns them
2961             as, call C<$db-EsetNameArg('NAME')>.
2962              
2963             Aliases: set_name_arg
2964              
2965             =cut
2966             sub setNameArg {
2967 0     0 1   my $self = shift;
2968 0           $self->_set_i_val('_name_arg', shift());
2969             }
2970             *set_name_arg = \&setNameArg;
2971              
2972             sub setErr {
2973 0     0 0   my ($self, $num, $str) = @_;
2974 0           $self->_set_i_val('_err_num', $num);
2975 0           $self->_set_i_val('_err_str', $str);
2976 0           return undef;
2977             }
2978              
2979             sub getErrorString {
2980 0     0 0   my $self = shift;
2981 0           return $self->_get_i_val('_err_str');
2982             }
2983              
2984             sub getErrorNum {
2985 0     0 0   my $self = shift;
2986 0           return $self->_get_i_val('_err_num');
2987             }
2988              
2989             =pod
2990              
2991             =head2 C
2992              
2993             Calls C on the underlying DBI object, which returns the
2994             native database engine error code from the last driver method
2995             called.
2996              
2997             =cut
2998             sub err {
2999 0     0 1   my ($self) = @_;
3000 0           my $dbh = $self->_getDatabaseHandle;
3001 0 0         return $dbh->err if $dbh;
3002 0           return 0;
3003             }
3004              
3005             =pod
3006              
3007             =head2 C
3008              
3009             Calls C on the underlying DBI object, which returns the
3010             native database engine error message from the last driver method
3011             called.
3012              
3013             =cut
3014             sub errstr {
3015 0     0 1   my $self = shift;
3016 0           my $dbh = $self->_getDatabaseHandle;
3017 0 0         return $dbh ? $dbh->errstr : undef;
3018             }
3019            
3020             sub _getAttr {
3021 0     0     my $self = shift;
3022 0           return $self->_get_i_val('_attr');
3023             }
3024              
3025             sub _setAttr {
3026 0     0     my $self = shift;
3027 0           $self->_set_i_val('_attr', shift());
3028             }
3029              
3030             sub _getAuth {
3031 0     0     my $self = shift;
3032 0           return $self->_get_i_val('_auth');
3033             }
3034              
3035             sub _setAuth {
3036 0     0     my $self = shift;
3037 0           $self->_set_i_val('_auth', shift());
3038             }
3039              
3040             sub _getUsername {
3041 0     0     my ($self) = @_;
3042 0           return $self->_get_i_val('_username');
3043             }
3044              
3045             sub _setUsername {
3046 0     0     my $self = shift;
3047 0           my $username = shift;
3048 0           $self->_set_i_val('_username', $username);
3049             }
3050              
3051             sub _getDatabaseHandle {
3052 0     0     my $self = shift;
3053 0           return $self->_get_i_val('_dbh');
3054             }
3055              
3056             sub _setDatabaseHandle {
3057 0     0     my $self = shift;
3058 0           my $dbh = shift;
3059 0           $self->_set_i_val('_dbh', $dbh);
3060             }
3061              
3062             sub _deleteDatabaseHandle {
3063 0     0     my $self = shift;
3064 0           my $data = $self->_get_i_data();
3065 0           delete $data->{_dbh};
3066             }
3067              
3068             sub getDataSourceAsString {
3069 0     0 0   return shift()->_getDataSourceStr;
3070             }
3071              
3072             sub _getDataSourceStr {
3073 0     0     my $self = shift;
3074 0           return $self->_get_i_val('_data_source_str');
3075             }
3076              
3077             sub _setDataSourceStr {
3078 0     0     my $self = shift;
3079 0           $self->_set_i_val('_data_source_str', shift());
3080             }
3081              
3082             sub _getDataSource {
3083 0     0     my $self = shift;
3084 0           return $self->_get_i_val('_data_source');
3085             }
3086              
3087             sub _setDataSource {
3088 0     0     my $self = shift;
3089 0           $self->_set_i_val('_data_source', shift());
3090             }
3091              
3092             sub _getDisconnect {
3093 0     0     my $self = shift;
3094 0           return $self->_get_i_val('_should_disconnect');
3095             }
3096              
3097             sub _setErrorHandler {
3098 0     0     my $self = shift;
3099 0           $self->_set_i_val('_error_handler', shift());
3100             }
3101              
3102             sub _getErrorHandler {
3103 0     0     return shift()->_get_i_val('_error_handler');
3104             }
3105              
3106             sub _setDebugHandler {
3107 0     0     my $self = shift;
3108 0           $self->_set_i_val('_debug_handler', shift());
3109             }
3110            
3111             sub _getDebugHandler {
3112 0     0     return shift()->_get_i_val('_debug_handler');
3113             }
3114              
3115             sub _setDbStyle {
3116 0     0     my $self = shift;
3117 0           $self->_set_i_val('_db_style', shift());
3118             }
3119              
3120             sub _getDbStyle {
3121 0     0     return shift()->_get_i_val('_db_style');
3122             }
3123              
3124             sub _setDbdDriver {
3125 0     0     my $self = shift;
3126 0           $self->_set_i_val('_dbd_driver', shift());
3127             }
3128              
3129             sub _getDbdDriver {
3130 0     0     return shift()->_get_i_val('_dbd_driver');
3131             }
3132              
3133             # whether or not to disconnect when the Wrapper object is
3134             # DESTROYed
3135             sub _setDisconnect {
3136 0     0     my ($self, $val) = @_;
3137 0           $self->_set_i_val('_should_disconnect', 1);
3138             }
3139              
3140             sub _setNoPlaceholders {
3141 0     0     my $self = shift;
3142 0           $self->_set_i_val('_no_placeholders', shift());
3143             }
3144              
3145             sub _getNoPlaceholders {
3146 0     0     my $self = shift;
3147 0           return $self->_get_i_val('_no_placeholders');
3148             }
3149              
3150             sub _setHeavy {
3151 0     0     my $self = shift;
3152 0           $self->_set_i_val('_heavy', shift());
3153             }
3154              
3155             sub _getHeavy {
3156 0     0     my $self = shift;
3157 0           return $self->_get_i_val('_heavy');
3158             }
3159              
3160             sub shouldBeHeavy {
3161 0     0 0   my $self = shift;
3162 0 0 0       return 1 if $Heavy or $self->_getHeavy;
3163 0           return undef;
3164             }
3165              
3166             # sub get_info {
3167             # my ($self, $name) = @_;
3168             # require DBI::Const::GetInfoType;
3169             # my $dbh = $self->_getDatabaseHandle;
3170             # return $dbh->get_info($DBI::Const::GetInfoType::GetInfoType{$name});
3171             # }
3172              
3173             sub get_info {
3174 0     0 0   my $self = shift;
3175 0           my $name = shift;
3176 0           my $dbh = $self->_getDatabaseHandle;
3177 0           return $dbh->get_info($name);
3178             }
3179              
3180             =pod
3181              
3182             =head2 DBI-compatible methods
3183              
3184             The following method calls use the same interface as the DBI
3185             method. However, these are not simply passed through to DBI
3186             (see DBI methods below), so any hooks you have defined for
3187             C will be called.
3188              
3189             =over 4
3190              
3191             =item C
3192              
3193             =back
3194              
3195             =cut
3196             sub do {
3197 0     0 1   my ($self, $statement, $attr, @bind_values) = @_;
3198 0           return $self->nativeQuery($statement, \@bind_values, $attr);
3199             }
3200              
3201             =pod
3202              
3203             =head2 DBI methods
3204              
3205             The following method calls are just passed through to the
3206             underlying DBI object for convenience. See the documentation
3207             for DBI for details.
3208              
3209             =over 4
3210              
3211             =item C
3212              
3213             This method may call hooks in the future. Use
3214             C if you want to ensure that it will be a
3215             simple DBI call.
3216              
3217             =back
3218              
3219             =cut
3220             sub prepare {
3221 0     0 1   my $self = shift;
3222 0           my $query = shift;
3223              
3224 0           my $dbi_obj = $self->getDBI;
3225 0           my $sth = $dbi_obj->prepare($query);
3226              
3227 0           return $sth;
3228             }
3229              
3230             =pod
3231              
3232             =over 4
3233              
3234             =item C
3235              
3236             =back
3237              
3238             =cut
3239             sub selectrow_arrayref {
3240 0     0 1   my $self = shift;
3241 0           my $dbh = $self->_getDatabaseHandle;
3242 0           return $dbh->selectrow_arrayref(@_);
3243             }
3244              
3245             =pod
3246              
3247             =over 4
3248              
3249             =item C
3250              
3251             =back
3252              
3253             =cut
3254             sub selectrow_hashref {
3255 0     0 1   my $self = shift;
3256 0           my $dbh = $self->_getDatabaseHandle;
3257 0           return $dbh->selectrow_hashref(@_);
3258             }
3259              
3260             =pod
3261              
3262             =over 4
3263              
3264             =item C
3265              
3266             =back
3267              
3268             =cut
3269             sub selectall_arrayref {
3270 0     0 1   my ($self, @args) = @_;
3271 0           my $dbh = $self->_getDatabaseHandle;
3272 0           return $dbh->selectall_arrayref(@args);
3273             }
3274              
3275             =pod
3276              
3277             =over 4
3278              
3279             =item C
3280              
3281             =back
3282              
3283             =cut
3284             sub selectall_hashref {
3285 0     0 1   my ($self, @args) = @_;
3286 0           my $dbh = $self->_getDatabaseHandle;
3287 0           return $dbh->selectall_hashref(@args);
3288             }
3289              
3290             =pod
3291              
3292             =over 4
3293              
3294             =item C
3295              
3296             =back
3297              
3298             =cut
3299             sub selectcol_arrayref {
3300 0     0 1   my ($self, @args) = @_;
3301 0           my $dbh = $self->_getDatabaseHandle;
3302 0           return $dbh->selectcol_arrayref(@args);
3303             }
3304              
3305             =pod
3306              
3307             =over 4
3308              
3309             =item C
3310              
3311             =back
3312              
3313             =cut
3314             sub quote {
3315 0     0 1   my ($self, @args) = @_;
3316 0           my $dbh = $self->_getDatabaseHandle;
3317 0           return $dbh->quote(@args);
3318             }
3319              
3320             =pod
3321              
3322             =over 4
3323              
3324             =item C
3325              
3326             =back
3327              
3328             =cut
3329             sub commit {
3330 0     0 1   my ($self) = @_;
3331 0           my $dbh = $self->_getDatabaseHandle;
3332 0 0         if ($dbh) {
3333 0           return $dbh->commit;
3334             }
3335 0           return undef;
3336             }
3337              
3338             =pod
3339              
3340             =over 4
3341              
3342             =item C
3343              
3344             =back
3345              
3346             =cut
3347             sub begin_work {
3348 0     0 1   my $self = shift;
3349 0           my $dbh = $self->_getDatabaseHandle;
3350 0 0         if ($dbh) {
3351 0           return $dbh->begin_work;
3352             }
3353 0           return undef;
3354             }
3355              
3356             =pod
3357              
3358             =over 4
3359              
3360             =item C
3361              
3362             =back
3363              
3364             =cut
3365             sub rollback {
3366 0     0 1   my $self = shift;
3367 0           my $dbh = $self->_getDatabaseHandle;
3368 0 0         if ($dbh) {
3369 0           return $dbh->rollback;
3370             }
3371 0           return undef;
3372             }
3373              
3374             =pod
3375              
3376             =over 4
3377              
3378             =item C
3379              
3380             =back
3381              
3382             =cut
3383             sub ping {
3384 0     0 1   my ($self) =@_;
3385 0           my $dbh = $self->_getDatabaseHandle;
3386 0 0         return undef unless $dbh;
3387              
3388 0           return $dbh->ping;
3389             }
3390              
3391             # =pod
3392              
3393             # =head2 getLastInsertId($catalog, $schema, $table, $field, \%attr)
3394              
3395             # Returns a value identifying the row just inserted, if possible.
3396             # If using DBI version 1.38 or later, this method calls
3397             # last_insert_id() on the underlying DBI object. Otherwise, does a
3398             # "SELECT LAST_INSERT_ID()", which is MySQL specific. The
3399             # parameters passed to this method are driver-specific. See the
3400             # documentation on DBI for details.
3401              
3402             # get_last_insert_id() and last_insert_id() are aliases for this
3403             # method.
3404              
3405             # =cut
3406              
3407             # bah, DBI's last_insert_id is not working for me, so for
3408             # now this will be MySQL only
3409              
3410             =pod
3411              
3412             =head2 C, C, C
3413              
3414             Returns the last_insert_id. The default is to be MySQL
3415             specific. It just runs the query C<"SELECT LAST_INSERT_ID()">.
3416             However, it will also work with MSSQL with the right parameters
3417             (see the db_style parameter in the section explaining the
3418             C method).
3419              
3420             =cut
3421             sub getLastInsertId {
3422 0     0 1   my ($self, $catalog, $schema, $table, $field, $attr) = @_;
3423 0           if (0 and DBI->VERSION >= 1.38) {
3424             my $dbh = $self->_getDatabaseHandle;
3425             return $dbh->last_insert_id($catalog, $schema, $table, $field, $attr);
3426             } else {
3427 0           my $query;
3428 0           my $db_style = $self->_getDbStyle;
3429 0           my $dbd_driver = $self->_getDbdDriver;
3430 0 0 0       if (defined($db_style) and $db_style ne '') {
    0 0        
3431 0           $query = $self->_get_query_for_last_insert_id($db_style);
3432             } elsif (defined($dbd_driver) and $dbd_driver ne '') {
3433 0           $query = $self->_get_query_for_last_insert_id($dbd_driver);
3434             } else {
3435 0           $query = qq{SELECT LAST_INSERT_ID()};
3436             }
3437            
3438 0           my $row = $self->nativeSelectWithArrayRef($query);
3439 0 0 0       if ($row and @$row) {
3440 0           return $$row[0];
3441             }
3442              
3443 0           return undef;
3444             }
3445             }
3446              
3447             *get_last_insert_id = \&getLastInsertId;
3448             *last_insert_id = \&getLastInsertId;
3449              
3450             sub _get_query_for_last_insert_id {
3451 0     0     my ($self, $db_style) = @_;
3452 0           my $query;
3453              
3454 0           $db_style = lc($db_style);
3455 0 0 0       if ($db_style eq 'mssql' or $db_style eq 'sybase' or $db_style eq 'asa'
    0 0        
    0 0        
3456             or $db_style eq 'asany') {
3457 0           $query = q{select @@IDENTITY};
3458             } elsif ($db_style eq 'mysql') {
3459 0           $query = qq{SELECT LAST_INSERT_ID()};
3460             } elsif ($db_style eq 'sqlite') {
3461 0           $query = qq{SELECT last_insert_rowid()};
3462             } else {
3463 0           $query = qq{SELECT LAST_INSERT_ID()};
3464             }
3465              
3466 0           return $query;
3467             }
3468              
3469             sub debug_dump {
3470 0     0 0   my $self = shift;
3471 0           my $var = shift;
3472 0           my $data = $self->_get_i_data;
3473 0           require Data::Dumper;
3474 0 0         if (defined($var)) {
3475 0           return Data::Dumper->Dump([ $data ], [ $var ]);
3476             } else {
3477 0           return Data::Dumper::Dumper($data);
3478             }
3479             }
3480             *debugDump = \&debug_dump;
3481              
3482             # version 0.22
3483             sub unix_to_mysql_timestamp {
3484 0     0 0   my $self = shift;
3485 0           my $unix_ts = shift;
3486              
3487 0 0         $unix_ts = time() unless defined $unix_ts;
3488              
3489 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($unix_ts);
3490 0           $mon++;
3491 0 0         $year += 1900 unless $year > 1000;
3492              
3493 0           return sprintf "%04d%02d%02d%02d%02d%02d", $year, $mon, $mday, $hour, $min, $sec;
3494             }
3495              
3496             # version 0.22
3497             sub unix_to_mysql_date_time {
3498 0     0 0   my $self = shift;
3499 0           my $unix_ts = shift;
3500              
3501 0 0         $unix_ts = time() unless defined $unix_ts;
3502              
3503 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($unix_ts);
3504 0           $mon++;
3505 0 0         $year += 1900 unless $year > 1000;
3506              
3507 0           return sprintf "%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec;
3508            
3509             }
3510              
3511             # version 0.22
3512             sub query_oracle_date_as_mysql_timestamp {
3513 0     0 0   my $self = shift;
3514 0           my $field = shift;
3515 0           my $as = shift;
3516              
3517 0           my $sf_field = $self->_quote_field_name($field);
3518 0           my $sf_as = $self->_quote_field_name($as);
3519 0           my $query = qq{TO_CHAR($sf_field,'YYYYMMDDHH24MISS') AS $sf_as};
3520 0           return \$query;
3521             }
3522              
3523             =pod
3524              
3525             =head2 Hooks
3526              
3527             C supports hooks that get called just before and just
3528             after various query operations. The add*Hook methods take a
3529             single argument that is either a code reference (e.g., anonymous
3530             subroutine reference), or an array whose first element is an
3531             object and whose second element is the name of a method to call
3532             on that object.
3533              
3534             The hooks will be called with a request object as the first
3535             argument. See L.
3536              
3537             The two expected return values are C<$request-EOK> and
3538             C<$request-EDECLINED>. The first tells C that the
3539             current hook has done everything that needs to be done and
3540             doesn't call any other hooks in the stack for the current
3541             request. C tells C to continue down the
3542             hook stack as if the current handler was never invoked.
3543              
3544             See L for example hooks.
3545              
3546             =cut
3547              
3548             =pod
3549              
3550             =head3 C
3551              
3552             Specifies a hook to be called just before any SQL statement is
3553             prepare()'d.
3554              
3555             =cut
3556             sub addPrePrepareHook {
3557 0     0 1   my $self = shift;
3558 0           my $handler = shift;
3559 0           push @{ $self->_get_i_val('_pre_prepare_hooks') }, [ $handler ];
  0            
3560             }
3561              
3562             *add_pre_prepare_handler = \&addPrePrepareHook;
3563             *addPrePrepareHandler = \&addPrePrepareHook;
3564             *add_pre_prepare_hook = \&addPrePrepareHook;
3565              
3566             =pod
3567              
3568             =head3 C
3569              
3570             Specifies a hook to be called just after any SQL statement is
3571             prepare()'d.
3572              
3573             =cut
3574             sub addPostPrepareHook {
3575 0     0 1   my $self = shift;
3576 0           my $handler = shift;
3577 0           push @{ $self->_get_i_val('_post_prepare_hooks') }, [ $handler ];
  0            
3578             }
3579              
3580             *add_post_prepare_hook = \&addPostPrepareHook;
3581              
3582             =pod
3583              
3584             =head3 C
3585              
3586             Specifies a hook to be called just before any SQL statement is
3587             execute()'d.
3588              
3589             =cut
3590             sub addPreExecHook {
3591 0     0 1   my $self = shift;
3592 0           my $handler = shift;
3593 0           push @{ $self->_get_i_val('_pre_exec_hooks') }, [ $handler ];
  0            
3594             }
3595              
3596             *add_pre_exec_hook = \&addPreExecHook;
3597              
3598             =pod
3599              
3600             =head3 C
3601              
3602             Adds a hook to be called just after a statement is execute()'d.
3603              
3604             =cut
3605             sub addPostExecHook {
3606 0     0 1   my $self = shift;
3607 0           my $handler = shift;
3608 0           push @{ $self->_get_i_val('_post_exec_hooks') }, [ $handler ];
  0            
3609             }
3610              
3611             *add_post_exec_handler = \&addPostExecHook;
3612             *addPostExecHandler = \&addPostExecHook;
3613             *add_post_exec_hook = \&addPostExecHook;
3614              
3615             =pod
3616              
3617             =head3 C
3618              
3619             Adds a hook to be called just before data is fetch()'d from the server.
3620              
3621             =cut
3622             sub addPreFetchHook {
3623 0     0 1   my $self = shift;
3624 0           my $handler = shift;
3625 0           push @{ $self->_get_i_val('_pre_fetch_hooks') }, [ $handler ];
  0            
3626             }
3627              
3628             *add_pre_fetch_hook = \&addPreFetchHook;
3629             *addPreFetchHandler = \&addPreFetchHook;
3630              
3631             =pod
3632              
3633             =head3 C
3634              
3635             Adds a hook to be called just after data is fetch()'d from the server.
3636              
3637             =cut
3638             sub addPostFetchHook {
3639 0     0 1   my $self = shift;
3640 0           my $handler = shift;
3641 0           push @{ $self->_get_i_val('_post_fetch_hooks') }, [ $handler ];
  0            
3642             }
3643              
3644             *addPostFetchHandler = \&addPostFetchHook;
3645              
3646             sub _to_csv_line {
3647 0     0     my $cols = shift;
3648 0           my $sep = shift;
3649 0           my $quote = shift;
3650            
3651 0 0         $sep = "," unless defined($sep);
3652 0 0         $quote = "\"" unless defined($quote);
3653              
3654 0           my $sf_sep = quotemeta($sep);
3655 0           my $sf_quote = quotemeta($quote);
3656              
3657 0           my @sf_cols;
3658 0           foreach my $col (@$cols) {
3659 0 0 0       if (index($col, $sep) >= 0 or index($col, $quote) >= 0) {
3660 0           $col =~ s/$sf_quote/$quote$quote/g;
3661 0           $col = $quote . $col . $quote;
3662             }
3663 0           push @sf_cols, $col;
3664             }
3665              
3666 0           return join($sep, @sf_cols);
3667             }
3668              
3669             =pod
3670              
3671             =head2 Convenience methods
3672              
3673             =cut
3674              
3675             =pod
3676              
3677             =head3 C
3678              
3679             Convert the given query result rows in C<@rows> to a CSV string.
3680             If each row is a hash, a header row will be included by the
3681             default giving the column names. This method also supports rows
3682             as arrays, as well as C<$rows> itself being a hash ref.
3683              
3684             Valid parameters in C<%params>:
3685              
3686             =over 4
3687              
3688             =item C
3689              
3690             The separator to use between columns.
3691              
3692             =item C
3693              
3694             The quote to use in cases where values contain the separator.
3695             If a quote is found in a value, it is converted to two quotes
3696             and then the whole value is quoted.
3697              
3698             =item C
3699              
3700             If set to a true value, do not output the header row containing
3701             the column names.
3702              
3703             =back
3704              
3705              
3706             Aliases: toCsv()
3707              
3708             =cut
3709             sub to_csv {
3710 0     0 1   my $self = shift;
3711 0           my $rows = shift;
3712 0   0       my $params = shift || {};
3713              
3714 0           my $sep = $params->{sep};
3715 0           my $quote = $params->{quote};
3716 0           my $no_header = $params->{no_header};
3717              
3718 0           my $csv = '';
3719            
3720 0 0         if (reftype($rows) eq 'ARRAY') {
    0          
3721 0 0         return '' unless @$rows;
3722              
3723 0           my $first_row = $rows->[0];
3724            
3725 0 0         if (reftype($first_row) eq 'HASH') {
    0          
3726 0           my @fields = sort keys %$first_row;
3727            
3728 0 0         unless ($no_header) {
3729 0           $csv .= _to_csv_line(\@fields, $sep, $quote) . "\n";
3730             }
3731            
3732 0           foreach my $row (@$rows) {
3733 0           $csv .= _to_csv_line([ map { $row->{$_} } @fields ], $sep, $quote) . "\n";
  0            
3734             }
3735             } elsif (reftype($first_row) eq 'ARRAY') {
3736 0           foreach my $row (@$rows) {
3737 0           $csv .= _to_csv_line($row, $sep, $quote) . "\n";
3738             }
3739             }
3740             }
3741             elsif (reftype($rows) eq 'HASH') {
3742 0           my $row = $rows;
3743 0           my @fields = sort keys %$row;
3744 0 0         unless ($no_header) {
3745 0           $csv .= _to_csv_line(\@fields, $sep, $quote) . "\n";
3746             }
3747            
3748 0           $csv .= _to_csv_line([ map { $row->{$_} } @fields ], $sep, $quote) . "\n";
  0            
3749             }
3750             else {
3751             # error
3752 0           return;
3753             }
3754              
3755 0           return $csv;
3756             }
3757             *toCsv = \&to_csv;
3758              
3759             sub _hash_to_xml {
3760 0     0     my $self = shift;
3761 0           my $hash = shift;
3762 0           my $indent = shift;
3763              
3764 0           my $xml = '';
3765 0           my @keys = sort keys %$hash;
3766 0           foreach my $key (@keys) {
3767 0 0         $xml .= ' ' x 4 if $indent;
3768 0           $xml .= '<' . $key . '>' . $self->escape_xml($hash->{$key}) . '';
3769 0 0         $xml .= "\n" if $indent;
3770             }
3771            
3772 0           return $xml;
3773             }
3774              
3775             =pod
3776              
3777             =head3 C
3778              
3779             Converts C<$data> to xml. $data is expected to be either a hash
3780             ref or a reference to an array of hash refs. If C<$data> is an
3781             array ref, enclosing tags are put around each record. The tags
3782             are named "record" by default but can be changed by specifying
3783             record_tag in C<%params>. If C<$params{indent}> is set to a true
3784             value, tags will be indented and unix newlines inserted. This
3785             method does not output an encoding specification, e.g.,
3786              
3787             =for pod2rst next-code-block: xml
3788              
3789            
3790              
3791             Aliases: toXml()
3792              
3793             =cut
3794             sub to_xml {
3795 0     0 1   my $self = shift;
3796 0           my $rows = shift;
3797 0   0       my $params = shift || {};
3798              
3799 0           my $indent = $params->{indent};
3800 0           my $record_tag_name = $params->{record_tag};
3801 0 0         unless (defined($record_tag_name)) {
3802 0           $record_tag_name = 'record';
3803             }
3804              
3805 0 0         if (reftype($rows) eq 'ARRAY') {
    0          
3806 0 0         return '' unless @$rows;
3807              
3808 0           my $xml = '';
3809 0           foreach my $row (@$rows) {
3810 0           $xml .= '<' . $record_tag_name . '>';
3811 0 0         $xml .= "\n" if $indent;
3812 0           $xml .= _hash_to_xml($self, $row, $indent);
3813 0           $xml .= '';
3814 0 0         $xml .= "\n" if $indent;
3815              
3816             }
3817              
3818 0           return $xml;
3819             } elsif (reftype($rows) eq 'HASH') {
3820 0           return _hash_to_xml($self, $rows);
3821             }
3822              
3823 0           return;
3824             }
3825              
3826             sub escape_xml {
3827 0     0 0   my $self = shift;
3828 0           my $text = shift;
3829 0 0         return '' unless defined $text;
3830            
3831 0           $text =~ s/\&/\&/g;
3832 0           $text =~ s/
3833 0           $text =~ s/>/\>/g;
3834             # $text =~ s/\"/\"/g;
3835              
3836 0           return $text;
3837             }
3838              
3839             *toXml = \&to_xml;
3840              
3841             =pod
3842              
3843             =head3 C
3844              
3845             Returns the bencoded representation of C<$data> (arbitrary
3846             datastructure -- but not objects). This module extends the
3847             bencode scheme to support undef. See
3848             L for details on the bencode
3849             encoding.
3850              
3851             Aliases: bEncode()
3852              
3853             =cut
3854             sub bencode {
3855 0     0 1   my $self = shift;
3856 0           my $to_encode = shift;
3857              
3858 0 0         unless (defined($to_encode)) {
3859 0           return 'n';
3860             }
3861              
3862 0           my $encoded = '';
3863 0           my $type = reftype($to_encode);
3864              
3865 0 0         unless ($type) {
3866 0           $encoded .= length($to_encode) . ':' . $to_encode;
3867 0           return $encoded;
3868             }
3869            
3870 0 0         if ($type eq 'HASH') {
    0          
    0          
3871 0           $encoded .= 'd';
3872 0           foreach my $key (sort keys %$to_encode) {
3873 0           $encoded .= $self->bencode($key);
3874 0           $encoded .= $self->bencode($to_encode->{$key});
3875             }
3876 0           $encoded .= 'e';
3877             }
3878             elsif ($type eq 'ARRAY') {
3879 0           $encoded .= 'l';
3880 0           foreach my $element (@$to_encode) {
3881 0           $encoded .= $self->bencode($element);
3882             }
3883 0           $encoded .= 'e';
3884             }
3885             elsif ($to_encode =~ /\A\d+\Z/) {
3886 0           $encoded .= 'i' . $to_encode . 'e';
3887             }
3888              
3889 0           return $encoded;
3890             }
3891              
3892             *bEncode = \&bencode;
3893              
3894             =pod
3895              
3896             =head3 C
3897              
3898             The opposite of C. Returns the deserialized data from
3899             the bencoded string.
3900              
3901             Aliases: bDecode()
3902              
3903             =cut
3904             sub bdecode {
3905 0     0 1   my $self = shift;
3906 0           my $to_decode = shift;
3907              
3908 0           return $self->_bdecode(\$to_decode);
3909             }
3910              
3911             *bDecode = \&bdecode;
3912              
3913             sub _bdecode {
3914 0     0     my $self = shift;
3915 0           my $str_ref = shift;
3916            
3917 0 0         if ($$str_ref =~ m/\A(\d+):/) {
    0          
3918 0           my $length = $1;
3919 0           my $val = substr($$str_ref, length($1) + 1, $length);
3920 0           substr($$str_ref, 0, length($1) + 1 + $length) = '';
3921              
3922 0           return $val;
3923             }
3924             elsif ($$str_ref =~ s/\A(.)//) {
3925 0           my $letter = $1;
3926 0 0         if ($letter eq 'n') {
    0          
    0          
    0          
3927 0           return undef;
3928             }
3929             elsif ($letter eq 'i') {
3930 0           $$str_ref =~ s/\A(\d+)e//;
3931 0           return $1;
3932             }
3933             elsif ($letter eq 'l') {
3934 0           my @list;
3935 0   0       while ($$str_ref !~ m/\Ae/ and $$str_ref ne '') {
3936 0           push @list, $self->_bdecode($str_ref);
3937             }
3938 0           $$str_ref =~ s/\Ae//;
3939              
3940 0           return \@list;
3941             }
3942             elsif ($letter eq 'd') {
3943 0           my %hash;
3944 0   0       while ($$str_ref !~ m/\Ae/ and $$str_ref ne '') {
3945 0           my $key = $self->_bdecode($str_ref);
3946 0           $hash{$key} = $self->_bdecode($str_ref);
3947             }
3948 0           $$str_ref =~ s/\Ae//;
3949              
3950 0           return \%hash;
3951             }
3952             }
3953            
3954 0           return;
3955             }
3956              
3957             =pod
3958              
3959             =head3 C
3960              
3961             Returns the JSON representation of C<$data> (arbitrary
3962             datastructure -- but not objects). See http://www.json.org/ or
3963             http://en.wikipedia.org/wiki/JSON for details. In this
3964             implementation, hash keys are sorted so that the output is
3965             consistent.
3966              
3967             =cut
3968             sub to_json {
3969 0     0 1   my $self = shift;
3970 0           my $data = shift;
3971              
3972 0 0         return 'null' unless defined $data;
3973            
3974 0           my $type = reftype($data);
3975 0 0         unless (defined($type)) {
3976 0           return $self->_escape_json_str($data);
3977             }
3978            
3979 0 0         if ($type eq 'ARRAY') {
    0          
3980 0           return '[' . join(',', map { $self->to_json($_) } @$data) . ']';
  0            
3981             }
3982             elsif ($type eq 'HASH') {
3983 0           my @keys = sort keys %$data;
3984 0           return '{' . join(',', map { $self->_escape_json_str($_) . ':'
  0            
3985             . $self->to_json($data->{$_}) } @keys ) . '}';
3986             }
3987             else {
3988 0           return $self->_escape_json_str($data);
3989             }
3990             }
3991             *toJson = \&to_json;
3992              
3993             sub _escape_json_str {
3994 0     0     my $self = shift;
3995 0           my $str = shift;
3996              
3997 0 0         return 'null' unless defined $str;
3998              
3999             # \b means word boundary in a regex, so create it here in a
4000             # string, then interpolate
4001 0           my $backspace = quotemeta("\b");
4002              
4003 0           $str =~ s{([\"\\/])}{\\$1}g;
4004 0           $str =~ s{$backspace}{\\b}g;
4005 0           $str =~ s{\f}{\\f}g;
4006 0           $str =~ s{\x0a}{\\n}g;
4007 0           $str =~ s{\x0d}{\\r}g;
4008 0           $str =~ s{\t}{\\t}g;
4009 0           $str =~ s{([^\x00-\xff])}{sprintf "\\u%04x", ord($1)}eg;
  0            
4010              
4011 0           return '"' . $str . '"';
4012             }
4013              
4014             sub from_json {
4015 0     0 0   my $self = shift;
4016              
4017 0           return _parse_json($_[0]);
4018             }
4019              
4020             {
4021             my $to_parse;
4022             my $len;
4023             my $char;
4024             my $pos;
4025             my $looking_at;
4026             my $json_warn = 1;
4027              
4028             my $json_escape_map = { b => "\b",
4029             t => "\t",
4030             n => "\x0a",
4031             r => "\x0d",
4032             f => "\x0c",
4033             '\\' => '\\',
4034             };
4035              
4036             my $json_bareword_map = { true => 1,
4037             false => 0,
4038             null => undef,
4039             };
4040            
4041             sub _parse_json {
4042 0     0     $to_parse = shift;
4043 0           $len = length($to_parse);
4044 0           $char = '';
4045 0           $pos = 0;
4046 0           $looking_at = -1;
4047              
4048 0           return _parse_json_parse_value();
4049             }
4050              
4051             sub _parse_json_next_char {
4052 0 0   0     return $char = undef if ($pos >= $len);
4053 0           $char = substr($to_parse, $pos, 1);
4054 0           $looking_at = $pos;
4055 0           $pos++;
4056            
4057 0           return $char;
4058             }
4059              
4060             sub _parse_json_peek {
4061 0     0     my $count = shift;
4062 0 0         if ($count > $len - $pos) {
4063 0           return $char = substr($to_parse, $pos, $len - $pos);
4064             }
4065 0           return $char = substr($to_parse, $pos + 1, $count);
4066             }
4067              
4068             # eat whitespace and comments
4069             sub _parse_json_eat_whitespace {
4070 0     0     while (defined($char)) {
4071 0 0 0       if ($char =~ /\s/ or $char eq '') {
    0          
4072 0           _parse_json_next_char();
4073             }
4074             elsif ($char eq '/') {
4075 0           _parse_json_next_char();
4076 0 0         if ($char eq '/') {
    0          
4077             # single line comment
4078 0   0       1 while (defined(_parse_json_next_char()) and $char ne "\n" and $char ne "\r");
      0        
4079             }
4080             elsif ($char eq '*') {
4081             # multiple line comment
4082 0           _parse_json_next_char();
4083 0           while (1) {
4084 0 0         unless (defined($char)) {
4085             # error - unterminated comment
4086 0           last;
4087             }
4088              
4089 0 0         if ($char eq '*') {
4090 0 0 0       if (defined(_parse_json_next_char()) and $char eq '/') {
4091 0           _parse_json_next_char();
4092 0           last;
4093             }
4094             }
4095             else {
4096 0           _parse_json_next_char();
4097             }
4098            
4099             }
4100 0           next;
4101             }
4102             else {
4103             # error -- syntax error with comment -- can't have '/' by itself
4104             }
4105             }
4106             else {
4107 0           last;
4108             }
4109             }
4110             }
4111            
4112             sub _parse_json_parse_string {
4113 0 0 0 0     unless ($char eq '"' or $char eq "'") {
4114 0           warn "bad string at pos $looking_at, char=$char";
4115 0           return;
4116             }
4117              
4118 0           my $boundary = $char;
4119 0           my $str = '';
4120 0           my $start_pos = $looking_at;
4121              
4122 0           while ( defined(_parse_json_next_char()) ) {
4123 0 0         if ($char eq $boundary) {
    0          
4124 0           _parse_json_next_char();
4125 0           return $str;
4126             }
4127             elsif ($char eq '\\') {
4128 0           _parse_json_next_char();
4129 0 0         if (exists($json_escape_map->{$char})) {
    0          
4130 0           $str .= $json_escape_map->{$char};
4131             }
4132             elsif ($char eq 'u') {
4133 0           my $u = '';
4134              
4135 0           for (1 .. 4) {
4136 0           _parse_json_next_char();
4137              
4138 0 0         if ($char !~ /[0-9A-Fa-f]/) {
4139             # error -- bad unicode specifier
4140 0 0         if ($json_warn) {
4141 0           warn "bad unicode specifier at pos $looking_at, char=$char";
4142             }
4143 0           last;
4144             }
4145 0           $u .= $char;
4146             }
4147              
4148 0           my $full_char = chr(hex($u));
4149 0           $str .= $full_char;
4150             }
4151             else {
4152 0           $str .= $char;
4153             }
4154             }
4155             else {
4156 0           $str .= $char;
4157             }
4158             }
4159              
4160             # error -- unterminated string
4161 0           warn "unterminated string starting at $start_pos";
4162             }
4163              
4164             sub _parse_json_parse_object {
4165 0 0   0     return unless $char eq '{';
4166              
4167 0           my $obj = {};
4168 0           my $key;
4169            
4170 0           _parse_json_next_char();
4171 0           _parse_json_eat_whitespace();
4172 0 0         if ($char eq '}') {
4173 0           _parse_json_next_char();
4174 0           return $obj;
4175             }
4176              
4177 0           while (defined($char)) {
4178 0           $key = _parse_json_parse_string();
4179 0           _parse_json_eat_whitespace();
4180            
4181 0 0         unless ($char eq ':') {
4182 0           last;
4183             }
4184              
4185 0           _parse_json_next_char();
4186 0           _parse_json_eat_whitespace();
4187 0           $obj->{$key} = _parse_json_parse_value();
4188 0           _parse_json_eat_whitespace();
4189              
4190 0 0         if ($char eq '}') {
    0          
4191 0           _parse_json_next_char();
4192 0           return $obj;
4193             }
4194             elsif ($char eq ',') {
4195 0           _parse_json_next_char();
4196 0           _parse_json_eat_whitespace();
4197             }
4198             else {
4199 0           last;
4200             }
4201             }
4202              
4203 0 0         warn "bad object at pos $looking_at, char=$char" if $json_warn;
4204             }
4205              
4206             sub _parse_json_parse_array {
4207 0 0   0     return unless $char eq '[';
4208 0           my @array;
4209             my $val;
4210              
4211 0           _parse_json_next_char();
4212 0           _parse_json_eat_whitespace();
4213 0 0         if ($char eq ']') {
4214 0           return \@array;
4215             }
4216              
4217 0           while (defined($char)) {
4218 0           $val = _parse_json_parse_value();
4219 0           push @array, $val;
4220 0           _parse_json_eat_whitespace();
4221 0 0         if ($char eq ']') {
    0          
4222 0           _parse_json_next_char();
4223 0           return \@array;
4224             }
4225             elsif ($char eq ',') {
4226 0           _parse_json_next_char();
4227 0           _parse_json_eat_whitespace();
4228             }
4229             else {
4230 0           last;
4231             }
4232             }
4233              
4234 0 0         warn "bad array: pos $looking_at, char=$char" if $json_warn;
4235 0           return;
4236             }
4237              
4238             sub _parse_json_parse_number {
4239 0     0     my $num = '';
4240              
4241 0 0         if ($char eq '0') {
4242 0           $num .= $char;
4243 0           my $hex = _parse_json_peek(1) =~ /[Xx]/;
4244 0           _parse_json_next_char();
4245            
4246 0   0       while (defined($char) and $char !~ /[[:space:],\}\]:]/) {
4247 0           $num .= $char;
4248 0           _parse_json_next_char();
4249             }
4250              
4251 0 0         return $hex ? hex($num) : oct($num);
4252             }
4253              
4254 0   0       while (defined($char) and $char !~ /[[:space:],\}\]:]/) {
4255 0           $num .= $char;
4256 0           _parse_json_next_char();
4257             }
4258              
4259 0           return 0 + $num;
4260             }
4261              
4262             sub _parse_json_parse_word {
4263 0     0     my $word = '';
4264 0           while ($char !~ /[[:space:]\]\},:]/) {
4265 0           $word .= $char;
4266 0           _parse_json_next_char();
4267             }
4268              
4269 0 0         if (exists($json_bareword_map->{$word})) {
4270 0           return $json_bareword_map->{$word};
4271             }
4272              
4273 0 0         warn "syntax error at char $looking_at: char='$char', word='$word'" if $json_warn;
4274 0           return;
4275             }
4276              
4277             sub _parse_json_parse_value {
4278 0     0     _parse_json_eat_whitespace();
4279 0 0         return unless defined($char);
4280 0 0         return _parse_json_parse_object() if $char eq '{';
4281 0 0         return _parse_json_parse_array() if $char eq '[';
4282 0 0 0       return _parse_json_parse_string() if $char eq '"' or $char eq "'";
4283 0 0         return _parse_json_parse_number() if $char eq '-';
4284 0 0         return $char =~ /\d/ ? _parse_json_parse_number() : _parse_json_parse_word();
4285             }
4286              
4287             }
4288              
4289             sub _do_benchmark {
4290 0     0     my $self = shift;
4291            
4292 0           require Benchmark;
4293 0           my $data = { _dbh => 'dummy' };
4294            
4295             my $results = Benchmark::cmpthese(1000000, {
4296 0     0     'Plain hash' => sub { my $val = $data->{_dbh} },
4297 0     0     'Indirect hash' => sub { my $val = $i_data{ refaddr($self) }{_dbh} },
4298             }
4299 0           );
4300              
4301             }
4302              
4303             sub AUTOLOAD {
4304 0     0     my $self = shift;
4305              
4306 0           (my $func = $AUTOLOAD) =~ s/^.*::([^:]+)$/$1/;
4307            
4308 2     2   30 no strict 'refs';
  2         3  
  2         529  
4309              
4310 0 0         if (ref($self)) {
4311 0           my $dbh = $self->_getDatabaseHandle;
4312 0           return $dbh->$func(@_);
4313             } else {
4314 0           return DBI->$func(@_);
4315             }
4316             }
4317              
4318             =pod
4319              
4320             =head2 There are also underscore_separated versions of these methods.
4321              
4322             E.g., C becomes C
4323              
4324             =head1 DEPENDENCIES
4325              
4326             DBI
4327              
4328             =head1 ACKNOWLEDGEMENTS
4329              
4330             Others who have contributed ideas and/or code for this module:
4331              
4332             =over 4
4333              
4334             =item Kevin Wilson
4335              
4336             =item Mark Stosberg
4337              
4338             =item David Bushong
4339              
4340             =back
4341              
4342             =head1 AUTHOR
4343              
4344             Don Owens
4345              
4346             =head1 LICENSE AND COPYRIGHT
4347              
4348             Copyright (c) 2003-2012 Don Owens (don@regexguy.com). All rights reserved.
4349              
4350             This free software; you can redistribute it and/or modify it
4351             under the same terms as Perl itself. See perlartistic.
4352              
4353             This program is distributed in the hope that it will be
4354             useful, but WITHOUT ANY WARRANTY; without even the implied
4355             warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
4356             PURPOSE.
4357              
4358             =head1 SEE ALSO
4359              
4360             L, perl
4361              
4362             =head1 VERSION
4363              
4364             0.29
4365              
4366             =cut
4367              
4368             1;
4369