File Coverage

blib/lib/POE/Component/EasyDBI/SubProcess.pm
Criterion Covered Total %
statement 21 685 3.0
branch 0 394 0.0
condition 0 108 0.0
subroutine 7 60 11.6
pod 0 21 0.0
total 28 1268 2.2


line stmt bran cond sub pod time code
1             package POE::Component::EasyDBI::SubProcess;
2              
3 2     2   8 use strict;
  2         4  
  2         82  
4 2     2   9 use warnings FATAL => 'all';
  2         3  
  2         119  
5              
6             # Initialize our version
7             our $VERSION = '1.28';
8              
9 2     2   881 use Try::Tiny qw( try catch );
  2         2053  
  2         111  
10              
11             # We pass in data to POE::Filter::Reference
12 2     2   11 use POE::Filter::Reference;
  2         2  
  2         31  
13              
14             # We run the actual DB connection here
15 2     2   8 use DBI;
  2         2  
  2         3308  
16              
17             sub new {
18 0     0 0   my ($class, $opts) = @_;
19 0           my $obj = bless($opts, $class);
20 0           $obj->{queue} = [];
21 0   0       $obj->{ping_timeout} = $obj->{ping_timeout} || 0;
22 0           return $obj;
23             }
24              
25             # This is the subroutine that will get executed upon the fork() call by our parent
26             sub main {
27 0 0   0 0   if ( $^O eq 'MSWin32' ) {
28 0           binmode(STDIN); binmode(STDOUT);
  0            
29             }
30             # Autoflush to avoid weirdness
31             #select((select(STDOUT), $| = 1)[0]);
32 0           select(STDOUT); $|++;
  0            
33 0           select(STDERR); $|++;
  0            
34              
35 0           $SIG{__WARN__} = 'DEFAULT';
36 0           $SIG{__DIE__} = 'DEFAULT';
37              
38 0           my $self;
39             # check for alternate fork
40 0 0         if ($_[0] == 1) {
41             # we need to read in the first
42 0           my $filter = POE::Filter::Reference->new();
43 0           my $opts;
44             # get our first option hashref
45 0           while ( sysread( STDIN, my $buffer = '', 1024 ) ) {
46 0           $opts = $filter->get( [ $buffer ] );
47 0 0         last if (defined $opts);
48             }
49 0           $self = __PACKAGE__->new(splice(@{$opts},0,1));
  0            
50 0           $self->{filter} = $filter;
51 0 0         if (@{$opts}) {
  0            
52 0           push(@{$self->{queue}},@{$opts});
  0            
  0            
53             }
54 0           undef $filter;
55             } else {
56 0           $self = __PACKAGE__->new(shift);
57 0           $self->{filter} = POE::Filter::Reference->new();
58             }
59            
60 0           $self->{0} = $0 = "$0 ".__PACKAGE__;
61            
62 0           $self->{lastpingtime} = time();
63              
64 0 0         unless (defined($self->{sig_ignore_off})) {
65 0           $SIG{INT} = $SIG{TERM} = $SIG{HUP} = 'IGNORE';
66             }
67              
68             # if (defined($self->{use_cancel})) {
69             # Signal INT causes query cancel
70             # XXX disabled for now
71             #$SIG{INT} = sub { if ($sth) { $sth->cancel; } };
72             # }
73              
74 0           while (!$self->connect()) { }
75            
76 0           $self->pt("connected at ".localtime());
77              
78 0 0         return if ($self->{done});
79              
80             # check for data in queue first
81 0           $self->process();
82              
83 0 0         if ($self->{done}) {
84 0           $self->pt("disconnected at ".localtime());
85 0 0         if ($self->{dbh}) {
86 0           $self->{dbh}->disconnect();
87             }
88 0           return;
89             }
90              
91             # listen for commands from our parent
92 0           READ: while ( sysread( STDIN, my $buffer = '', 1024 ) ) {
93             # Feed the line into the filter
94             # and put the data in the queue
95 0           my $d = $self->{filter}->get( [ $buffer ] );
96 0 0         push(@{$self->{queue}},@$d) if ($d);
  0            
97            
98             # INPUT STRUCTURE IS:
99             # $d->{action} = SCALAR -> WHAT WE SHOULD DO
100             # $d->{sql} = SCALAR -> THE ACTUAL SQL
101             # $d->{placeholders} = ARRAY -> PLACEHOLDERS WE WILL USE
102             # $d->{id} = SCALAR -> THE QUERY ID ( FOR PARENT TO KEEP TRACK OF WHAT IS WHAT )
103             # $d->{primary_key} = SCALAR -> PRIMARY KEY FOR A HASH OF HASHES
104             # $d->{last_insert_id} = SCALAR|HASH -> HASH REF OF TABLE AND FIELD OR SCALAR OF A QUERY TO RUN AFTER
105             # and others..
106              
107             # process all in the queue until a problem occurs or done
108             REDO:
109 0 0         unless ($self->process()) {
110 0 0         last READ if ($self->{done});
111             # oops problem...
112 0 0         if ($self->{reconnect}) {
113             # need to reconnect
114 0           delete $self->{reconnect};
115             # keep trying to connect
116 0           while (!$self->connect()) { }
117             # and bail when we are told
118 0 0         last READ if ($self->{done});
119 0           goto REDO;
120             }
121             }
122             }
123             # Arrived here due to error in sysread/etc
124 0 0         if ($self->{dbh}) {
125 0           $self->{dbh}->disconnect();
126 0           delete $self->{dbh};
127             }
128            
129             # debug
130             # require POE::API::Peek;
131             # my $p = POE::API::Peek->new();
132             # my @sessions = $p->session_list();
133             # require Data::Dumper;
134             # open(FH,">db.txt");
135             # print FH Data::Dumper->Dump([\@sessions]);
136             # close(FH);
137             }
138              
139             sub pt {
140 0     0 0   $0 = shift->{0}.' '.shift;
141             }
142              
143             sub connect {
144 0     0 0   my $self = shift;
145            
146 0           $self->{output} = undef;
147 0           $self->{error} = undef;
148              
149             # Actually make the connection
150             try {
151 0           $self->{dbh} = DBI->connect(
152             # The DSN we just set up
153 0           (map { $self->{$_} } qw( dsn username password )),
154              
155             # We set some configuration stuff here
156             {
157 0 0   0     ((ref($self->{options}) eq 'HASH') ? %{$self->{options}} : ()),
158            
159             # quiet!!
160             'PrintError' => 0,
161             'PrintWarn' => 0,
162              
163             # Automatically raise errors so we can catch them with try/catch
164             'RaiseError' => 1,
165              
166             # Disable the DBI tracing
167             'TraceLevel' => 0,
168             },
169             );
170              
171             # Check for undefined-ness
172 0 0         if (!defined($self->{dbh})) {
173 0           die "Error Connecting to Database: $DBI::errstr";
174             }
175             } catch {
176 0     0     $self->output( $self->make_error( 'DBI', shift ) );
177 0           };
178              
179             # Catch errors!
180 0 0 0       if ($self->{error} && $self->{no_connect_failures}) {
    0          
181 0 0         sleep($self->{reconnect_wait}) if ($self->{reconnect_wait});
182 0           return 0;
183             } elsif ($self->{error}) {
184             # QUIT
185 0           $self->{done} = 1;
186 0           return 1;
187             }
188              
189             # if ($self->{dsn} =~ m/SQLite/ && $self->{options}
190             # && ref($self->{options}) eq 'HASH' && $self->{options}->{AutoCommit}) {
191             # # TODO error checking
192             # $self->db_do({ sql => 'BEGIN', id => -1 });
193             # delete $self->{output};
194             # }
195            
196             # send connect notice
197 0           $self->output({ id => 'DBI-CONNECTED' });
198            
199 0           return 1;
200             }
201              
202             sub process {
203 0     0 0   my $self = shift;
204              
205 0 0         return 0 unless (@{$self->{queue}});
  0            
206            
207             # Process each data structure
208 0           foreach my $input (shift(@{$self->{queue}})) {
  0            
209 0           $input->{action} = lc($input->{action});
210            
211             # Now, we do the actual work depending on what kind of query it was
212 0 0         if ($input->{action} eq 'exit') {
213             # Disconnect!
214 0           $self->{done} = 1;
215 0           return 0;
216             }
217              
218 0           my $now = time();
219 0 0 0       my $needping = (($self->{ping_timeout} == 0 or $self->{ping_timeout} > 0)
220             and (($now - $self->{lastpingtime}) >= $self->{ping_timeout})) ? 1 : 0;
221            
222 0 0         if ($self->{dbh}) {
223             # Don't work:
224             # unless ($self->{dbh}->{Active}) {
225             # # put the query back on the stack
226             # unshift(@{$self->{queue}},$input);
227             # # and reconnect
228             # $self->{dbh}->disconnect();
229             # $self->{reconnect} = 1;
230             # return 0;
231             # }
232 0 0         if ($needping) {
233 0 0         if (eval{ $self->{dbh}->ping(); }) {
  0            
234 0           $self->pt("pinged at ".localtime());
235 0           $self->{lastpingtime} = $now;
236             } else {
237             # put the query back on the stack
238 0           unshift(@{$self->{queue}},$input);
  0            
239             # and reconnect
240 0           $self->{dbh}->disconnect();
241 0           $self->{reconnect} = 1;
242 0           return 0;
243             }
244             }
245             #} elsif (!$self->{dbh}) {
246             } else {
247             #die "Database gone? : $DBI::errstr";
248             # put the query back on the stack
249 0           unshift(@{$self->{queue}},$input);
  0            
250             # and reconnect
251 0           eval { $self->{dbh}->disconnect(); };
  0            
252 0           $self->{reconnect} = 1;
253 0           return 0;
254             }
255              
256 0 0 0       if (defined($self->{no_cache}) && !defined($input->{no_cache})) {
257 0           $input->{no_cache} = $self->{no_cache};
258             }
259              
260 0 0         if (defined($input->{sql})) {
261             # remove beginning whitespace
262 0           $input->{sql} =~ s/^\s*//;
263             }
264            
265 0 0         if ( $input->{action} =~ m/^(func|commit|rollback|begin_work)$/ ) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
266 0           $input->{method} = $input->{action};
267 0           $self->do_method( $input );
268             } elsif ( $input->{action} eq 'method') {
269             # Special command to do $dbh->$method->()
270 0           $self->do_method( $input );
271             } elsif ( $input->{action} eq 'insert' ) {
272             # Fire off the SQL and return success/failure + rows affected and insert id
273 0           $self->db_insert( $input );
274             } elsif ( $input->{action} eq 'do' ) {
275             # Fire off the SQL and return success/failure + rows affected
276 0           $self->db_do( $input );
277             } elsif ( $input->{action} eq 'single' ) {
278             # Return a single result
279 0           $self->db_single( $input );
280             } elsif ( $input->{action} eq 'quote' ) {
281 0           $self->db_quote( $input );
282             } elsif ( $input->{action} eq 'arrayhash' ) {
283             # Get many results, then return them all at the same time in a array of hashes
284 0           $self->db_arrayhash( $input );
285             } elsif ( $input->{action} eq 'hashhash' ) {
286             # Get many results, then return them all at the same time in a hash of hashes
287             # on a primary key of course. the columns are returned in the cols key
288 0           $self->db_hashhash( $input );
289             } elsif ( $input->{action} eq 'hasharray' ) {
290             # Get many results, then return them all at the same time in a hash of arrays
291             # on a primary key of course. the columns are returned in the cols key
292 0           $self->db_hasharray( $input );
293             } elsif ( $input->{action} eq 'array' ) {
294             # Get many results, then return them all at the same time in an array of comma seperated values
295 0           $self->db_array( $input );
296             } elsif ( $input->{action} eq 'arrayarray' ) {
297             # Get many results, then return them all at the same time in an array of arrays
298 0           $self->db_arrayarray( $input );
299             } elsif ( $input->{action} eq 'hash' ) {
300             # Get many results, then return them all at the same time in a hash keyed off the
301             # on a primary key
302 0           $self->db_hash( $input );
303             } elsif ( $input->{action} eq 'keyvalhash' ) {
304             # Get many results, then return them all at the same time in a hash with
305             # the first column being the key and the second being the value
306 0           $self->db_keyvalhash( $input );
307             } else {
308             # Unrecognized action!
309 0           $self->{output} = $self->make_error( $input->{id}, "Unknown action sent '$input->{id}'" );
310             }
311             # XXX another way?
312 0 0 0       if ($input->{id} eq 'DBI' || ($self->{output}->{error}
      0        
      0        
313             && ($self->{output}->{error} =~ m/no connection to the server/i
314             || $self->{output}->{error} =~ m/server has gone away/i
315             || $self->{output}->{error} =~ m/server closed the connection/i
316             || $self->{output}->{error} =~ m/connect failed/i))) {
317            
318 0           unshift(@{$self->{queue}},$input);
  0            
319 0           eval { $self->{dbh}->disconnect(); };
  0            
320 0           $self->{reconnect} = 1;
321 0           return 0;
322             }
323 0           $self->output;
324             }
325 0           return 1;
326             }
327              
328             sub commit {
329 0     0 0   my $self = shift;
330 0           my $id = shift->{id};
331             try {
332 0     0     $self->{dbh}->commit;
333             } catch {
334 0     0     $self->{output} = $self->make_error( $id, shift );
335 0           };
336 0 0         return ($self->{output}) ? 0 : 1;
337             }
338              
339             sub begin_work {
340 0     0 0   my $self = shift;
341 0           my $id = shift->{id};
342             try {
343 0     0     $self->{dbh}->begin_work;
344             } catch {
345 0     0     $self->{output} = $self->make_error( $id, shift );
346 0           };
347 0 0         return ($self->{output}) ? 0 : 1;
348             }
349              
350             # This subroutine makes a generic error structure
351             sub make_error {
352 0     0 0   my $self = shift;
353            
354             # Make the structure
355 0           my $data = { id => shift };
356              
357             # Get the error, and stringify it in case of Error::Simple objects
358 0           my $error = shift;
359              
360 0 0 0       if (ref($error) && ref($error) eq 'Error::Simple') {
361 0           $data->{error} = $error->text;
362             } else {
363 0           $data->{error} = $error;
364             }
365              
366 0 0 0       if ($data->{error} =~ m/has gone away/i || $data->{error} =~ m/lost connection/i) {
367 0           $data->{id} = 'DBI';
368             }
369              
370 0           $self->{error} = $data;
371              
372             # All done!
373 0           return $data;
374             }
375              
376             # This subroute is for supporting any type of $dbh->$method->() calls
377             sub do_method {
378             # Get the dbi handle
379 0     0 0   my $self = shift;
380              
381             # Get the input structure
382 0           my $data = shift;
383              
384             # The result
385 0           my $result = undef;
386            
387 0           my $method = $data->{method};
388 0           my $dbh = $self->{dbh};
389              
390             SWITCH: {
391            
392 0 0         if ($data->{begin_work}) {
  0            
393 0 0         $self->begin_work($data) or last SWITCH;
394             }
395              
396             # Catch any errors
397             try {
398 0 0 0 0     if ($data->{args} && ref($data->{args}) eq 'ARRAY') {
399 0           $result = $dbh->$method(@{$data->{args}});
  0            
400             } else {
401 0           $result = $dbh->$method();
402             }
403            
404             } catch {
405 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
406 0           };
407            
408             }
409            
410             # Check if we got any errors
411 0 0         if (!defined($self->{output})) {
412             # Make output include the results
413 0           $self->{output} = { result => $result, id => $data->{id} };
414             }
415            
416 0           return;
417             }
418              
419             # This subroutine does a DB QUOTE
420             sub db_quote {
421 0     0 0   my $self = shift;
422            
423             # Get the input structure
424 0           my $data = shift;
425              
426             # The result
427 0           my $quoted = undef;
428              
429             # Quote it!
430             try {
431 0     0     $quoted = $self->{dbh}->quote( $data->{sql} );
432             } catch {
433 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
434 0           };
435              
436             # Check for errors
437 0 0         if (!defined($self->{output})) {
438             # Make output include the results
439 0           $self->{output} = { result => $quoted, id => $data->{id} };
440             }
441 0           return;
442             }
443              
444             # This subroutine runs a 'SELECT ... LIMIT 1' style query on the db
445             sub db_single {
446             # Get the dbi handle
447 0     0 0   my $self = shift;
448              
449             # Get the input structure
450 0           my $data = shift;
451              
452             # Variables we use
453 0           my $sth = undef;
454 0           my $result = undef;
455              
456             # Check if this is a non-select statement
457             # if ( $data->{sql} !~ /^SELECT/i ) {
458             # $self->{output} = $self->make_error( $data->{id}, "SINGLE is for SELECT queries only! ( $data->{sql} )" );
459             # return;
460             # }
461              
462             SWITCH: {
463 0 0         if ($data->{begin_work}) {
  0            
464 0 0         $self->begin_work($data) or last SWITCH;
465             }
466            
467             # Catch any errors
468             try {
469             # Make a new statement handler and prepare the query
470 0 0   0     if ($data->{no_cache}) {
471 0           $sth = $self->{dbh}->prepare( $data->{sql} );
472             } else {
473             # We use the prepare_cached method in hopes of hitting a cached one...
474 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
475             }
476              
477             # Check for undef'ness
478 0 0         if (!defined($sth)) {
479 0           die 'Did not get a statement handler';
480             } else {
481             # Execute the query
482             try {
483 0           $sth->execute( @{ $data->{placeholders} } );
  0            
484             } catch {
485 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
486 0           };
487 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
488             }
489            
490             # Actually do the query!
491             try {
492             # There are warnings when joining a NULL field, which is undef
493 2     2   11 no warnings;
  2         3  
  2         5713  
494 0 0         if (exists($data->{separator})) {
495 0           $result = join($data->{separator},$sth->fetchrow_array());
496             } else {
497 0           $result = $sth->fetchrow_array();
498             }
499             } catch {
500 0           die $sth->errstr;
501 0           };
502            
503 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
504             } catch {
505 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
506 0           };
507             }
508              
509             # Check if we got any errors
510 0 0         if (!defined($self->{output})) {
511             # Make output include the results
512 0           $self->{output} = { result => $result, id => $data->{id} };
513             }
514              
515             # Finally, we clean up this statement handle
516 0 0         if (defined($sth)) {
517 0           $sth->finish();
518             }
519              
520 0           return;
521             }
522              
523             # This subroutine does an insert into the db
524             sub db_insert {
525             # Get the dbi handle
526 0     0 0   my $self = shift;
527              
528             # Get the input structure
529 0           my $data = shift;
530              
531 0   0       my $dsn = $self->{dsn} || '';
532              
533             # Variables we use
534 0           my $sth = undef;
535 0           my $rows = undef;
536              
537 0           my @queries;
538             my @placeholders;
539            
540             # XXX depricate hash for insert
541 0 0 0       if (defined($data->{hash}) && !defined($data->{insert})) {
542 0           $data->{insert} = delete $data->{hash};
543             }
544            
545 0 0 0       if (defined($data->{insert}) && ref($data->{insert}) eq 'HASH') {
546 0           $data->{insert} = [$data->{insert}];
547             }
548            
549             # Check if this is a non-insert statement
550 0 0 0       if (defined($data->{insert}) && ref($data->{insert}) eq 'ARRAY') {
    0 0        
551 0           delete $data->{placeholders};
552 0           delete $data->{sql};
553 0           foreach my $hash (@{$data->{insert}}) {
  0            
554             # sort so we always get a consistant list of fields in the errors and placeholders
555 0           my @fields = sort keys %{$hash};
  0            
556             # adjust the placeholders, they should know that placeholders passed in are irrelevant
557             # XXX subtypes when a hash value is a HASH or ARRAY?
558 0           push(@placeholders,[ map { $hash->{$_} } @fields ]);
  0            
559 0           push(@queries,"INSERT INTO $data->{table} ("
560 0           .join(',',@fields).") VALUES (".join(',',(map { '?' } @fields)).")");
561             }
562             } elsif (!defined($data->{sql}) || $data->{sql} !~ /^INSERT/i ) {
563 0           $self->{output} = $self->make_error( $data->{id}, "INSERT is for INSERTS only! ( $data->{sql} )" );
564 0           return;
565             } else {
566 0           push(@queries,$data->{sql});
567 0           push(@placeholders,$data->{placeholders});
568             }
569              
570 0           for my $i ( 0 .. $#queries ) {
571 0           $data->{sql} = $queries[$i];
572 0           $data->{placeholders} = $placeholders[$i];
573 0           my $do_last = 0;
574            
575 0 0 0       if ($data->{begin_work} && $i == 0) {
576 0 0         $self->begin_work($data) or last;
577             }
578            
579             # Catch any errors
580             try {
581             # Make a new statement handler and prepare the query
582 0 0   0     if ($data->{no_cache}) {
583 0           $sth = $self->{dbh}->prepare( $data->{sql} );
584             } else {
585             # We use the prepare_cached method in hopes of hitting a cached one...
586 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
587             }
588            
589             # Check for undef'ness
590 0 0         if (!defined($sth)) {
591 0           die 'Did not get a statement handler';
592             } else {
593             # Execute the query
594             try {
595 0           $rows += $sth->execute( @{ $data->{placeholders} } );
  0            
596             } catch {
597 0 0         if (defined($sth->errstr)) {
598 0           die $sth->errstr;
599             } else {
600 0           die "error when trying to execute bind of placeholders in insert: $_[0]";
601             }
602 0           };
603 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
604             }
605             } catch {
606 0     0     my $e = shift;
607 0           $self->{output} = $self->make_error( $data->{id}, "failed at query #$i : $e" );
608 0           $do_last = 1; # can't use last here
609 0           };
610 0 0         last if ($do_last);
611             }
612              
613 0 0 0       if ($data->{commit} && defined($rows) && !defined($self->{output})) {
      0        
614 0           $self->commit($data);
615             }
616              
617             # If rows is not undef, that means we were successful
618 0 0 0       if (defined($rows) && !defined($self->{output})) {
    0 0        
619             # Make the data structure
620 0           $self->{output} = { rows => $rows, result => $rows, id => $data->{id} };
621            
622 0 0         unless ($data->{last_insert_id}) {
623 0 0         if (defined($sth)) {
624 0           $sth->finish();
625             }
626 0           return;
627             }
628             # get the last insert id
629             try {
630 0     0     my $qry = '';
631 0 0         if (ref($data->{last_insert_id}) eq 'HASH') {
632 0           my $l = $data->{last_insert_id};
633             # checks for different database types
634 0 0         if ($dsn =~ m/dbi:pg/i) {
    0          
    0          
    0          
635 0           $qry = "SELECT $l->{field} FROM $l->{table} WHERE oid='".$sth->{'pg_oid_status'}."'";
636             } elsif ($dsn =~ m/dbi:mysql/i) {
637 0 0         if (defined($self->{dbh}->{'mysql_insertid'})) {
638 0           $self->{output}->{insert_id} = $self->{dbh}->{'mysql_insertid'};
639             } else {
640 0           $qry = 'SELECT LAST_INSERT_ID()';
641             }
642             } elsif ($dsn =~ m/dbi:oracle/i) {
643 0           $qry = "SELECT $l->{field} FROM $l->{table}";
644             } elsif ($dsn =~ /dbi:sqlite/i) {
645 0           $self->{output}->{insert_id} = $self->{dbh}->func('last_insert_rowid');
646             } else {
647 0           die "EasyDBI doesn't know how to handle a last_insert_id with your dbi, contact the author.";
648             }
649             } else {
650             # they are supplying thier own query
651 0           $qry = $data->{last_insert_id};
652             }
653              
654 0 0         if (defined($sth)) {
655 0           $sth->finish();
656             }
657              
658 0 0         if ($qry) {
659             try {
660 0           $self->{output}->{insert_id} = $self->{dbh}->selectrow_array($qry);
661             } catch {
662 0           die $sth->error;
663 0           };
664            
665 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
666             }
667             } catch {
668             # special case, insert was ok, but last_insert_id errored
669 0     0     $self->{output}->{error} = shift;
670 0           };
671             } elsif (!defined($rows) && !defined($self->{output})) {
672             # Internal error...
673 0           $self->{output} = $self->make_error( $data->{id}, 'Internal Error in db_do of EasyDBI Subprocess' );
674             #die 'Internal Error in db_do';
675             }
676              
677             # Finally, we clean up this statement handle
678 0 0         if (defined($sth)) {
679 0           $sth->finish();
680             }
681            
682 0           return;
683             }
684              
685             # This subroutine runs a 'DO' style query on the db
686             sub db_do {
687             # Get the dbi handle
688 0     0 0   my $self = shift;
689              
690             # Get the input structure
691 0           my $data = shift;
692              
693             # Variables we use
694 0           my $sth = undef;
695 0           my $rows = undef;
696              
697             # Check if this is a non-select statement
698             # if ( $data->{sql} =~ /^SELECT/i ) {
699             # $self->{output} = $self->make_error( $data->{id}, "DO is for non-SELECT queries only! ( $data->{sql} )" );
700             # return;
701             # }
702              
703             SWITCH: {
704            
705 0 0         if ($data->{begin_work}) {
  0            
706 0 0         $self->begin_work($data) or last SWITCH;
707             }
708            
709             # Catch any errors
710             try {
711             # Make a new statement handler and prepare the query
712 0 0   0     if ($data->{no_cache}) {
713 0           $sth = $self->{dbh}->prepare( $data->{sql} );
714             } else {
715             # We use the prepare_cached method in hopes of hitting a cached one...
716 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
717             }
718            
719             # Check for undef'ness
720 0 0         if (!defined($sth)) {
721 0           die 'Did not get a statement handler';
722             } else {
723             # Execute the query
724             try {
725 0           $rows += $sth->execute( @{ $data->{placeholders} } );
  0            
726             } catch {
727 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
728 0           };
729 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
730             }
731             } catch {
732 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
733 0           };
734              
735             }
736              
737 0 0 0       if ($data->{commit} && defined($rows) && !defined($self->{output})) {
      0        
738 0           $self->commit($data);
739             }
740              
741             # If rows is not undef, that means we were successful
742 0 0 0       if (defined($rows) && !defined($self->{output})) {
    0 0        
743             # Make the data structure
744 0           $self->{output} = { rows => $rows, result => $rows, id => $data->{id} };
745             } elsif (!defined($rows) && !defined($self->{output})) {
746             # Internal error...
747 0           $self->{output} = $self->make_error( $data->{id}, 'Internal Error in db_do of EasyDBI Subprocess' );
748             #die 'Internal Error in db_do';
749             }
750              
751             # Finally, we clean up this statement handle
752 0 0         if (defined($sth)) {
753 0           $sth->finish();
754             }
755            
756 0           return;
757             }
758              
759             sub db_arrayhash {
760             # Get the dbi handle
761 0     0 0   my $self = shift;
762              
763             # Get the input structure
764 0           my $data = shift;
765              
766             # Variables we use
767 0           my $sth = undef;
768 0           my $result = [];
769 0           my $rows = 0;
770              
771             # Check if this is a non-select statement
772             # if ( $data->{sql} !~ /^SELECT/i ) {
773             # $self->{output} = $self->make_error( $data->{id}, "ARRAYHASH is for SELECT queries only! ( $data->{sql} )" );
774             # return;
775             # }
776              
777             SWITCH: {
778              
779 0 0         if ($data->{begin_work}) {
  0            
780 0 0         $self->begin_work($data) or last SWITCH;
781             }
782              
783             # Catch any errors
784             try {
785             # Make a new statement handler and prepare the query
786 0 0   0     if ($data->{no_cache}) {
787 0           $sth = $self->{dbh}->prepare( $data->{sql} );
788             } else {
789             # We use the prepare_cached method in hopes of hitting a cached one...
790 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
791             }
792            
793             # Check for undef'ness
794 0 0         if (!defined($sth)) {
795 0           die 'Did not get a statement handler';
796             } else {
797             # Execute the query
798             try {
799 0           $sth->execute( @{ $data->{placeholders} } );
  0            
800             } catch {
801 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
802 0           };
803 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
804             }
805            
806             # my $newdata;
807             #
808             # # Bind the columns
809             # try {
810             # $sth->bind_columns( \( @$newdata{ @{ $sth->{'NAME_lc'} } } ) );
811             # } catch {
812             # die $sth->errstr;
813             # };
814            
815             # Actually do the query!
816             try {
817 0           while ( my $hash = $sth->fetchrow_hashref() ) {
818 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
819             # chunk results ready to send
820 0           $self->output();
821 0           $result = [];
822 0           $rows = 0;
823             }
824 0           $rows++;
825             # Copy the data, and push it into the array
826 0           push( @{ $result }, { %{ $hash } } );
  0            
  0            
827 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
828             # Make output include the results
829 0           $self->{output} = { rows => $rows, id => $data->{id}, result => $result, chunked => $data->{chunked} };
830             }
831             }
832             # in the case that our rows == chunk
833 0           $self->{output} = undef;
834            
835             } catch {
836 0           die $sth->errstr;
837 0           };
838            
839             # XXX is dbh->err the same as sth->err?
840 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
841              
842             # Check for any errors that might have terminated the loop early
843 0 0         if ( $sth->err() ) {
844             # Premature termination!
845 0           die $sth->errstr;
846             }
847             } catch {
848 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
849 0           };
850            
851             }
852            
853             # Check if we got any errors
854 0 0         if (!defined($self->{output})) {
855             # Make output include the results
856 0           $self->{output} = { rows => $rows, id => $data->{id}, result => $result };
857 0 0         if (exists($data->{chunked})) {
858 0           $self->{output}->{last_chunk} = 1;
859 0           $self->{output}->{chunked} = $data->{chunked};
860             }
861             }
862              
863             # Finally, we clean up this statement handle
864 0 0         if (defined($sth)) {
865 0           $sth->finish();
866             }
867            
868 0           return;
869             }
870              
871             sub db_hashhash {
872             # Get the dbi handle
873 0     0 0   my $self = shift;
874              
875             # Get the input structure
876 0           my $data = shift;
877              
878             # Variables we use
879 0           my $sth = undef;
880 0           my $result = {};
881 0           my $rows = 0;
882              
883             # Check if this is a non-select statement
884             # if ( $data->{sql} !~ /^SELECT/i ) {
885             # $self->{output} = $self->make_error( $data->{id}, "HASHHASH is for SELECT queries only! ( $data->{sql} )" );
886             # return;
887             # }
888              
889 0           my (@cols, %col);
890            
891             SWITCH: {
892              
893 0 0         if ($data->{begin_work}) {
  0            
894 0 0         $self->begin_work($data) or last SWITCH;
895             }
896            
897             # Catch any errors
898             try {
899             # Make a new statement handler and prepare the query
900 0 0   0     if ($data->{no_cache}) {
901 0           $sth = $self->{dbh}->prepare( $data->{sql} );
902             } else {
903             # We use the prepare_cached method in hopes of hitting a cached one...
904 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
905             }
906            
907             # Check for undef'ness
908 0 0         if (!defined($sth)) {
909 0           die 'Did not get a statement handler';
910             } else {
911             # Execute the query
912             try {
913 0           $sth->execute( @{ $data->{placeholders} } );
  0            
914             } catch {
915 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
916 0           };
917 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
918             }
919            
920             # The result hash
921 0           my $newdata = {};
922            
923             # Check the primary key
924 0           my $foundprimary = 0;
925            
926             # default to the first one
927 0 0         unless (defined($data->{primary_key})) {
928 0           $data->{primary_key} = 1;
929             }
930            
931 0 0         if ($data->{primary_key} =~ m/^\d+$/) {
932             # primary_key can be a 1 based index
933 0 0         if ($data->{primary_key} > $sth->{NUM_OF_FIELDS}) {
934             # die "primary_key ($data->{primary_key}) is out of bounds (".$sth->{NUM_OF_FIELDS}.")";
935 0           die "primary_key ($data->{primary_key}) is out of bounds";
936             }
937            
938 0           $data->{primary_key} = $sth->{NAME}->[($data->{primary_key}-1)];
939             }
940            
941             # Find the column names
942 0           for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
943 0           $col{$sth->{NAME}->[$i]} = $i;
944 0           push(@cols, $sth->{NAME}->[$i]);
945 0 0         $foundprimary = 1 if ($sth->{NAME}->[$i] eq $data->{primary_key});
946             }
947            
948 0 0         unless ($foundprimary == 1) {
949 0           die "primary key ($data->{primary_key}) not found";
950             }
951            
952             # Actually do the query!
953             try {
954 0           while ( my @row = $sth->fetchrow_array() ) {
955 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
956             # chunk results ready to send
957 0           $self->output();
958 0           $result = {};
959 0           $rows = 0;
960             }
961 0           $rows++;
962 0           foreach (@cols) {
963 0           $result->{$row[$col{$data->{primary_key}}]}{$_} = $row[$col{$_}];
964             }
965 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
966             # Make output include the results
967 0           $self->{output} = {
968             rows => $rows,
969             result => $result,
970             id => $data->{id},
971             cols => [ @cols ],
972             chunked => $data->{chunked},
973             primary_key => $data->{primary_key}
974             };
975             }
976             }
977             # in the case that our rows == chunk
978 0           $self->{output} = undef;
979            
980             } catch {
981 0           die $sth->errstr;
982 0           };
983            
984 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
985            
986             # Check for any errors that might have terminated the loop early
987 0 0         if ( $sth->err() ) {
988             # Premature termination!
989 0           die $sth->errstr;
990             }
991             } catch {
992 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
993 0           };
994            
995             }
996              
997             # Check if we got any errors
998 0 0         if (!defined($self->{output})) {
999             # Make output include the results
1000 0           $self->{output} = { rows => $rows, id => $data->{id}, result => $result, cols => [ @cols ], primary_key => $data->{primary_key} };
1001 0 0         if (exists($data->{chunked})) {
1002 0           $self->{output}->{last_chunk} = 1;
1003 0           $self->{output}->{chunked} = $data->{chunked};
1004             }
1005             }
1006              
1007             # Finally, we clean up this statement handle
1008 0 0         if (defined($sth)) {
1009 0           $sth->finish();
1010             }
1011            
1012 0           return;
1013             }
1014              
1015             sub db_hasharray {
1016             # Get the dbi handle
1017 0     0 0   my $self = shift;
1018              
1019             # Get the input structure
1020 0           my $data = shift;
1021              
1022             # Variables we use
1023 0           my $sth = undef;
1024 0           my $result = {};
1025 0           my $rows = 0;
1026              
1027             # Check if this is a non-select statement
1028             # if ( $data->{sql} !~ /^SELECT/i ) {
1029             # $self->{output} = $self->make_error( $data->{id}, "HASHARRAY is for SELECT queries only! ( $data->{sql} )" );
1030             # return;
1031             # }
1032              
1033 0           my (@cols, %col);
1034            
1035             SWITCH: {
1036              
1037 0 0         if ($data->{begin_work}) {
  0            
1038 0 0         $self->begin_work($data) or last SWITCH;
1039             }
1040            
1041             # Catch any errors
1042             try {
1043             # Make a new statement handler and prepare the query
1044 0 0   0     if ($data->{no_cache}) {
1045 0           $sth = $self->{dbh}->prepare( $data->{sql} );
1046             } else {
1047             # We use the prepare_cached method in hopes of hitting a cached one...
1048 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
1049             }
1050            
1051             # Check for undef'ness
1052 0 0         if (!defined($sth)) {
1053 0           die 'Did not get a statement handler';
1054             } else {
1055             # Execute the query
1056             try {
1057 0           $sth->execute( @{ $data->{placeholders} } );
  0            
1058             } catch {
1059 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
1060 0           };
1061 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1062             }
1063              
1064             # The result hash
1065 0           my $newdata = {};
1066            
1067             # Check the primary key
1068 0           my $foundprimary = 0;
1069              
1070 0 0         if ($data->{primary_key} =~ m/^\d+$/) {
1071             # primary_key can be a 1 based index
1072 0 0         if ($data->{primary_key} > $sth->{NUM_OF_FIELDS}) {
1073             # die "primary_key ($data->{primary_key}) is out of bounds (".$sth->{NUM_OF_FIELDS}.")";
1074 0           die "primary_key ($data->{primary_key}) is out of bounds";
1075             }
1076            
1077 0           $data->{primary_key} = $sth->{NAME}->[($data->{primary_key}-1)];
1078             }
1079            
1080             # Find the column names
1081 0           for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
1082 0           $col{$sth->{NAME}->[$i]} = $i;
1083 0           push(@cols, $sth->{NAME}->[$i]);
1084 0 0         $foundprimary = 1 if ($sth->{NAME}->[$i] eq $data->{primary_key});
1085             }
1086            
1087 0 0         unless ($foundprimary == 1) {
1088 0           die "primary key ($data->{primary_key}) not found";
1089             }
1090            
1091             # Actually do the query!
1092             try {
1093 0           while ( my @row = $sth->fetchrow_array() ) {
1094 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
1095             # chunk results ready to send
1096 0           $self->output();
1097 0           $result = {};
1098 0           $rows = 0;
1099             }
1100 0           $rows++;
1101 0           push(@{ $result->{$row[$col{$data->{primary_key}}]} }, @row);
  0            
1102 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1103             # Make output include the results
1104 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id}, cols => [ @cols ], chunked => $data->{chunked}, primary_key => $data->{primary_key} };
1105             }
1106             }
1107             # in the case that our rows == chunk
1108 0           $self->{output} = undef;
1109            
1110             } catch {
1111 0           die $sth->errstr;
1112 0           };
1113            
1114 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1115            
1116             # Check for any errors that might have terminated the loop early
1117 0 0         if ( $sth->err() ) {
1118             # Premature termination!
1119 0           die $sth->errstr;
1120             }
1121             } catch {
1122 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
1123 0           };
1124            
1125             }
1126            
1127             # Check if we got any errors
1128 0 0         if (!defined($self->{output})) {
1129             # Make output include the results
1130 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id}, cols => [ @cols ], primary_key => $data->{primary_key} };
1131 0 0         if (exists($data->{chunked})) {
1132 0           $self->{output}->{last_chunk} = 1;
1133 0           $self->{output}->{chunked} = $data->{chunked};
1134             }
1135             }
1136              
1137             # Finally, we clean up this statement handle
1138 0 0         if (defined($sth)) {
1139 0           $sth->finish();
1140             }
1141            
1142 0           return;
1143             }
1144              
1145             sub db_array {
1146             # Get the dbi handle
1147 0     0 0   my $self = shift;
1148              
1149             # Get the input structure
1150 0           my $data = shift;
1151              
1152             # Variables we use
1153 0           my $sth = undef;
1154 0           my $result = [];
1155 0           my $rows = 0;
1156              
1157             # Check if this is a non-select statement
1158             # if ( $data->{sql} !~ /^SELECT/i ) {
1159             # $self->{output} = $self->make_error( $data->{id}, "ARRAY is for SELECT queries only! ( $data->{sql} )" );
1160             # return;
1161             # }
1162              
1163             SWITCH: {
1164              
1165 0 0         if ($data->{begin_work}) {
  0            
1166 0 0         $self->begin_work($data) or last SWITCH;
1167             }
1168            
1169             # Catch any errors
1170             try {
1171             # Make a new statement handler and prepare the query
1172 0 0   0     if ($data->{no_cache}) {
1173 0           $sth = $self->{dbh}->prepare( $data->{sql} );
1174             } else {
1175             # We use the prepare_cached method in hopes of hitting a cached one...
1176 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
1177             }
1178              
1179             # Check for undef'ness
1180 0 0         if (!defined($sth)) {
1181 0           die 'Did not get a statement handler';
1182             } else {
1183             # Execute the query
1184             try {
1185 0           $sth->execute( @{ $data->{placeholders} } );
  0            
1186             } catch {
1187 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
1188 0           };
1189 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1190             }
1191            
1192             # The result hash
1193 0           my $newdata = {};
1194            
1195             # Actually do the query!
1196             try {
1197             # There are warnings when joining a NULL field, which is undef
1198 2     2   12 no warnings;
  2         2  
  2         2865  
1199              
1200 0           while ( my @row = $sth->fetchrow_array() ) {
1201 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
1202             # chunk results ready to send
1203 0           $self->output();
1204 0           $result = [];
1205 0           $rows = 0;
1206             }
1207 0           $rows++;
1208 0 0         if (exists($data->{separator})) {
1209 0           push(@{$result},join($data->{separator},@row));
  0            
1210             } else {
1211 0           push(@{$result},join(',',@row));
  0            
1212             }
1213 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1214             # Make output include the results
1215 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1216             }
1217             }
1218             # in the case that our rows == chunk
1219 0           $self->{output} = undef;
1220            
1221             } catch {
1222 0           die $!;
1223             #die $sth->errstr;
1224 0           };
1225            
1226 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1227            
1228             # Check for any errors that might have terminated the loop early
1229 0 0         if ( $sth->err() ) {
1230             # Premature termination!
1231 0           die $sth->errstr;
1232             }
1233             } catch {
1234 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
1235 0           };
1236              
1237             }
1238            
1239             # Check if we got any errors
1240 0 0         if (!defined($self->{output})) {
1241             # Make output include the results
1242 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1243 0 0         if (exists($data->{chunked})) {
1244 0           $self->{output}->{last_chunk} = 1;
1245 0           $self->{output}->{chunked} = $data->{chunked};
1246             }
1247             }
1248              
1249             # Finally, we clean up this statement handle
1250 0 0         if (defined($sth)) {
1251 0           $sth->finish();
1252             }
1253            
1254 0           return;
1255             }
1256              
1257             sub db_arrayarray {
1258             # Get the dbi handle
1259 0     0 0   my $self = shift;
1260              
1261             # Get the input structure
1262 0           my $data = shift;
1263              
1264             # Variables we use
1265 0           my $sth = undef;
1266 0           my $result = [];
1267 0           my $rows = 0;
1268              
1269             # Check if this is a non-select statement
1270             # if ( $data->{sql} !~ /^SELECT/i ) {
1271             # $self->{output} = $self->make_error( $data->{id}, "ARRAYARRAY is for SELECT queries only! ( $data->{sql} )" );
1272             # return;
1273             # }
1274              
1275             SWITCH: {
1276              
1277 0 0         if ($data->{begin_work}) {
  0            
1278 0 0         $self->begin_work($data) or last SWITCH;
1279             }
1280              
1281             # Catch any errors
1282             try {
1283             # Make a new statement handler and prepare the query
1284 0 0   0     if ($data->{no_cache}) {
1285 0           $sth = $self->{dbh}->prepare( $data->{sql} );
1286             } else {
1287             # We use the prepare_cached method in hopes of hitting a cached one...
1288 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
1289             }
1290            
1291             # Check for undef'ness
1292 0 0         if (!defined($sth)) {
1293 0           die 'Did not get a statement handler';
1294             } else {
1295             # Execute the query
1296             try {
1297 0           $sth->execute( @{ $data->{placeholders} } );
  0            
1298             } catch {
1299 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
1300 0           };
1301 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1302             }
1303            
1304             # The result hash
1305 0           my $newdata = {};
1306            
1307             # Actually do the query!
1308             try {
1309 0           while ( my @row = $sth->fetchrow_array() ) {
1310 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
1311             # chunk results ready to send
1312 0           $self->output();
1313 0           $result = [];
1314 0           $rows = 0;
1315             }
1316 0           $rows++;
1317             # There are warnings when joining a NULL field, which is undef
1318 0           push(@{$result},\@row);
  0            
1319 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1320             # Make output include the results
1321 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1322             }
1323             }
1324             # in the case that our rows == chunk
1325 0           $self->{output} = undef;
1326            
1327             } catch {
1328 0           die $!;
1329             #die $sth->errstr;
1330 0           };
1331            
1332 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1333            
1334             # Check for any errors that might have terminated the loop early
1335 0 0         if ( $sth->err() ) {
1336             # Premature termination!
1337 0           die $sth->errstr;
1338             }
1339             } catch {
1340 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
1341 0           };
1342            
1343             }
1344            
1345              
1346             # Check if we got any errors
1347 0 0         if (!defined($self->{output})) {
1348             # Make output include the results
1349 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1350 0 0         if (exists($data->{chunked})) {
1351 0           $self->{output}->{last_chunk} = 1;
1352 0           $self->{output}->{chunked} = $data->{chunked};
1353             }
1354             }
1355              
1356             # Finally, we clean up this statement handle
1357 0 0         if (defined($sth)) {
1358 0           $sth->finish();
1359             }
1360            
1361 0           return;
1362             }
1363              
1364             sub db_hash {
1365             # Get the dbi handle
1366 0     0 0   my $self = shift;
1367              
1368             # Get the input structure
1369 0           my $data = shift;
1370              
1371             # Variables we use
1372 0           my $sth = undef;
1373 0           my $result = {};
1374 0           my $rows = 0;
1375              
1376             # Check if this is a non-select statement
1377             # if ( $data->{sql} !~ /^SELECT/i ) {
1378             # $self->{output} = $self->make_error( $data->{id}, "HASH is for SELECT queries only! ( $data->{sql} )" );
1379             # return;
1380             # }
1381              
1382             SWITCH: {
1383              
1384 0 0         if ($data->{begin_work}) {
  0            
1385 0 0         $self->begin_work($data) or last SWITCH;
1386             }
1387              
1388             # Catch any errors
1389             try {
1390             # Make a new statement handler and prepare the query
1391 0 0   0     if ($data->{no_cache}) {
1392 0           $sth = $self->{dbh}->prepare( $data->{sql} );
1393             } else {
1394             # We use the prepare_cached method in hopes of hitting a cached one...
1395 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
1396             }
1397            
1398             # Check for undef'ness
1399 0 0         if (!defined($sth)) {
1400 0           die 'Did not get a statement handler';
1401             } else {
1402             # Execute the query
1403             try {
1404 0           $sth->execute( @{ $data->{placeholders} } );
  0            
1405             } catch {
1406 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
1407 0           };
1408 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1409             }
1410            
1411             # The result hash
1412 0           my $newdata = {};
1413            
1414             # Actually do the query!
1415             try {
1416            
1417 0           my @row = $sth->fetchrow_array();
1418            
1419 0 0         if (@row) {
1420 0           $rows = @row;
1421 0           for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
1422 0           $result->{$sth->{NAME}->[$i]} = $row[$i];
1423             }
1424             }
1425            
1426             } catch {
1427 0           die $sth->errstr;
1428 0           };
1429            
1430 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1431            
1432             # Check for any errors that might have terminated the loop early
1433 0 0         if ( $sth->err() ) {
1434             # Premature termination!
1435 0           die $sth->errstr;
1436             }
1437             } catch {
1438 0     0     $self->{output} = $self->make_error( $data->{id}, shift );
1439 0           };
1440            
1441             }
1442              
1443             # Check if we got any errors
1444 0 0         if (!defined($self->{output})) {
1445             # Make output include the results
1446 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1447             }
1448              
1449             # Finally, we clean up this statement handle
1450 0 0         if (defined($sth)) {
1451 0           $sth->finish();
1452             }
1453              
1454 0           return;
1455             }
1456              
1457             sub db_keyvalhash {
1458             # Get the dbi handle
1459 0     0 0   my $self = shift;
1460              
1461             # Get the input structure
1462 0           my $data = shift;
1463              
1464             # Variables we use
1465 0           my $sth = undef;
1466 0           my $result = {};
1467 0           my $rows = 0;
1468              
1469             # Check if this is a non-select statement
1470             # if ( $data->{sql} !~ /^SELECT/i ) {
1471             # $self->{output} = $self->make_error( $data->{id}, "KEYVALHASH is for SELECT queries only! ( $data->{sql} )" );
1472             # return;
1473             # }
1474              
1475             SWITCH: {
1476              
1477 0 0         if ($data->{begin_work}) {
  0            
1478 0 0         $self->begin_work($data) or last SWITCH;
1479             }
1480            
1481             # Catch any errors
1482             try {
1483             # Make a new statement handler and prepare the query
1484 0 0   0     if ($data->{no_cache}) {
1485 0           $sth = $self->{dbh}->prepare( $data->{sql} );
1486             } else {
1487             # We use the prepare_cached method in hopes of hitting a cached one...
1488 0           $sth = $self->{dbh}->prepare_cached( $data->{sql} );
1489             }
1490            
1491             # Check for undef'ness
1492 0 0         if (!defined($sth)) {
1493 0           die 'Did not get a statement handler';
1494             } else {
1495             # Execute the query
1496             try {
1497 0           $sth->execute( @{ $data->{placeholders} } );
  0            
1498             } catch {
1499 0 0         die ( defined($sth->errstr) ? $sth->errstr : $@ );
1500 0           };
1501 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1502             }
1503            
1504             # Actually do the query!
1505             try {
1506 0           while (my @row = $sth->fetchrow_array()) {
1507 0 0         if ($#row < 1) {
1508 0           die 'You need at least 2 columns selected for a keyvalhash query';
1509             }
1510 0 0 0       if (exists($data->{chunked}) && defined($self->{output})) {
1511             # chunk results ready to send
1512 0           $self->output();
1513 0           $result = {};
1514 0           $rows = 0;
1515             }
1516 0           $rows++;
1517 0           $result->{$row[0]} = $row[1];
1518 0 0 0       if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1519             # Make output include the results
1520 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1521             }
1522             }
1523             # in the case that our rows == chunk
1524 0           $self->{output} = undef;
1525            
1526             } catch {
1527 0           die $sth->errstr;
1528 0           };
1529            
1530 0 0         die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1531            
1532             # Check for any errors that might have terminated the loop early
1533 0 0         if ( $sth->err() ) {
1534             # Premature termination!
1535 0           die $sth->errstr;
1536             }
1537             } catch {
1538 0     0     $self->{output} = $self->make_error( $data->{id}, shift);
1539 0           };
1540              
1541             }
1542              
1543             # Check if we got any errors
1544 0 0         if (!defined($self->{output})) {
1545             # Make output include the results
1546 0           $self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1547 0 0         if (exists($data->{chunked})) {
1548 0           $self->{output}->{last_chunk} = 1;
1549 0           $self->{output}->{chunked} = $data->{chunked};
1550             }
1551             }
1552              
1553             # Finally, we clean up this statement handle
1554 0 0         if (defined($sth)) {
1555 0           $sth->finish();
1556             }
1557            
1558 0           return;
1559             }
1560              
1561             # Prints any output to STDOUT
1562             sub output {
1563 0     0 0   my $self = shift;
1564            
1565             # Get the data
1566 0   0       my $data = shift || undef;
1567              
1568 0 0         unless (defined($data)) {
1569 0           $data = $self->{output};
1570 0           $self->{output} = undef;
1571             # TODO use this at some point
1572 0           $self->{error} = undef;
1573             }
1574            
1575             # Freeze it!
1576 0           my $outdata = $self->{filter}->put( [ $data ] );
1577              
1578             # Print it!
1579 0           print STDOUT @$outdata;
1580            
1581 0           return;
1582             }
1583              
1584             1;
1585              
1586             __END__