File Coverage

blib/lib/DBIx/FlexibleBinding.pm
Criterion Covered Total %
statement 359 390 92.0
branch 126 204 61.7
condition 31 60 51.6
subroutine 70 72 97.2
pod 1 1 100.0
total 587 727 80.7


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             DBIx::FlexibleBinding - Greater flexibility on statement placeholder choice and data binding
5              
6             =head1 VERSION
7              
8             version 2.0.1
9              
10             =cut
11              
12             =head1 SYNOPSIS
13              
14             This module extends the DBI allowing you choose from a variety of supported
15             parameter placeholder and binding patterns as well as offering simplified
16             ways to interact with datasources, while improving general readability.
17              
18             #########################################################
19             # SCENARIO 1 #
20             # A connect followed by a prepare-execute-process cycle #
21             #########################################################
22              
23             use DBIx::FlexibleBinding;
24             use constant DSN => 'dbi:mysql:test;host=127.0.0.1';
25             use constant SQL => << '//';
26             SELECT solarSystemName AS name
27             FROM mapsolarsystems
28             WHERE regional = :is_regional
29             AND security >= :minimum_security
30             //
31              
32             # Pretty standard connect, just with the new DBI subclass ...
33             #
34             my $dbh = DBIx::FlexibleBinding->connect(DSN, '', '', { RaiseError => 1 });
35              
36             # Prepare statement using named placeholders (not bad for MySQL, eh) ...
37             #
38             my $sth = $dbh->prepare(SQL);
39              
40             # Execute the statement (parameter binding is automatic) ...
41             #
42             my $rv = $sth->execute(is_regional => 1,
43             minimum_security => 1.0);
44              
45             # Fetch and transform rows with a blocking callback to get only the data you
46             # want without cluttering the place up with intermediate state ...
47             #
48             my @system_names = $sth->getrows_hashref(callback { $_->{name} });
49              
50             ############################################################################
51             # SCENARIO 2 #
52             # Let's simplify the previous scenario using the database handle's version #
53             # of that getrows_hashref method. #
54             ############################################################################
55              
56             use DBIx::FlexibleBinding -alias => 'DFB';
57             use constant DSN => 'dbi:mysql:test;host=127.0.0.1';
58             use constant SQL => << '//';
59             SELECT solarSystemName AS name
60             FROM mapsolarsystems
61             WHERE regional = :is_regional
62             AND security >= :minimum_security
63             //
64              
65             # Pretty standard connect, this time with the DBI subclass package alias ...
66             #
67             my $dbh = DFB->connect(DSN, '', '', { RaiseError => 1 });
68              
69             # Cut out the middle men ...
70             #
71             my @system_names = $dbh->getrows_hashref(SQL,
72             is_regional => 1,
73             minimum_security => 1.0,
74             callback { $_->{name} });
75              
76             #############################################################################
77             # SCENARIO 3 #
78             # The subclass import method provides a versatile mechanism for simplifying #
79             # matters further. #
80             #############################################################################
81              
82             use DBIx::FlexibleBinding -subs => [ 'MyDB' ];
83             use constant DSN => 'dbi:mysql:test;host=127.0.0.1';
84             use constant SQL => << '//';
85             SELECT solarSystemName AS name
86             FROM mapsolarsystems
87             WHERE regional = :is_regional
88             AND security >= :minimum_security
89             //
90              
91             # MyDB will represent our datasource; initialise it ...
92             #
93             MyDB DSN, '', '', { RaiseError => 1 };
94              
95             # Cut out the middle men and some of the line-noise, too ...
96             #
97             my @system_names = MyDB(SQL,
98             is_regional => 1,
99             minimum_security => 1.0,
100             callback { $_->{name} });
101             =cut
102              
103             =head1 DESCRIPTION
104              
105             This module subclasses the DBI to provide improvements and greater flexibility
106             in the following areas:
107              
108             =over 2
109              
110             =item * Parameter placeholders and data binding
111              
112             =item * Data retrieval and processing
113              
114             =item * Accessing and interacting with datasources
115              
116             =back
117              
118             =head2 Parameter placeholders and data binding
119              
120             This module provides support for a wider range of parameter placeholder and
121             data-binding schemes. As well as continued support for the simple positional
122             placeholders (C), additional support is provided for numeric placeholders (C<:N>
123             and C), and named placeholders (C<:NAME> and C<@NAME>).
124              
125             As for the process of binding data values to parameters: that is, by default,
126             now completely automated, removing a significant part of the workload from the
127             prepare-bind-execute cycle. It is, however, possible to swtch off automatic
128             data-binding globally and on a statement-by-statement basis.
129              
130             The following familiar operations have been modified to accommodate all of these
131             changes, though developers continue to use them as they always have done:
132              
133             =over 2
134              
135             =item * C<$DATABASE_HANDLE-Eprepare($STATEMENT, \%ATTR);>
136              
137             =item * C<$DATABASE_HANDLE-Edo($STATEMENT, \%ATTR, @DATA);>
138              
139             =item * C<$STATEMENT_HANDLE-Ebind_param($NAME_OR_POSITION, $VALUE, \%ATTR);>
140              
141             =item * C<$STATEMENT_HANDLE-Eexecute(@DATA);>
142              
143             =back
144              
145             =head2 Data retrieval and processing
146              
147             Four new methods, each available for database B statement handles, have
148             been implemented:
149              
150             =over 2
151              
152             =item * C
153              
154             =item * C
155              
156             =item * C
157              
158             =item * C
159              
160             =back
161              
162             These methods complement DBI's existing fetch methods, providing new ways to
163             retrieve and process data.
164              
165             =head2 Accessing and interacting with datasources
166              
167             The module's C<-subs> import option may be used to create subroutines,
168             during the compile phase, and export them to the caller's namespace for
169             use later as representations of database and statement handles.
170              
171             =over 2
172              
173             =item * Use for connecting to datasources
174              
175             use DBIx::FlexibleBinding -subs => [ 'MyDB' ];
176              
177             # Pass in any set of well-formed DBI->connect(...) arguments to associate
178             # your name with a live database connection ...
179             #
180             MyDB( 'dbi:mysql:test;host=127.0.0.1', '', '', { RaiseError => 1 } );
181              
182             # Or, simply pass an existing database handle as the only argument ...
183             #
184             MyDB($dbh);
185              
186             =item * Use them to represent database handles
187              
188             use DBIx::FlexibleBinding -subs => [ 'MyDB' ];
189             use constant SQL => << '//';
190             SELECT *
191             FROM mapsolarsystems
192             WHERE regional = :is_regional
193             AND security >= :minimum_security
194             //
195              
196             MyDB( 'dbi:mysql:test;host=127.0.0.1', '', '', { RaiseError => 1 } );
197              
198             # If your name is already associated with a database handle then just call
199             # it with no parameters to use it as such ...
200             #
201             my $sth = MyDB->prepare(SQL);
202              
203             =item * Use them to represent statement handles
204              
205             use DBIx::FlexibleBinding -subs => [ 'MyDB', 'solar_systems' ];
206             use constant SQL => << '//';
207             SELECT *
208             FROM mapsolarsystems
209             WHERE regional = :is_regional
210             AND security >= :minimum_security
211             //
212              
213             MyDB( 'dbi:mysql:test;host=127.0.0.1', '', '', { RaiseError => 1 } );
214              
215             my $sth = MyDB->prepare(SQL);
216              
217             # Simply call the statement handle proxy, passing a statement handle in as
218             # the only argument ...
219             #
220             solar_systems($sth);
221              
222             =item * Use to interact with the represented database and statement handles
223              
224             use DBIx::FlexibleBinding -subs => [ 'MyDB', 'solar_systems' ];
225             use constant SQL => << '//';
226             SELECT *
227             FROM mapsolarsystems
228             WHERE regional = :is_regional
229             AND security >= :minimum_security
230             //
231              
232             MyDB( 'dbi:mysql:test;host=127.0.0.1', '', '', { RaiseError => 1 } );
233              
234             # Use the database handle proxy to prepare, bind and execute statements, then
235             # retrieve the results ...
236             #
237             # Use the database handle proxy to prepare, bind and execute statements, then
238             # retrieve the results ...
239             #
240             my $array_of_hashrefs = MyDB(SQL,
241             is_regional => 1,
242             minimum_security => 1.0);
243              
244             # In list context, results come back as lists ...
245             #
246             my @array_of_hashrefs = MyDB(SQL,
247             is_regional => 1,
248             minimum_security => 1.0);
249              
250             # Using -subs also relaxes strict 'subs' in the caller's scope, so pretty-up
251             # void context calls by losing the parentheses, if you wish to use callbacks
252             # to process the results ...
253             #
254             MyDB SQL, is_regional => 1, minimum_security => 1.0, callback {
255             printf "%-16s %.1f\n", $_->{solarSystemName}, $_->{security};
256             };
257              
258             # You can use proxies to represent statements, too. Simply pass in a statement
259             # handle as the only argument ...
260             #
261             my $sth = MyDB->prepare(SQL);
262             solar_systems($sth); # Using "solar_systems" as statement proxy.
263              
264             # Now, when called with other types of arguments, those argument values are
265             # bound and the statement is executed ...
266             #
267             my $array_of_hashrefs = solar_systems(is_regional => 1,
268             minimum_security => 1.0);
269              
270             # In list context, results come back as lists ...
271             #
272             my @array_of_hashrefs = solar_systems(is_regional => 1,
273             minimum_security => 1.0);
274              
275             # Statements requiring no parameters cannot be used in this manner because
276             # making a call to a statement proxy with an arity of zero results in the
277             # statement handle being returned. In this situation, use something like
278             # undef as an argument (it will be ignored in this particular instance) ...
279             #
280             my $rv = statement_proxy(undef);
281             #
282             # Meh, you can't win 'em all!
283              
284             =back
285              
286             =cut
287              
288 4     4   56637 use strict;
  4         9  
  4         96  
289 4     4   19 use warnings;
  4         7  
  4         102  
290 4     4   2866 use MRO::Compat 'c3';
  4         48444  
  4         240  
291              
292             package DBIx::FlexibleBinding;
293             our $VERSION = '2.0.2'; # VERSION
294             # ABSTRACT: Adds more statement placeholder and data-binding flexibility.
295 4     4   37 use Carp qw(confess);
  4         8  
  4         289  
296 4     4   21 use Exporter ();
  4         8  
  4         63  
297 4     4   10682 use DBI ();
  4         73556  
  4         158  
298 4     4   37 use Scalar::Util qw(reftype);
  4         7  
  4         364  
299 4     4   5778 use namespace::clean;
  4         86360  
  4         24  
300 4     4   4372 use Params::Callbacks 'callback';
  4         3733  
  4         625  
301              
302             our @ISA = ( 'DBI', 'Exporter' );
303             our @EXPORT = qw(callback);
304              
305             =head1 PACKAGE GLOBALS
306              
307             =head2 $DBIx::FlexibleBinding::AUTO_BINDING_ENABLED
308              
309             A boolean setting used to determine whether or not automatic binding is enabled
310             or disabled globally.
311              
312             The default setting is C<"1"> (I).
313              
314             =cut
315              
316             our $AUTO_BINDING_ENABLED = 1;
317              
318             =head1 IMPORT TAGS AND OPTIONS
319              
320             =head2 -alias
321              
322             This option may be used by the caller to select an alias to use for this
323             package's unwieldly namespace.
324              
325             use DBIx::FlexibleBinding -alias => 'DBIF';
326              
327             my $dbh = DBIF->connect('dbi:SQLite:test.db', '', '');
328              
329             =head2 -subs
330              
331             This option may be used to create subroutines, during the compile phase, in
332             the caller's namespace to be used as representations of database and statement
333             handles.
334              
335             use DBIx::FlexibleBinding -subs => [ 'MyDB' ];
336              
337             # Initialise by passing in a valid set of DBI->connect(...) arguments.
338             # The database handle will be the return value.
339             #
340             MyDB 'dbi:mysql:test;host=127.0.0.1', '', '', { RaiseError => 1 };
341              
342             # Or, initialise by passing in a DBI database handle.
343             # The handle is also the return value.
344             #
345             MyDB $dbh;
346              
347             # Once initialised, use the subroutine as you would a DBI database handle.
348             #
349             my $statement = << '//';
350             SELECT solarSystemName AS name
351             FROM mapsolarsystems
352             WHERE security >= :minimum_security
353             //
354             my $sth = MyDB->prepare($statement);
355              
356             # Or use it as an expressive time-saver!
357             #
358             my $array_of_hashrefs = MyDB($statement, security => 1.0);
359             my @system_names = MyDB($statement, minimum_security => 1.0, callback {
360             return $_->{name};
361             });
362             MyDB $statement, minimum_security => 1.0, callback {
363             my ($row) = @_;
364             print "$row->{name}\n";
365             };
366              
367             Use of this option automatically relaxes C for the remainder of
368             scope containing the C directive. That is unless C or
369             C appears afterwards.
370              
371             =cut
372              
373             sub import
374             {
375 4     4   39 my ( $package, @args ) = @_;
376 4         10 my $caller = caller;
377 4         10 @_ = ($package);
378              
379 4         21 while (@args) {
380 5         11 my $arg = shift(@args);
381              
382 5 50       26 if ( substr( $arg, 0, 1 ) eq '-' ) {
383 5 100       25 if ( $arg eq '-alias' ) {
    50          
384 4     4   48 no strict 'refs'; ## no critic [TestingAndDebugging::ProhibitNoStrict]
  4         6  
  4         1510  
385 1         2 my $package_alias = shift(@args);
386 1         2 *{ $package_alias . '::' } = *{ __PACKAGE__ . '::' };
  1         37  
  1         3  
387 1         5 *{ $package_alias . '::db::' } = *{ __PACKAGE__ . '::db::' };
  1         4  
  1         3  
388 1         1 *{ $package_alias . '::st::' } = *{ __PACKAGE__ . '::st::' };
  1         4  
  1         3  
389             }
390             elsif ( $arg eq '-subs' ) {
391 4         7 my $list = shift(@args);
392 4 50 33     75 confess "Expected anonymous list or array reference after '$arg'"
393             unless ref($list) && reftype($list) eq 'ARRAY';
394 4         41 $caller->unimport( 'strict', 'subs' );
395 4         9 for my $name (@$list) {
396 5         16 DBIx::FlexibleBinding::ObjectProxy->create( $name, $caller );
397             }
398             }
399             else {
400 0         0 confess "Unrecognised import option '$arg'";
401             }
402             }
403             else {
404 0         0 push @_, $arg;
405             }
406             }
407              
408 4         187 goto &Exporter::import;
409             }
410              
411             =head1 CLASS METHODS
412              
413             =cut
414              
415             =head2 connect
416              
417             $dbh = DBIx::FlexibleBinding->connect($data_source, $user, $pass)
418             or die $DBI::errstr;
419             $dbh = DBIx::FlexibleBinding->connect($data_source, $user, $pass, \%attr)
420             or die $DBI::errstr;
421              
422             Establishes a database connection, or session, to the requested data_source and
423             returns a database handle object if the connection succeeds or undef if it does
424             not.
425              
426             Refer to L for a more detailed
427             description of this method.
428              
429             =cut
430              
431             sub connect
432             {
433 5     5 1 12 my ( $invocant, $dsn, $user, $pass, $attr ) = @_;
434 5 50       27 $attr = {} unless defined $attr;
435 5 50 33     45 $attr->{RootClass} = ref($invocant) || $invocant unless defined $attr->{RootClass};
436 5         95 return $invocant->next::method( $dsn, $user, $pass, $attr );
437             }
438              
439             package # Hide from PAUSE
440             DBIx::FlexibleBinding::db;
441             our $VERSION = '2.0.2'; # VERSION
442              
443 4     4   21 use Carp 'confess';
  4         7  
  4         176  
444 4     4   20 use Params::Callbacks 'callbacks';
  4         7  
  4         160  
445 4     4   19 use namespace::clean;
  4         7  
  4         13  
446              
447             our @ISA = 'DBI::db';
448              
449             =head1 DATABASE HANDLE METHODS
450              
451             =cut
452              
453             =head2 do
454              
455             $rows = $dbh->do($statement_string) or die $dbh->errstr;
456             $rows = $dbh->do($statement_string, @bind_values) or die $dbh->errstr;
457             $rows = $dbh->do($statement_string, \%attr) or die $dbh->errstr;
458             $rows = $dbh->do($statement_string, \%attr, @bind_values) or die $dbh->errstr;
459             $rows = $dbh->do($statement_handle) or die $dbh->errstr;
460             $rows = $dbh->do($statement_handle, @bind_values) or die $dbh->errstr;
461              
462              
463             Prepares (if necessary) and executes a single statement. Returns the number of
464             rows affected or undef on error. A return value of -1 means the number of rows
465             is not known, not applicable, or not available. When no rows have been affected
466             this method continues the C tradition of returning C<0E0> on successful
467             execution and C on failure.
468              
469             The C method accepts optional callbacks for further processing of the result.
470              
471             The C implementation provided by this module allows for some minor
472             deviations in usage over the standard C implementation. In spite
473             of this, the new method may be used just like the original.
474              
475             Refer to L for a more detailed
476             description of this method.
477              
478             B
479              
480             =over
481              
482             =item 1. Statement attributes are now optional:
483              
484             $sql = << '//';
485             UPDATE employees
486             SET salary = :salary
487             WHERE employee_id = :employee_id
488             //
489              
490             $dbh->do($sql, employee_id => 52, salary => 35_000)
491             or die $dbh->errstr;
492              
493             A reference to the statement attributes hash is no longer required, even if it's
494             empty. If, however, a hash reference is supplied as the first parameter then it
495             would be used for that purpose.
496              
497             =item 2. Prepared statements now may be re-used:
498              
499             $sth = $dbh->prepare(<< '//');
500             UPDATE employees
501             SET salary = ?
502             WHERE employee_id = ?
503             //
504              
505             $dbh->do($sth, 35_000, 52) or die $dbh->errstr;
506              
507             A prepared statement may also be used in lieu of a statement string. In such
508             cases, referencing a statement attributes hash is neither required nor expected.
509              
510             =back
511              
512             =cut
513              
514             sub do
515             {
516 15862     15862   2975509 my ( $callbacks, $dbh, $sth, @bind_values ) = &callbacks;
517              
518 15862 50       511381 if ( !ref($sth) ) {
519 15862         27228 my $attr;
520 15862 100 100     123117 $attr = shift(@bind_values)
521             if ref( $bind_values[0] ) && ref( $bind_values[0] ) eq 'HASH';
522 15862         62906 $sth = $dbh->prepare( $sth, $attr );
523 15862 50       133893 return if $sth->err;
524             }
525              
526 15862         38349 my $result;
527 15862 50       66639 return $result if $sth->err;
528              
529 15862         66675 $result = $sth->execute(@bind_values);
530 15862 50       233182 return $result if $sth->err;
531              
532 15862 50       64408 if ($result) {
533 15862 50       77985 if (@$callbacks) {
534 0         0 local $_;
535 0         0 $result = $callbacks->smart_transform( $_ = $result );
536             }
537             }
538              
539 15862         625174 return $result;
540             }
541              
542             =head2 prepare
543              
544             $sth = $dbh->prepare($statement_string);
545             $sth = $dbh->prepare($statement_string, \%attr);
546              
547             Prepares a statement for later execution by the database engine and returns a
548             reference to a statement handle object.
549              
550             Refer to L for a more detailed
551             description of this method.
552              
553             B
554              
555             =over
556              
557             =item 1. Prepare a statement using positional placeholders:
558              
559             $sql = << '//';
560             UPDATE employees
561             SET salary = ?
562             WHERE employee_id = ?
563             //
564              
565             $sth = $dbh->prepare($sql);
566              
567             =item 2. Prepare a statement using named placeholders:
568              
569             I<(Yes, even for those MySQL connections!)>
570              
571             $sql = << '//';
572             UPDATE employees
573             SET salary = :salary
574             WHERE employee_id = :employee_id
575             //
576              
577             $sth = $dbh->prepare($sql);
578              
579             =back
580              
581             =cut
582              
583             sub prepare
584             {
585 15925     15925   76570 my ( $dbh, $stmt, @args ) = @_;
586 15925         26981 my @params;
587              
588 15925 100       222885 if ( $stmt =~ /:\w+\b/ ) {
    100          
    100          
589 7060         228936 @params = ( $stmt =~ /:(\w+)\b/g );
590 7060         179975 $stmt =~ s/:\w+\b/?/g;
591             }
592             elsif ( $stmt =~ /\@\w+\b/ ) {
593 5292         163427 @params = ( $stmt =~ /(\@\w+)\b/g );
594 5292         133317 $stmt =~ s/\@\w+\b/?/g;
595             }
596             elsif ( $stmt =~ /\?\d+\b/ ) {
597 1766         54495 @params = ( $stmt =~ /\?(\d+)\b/g );
598 1766         44171 $stmt =~ s/\?\d+\b/?/g;
599             }
600              
601 15925 50       119401 my $sth = $dbh->next::method( $stmt, @args ) or return;
602 15925         49072429 return $sth->_init_private_attributes( \@params );
603             }
604              
605             =head2 getrows_arrayref I<(database handles)>
606              
607             $results = $dbh->getrows_arrayref($statement_string, @bind_values);
608             @results = $dbh->getrows_arrayref($statement_string, @bind_values);
609             $results = $dbh->getrows_arrayref($statement_string, \%attr, @bind_values);
610             @results = $dbh->getrows_arrayref($statement_string, \%attr, @bind_values);
611             $results = $dbh->getrows_arrayref($statement_handle, @bind_values);
612             @results = $dbh->getrows_arrayref($statement_handle, @bind_values);
613              
614             Prepares (if necessary) and executes a single statement with the specified data
615             bindings and fetches the result set as an array of array references.
616              
617             The C method accepts optional callbacks for further processing
618             of the results by the caller.
619              
620             B
621              
622             =over
623              
624             =item 1. Prepare, execute it then get the results as a reference:
625              
626             $sql = << '//';
627             SELECT solarSystemName AS name
628             , security
629             FROM mapsolarsystems
630             WHERE regional = 1
631             AND security >= :minimum_security
632             //
633              
634             $systems = $dbh->getrows_arrayref($sql, minimum_security => 1.0);
635              
636             # Returns a structure something like this:
637             #
638             # [ [ 'Kisogo', '1' ],
639             # [ 'New Caldari', '1' ],
640             # [ 'Amarr', '1' ],
641             # [ 'Bourynes', '1' ],
642             # [ 'Ryddinjorn', '1' ],
643             # [ 'Luminaire', '1' ],
644             # [ 'Duripant', '1' ],
645             # [ 'Yulai', '1' ] ]
646              
647             =item 2. Re-use a prepared statement, execute it then return the results as a list:
648              
649             We'll use the query from Example 1 but have the results returned as a list for
650             further processing by the caller.
651              
652             $sth = $dbh->prepare($sql);
653              
654             @systems = $dbh->getrows_arrayref($sql, minimum_security => 1.0);
655              
656             for my $system (@systems) {
657             printf "%-11s %.1f\n", @$system;
658             }
659              
660             # Output:
661             #
662             # Kisogo 1.0
663             # New Caldari 1.0
664             # Amarr 1.0
665             # Bourynes 1.0
666             # Ryddinjorn 1.0
667             # Luminaire 1.0
668             # Duripant 1.0
669             # Yulai 1.0
670              
671             =item 3. Re-use a prepared statement, execute it then return modified results as a
672             reference:
673              
674             We'll use the query from Example 1 but have the results returned as a list
675             for further processing by a caller who will be using callbacks to modify those
676             results.
677              
678             $sth = $dbh->prepare($sql);
679              
680             $systems = $dbh->getrows_arrayref($sql, minimum_security => 1.0, callback {
681             my ($row) = @_;
682             return sprintf("%-11s %.1f\n", @$row);
683             });
684              
685             # Returns a structure something like this:
686             #
687             # [ 'Kisogo 1.0',
688             # 'New Caldari 1.0',
689             # 'Amarr 1.0',
690             # 'Bourynes 1.0',
691             # 'Ryddinjorn 1.0',
692             # 'Luminaire 1.0',
693             # 'Duripant 1.0',
694             # 'Yulai 1.0' ]
695              
696             =back
697              
698             =cut
699              
700             sub getrows_arrayref
701             {
702 24     24   60806 my ( $callbacks, $dbh, $sth, @bind_values ) = &callbacks;
703              
704 24 50       643 if ( !ref($sth) ) {
705 24         41 my $attr;
706 24 100 100     155 $attr = shift(@bind_values)
707             if ref( $bind_values[0] ) && ref( $bind_values[0] ) eq 'HASH';
708 24         88 $sth = $dbh->prepare( $sth, $attr );
709 24 50       138 return if $sth->err;
710             }
711              
712 24         91 $sth->execute(@bind_values);
713 24 50       267 return if $sth->err;
714              
715 24         123 return $sth->getrows_arrayref($callbacks);
716             }
717              
718             =head2 getrows_hashref I<(database handles)>
719              
720             $results = $dbh->getrows_hashref($statement_string, @bind_values);
721             @results = $dbh->getrows_hashref($statement_string, @bind_values);
722             $results = $dbh->getrows_hashref($statement_string, \%attr, @bind_values);
723             @results = $dbh->getrows_hashref($statement_string, \%attr, @bind_values);
724             $results = $dbh->getrows_hashref($statement_handle, @bind_values);
725             @results = $dbh->getrows_hashref($statement_handle, @bind_values);
726              
727             Prepares (if necessary) and executes a single statement with the specified data
728             bindings and fetches the result set as an array of hash references.
729              
730             The C method accepts optional callbacks for further processing
731             of the results by the caller.
732              
733             B
734              
735             =over
736              
737             =item 1. Prepare, execute it then get the results as a reference:
738              
739             $sql = << '//';
740             SELECT solarSystemName AS name
741             , security
742             FROM mapsolarsystems
743             WHERE regional = 1
744             AND security >= :minimum_security
745             //
746              
747             $systems = $dbh->getrows_hashref($sql, minimum_security => 1.0);
748              
749             # Returns a structure something like this:
750             #
751             # [ { name => 'Kisogo', security => '1' },
752             # { name => 'New Caldari', security => '1' },
753             # { name => 'Amarr', security => '1' },
754             # { name => 'Bourynes', security => '1' },
755             # { name => 'Ryddinjorn', security => '1' },
756             # { name => 'Luminaire', security => '1' },
757             # { name => 'Duripant', security => '1' },
758             # { name => 'Yulai', security => '1' } ]
759              
760             =item 2. Re-use a prepared statement, execute it then return the results as a list:
761              
762             We'll use the query from Example 1 but have the results returned as a list for
763             further processing by the caller.
764              
765             $sth = $dbh->prepare($sql);
766              
767             @systems = $dbh->getrows_hashref($sql, minimum_security => 1.0);
768              
769             for my $system (@systems) {
770             printf "%-11s %.1f\n", @{$system}{'name', 'security'}; # Hash slice
771             }
772              
773             # Output:
774             #
775             # Kisogo 1.0
776             # New Caldari 1.0
777             # Amarr 1.0
778             # Bourynes 1.0
779             # Ryddinjorn 1.0
780             # Luminaire 1.0
781             # Duripant 1.0
782             # Yulai 1.0
783              
784             =item 3. Re-use a prepared statement, execute it then return modified results as a
785             reference:
786              
787             We'll use the query from Example 1 but have the results returned as a list
788             for further processing by a caller who will be using callbacks to modify those
789             results.
790              
791             $sth = $dbh->prepare($sql);
792              
793             $systems = $dbh->getrows_hashref($sql, minimum_security => 1.0, callback {
794             sprintf("%-11s %.1f\n", @{$_}{'name', 'security'}); # Hash slice
795             });
796              
797             # Returns a structure something like this:
798             #
799             # [ 'Kisogo 1.0',
800             # 'New Caldari 1.0',
801             # 'Amarr 1.0',
802             # 'Bourynes 1.0',
803             # 'Ryddinjorn 1.0',
804             # 'Luminaire 1.0',
805             # 'Duripant 1.0',
806             # 'Yulai 1.0' ]
807              
808             =back
809              
810             =cut
811              
812             sub getrows_hashref
813             {
814 2     2   1912 my ( $callbacks, $dbh, $sth, @bind_values ) = &callbacks;
815              
816 2 50       52 if ( !ref($sth) ) {
817 2         5 my $attr;
818 2 50 33     10 $attr = shift(@bind_values)
819             if ref( $bind_values[0] ) && ref( $bind_values[0] ) eq 'HASH';
820 2         10 $sth = $dbh->prepare( $sth, $attr );
821 2 50       14 return if $sth->err;
822             }
823              
824 2         10 $sth->execute(@bind_values);
825 2 50       18 return if $sth->err;
826              
827 2         18 return $sth->getrows_hashref($callbacks);
828             }
829              
830             =head2 getrows I<(database handles)>
831              
832             $results = $dbh->getrows($statement_string, @bind_values);
833             @results = $dbh->getrows($statement_string, @bind_values);
834             $results = $dbh->getrows($statement_string, \%attr, @bind_values);
835             @results = $dbh->getrows($statement_string, \%attr, @bind_values);
836             $results = $dbh->getrows($statement_handle, @bind_values);
837             @results = $dbh->getrows$statement_handle, @bind_values);
838              
839             Alias for C.
840              
841             If array references are preferred, have the symbol table glob point alias the
842             C method.
843              
844             The C method accepts optional callbacks for further processing
845             of the results by the caller.
846              
847             =cut
848              
849 4     4   4434 BEGIN { *getrows = \&getrows_hashref }
850              
851             =head2 getrow_arrayref I<(database handles)>
852              
853             $result = $dbh->getrow_arrayref($statement_string, @bind_values);
854             $result = $dbh->getrow_arrayref($statement_string, \%attr, @bind_values);
855             $result = $dbh->getrow_arrayref($statement_handle, @bind_values);
856              
857             Prepares (if necessary) and executes a single statement with the specified data
858             bindings and fetches the first row as an array reference.
859              
860             The C method accepts optional callbacks for further processing
861             of the result by the caller.
862              
863             =cut
864              
865             sub getrow_arrayref
866             {
867 2     2   2380 my ( $callbacks, $dbh, $sth, @bind_values ) = &callbacks;
868              
869 2 50       69 if ( !ref($sth) ) {
870 2         4 my $attr;
871 2 50 33     14 $attr = shift(@bind_values)
872             if ref( $bind_values[0] ) && ref( $bind_values[0] ) eq 'HASH';
873 2         9 $sth = $dbh->prepare( $sth, $attr );
874 2 50       15 return if $sth->err;
875             }
876              
877 2         8 $sth->execute(@bind_values);
878 2 50       17 return if $sth->err;
879              
880 2         11 return $sth->getrow_arrayref($callbacks);
881             }
882              
883             =head2 getrow_hashref I<(database handles)>
884              
885             $result = $dbh->getrow_hashref($statement_string, @bind_values);
886             $result = $dbh->getrow_hashref($statement_string, \%attr, @bind_values);
887             $result = $dbh->getrow_hashref($statement_handle, @bind_values);
888              
889             Prepares (if necessary) and executes a single statement with the specified data
890             bindings and fetches the first row as a hash reference.
891              
892             The C method accepts optional callbacks for further processing
893             of the result by the caller.
894              
895             =cut
896              
897             sub getrow_hashref
898             {
899 2     2   1717 my ( $callbacks, $dbh, $sth, @bind_values ) = &callbacks;
900              
901 2 50       52 if ( !ref($sth) ) {
902 2         4 my $attr;
903 2 50 33     15 $attr = shift(@bind_values)
904             if ref( $bind_values[0] ) && ref( $bind_values[0] ) eq 'HASH';
905 2         8 $sth = $dbh->prepare( $sth, $attr );
906 2 50       12 return if $sth->err;
907             }
908              
909 2         8 $sth->execute(@bind_values);
910 2 50       18 return if $sth->err;
911              
912 2         8 return $sth->getrow_hashref($callbacks);
913             }
914              
915             =head2 getrow I<(database handles)>
916              
917             $result = $dbh->getrow($statement_string, @bind_values);
918             $result = $dbh->getrow($statement_string, \%attr, @bind_values);
919             $result = $dbh->getrow($statement_handle, @bind_values);
920              
921             Alias for C.
922              
923             If array references are preferred, have the symbol table glob point alias the
924             C method.
925              
926             The C method accepts optional callbacks for further processing
927             of the result by the caller.
928              
929             =cut
930              
931 4     4   196 BEGIN { *getrow = \&getrow_hashref }
932              
933             package # Hide from PAUSE
934             DBIx::FlexibleBinding::st;
935             our $VERSION = '2.0.2'; # VERSION
936              
937 4     4   20 use Carp 'confess';
  4         8  
  4         178  
938 4     4   3310 use List::MoreUtils 'any';
  4         45641  
  4         27  
939 4     4   2331 use Params::Callbacks 'callbacks';
  4         9  
  4         199  
940 4     4   20 use Scalar::Util 'reftype';
  4         6  
  4         164  
941 4     4   18 use namespace::clean;
  4         7  
  4         27  
942              
943             our @ISA = 'DBI::st';
944              
945             sub _init_private_attributes
946             {
947 15925     15925   39185 my ( $sth, $params_arrayref ) = @_;
948              
949 15925 50 33     169603 if ( ref($params_arrayref) && reftype($params_arrayref) eq 'ARRAY' ) {
950 15925         74654 $sth->_param_order($params_arrayref);
951 15925 100       72173 return $sth->_using_positional(1) unless @$params_arrayref;
952              
953 14118         65071 $sth->_auto_bind($DBIx::FlexibleBinding::AUTO_BINDING_ENABLED);
954              
955 14118         56778 my $param_count = $sth->_param_count;
956 14118         61550 for my $param (@$params_arrayref) {
957 366540 50       865418 if ( defined $param_count->{$param} ) {
958 0         0 $param_count->{$param}++;
959             }
960             else {
961 366540         947587 $param_count->{$param} = 1;
962             }
963             }
964              
965 14118 100   102226   148031 return $sth->_using_named(1) if any {/\D/} @$params_arrayref;
  102226         271134  
966 3532         26356 return $sth->_using_numbered(1);
967             }
968              
969 0         0 return $sth;
970             }
971              
972             sub _auto_bind
973             {
974 30040 100   30040   98096 if ( @_ > 1 ) {
975 14118         108138 $_[0]{private_dbix_flexbind}{auto_bind} = !!$_[1];
976 14118         43269 return $_[0];
977             }
978              
979 15922         125029 return $_[0]{private_dbix_flexbind}{auto_bind};
980             }
981              
982             sub _param_count
983             {
984 380658 50   380658   906225 if ( @_ > 1 ) {
985 0         0 $_[0]{private_dbix_flexbind}{param_count} = $_[1];
986 0         0 return $_[0];
987             }
988             else {
989             $_[0]{private_dbix_flexbind}{param_count} = {}
990 380658 100       2353187 unless exists $_[0]{private_dbix_flexbind}{param_count};
991             }
992              
993 380658 50       1288789 return %{ $_[0]{private_dbix_flexbind}{param_count} } if wantarray;
  0         0  
994 380658         1946123 return $_[0]{private_dbix_flexbind}{param_count};
995             }
996              
997             sub _param_order
998             {
999 382465 100   382465   942685 if ( @_ > 1 ) {
1000 15925         303497 $_[0]{private_dbix_flexbind}{param_order} = $_[1];
1001 15925         262352 return $_[0];
1002             }
1003             else {
1004             $_[0]{private_dbix_flexbind}{param_order} = []
1005 366540 50       2192187 unless exists $_[0]{private_dbix_flexbind}{param_order};
1006             }
1007              
1008 366540 50       1211410 return @{ $_[0]{private_dbix_flexbind}{param_order} } if wantarray;
  366540         3630683  
1009 0         0 return $_[0]{private_dbix_flexbind}{param_order};
1010             }
1011              
1012             sub _using_named
1013             {
1014 10586 50   10586   45956 if ( @_ > 1 ) {
1015             # If new value is true, set alternatives to false to save us the overhead
1016             # of making the other two calls that would have had to be made anyway.
1017             # Apologies for the terse code, these need to be zippy because they're
1018             # called a lot, and often in loops. +--(naughty assignment)
1019             # v
1020 10586 50       105795 if ( $_[0]{private_dbix_flexbind}{using_named} = !!$_[1] ) {
1021 10586         69670 $_[0]{private_dbix_flexbind}{using_numbered} = '';
1022 10586         69939 $_[0]{private_dbix_flexbind}{using_positional} = '';
1023             }
1024 10586         68734 return $_[0];
1025             }
1026              
1027 0         0 return $_[0]{private_dbix_flexbind}{using_named};
1028             }
1029              
1030             sub _using_numbered
1031             {
1032 14122 100   14122   49322 if ( @_ > 1 ) {
1033             # If new value is true, set alternatives to false to save us the overhead
1034             # of making the other two calls that would have had to be made anyway.
1035             # Apologies for the terse code, these need to be zippy because they're
1036             # called a lot, and often in loops. +--(naughty assignment)
1037             # v
1038 3532 50       37729 if ( $_[0]{private_dbix_flexbind}{using_numbered} = !!$_[1] ) {
1039 3532         23799 $_[0]{private_dbix_flexbind}{using_named} = '';
1040 3532         24373 $_[0]{private_dbix_flexbind}{using_positional} = '';
1041             }
1042 3532         22480 return $_[0];
1043             }
1044              
1045 10590         92264 return $_[0]{private_dbix_flexbind}{using_numbered};
1046             }
1047              
1048             sub _using_positional
1049             {
1050 382465 100   382465   1095239 if ( @_ > 1 ) {
1051             # If new value is true, set alternatives to false to save us the overhead
1052             # of making the other two calls that would have had to be made anyway.
1053             # Apologies for the terse code, these need to be zippy because they're
1054             # called a lot, and often in loops. +--(naughty assignment)
1055             # v
1056 1807 50       17469 if ( $_[0]{private_dbix_flexbind}{using_positional} = !!$_[1] ) {
1057 1807         12676 $_[0]{private_dbix_flexbind}{using_numbered} = '';
1058 1807         13247 $_[0]{private_dbix_flexbind}{using_named} = '';
1059             }
1060 1807         11689 return $_[0];
1061             }
1062              
1063 380658         2645163 return $_[0]{private_dbix_flexbind}{using_positional};
1064             }
1065              
1066             sub _bind_arrayref
1067             {
1068 3532     3532   8719 my ( $sth, $arrayref ) = @_;
1069              
1070 3532         16637 for ( my $n = 0; $n < @$arrayref; $n++ ) {
1071 91640         289618 $sth->bind_param( $n + 1, $arrayref->[$n] );
1072             }
1073              
1074 3532         10158 return $sth;
1075             }
1076              
1077             sub _bind_hashref
1078             {
1079 10586     10586   27780 my ( $sth, $hashref ) = @_;
1080              
1081 10586         70767 while ( my ( $k, $v ) = each %$hashref ) {
1082 274900         786977 $sth->bind_param( $k, $v );
1083             }
1084              
1085 10586         48836 return $sth;
1086             }
1087              
1088             sub _bind
1089             {
1090 14118     14118   81348 my ( $sth, @args ) = @_;
1091 14118 50       57468 return $sth unless @args;
1092 14118 50       59041 return $sth->_bind_arrayref( \@args ) if $sth->_using_positional;
1093              
1094 14118   66     110758 my $ref = ( @args == 1 ) && reftype( $args[0] );
1095              
1096 14118 100       44021 if ($ref) {
1097 8660 50 66     56231 unless ( $ref eq 'HASH' || $ref eq 'ARRAY' ) {
1098 0         0 return $sth->set_err( $DBI::stderr, 'Expected a reference to a HASH or ARRAY' );
1099             }
1100              
1101 8660 100       38768 return $sth->_bind_hashref( $args[0] ) if $ref eq 'HASH';
1102 5132 100       17894 return $sth->_bind_arrayref( $args[0] ) if $sth->_using_numbered;
1103 3528         11294 return $sth->_bind_hashref( { @{ $args[0] } } );
  3528         71212  
1104             }
1105             else {
1106 5458 50       20746 if (@args) {
1107 5458 100       19088 return $sth->_bind_arrayref( \@args ) if $sth->_using_numbered;
1108 3530         72289 return $sth->_bind_hashref( {@args} );
1109             }
1110             }
1111              
1112 0         0 return $sth;
1113             }
1114              
1115             =head1 STATEMENT HANDLE METHODS
1116              
1117             =head2 bind_param
1118              
1119             $sth->bind_param($param_num, $bind_value)
1120             $sth->bind_param($param_num, $bind_value, \%attr)
1121             $sth->bind_param($param_num, $bind_value, $bind_type)
1122              
1123             $sth->bind_param($param_name, $bind_value)
1124             $sth->bind_param($param_name, $bind_value, \%attr)
1125             $sth->bind_param($param_name, $bind_value, $bind_type)
1126              
1127             The C method associates (binds) a value to a placeholder embedded in the
1128             prepared statement. The implementation provided by this module allows the use of
1129             parameter names, if appropriate, in addition to parameter positions.
1130              
1131             I for a more detailed
1132             explanation of how to use this method>.
1133              
1134             =cut
1135              
1136             sub bind_param
1137             {
1138 366540     366540   790405 my ( $sth, $param, $value, $attr ) = @_;
1139              
1140 366540 50       976545 unless ( !!$param ) {
1141 0         0 return $sth->set_err( $DBI::stderr, "Binding identifier is missing" );
1142             }
1143              
1144 366540 50       1215220 if ( $param =~ /[^\@\w]/ ) {
1145 0         0 return $sth->set_err( $DBI::stderr,
1146             'Malformed binding identifier "' . $param . '"' );
1147             }
1148              
1149 366540         518182 my $bind_rv;
1150              
1151 366540 50       922918 if ( $sth->_using_positional ) {
1152 0         0 $bind_rv = $sth->next::method( $param, $value, $attr );
1153             }
1154             else {
1155 366540         600162 my $pos = 0;
1156 366540         522686 my $count = 0;
1157 366540         948013 my $param_count = $sth->_param_count;
1158              
1159 366540         1250857 for my $identifier ( $sth->_param_order ) {
1160 9528984         16432084 $pos++;
1161              
1162 9528984 100       22826480 if ( $identifier eq $param ) {
1163 366540         468013 $count++;
1164 366540 50       991688 last if $count > $param_count->{$param};
1165 366540         1390831 $bind_rv = $sth->next::method( $pos, $value, $attr );
1166             }
1167             }
1168             }
1169              
1170 366540         3076833 return $bind_rv;
1171             }
1172              
1173             =head2 execute
1174              
1175             $rv = $sth->execute() or die $DBI::errstr;
1176             $rv = $sth->execute(@bind_values) or die $DBI::errstr;
1177              
1178             Perform whatever processing is necessary to execute the prepared statement. An
1179             C is returned if an error occurs. A successful call returns true regardless
1180             of the number of rows affected, even if it's zero.
1181              
1182             Refer to L for a more detailed
1183             description of this method.
1184              
1185             B
1186              
1187             =over
1188              
1189             =item Use prepare, execute and getrow_hashref with a callback to modify my data:
1190              
1191             use strict;
1192             use warnings;
1193              
1194             use DBIx::FlexibleBinding -subs => [ 'TestDB' ];
1195             use Data::Dumper;
1196             use Test::More;
1197              
1198             $Data::Dumper::Terse = 1;
1199             $Data::Dumper::Indent = 1;
1200              
1201             TestDB 'dbi:mysql:test', '', '', { RaiseError => 1 };
1202              
1203             my $sth = TestDB->prepare(<< '//');
1204             SELECT solarSystemID AS id
1205             , solarSystemName AS name
1206             , security
1207             FROM mapsolarsystems
1208             WHERE solarSystemName RLIKE "^U[^0-9\-]+$"
1209             ORDER BY id, name, security DESC
1210             LIMIT 5
1211             //
1212              
1213             $sth->execute() or die $DBI::errstr;
1214              
1215             my @rows;
1216             my @callback_list = (
1217             callback {
1218             my ($row) = @_;
1219             $row->{filled_with} = ( $row->{security} >= 0.5 )
1220             ? 'Carebears' : 'Yarrbears';
1221             $row->{security} = sprintf('%.1f', $row->{security});
1222             return $row;
1223             }
1224             );
1225              
1226             while ( my $row = $sth->getrow_hashref(@callback_list) ) {
1227             push @rows, $row;
1228             }
1229              
1230             my $expected_result = [
1231             {
1232             'name' => 'Uplingur',
1233             'filled_with' => 'Yarrbears',
1234             'id' => '30000037',
1235             'security' => '0.4'
1236             },
1237             {
1238             'security' => '0.4',
1239             'id' => '30000040',
1240             'name' => 'Uzistoon',
1241             'filled_with' => 'Yarrbears'
1242             },
1243             {
1244             'name' => 'Usroh',
1245             'filled_with' => 'Carebears',
1246             'id' => '30000068',
1247             'security' => '0.6'
1248             },
1249             {
1250             'filled_with' => 'Yarrbears',
1251             'name' => 'Uhtafal',
1252             'id' => '30000101',
1253             'security' => '0.5'
1254             },
1255             {
1256             'security' => '0.3',
1257             'id' => '30000114',
1258             'name' => 'Ubtes',
1259             'filled_with' => 'Yarrbears'
1260             }
1261             ];
1262              
1263             is_deeply( \@rows, $expected_result, 'iterate' )
1264             and diag( Dumper(\@rows) );
1265             done_testing();
1266              
1267             =back
1268              
1269             =cut
1270              
1271             sub execute
1272             {
1273 15922     15922   93779 my ( $sth, @bind_values ) = @_;
1274 15922         27601 my $rows;
1275              
1276 15922 100       46389 if ( $sth->_auto_bind ) {
1277 14118         57964 $sth->_bind(@bind_values);
1278 14118         97246 $rows = $sth->next::method();
1279             }
1280             else {
1281 1804 100 66     16117 if ( @bind_values == 1
      66        
1282             && ref( $bind_values[0] )
1283             && reftype( $bind_values[0] ) eq 'ARRAY' )
1284             {
1285 882         1927 $rows = $sth->next::method( @{ $bind_values[0] } );
  882         6729  
1286             }
1287             else {
1288 922         4822 $rows = $sth->next::method(@bind_values);
1289             }
1290             }
1291              
1292 15922         217308937 return $rows;
1293             }
1294              
1295             =head2 iterate
1296              
1297             $iterator = $sth->iterate() or die $DBI::errstr;
1298             $iterator = $sth->iterate(@bind_values) or die $DBI::errstr;
1299              
1300             Perform whatever processing is necessary to execute the prepared statement. An
1301             C is returned if an error occurs. A successful call returns an iterator
1302             which can be used to traverse the result set.
1303              
1304             B
1305              
1306             =over
1307              
1308             =item 1. Using an iterator and callbacks to process the result set:
1309              
1310             use strict;
1311             use warnings;
1312              
1313             use DBIx::FlexibleBinding -subs => [ 'TestDB' ];
1314             use Data::Dumper;
1315             use Test::More;
1316              
1317             $Data::Dumper::Terse = 1;
1318             $Data::Dumper::Indent = 1;
1319              
1320             my @drivers = grep { /^SQLite$/ } DBI->available_drivers();
1321              
1322             SKIP: {
1323             skip("iterate tests (No DBD::SQLite installed)", 1) unless @drivers;
1324              
1325             TestDB "dbi:SQLite:test.db", '', '', { RaiseError => 1 };
1326              
1327             my $sth = TestDB->prepare(<< '//');
1328             SELECT solarSystemID AS id
1329             , solarSystemName AS name
1330             , security
1331             FROM mapsolarsystems
1332             WHERE solarSystemName REGEXP "^U[^0-9\-]+$"
1333             ORDER BY id, name, security DESC
1334             LIMIT 5
1335             //
1336              
1337             # Iterate over the result set
1338             # ---------------------------
1339             # We also queue up a sneaky callback to modify each row of data as it
1340             # is fetched from the result set.
1341              
1342             my $it = $sth->iterate( callback {
1343             my ($row) = @_;
1344             $row->{filled_with} = ( $row->{security} >= 0.5 )
1345             ? 'Carebears' : 'Yarrbears';
1346             $row->{security} = sprintf('%.1f', $row->{security});
1347             return $row;
1348             } );
1349              
1350             my @rows;
1351             while ( my $row = $it->() ) {
1352             push @rows, $row;
1353             }
1354              
1355             # Done, now check the results ...
1356              
1357             my $expected_result = [
1358             {
1359             'name' => 'Uplingur',
1360             'filled_with' => 'Yarrbears',
1361             'id' => '30000037',
1362             'security' => '0.4'
1363             },
1364             {
1365             'security' => '0.4',
1366             'id' => '30000040',
1367             'name' => 'Uzistoon',
1368             'filled_with' => 'Yarrbears'
1369             },
1370             {
1371             'name' => 'Usroh',
1372             'filled_with' => 'Carebears',
1373             'id' => '30000068',
1374             'security' => '0.6'
1375             },
1376             {
1377             'filled_with' => 'Yarrbears',
1378             'name' => 'Uhtafal',
1379             'id' => '30000101',
1380             'security' => '0.5'
1381             },
1382             {
1383             'security' => '0.3',
1384             'id' => '30000114',
1385             'name' => 'Ubtes',
1386             'filled_with' => 'Yarrbears'
1387             }
1388             ];
1389              
1390             is_deeply( \@rows, $expected_result, 'iterate' )
1391             and diag( Dumper(\@rows) );
1392             }
1393              
1394             done_testing();
1395              
1396             In this example, we're traversing the result set using an iterator. As we iterate
1397             through the result set, a callback is applied to each row and we're left with
1398             an array of transformed rows.
1399              
1400             =item 2. Using an iterator's C method and callbacks to process the
1401             result set:
1402              
1403             use strict;
1404             use warnings;
1405              
1406             use DBIx::FlexibleBinding -subs => [ 'TestDB' ];
1407             use Data::Dumper;
1408             use Test::More;
1409              
1410             $Data::Dumper::Terse = 1;
1411             $Data::Dumper::Indent = 1;
1412              
1413             my @drivers = grep { /^SQLite$/ } DBI->available_drivers();
1414              
1415             SKIP: {
1416             skip("iterate tests (No DBD::SQLite installed)", 1) unless @drivers;
1417              
1418             TestDB "dbi:SQLite:test.db", '', '', { RaiseError => 1 };
1419              
1420             my $sth = TestDB->prepare(<< '//');
1421             SELECT solarSystemID AS id
1422             , solarSystemName AS name
1423             , security
1424             FROM mapsolarsystems
1425             WHERE solarSystemName REGEXP "^U[^0-9\-]+$"
1426             ORDER BY id, name, security DESC
1427             LIMIT 5
1428             //
1429              
1430             # Iterate over the result set
1431             # ---------------------------
1432             # This time around we call the iterator's "for_each" method to process
1433             # the data. Bonus: we haven't had to store the iterator anywhere or
1434             # pre-declare an empty array to accommodate our rows.
1435              
1436             my @rows = $sth->iterate->for_each( callback {
1437             my ($row) = @_;
1438             $row->{filled_with} = ( $row->{security} >= 0.5 )
1439             ? 'Carebears' : 'Yarrbears';
1440             $row->{security} = sprintf('%.1f', $row->{security});
1441             return $row;
1442             } );
1443              
1444             # Done, now check the results ...
1445              
1446             my $expected_result = [
1447             {
1448             'name' => 'Uplingur',
1449             'filled_with' => 'Yarrbears',
1450             'id' => '30000037',
1451             'security' => '0.4'
1452             },
1453             {
1454             'security' => '0.4',
1455             'id' => '30000040',
1456             'name' => 'Uzistoon',
1457             'filled_with' => 'Yarrbears'
1458             },
1459             {
1460             'name' => 'Usroh',
1461             'filled_with' => 'Carebears',
1462             'id' => '30000068',
1463             'security' => '0.6'
1464             },
1465             {
1466             'filled_with' => 'Yarrbears',
1467             'name' => 'Uhtafal',
1468             'id' => '30000101',
1469             'security' => '0.5'
1470             },
1471             {
1472             'security' => '0.3',
1473             'id' => '30000114',
1474             'name' => 'Ubtes',
1475             'filled_with' => 'Yarrbears'
1476             }
1477             ];
1478              
1479             is_deeply( \@rows, $expected_result, 'iterate' )
1480             and diag( Dumper(\@rows) );
1481             }
1482              
1483             done_testing();
1484              
1485             Like the previous example, we're traversing the result set using an iterator but
1486             this time around we have done away with C<$it> in favour of calling the iterator's
1487             own C method. The callback we were using to process each row of the
1488             result set has now been passed into the C method also eliminating a
1489             C loop and an empty declaration for C<@rows>.
1490              
1491             =back
1492              
1493             =cut
1494              
1495             sub iterate
1496             {
1497 2     2   34 my ( $callbacks, $sth, @bind_values ) = &callbacks;
1498 2         77 my $rows = $sth->execute(@bind_values);
1499 2 50       10 return $rows unless defined $rows;
1500 2     12   21 DBIx::FlexibleBinding::Iterator->new( sub { $sth->getrow($callbacks) } );
  12         166  
1501             }
1502              
1503             =head2 getrows_arrayref I<(database handles)>
1504              
1505             $results = $sth->getrows_arrayref();
1506             @results = $sth->getrows_arrayref();
1507              
1508             Fetches the entire result set as an array of array references.
1509              
1510             The C method accepts optional callbacks for further processing
1511             of the results by the caller.
1512              
1513             =cut
1514              
1515             sub getrows_arrayref
1516             {
1517 26     26   93 local $_;
1518 26         178 my ( $callbacks, $sth ) = &callbacks;
1519 26         26671 my $result = $sth->fetchall_arrayref();
1520              
1521 26 50       2896 if ($result) {
1522 26 50       145 unless ( $sth->err ) {
1523 26 50       93 if (@$callbacks) {
1524 26         70 $result = [ map { $callbacks->transform($_) } @$result ];
  180         4691  
1525             }
1526             }
1527             }
1528              
1529 26 50       719 return $result unless defined $result;
1530 26 50       400 return wantarray ? @$result : $result;
1531             }
1532              
1533             =head2 getrows_hashref I<(database handles)>
1534              
1535             $results = $sth->getrows_hashref();
1536             @results = $sth->getrows_hashref();
1537              
1538             Fetches the entire result set as an array of hash references.
1539              
1540             The C method accepts optional callbacks for further processing
1541             of the results by the caller.
1542              
1543             =cut
1544              
1545             sub getrows_hashref
1546             {
1547 6     6   59 local $_;
1548 6         54 my ( $callbacks, $sth ) = &callbacks;
1549 6         203 my $result = $sth->fetchall_arrayref( {} );
1550              
1551 6 50       3255 if ($result) {
1552 6 50       37 unless ( $sth->err ) {
1553 6 100       27 if (@$callbacks) {
1554 4         11 $result = [ map { $callbacks->transform($_) } @$result ];
  4         22  
1555             }
1556             }
1557             }
1558              
1559 6 50       95 return $result unless defined $result;
1560 6 50       64 return wantarray ? @$result : $result;
1561             }
1562              
1563             =head2 getrows I<(database handles)>
1564              
1565             $results = $sth->getrows();
1566             @results = $sth->getrows();
1567              
1568             Alias for C.
1569              
1570             If array references are preferred, have the symbol table glob point alias the
1571             C method.
1572              
1573             The C method accepts optional callbacks for further processing
1574             of the results by the caller.
1575              
1576             =cut
1577              
1578 4     4   8067 BEGIN { *getrows = \&getrows_hashref }
1579              
1580             =head2 getrow_arrayref I<(database handles)>
1581              
1582             $result = $sth->getrow_arrayref();
1583              
1584             Fetches the next row as an array reference. Returns C if there are no more
1585             rows available.
1586              
1587             The C method accepts optional callbacks for further processing
1588             of the result by the caller.
1589              
1590             =cut
1591              
1592             sub getrow_arrayref
1593             {
1594 4     4   70 local $_;
1595 4         19 my ( $callbacks, $sth ) = &callbacks;
1596 4         173 my $result = $sth->fetchrow_arrayref();
1597              
1598 4 50       102 if ($result) {
1599 4 50       26 unless ( $sth->err ) {
1600 4         11 $result = [@$result];
1601              
1602 4 50       20 if (@$callbacks) {
1603 4         19 $result = $callbacks->smart_transform( $_ = $result );
1604             }
1605             }
1606             }
1607              
1608 4         130 return $result;
1609             }
1610              
1611             =head2 getrow_hashref I<(database handles)>
1612              
1613             $result = $sth->getrow_hashref();
1614              
1615             Fetches the next row as a hash reference. Returns C if there are no more
1616             rows available.
1617              
1618             The C method accepts optional callbacks for further processing
1619             of the result by the caller.
1620              
1621             =cut
1622              
1623             sub getrow_hashref
1624             {
1625 22     22   110 local $_;
1626 22         99 my ( $callbacks, $sth ) = &callbacks;
1627 22         749 my $result = $sth->fetchrow_hashref();
1628              
1629 22 100       1700 if ($result) {
1630 19 50       111 unless ( $sth->err ) {
1631 19 100       59 if (@$callbacks) {
1632 14         46 $result = $callbacks->smart_transform( $_ = $result );
1633             }
1634             }
1635             }
1636              
1637 22         478 return $result;
1638             }
1639              
1640             =head2 getrow I<(database handles)>
1641              
1642             $result = $sth->getrow();
1643              
1644             Alias for C.
1645              
1646             If array references are preferred, have the symbol table glob point alias the
1647             C method.
1648              
1649             The C method accepts optional callbacks for further processing
1650             of the result by the caller.
1651              
1652             =cut
1653              
1654 4     4   202 BEGIN { *getrow = \&getrow_hashref }
1655              
1656             package # Hide from PAUSE
1657             DBIx::FlexibleBinding::ObjectProxy;
1658             our $VERSION = '2.0.2'; # VERSION
1659              
1660 4     4   29 use Carp 'confess';
  4         6  
  4         197  
1661 4     4   18 use Scalar::Util 'blessed';
  4         8  
  4         151  
1662 4     4   12223 use Sub::Install ();
  4         7446  
  4         87  
1663 4     4   27 use namespace::clean;
  4         6  
  4         33  
1664              
1665             our $AUTOLOAD;
1666              
1667             my %proxies;
1668              
1669             sub create
1670             {
1671 5     5   13 my ( $class, $name, $caller ) = @_;
1672 5   33     25 $class = ref($class) || $class;
1673             Sub::Install::install_sub(
1674 16     16   187018 { code => sub { $class->handle( $name, @_ ) },
1675 5         35 into => $caller,
1676             as => $name
1677             }
1678             );
1679 5         249 return $class->get($name);
1680             }
1681              
1682             sub handle
1683             {
1684 16     16   47 my ( $self, $name, @args ) = &get;
1685              
1686 16 100       58 if (@args) {
1687 9 50 66     117 if ( @args == 1 && !defined( $args[0] ) ) {
    100 66        
    100          
1688 0         0 $self->assign_nothing();
1689             }
1690             elsif ( @args == 1 && blessed( $args[0] ) ) {
1691 2 50       30 if ( $args[0]->isa('DBI::db') ) {
    50          
1692 0         0 $self->assign_database_connection(@args);
1693             }
1694             elsif ( $args[0]->isa('DBI::st') ) {
1695 2         23 $self->assign_statement(@args);
1696             }
1697             else {
1698 0         0 confess "A database or statement handle was expected";
1699             }
1700             }
1701             elsif ( $args[0] =~ /^dbi:/i ) {
1702 5         45 $self->assign_database_connection(@args);
1703             }
1704             else {
1705 2         11 return $self->process(@args);
1706             }
1707             }
1708              
1709 14         109 return $self->{target};
1710             }
1711              
1712             sub get
1713             {
1714 21     21   62 my ( $class, $name, @args ) = @_;
1715 21   33     154 $class = ref($class) || $class;
1716 21         51 my $self = $proxies{$name};
1717              
1718 21 100       57 unless ( defined $self ) {
1719 5         15 $self = bless( { name => $name }, $class );
1720 5         13 $proxies{$name} = $self->assign_nothing();
1721             }
1722              
1723 21         95 return ( $self, $name, @args );
1724             }
1725              
1726             sub assign_nothing
1727             {
1728 5     5   9 my ($self) = @_;
1729 5 50       29 delete $self->{target} if exists $self->{target};
1730 5         16 return bless( $self, 'DBIx::FlexibleBinding::UnassignedProxy' );
1731             }
1732              
1733             sub assign_database_connection
1734             {
1735 5     5   14 my ( $self, @args ) = @_;
1736              
1737 5 50 33     29 if ( @args == 1 && blessed( $args[0] ) ) {
1738 0 0       0 confess "Expected a database handle" unless $args[0]->isa('DBI::db');
1739 0         0 $self->{target} = $args[0];
1740             bless $self->{target}, 'DBIx::FlexibleBinding::db'
1741 0 0       0 unless $self->{target}->isa('DBIx::FlexibleBinding::db');
1742             }
1743             else {
1744 5 50       24 confess "Expected a set of database connection parameters"
1745             unless $args[0] =~ /^dbi:/i;
1746 5         39 $self->{target} = DBIx::FlexibleBinding->connect(@args);
1747             }
1748              
1749 5         297302 return bless( $self, 'DBIx::FlexibleBinding::DatabaseConnectionProxy' );
1750             }
1751              
1752             sub assign_statement
1753             {
1754 2     2   5 my ( $self, @args ) = @_;
1755              
1756 2 50       12 confess "Expected a statement handle" unless $args[0]->isa('DBI::st');
1757 2         5 $self->{target} = $args[0];
1758             bless $self->{target}, 'DBIx::FlexibleBinding::st'
1759 2 50       21 unless $self->{target}->isa('DBIx::FlexibleBinding::st');
1760 2         231 return bless( $self, 'DBIx::FlexibleBinding::StatementProxy' );
1761             }
1762              
1763             sub AUTOLOAD
1764             {
1765 0     0   0 my ( $self, @args ) = @_;
1766 0         0 ( my $method = $AUTOLOAD ) =~ s/.*:://;
1767 0 0       0 unless ( defined &$AUTOLOAD ) {
1768 4     4   3932 no strict 'refs'; ## no critic [TestingAndDebugging::ProhibitNoStrict]
  4         9  
  4         975  
1769 0 0       0 my $endpoint = $self->{target}->can($method) or confess "Invalid method '$method'";
1770             *$AUTOLOAD = sub {
1771 0     0   0 my ( $object, @args ) = @_;
1772 0         0 $object->{target}->$method(@args);
1773 0         0 };
1774             }
1775 0         0 goto &$AUTOLOAD;
1776             }
1777              
1778             package # Hide from PAUSE
1779             DBIx::FlexibleBinding::UnassignedProxy;
1780             our $VERSION = '2.0.2'; # VERSION
1781              
1782             our @ISA = 'DBIx::FlexibleBinding::ObjectProxy';
1783              
1784             package # Hide from PAUSE
1785             DBIx::FlexibleBinding::DatabaseConnectionProxy;
1786             our $VERSION = '2.0.2'; # VERSION
1787              
1788 4     4   25 use Carp 'confess';
  4         8  
  4         371  
1789              
1790             our @ISA = 'DBIx::FlexibleBinding::ObjectProxy';
1791              
1792             package # Hide from PAUSE
1793             DBIx::FlexibleBinding::StatementProxy;
1794             our $VERSION = '2.0.2'; # VERSION
1795              
1796 4     4   20 use Carp 'confess';
  4         10  
  4         875  
1797              
1798             our @ISA = 'DBIx::FlexibleBinding::ObjectProxy';
1799              
1800             sub process
1801             {
1802 2     2   6 my ( $self, @args ) = @_;
1803              
1804 2 50       19 if ( $self->{target}->isa('DBIx::FlexibleBinding::st') ) {
1805 2 50       19 if ( $self->{target}->{NUM_OF_PARAMS} ) {
1806 2         9 $self->{target}->execute(@args);
1807             }
1808             else {
1809 0         0 $self->{target}->execute();
1810             }
1811             }
1812              
1813 2         19 return $self->{target}->getrows(@args);
1814             }
1815              
1816             package # Hide from PAUSE
1817             DBIx::FlexibleBinding::Iterator;
1818             our $VERSION = '2.0.2'; # VERSION
1819              
1820 4     4   27 use Carp 'confess';
  4         13  
  4         238  
1821 4     4   26 use Params::Callbacks 'callbacks';
  4         18  
  4         239  
1822 4     4   22 use Scalar::Util 'reftype';
  4         6  
  4         193  
1823 4     4   22 use namespace::clean;
  4         6  
  4         22  
1824              
1825             sub new
1826             {
1827 2     2   5 my ( $class, $coderef ) = @_;
1828 2 50 33     30 confess "Expected a code reference"
1829             unless ref($coderef) && reftype($coderef) eq 'CODE';
1830 2   33     18 $class = ref($class) || $class;
1831 2         17 bless $coderef, $class;
1832             }
1833              
1834             sub for_each
1835             {
1836 1     1   11 local $_;
1837 1         10 my ( $callbacks, $self ) = &callbacks;
1838 1         69 my @results;
1839              
1840 1         5 while ( my @items = $self->() ) {
1841 6 100 66     26 last if @items == 1 && !defined( $items[0] );
1842 5         9 push @results, map { $callbacks->transform($_) } @items;
  5         14  
1843             }
1844              
1845 1         17 return @results;
1846             }
1847              
1848             1;
1849              
1850             =head1 EXPORTS
1851              
1852             The following symbols are exported by default:
1853              
1854             =head2 callback
1855              
1856             To enable the namespace using this module to take advantage of the callbacks,
1857             which are one of its main features, without the unnecessary burden of also
1858             including the module that provides the feature I<(see L for
1859             more detailed information)>.
1860              
1861             =cut
1862              
1863             =pod
1864              
1865             =head1 SEE ALSO
1866              
1867             =over 2
1868              
1869             =item * L
1870              
1871             =item * L
1872              
1873             =back
1874              
1875             =head1 REPOSITORY
1876              
1877             =over 2
1878              
1879             =item * L
1880              
1881             =item * L
1882              
1883             =back
1884              
1885             =head1 BUGS
1886              
1887             Please report any bugs or feature requests to C, or through
1888             the web interface at L. I will be notified, and then you'll
1889             automatically be notified of progress on your bug as I make changes.
1890              
1891             =head1 SUPPORT
1892              
1893             You can find documentation for this module with the perldoc command.
1894              
1895             perldoc DBIx::FlexibleBinding
1896              
1897              
1898             You can also look for information at:
1899              
1900             =over 4
1901              
1902             =item * RT: CPAN's request tracker (report bugs here)
1903              
1904             L
1905              
1906             =item * AnnoCPAN: Annotated CPAN documentation
1907              
1908             L
1909              
1910             =item * CPAN Ratings
1911              
1912             L
1913              
1914             =item * Search CPAN
1915              
1916             L
1917              
1918             =back
1919              
1920             =head1 ACKNOWLEDGEMENTS
1921              
1922             Many, many thanks to the CPANTesters network.
1923              
1924             Test data set extracted from Fuzzwork's MySQL conversion of CCP's EVE Online Static
1925             Data Export:
1926              
1927             =over 2
1928              
1929             =item * Fuzzwork L
1930              
1931             =item * EVE Online L
1932              
1933             =back
1934              
1935             Eternal gratitude to GitHub contributors:
1936              
1937             =over 2
1938              
1939             =item * Syohei Yoshida L
1940              
1941             =back
1942              
1943             =head1 AUTHOR
1944              
1945             Iain Campbell
1946              
1947             =head1 COPYRIGHT AND LICENSE
1948              
1949             This software is copyright (c) 2012-2015 by Iain Campbell.
1950              
1951             This is free software; you can redistribute it and/or modify it under
1952             the same terms as the Perl 5 programming language system itself.
1953              
1954             =cut