1package POE::Component::EasyDBI::SubProcess;
2
3use strict;
4use warnings FATAL => 'all';
5
6# Initialize our version
7our $VERSION = '1.28';
8
9use Try::Tiny qw( try catch );
10
11# We pass in data to POE::Filter::Reference
12use POE::Filter::Reference;
13
14# We run the actual DB connection here
15use DBI;
16
17sub new {
18	my ($class, $opts) = @_;
19	my $obj = bless($opts, $class);
20	$obj->{queue} = [];
21	$obj->{ping_timeout} = $obj->{ping_timeout} || 0;
22	return $obj;
23}
24
25# This is the subroutine that will get executed upon the fork() call by our parent
26sub main {
27	if ( $^O eq 'MSWin32' ) {
28		binmode(STDIN); binmode(STDOUT);
29	}
30	# Autoflush to avoid weirdness
31	#select((select(STDOUT), $| = 1)[0]);
32	select(STDOUT); $|++;
33	select(STDERR);	$|++;
34
35	$SIG{__WARN__} = 'DEFAULT';
36	$SIG{__DIE__} = 'DEFAULT';
37
38	my $self;
39	# check for alternate fork
40	if ($_[0] == 1) {
41		# we need to read in the first
42		my $filter = POE::Filter::Reference->new();
43		my $opts;
44		# get our first option hashref
45		while ( sysread( STDIN, my $buffer = '', 1024 ) ) {
46			$opts = $filter->get( [ $buffer ] );
47			last if (defined $opts);
48		}
49		$self = __PACKAGE__->new(splice(@{$opts},0,1));
50		$self->{filter} = $filter;
51		if (@{$opts}) {
52			push(@{$self->{queue}},@{$opts});
53		}
54		undef $filter;
55	} else {
56		$self = __PACKAGE__->new(shift);
57		$self->{filter} = POE::Filter::Reference->new();
58	}
59
60	$self->{0} = $0 = "$0 ".__PACKAGE__;
61
62	$self->{lastpingtime} = time();
63
64	unless (defined($self->{sig_ignore_off})) {
65		$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	while (!$self->connect()) {	}
75
76	$self->pt("connected at ".localtime());
77
78	return if ($self->{done});
79
80	# check for data in queue first
81	$self->process();
82
83	if ($self->{done}) {
84		$self->pt("disconnected at ".localtime());
85		if ($self->{dbh}) {
86			$self->{dbh}->disconnect();
87		}
88		return;
89	}
90
91	# listen for commands from our parent
92	READ: while ( sysread( STDIN, my $buffer = '', 1024 ) ) {
93		# Feed the line into the filter
94		# and put the data in the queue
95		my $d = $self->{filter}->get( [ $buffer ] );
96		push(@{$self->{queue}},@$d) if ($d);
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		unless ($self->process()) {
110			last READ if ($self->{done});
111			# oops problem...
112			if ($self->{reconnect}) {
113				# need to reconnect
114				delete $self->{reconnect};
115				# keep trying to connect
116				while (!$self->connect()) {	}
117				# and bail when we are told
118				last READ if ($self->{done});
119				goto REDO;
120			}
121		}
122	}
123	# Arrived here due to error in sysread/etc
124	if ($self->{dbh}) {
125		$self->{dbh}->disconnect();
126		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
139sub pt {
140	$0 = shift->{0}.' '.shift;
141}
142
143sub connect {
144	my $self = shift;
145
146	$self->{output} = undef;
147	$self->{error} = undef;
148
149	# Actually make the connection
150	try {
151		$self->{dbh} = DBI->connect(
152			# The DSN we just set up
153			(map { $self->{$_} } qw( dsn username password )),
154
155			# We set some configuration stuff here
156			{
157				((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		if (!defined($self->{dbh})) {
173			die "Error Connecting to Database: $DBI::errstr";
174		}
175	} catch {
176		$self->output( $self->make_error( 'DBI', shift ) );
177	};
178
179	# Catch errors!
180	if ($self->{error} && $self->{no_connect_failures}) {
181		sleep($self->{reconnect_wait}) if ($self->{reconnect_wait});
182		return 0;
183	} elsif ($self->{error}) {
184		# QUIT
185		$self->{done} = 1;
186		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	$self->output({ id => 'DBI-CONNECTED' });
198
199	return 1;
200}
201
202sub process {
203	my $self = shift;
204
205	return 0 unless (@{$self->{queue}});
206
207	# Process each data structure
208	foreach my $input (shift(@{$self->{queue}})) {
209		$input->{action} = lc($input->{action});
210
211		# Now, we do the actual work depending on what kind of query it was
212		if ($input->{action} eq 'exit') {
213			# Disconnect!
214			$self->{done} = 1;
215			return 0;
216		}
217
218		my $now = time();
219		my $needping = (($self->{ping_timeout} == 0 or $self->{ping_timeout} > 0)
220			and (($now - $self->{lastpingtime}) >= $self->{ping_timeout})) ? 1 : 0;
221
222		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			if ($needping) {
233				if (eval{ $self->{dbh}->ping(); }) {
234					$self->pt("pinged at ".localtime());
235					$self->{lastpingtime} = $now;
236				} else {
237					# put the query back on the stack
238					unshift(@{$self->{queue}},$input);
239					# and reconnect
240					$self->{dbh}->disconnect();
241					$self->{reconnect} = 1;
242					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			unshift(@{$self->{queue}},$input);
250			# and reconnect
251			eval { $self->{dbh}->disconnect(); };
252			$self->{reconnect} = 1;
253			return 0;
254		}
255
256		if (defined($self->{no_cache}) && !defined($input->{no_cache})) {
257			$input->{no_cache} = $self->{no_cache};
258		}
259
260		if (defined($input->{sql})) {
261			# remove beginning whitespace
262			$input->{sql} =~ s/^\s*//;
263		}
264
265		if ( $input->{action} =~ m/^(func|commit|rollback|begin_work)$/ ) {
266			$input->{method} = $input->{action};
267			$self->do_method( $input );
268		} elsif ( $input->{action} eq 'method') {
269			# Special command to do $dbh->$method->()
270			$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			$self->db_insert( $input );
274		} elsif ( $input->{action} eq 'do' ) {
275			# Fire off the SQL and return success/failure + rows affected
276			$self->db_do( $input );
277		} elsif ( $input->{action} eq 'single' ) {
278			# Return a single result
279			$self->db_single( $input );
280		} elsif ( $input->{action} eq 'quote' ) {
281			$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			$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			$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			$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			$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			$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			$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			$self->db_keyvalhash( $input );
307		} else {
308			# Unrecognized action!
309			$self->{output} = $self->make_error( $input->{id}, "Unknown action sent '$input->{id}'" );
310		}
311		# XXX another way?
312		if ($input->{id} eq 'DBI' || ($self->{output}->{error}
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			unshift(@{$self->{queue}},$input);
319			eval { $self->{dbh}->disconnect(); };
320			$self->{reconnect} = 1;
321			return 0;
322		}
323		$self->output;
324	}
325	return 1;
326}
327
328sub commit {
329	my $self = shift;
330	my $id = shift->{id};
331	try {
332		$self->{dbh}->commit;
333	} catch {
334		$self->{output} = $self->make_error( $id, shift );
335	};
336	return ($self->{output}) ? 0 : 1;
337}
338
339sub begin_work {
340	my $self = shift;
341	my $id = shift->{id};
342	try {
343		$self->{dbh}->begin_work;
344	} catch {
345		$self->{output} = $self->make_error( $id, shift );
346	};
347	return ($self->{output}) ? 0 : 1;
348}
349
350# This subroutine makes a generic error structure
351sub make_error {
352	my $self = shift;
353
354	# Make the structure
355	my $data = { id => shift };
356
357	# Get the error, and stringify it in case of Error::Simple objects
358	my $error = shift;
359
360	if (ref($error) && ref($error) eq 'Error::Simple') {
361		$data->{error} = $error->text;
362	} else {
363		$data->{error} = $error;
364	}
365
366	if ($data->{error} =~ m/has gone away/i || $data->{error} =~ m/lost connection/i) {
367		$data->{id} = 'DBI';
368	}
369
370	$self->{error} = $data;
371
372	# All done!
373	return $data;
374}
375
376# This subroute is for supporting any type of $dbh->$method->() calls
377sub do_method {
378	# Get the dbi handle
379	my $self = shift;
380
381	# Get the input structure
382	my $data = shift;
383
384	# The result
385	my $result = undef;
386
387	my $method = $data->{method};
388	my $dbh = $self->{dbh};
389
390	SWITCH: {
391
392		if ($data->{begin_work}) {
393			$self->begin_work($data) or last SWITCH;
394		}
395
396		# Catch any errors
397		try {
398			if ($data->{args} && ref($data->{args}) eq 'ARRAY') {
399				$result = $dbh->$method(@{$data->{args}});
400			} else {
401				$result = $dbh->$method();
402			}
403
404		} catch {
405			$self->{output} = $self->make_error( $data->{id}, shift );
406		};
407
408	}
409
410	# Check if we got any errors
411	if (!defined($self->{output})) {
412		# Make output include the results
413		$self->{output} = { result => $result, id => $data->{id} };
414	}
415
416	return;
417}
418
419# This subroutine does a DB QUOTE
420sub db_quote {
421	my $self = shift;
422
423	# Get the input structure
424	my $data = shift;
425
426	# The result
427	my $quoted = undef;
428
429	# Quote it!
430	try {
431		$quoted = $self->{dbh}->quote( $data->{sql} );
432	} catch {
433		$self->{output} = $self->make_error( $data->{id}, shift );
434	};
435
436	# Check for errors
437	if (!defined($self->{output})) {
438		# Make output include the results
439		$self->{output} = { result => $quoted, id => $data->{id} };
440	}
441	return;
442}
443
444# This subroutine runs a 'SELECT ... LIMIT 1' style query on the db
445sub db_single {
446	# Get the dbi handle
447	my $self = shift;
448
449	# Get the input structure
450	my $data = shift;
451
452	# Variables we use
453	my $sth = undef;
454	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		if ($data->{begin_work}) {
464			$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			if ($data->{no_cache}) {
471				$sth = $self->{dbh}->prepare( $data->{sql} );
472			} else {
473				# We use the prepare_cached method in hopes of hitting a cached one...
474				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
475			}
476
477			# Check for undef'ness
478			if (!defined($sth)) {
479				die 'Did not get a statement handler';
480			} else {
481				# Execute the query
482				try {
483					$sth->execute( @{ $data->{placeholders} } );
484				} catch {
485					die ( defined($sth->errstr) ? $sth->errstr : $@ );
486				};
487				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				no warnings;
494				if (exists($data->{separator})) {
495					$result = join($data->{separator},$sth->fetchrow_array());
496				} else {
497					$result = $sth->fetchrow_array();
498				}
499			} catch {
500				die $sth->errstr;
501			};
502
503			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
504		} catch {
505			$self->{output} = $self->make_error( $data->{id}, shift );
506		};
507	}
508
509	# Check if we got any errors
510	if (!defined($self->{output})) {
511		# Make output include the results
512		$self->{output} = { result => $result, id => $data->{id} };
513	}
514
515	# Finally, we clean up this statement handle
516	if (defined($sth)) {
517		$sth->finish();
518	}
519
520	return;
521}
522
523# This subroutine does an insert into the db
524sub db_insert {
525	# Get the dbi handle
526	my $self = shift;
527
528	# Get the input structure
529	my $data = shift;
530
531	my $dsn = $self->{dsn} || '';
532
533	# Variables we use
534	my $sth = undef;
535	my $rows = undef;
536
537	my @queries;
538	my @placeholders;
539
540	# XXX depricate hash for insert
541	if (defined($data->{hash}) && !defined($data->{insert})) {
542		$data->{insert} = delete $data->{hash};
543	}
544
545	if (defined($data->{insert}) && ref($data->{insert}) eq 'HASH') {
546		$data->{insert} = [$data->{insert}];
547	}
548
549	# Check if this is a non-insert statement
550	if (defined($data->{insert}) && ref($data->{insert}) eq 'ARRAY') {
551		delete $data->{placeholders};
552		delete $data->{sql};
553		foreach my $hash (@{$data->{insert}}) {
554			# sort so we always get a consistant list of fields in the errors and placeholders
555			my @fields = sort keys %{$hash};
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			push(@placeholders,[ map { $hash->{$_} } @fields ]);
559			push(@queries,"INSERT INTO $data->{table} ("
560				.join(',',@fields).") VALUES (".join(',',(map { '?' } @fields)).")");
561		}
562	} elsif (!defined($data->{sql}) || $data->{sql} !~ /^INSERT/i ) {
563		$self->{output} = $self->make_error( $data->{id}, "INSERT is for INSERTS only! ( $data->{sql} )" );
564		return;
565	} else {
566		push(@queries,$data->{sql});
567		push(@placeholders,$data->{placeholders});
568	}
569
570	for my $i ( 0 .. $#queries ) {
571		$data->{sql} = $queries[$i];
572		$data->{placeholders} = $placeholders[$i];
573		my $do_last = 0;
574
575		if ($data->{begin_work} && $i == 0) {
576			$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			if ($data->{no_cache}) {
583				$sth = $self->{dbh}->prepare( $data->{sql} );
584			} else {
585				# We use the prepare_cached method in hopes of hitting a cached one...
586				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
587			}
588
589			# Check for undef'ness
590			if (!defined($sth)) {
591				die 'Did not get a statement handler';
592			} else {
593				# Execute the query
594				try {
595					$rows += $sth->execute( @{ $data->{placeholders} } );
596				} catch {
597					if (defined($sth->errstr)) {
598						die $sth->errstr;
599					} else {
600						die "error when trying to execute bind of placeholders in insert: $_[0]";
601					}
602				};
603				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
604			}
605		} catch {
606			my $e = shift;
607			$self->{output} = $self->make_error( $data->{id}, "failed at query #$i : $e" );
608			$do_last = 1; # can't use last here
609		};
610		last if ($do_last);
611	}
612
613	if ($data->{commit} && defined($rows) && !defined($self->{output})) {
614		$self->commit($data);
615	}
616
617	# If rows is not undef, that means we were successful
618	if (defined($rows) && !defined($self->{output})) {
619		# Make the data structure
620		$self->{output} = { rows => $rows, result => $rows, id => $data->{id} };
621
622		unless ($data->{last_insert_id}) {
623			if (defined($sth)) {
624				$sth->finish();
625			}
626			return;
627		}
628		# get the last insert id
629		try {
630			my $qry = '';
631			if (ref($data->{last_insert_id}) eq 'HASH') {
632				my $l = $data->{last_insert_id};
633				# checks for different database types
634				if ($dsn =~ m/dbi:pg/i) {
635					$qry = "SELECT $l->{field} FROM $l->{table} WHERE oid='".$sth->{'pg_oid_status'}."'";
636				} elsif ($dsn =~ m/dbi:mysql/i) {
637					if (defined($self->{dbh}->{'mysql_insertid'})) {
638						$self->{output}->{insert_id} = $self->{dbh}->{'mysql_insertid'};
639					} else {
640						$qry = 'SELECT LAST_INSERT_ID()';
641					}
642				} elsif ($dsn =~ m/dbi:oracle/i) {
643					$qry = "SELECT $l->{field} FROM $l->{table}";
644				} elsif ($dsn =~ /dbi:sqlite/i) {
645					$self->{output}->{insert_id} = $self->{dbh}->func('last_insert_rowid');
646				} else {
647					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				$qry = $data->{last_insert_id};
652			}
653
654			if (defined($sth)) {
655				$sth->finish();
656			}
657
658			if ($qry) {
659				try {
660					$self->{output}->{insert_id} = $self->{dbh}->selectrow_array($qry);
661				} catch {
662					die $sth->error;
663				};
664
665				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
666			}
667		} catch {
668			# special case, insert was ok, but last_insert_id errored
669			$self->{output}->{error} = shift;
670		};
671	} elsif (!defined($rows) && !defined($self->{output})) {
672		# Internal error...
673		$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	if (defined($sth)) {
679		$sth->finish();
680	}
681
682	return;
683}
684
685# This subroutine runs a 'DO' style query on the db
686sub db_do {
687	# Get the dbi handle
688	my $self = shift;
689
690	# Get the input structure
691	my $data = shift;
692
693	# Variables we use
694	my $sth = undef;
695	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		if ($data->{begin_work}) {
706			$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			if ($data->{no_cache}) {
713				$sth = $self->{dbh}->prepare( $data->{sql} );
714			} else {
715				# We use the prepare_cached method in hopes of hitting a cached one...
716				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
717			}
718
719			# Check for undef'ness
720			if (!defined($sth)) {
721				die 'Did not get a statement handler';
722			} else {
723				# Execute the query
724				try {
725					$rows += $sth->execute( @{ $data->{placeholders} } );
726				} catch {
727					die ( defined($sth->errstr) ? $sth->errstr : $@ );
728				};
729				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
730			}
731		} catch {
732			$self->{output} = $self->make_error( $data->{id}, shift );
733		};
734
735	}
736
737	if ($data->{commit} && defined($rows) && !defined($self->{output})) {
738		$self->commit($data);
739	}
740
741	# If rows is not undef, that means we were successful
742	if (defined($rows) && !defined($self->{output})) {
743		# Make the data structure
744		$self->{output} = { rows => $rows, result => $rows, id => $data->{id} };
745	} elsif (!defined($rows) && !defined($self->{output})) {
746		# Internal error...
747		$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	if (defined($sth)) {
753		$sth->finish();
754	}
755
756	return;
757}
758
759sub db_arrayhash {
760	# Get the dbi handle
761	my $self = shift;
762
763	# Get the input structure
764	my $data = shift;
765
766	# Variables we use
767	my $sth = undef;
768	my $result = [];
769	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		if ($data->{begin_work}) {
780			$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			if ($data->{no_cache}) {
787				$sth = $self->{dbh}->prepare( $data->{sql} );
788			} else {
789				# We use the prepare_cached method in hopes of hitting a cached one...
790				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
791			}
792
793			# Check for undef'ness
794			if (!defined($sth)) {
795				die 'Did not get a statement handler';
796			} else {
797				# Execute the query
798				try {
799					$sth->execute( @{ $data->{placeholders} } );
800				} catch {
801					die ( defined($sth->errstr) ? $sth->errstr : $@ );
802				};
803				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				while ( my $hash = $sth->fetchrow_hashref() ) {
818					if (exists($data->{chunked}) && defined($self->{output})) {
819						# chunk results ready to send
820						$self->output();
821						$result = [];
822						$rows = 0;
823					}
824					$rows++;
825					# Copy the data, and push it into the array
826					push( @{ $result }, { %{ $hash } } );
827					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
828						# Make output include the results
829						$self->{output} = { rows => $rows, id => $data->{id}, result => $result, chunked => $data->{chunked} };
830					}
831				}
832				# in the case that our rows == chunk
833				$self->{output} = undef;
834
835			} catch {
836				die $sth->errstr;
837			};
838
839			# XXX is dbh->err the same as sth->err?
840			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
841
842			# Check for any errors that might have terminated the loop early
843			if ( $sth->err() ) {
844				# Premature termination!
845				die $sth->errstr;
846			}
847		} catch {
848			$self->{output} = $self->make_error( $data->{id}, shift );
849		};
850
851	}
852
853	# Check if we got any errors
854	if (!defined($self->{output})) {
855		# Make output include the results
856		$self->{output} = { rows => $rows, id => $data->{id}, result => $result };
857		if (exists($data->{chunked})) {
858			$self->{output}->{last_chunk} = 1;
859			$self->{output}->{chunked} = $data->{chunked};
860		}
861	}
862
863	# Finally, we clean up this statement handle
864	if (defined($sth)) {
865		$sth->finish();
866	}
867
868	return;
869}
870
871sub db_hashhash {
872	# Get the dbi handle
873	my $self = shift;
874
875	# Get the input structure
876	my $data = shift;
877
878	# Variables we use
879	my $sth = undef;
880	my $result = {};
881	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	my (@cols, %col);
890
891	SWITCH: {
892
893		if ($data->{begin_work}) {
894			$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			if ($data->{no_cache}) {
901				$sth = $self->{dbh}->prepare( $data->{sql} );
902			} else {
903				# We use the prepare_cached method in hopes of hitting a cached one...
904				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
905			}
906
907			# Check for undef'ness
908			if (!defined($sth)) {
909				die 'Did not get a statement handler';
910			} else {
911				# Execute the query
912				try {
913					$sth->execute( @{ $data->{placeholders} } );
914				} catch {
915					die ( defined($sth->errstr) ? $sth->errstr : $@ );
916				};
917				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
918			}
919
920			# The result hash
921			my $newdata = {};
922
923			# Check the primary key
924			my $foundprimary = 0;
925
926			# default to the first one
927			unless (defined($data->{primary_key})) {
928				$data->{primary_key} = 1;
929			}
930
931			if ($data->{primary_key} =~ m/^\d+$/) {
932				# primary_key can be a 1 based index
933				if ($data->{primary_key} > $sth->{NUM_OF_FIELDS}) {
934	#				die "primary_key ($data->{primary_key}) is out of bounds (".$sth->{NUM_OF_FIELDS}.")";
935					die "primary_key ($data->{primary_key}) is out of bounds";
936				}
937
938				$data->{primary_key} = $sth->{NAME}->[($data->{primary_key}-1)];
939			}
940
941			# Find the column names
942			for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
943				$col{$sth->{NAME}->[$i]} = $i;
944				push(@cols, $sth->{NAME}->[$i]);
945				$foundprimary = 1 if ($sth->{NAME}->[$i] eq $data->{primary_key});
946			}
947
948			unless ($foundprimary == 1) {
949				die "primary key ($data->{primary_key}) not found";
950			}
951
952			# Actually do the query!
953			try {
954				while ( my @row = $sth->fetchrow_array() ) {
955					if (exists($data->{chunked}) && defined($self->{output})) {
956						# chunk results ready to send
957						$self->output();
958						$result = {};
959						$rows = 0;
960					}
961					$rows++;
962					foreach (@cols) {
963						$result->{$row[$col{$data->{primary_key}}]}{$_} = $row[$col{$_}];
964					}
965					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
966						# Make output include the results
967						$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				$self->{output} = undef;
979
980			} catch {
981				die $sth->errstr;
982			};
983
984			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
985
986			# Check for any errors that might have terminated the loop early
987			if ( $sth->err() ) {
988				# Premature termination!
989				die $sth->errstr;
990			}
991		} catch {
992			$self->{output} = $self->make_error( $data->{id}, shift );
993		};
994
995	}
996
997	# Check if we got any errors
998	if (!defined($self->{output})) {
999		# Make output include the results
1000		$self->{output} = { rows => $rows, id => $data->{id}, result => $result, cols => [ @cols ], primary_key => $data->{primary_key} };
1001		if (exists($data->{chunked})) {
1002			$self->{output}->{last_chunk} = 1;
1003			$self->{output}->{chunked} = $data->{chunked};
1004		}
1005	}
1006
1007	# Finally, we clean up this statement handle
1008	if (defined($sth)) {
1009		$sth->finish();
1010	}
1011
1012	return;
1013}
1014
1015sub db_hasharray {
1016	# Get the dbi handle
1017	my $self = shift;
1018
1019	# Get the input structure
1020	my $data = shift;
1021
1022	# Variables we use
1023	my $sth = undef;
1024	my $result = {};
1025	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	my (@cols, %col);
1034
1035	SWITCH: {
1036
1037		if ($data->{begin_work}) {
1038			$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			if ($data->{no_cache}) {
1045				$sth = $self->{dbh}->prepare( $data->{sql} );
1046			} else {
1047				# We use the prepare_cached method in hopes of hitting a cached one...
1048				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
1049			}
1050
1051			# Check for undef'ness
1052			if (!defined($sth)) {
1053				die 'Did not get a statement handler';
1054			} else {
1055				# Execute the query
1056				try {
1057					$sth->execute( @{ $data->{placeholders} } );
1058				} catch {
1059					die ( defined($sth->errstr) ? $sth->errstr : $@ );
1060				};
1061				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1062			}
1063
1064			# The result hash
1065			my $newdata = {};
1066
1067			# Check the primary key
1068			my $foundprimary = 0;
1069
1070			if ($data->{primary_key} =~ m/^\d+$/) {
1071				# primary_key can be a 1 based index
1072				if ($data->{primary_key} > $sth->{NUM_OF_FIELDS}) {
1073#					die "primary_key ($data->{primary_key}) is out of bounds (".$sth->{NUM_OF_FIELDS}.")";
1074					die "primary_key ($data->{primary_key}) is out of bounds";
1075				}
1076
1077				$data->{primary_key} = $sth->{NAME}->[($data->{primary_key}-1)];
1078			}
1079
1080			# Find the column names
1081			for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
1082				$col{$sth->{NAME}->[$i]} = $i;
1083				push(@cols, $sth->{NAME}->[$i]);
1084				$foundprimary = 1 if ($sth->{NAME}->[$i] eq $data->{primary_key});
1085			}
1086
1087			unless ($foundprimary == 1) {
1088				die "primary key ($data->{primary_key}) not found";
1089			}
1090
1091			# Actually do the query!
1092			try {
1093				while ( my @row = $sth->fetchrow_array() ) {
1094					if (exists($data->{chunked}) && defined($self->{output})) {
1095						# chunk results ready to send
1096						$self->output();
1097						$result = {};
1098						$rows = 0;
1099					}
1100					$rows++;
1101					push(@{ $result->{$row[$col{$data->{primary_key}}]} }, @row);
1102					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1103						# Make output include the results
1104						$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				$self->{output} = undef;
1109
1110			} catch {
1111				die $sth->errstr;
1112			};
1113
1114			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1115
1116			# Check for any errors that might have terminated the loop early
1117			if ( $sth->err() ) {
1118				# Premature termination!
1119				die $sth->errstr;
1120			}
1121		} catch {
1122			$self->{output} = $self->make_error( $data->{id}, shift );
1123		};
1124
1125	}
1126
1127	# Check if we got any errors
1128	if (!defined($self->{output})) {
1129		# Make output include the results
1130		$self->{output} = { rows => $rows, result => $result, id => $data->{id}, cols => [ @cols ], primary_key => $data->{primary_key} };
1131		if (exists($data->{chunked})) {
1132			$self->{output}->{last_chunk} = 1;
1133			$self->{output}->{chunked} = $data->{chunked};
1134		}
1135	}
1136
1137	# Finally, we clean up this statement handle
1138	if (defined($sth)) {
1139		$sth->finish();
1140	}
1141
1142	return;
1143}
1144
1145sub db_array {
1146	# Get the dbi handle
1147	my $self = shift;
1148
1149	# Get the input structure
1150	my $data = shift;
1151
1152	# Variables we use
1153	my $sth = undef;
1154	my $result = [];
1155	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		if ($data->{begin_work}) {
1166			$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			if ($data->{no_cache}) {
1173				$sth = $self->{dbh}->prepare( $data->{sql} );
1174			} else {
1175				# We use the prepare_cached method in hopes of hitting a cached one...
1176				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
1177			}
1178
1179			# Check for undef'ness
1180			if (!defined($sth)) {
1181				die 'Did not get a statement handler';
1182			} else {
1183				# Execute the query
1184				try {
1185					$sth->execute( @{ $data->{placeholders} } );
1186				} catch {
1187					die ( defined($sth->errstr) ? $sth->errstr : $@ );
1188				};
1189				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1190			}
1191
1192			# The result hash
1193			my $newdata = {};
1194
1195			# Actually do the query!
1196			try {
1197				# There are warnings when joining a NULL field, which is undef
1198				no warnings;
1199
1200				while ( my @row = $sth->fetchrow_array() ) {
1201					if (exists($data->{chunked}) && defined($self->{output})) {
1202						# chunk results ready to send
1203						$self->output();
1204						$result = [];
1205						$rows = 0;
1206					}
1207					$rows++;
1208					if (exists($data->{separator})) {
1209						push(@{$result},join($data->{separator},@row));
1210					} else {
1211						push(@{$result},join(',',@row));
1212					}
1213					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1214						# Make output include the results
1215						$self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1216					}
1217				}
1218				# in the case that our rows == chunk
1219				$self->{output} = undef;
1220
1221			} catch {
1222				die $!;
1223				#die $sth->errstr;
1224			};
1225
1226			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1227
1228			# Check for any errors that might have terminated the loop early
1229			if ( $sth->err() ) {
1230				# Premature termination!
1231				die $sth->errstr;
1232			}
1233		} catch {
1234			$self->{output} = $self->make_error( $data->{id}, shift );
1235		};
1236
1237	}
1238
1239	# Check if we got any errors
1240	if (!defined($self->{output})) {
1241		# Make output include the results
1242		$self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1243		if (exists($data->{chunked})) {
1244			$self->{output}->{last_chunk} = 1;
1245			$self->{output}->{chunked} = $data->{chunked};
1246		}
1247	}
1248
1249	# Finally, we clean up this statement handle
1250	if (defined($sth)) {
1251		$sth->finish();
1252	}
1253
1254	return;
1255}
1256
1257sub db_arrayarray {
1258	# Get the dbi handle
1259	my $self = shift;
1260
1261	# Get the input structure
1262	my $data = shift;
1263
1264	# Variables we use
1265	my $sth = undef;
1266	my $result = [];
1267	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		if ($data->{begin_work}) {
1278			$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			if ($data->{no_cache}) {
1285				$sth = $self->{dbh}->prepare( $data->{sql} );
1286			} else {
1287				# We use the prepare_cached method in hopes of hitting a cached one...
1288				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
1289			}
1290
1291			# Check for undef'ness
1292			if (!defined($sth)) {
1293				die 'Did not get a statement handler';
1294			} else {
1295				# Execute the query
1296				try {
1297					$sth->execute( @{ $data->{placeholders} } );
1298				} catch {
1299					die ( defined($sth->errstr) ? $sth->errstr : $@ );
1300				};
1301				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1302			}
1303
1304			# The result hash
1305			my $newdata = {};
1306
1307			# Actually do the query!
1308			try {
1309				while ( my @row = $sth->fetchrow_array() ) {
1310					if (exists($data->{chunked}) && defined($self->{output})) {
1311						# chunk results ready to send
1312						$self->output();
1313						$result = [];
1314						$rows = 0;
1315					}
1316					$rows++;
1317					# There are warnings when joining a NULL field, which is undef
1318					push(@{$result},\@row);
1319					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1320						# Make output include the results
1321						$self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1322					}
1323				}
1324				# in the case that our rows == chunk
1325				$self->{output} = undef;
1326
1327			} catch {
1328				die $!;
1329				#die $sth->errstr;
1330			};
1331
1332			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1333
1334			# Check for any errors that might have terminated the loop early
1335			if ( $sth->err() ) {
1336				# Premature termination!
1337				die $sth->errstr;
1338			}
1339		} catch {
1340			$self->{output} = $self->make_error( $data->{id}, shift );
1341		};
1342
1343	}
1344
1345
1346	# Check if we got any errors
1347	if (!defined($self->{output})) {
1348		# Make output include the results
1349		$self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1350		if (exists($data->{chunked})) {
1351			$self->{output}->{last_chunk} = 1;
1352			$self->{output}->{chunked} = $data->{chunked};
1353		}
1354	}
1355
1356	# Finally, we clean up this statement handle
1357	if (defined($sth)) {
1358		$sth->finish();
1359	}
1360
1361	return;
1362}
1363
1364sub db_hash {
1365	# Get the dbi handle
1366	my $self = shift;
1367
1368	# Get the input structure
1369	my $data = shift;
1370
1371	# Variables we use
1372	my $sth = undef;
1373	my $result = {};
1374	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		if ($data->{begin_work}) {
1385			$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			if ($data->{no_cache}) {
1392				$sth = $self->{dbh}->prepare( $data->{sql} );
1393			} else {
1394				# We use the prepare_cached method in hopes of hitting a cached one...
1395				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
1396			}
1397
1398			# Check for undef'ness
1399			if (!defined($sth)) {
1400				die 'Did not get a statement handler';
1401			} else {
1402				# Execute the query
1403				try {
1404					$sth->execute( @{ $data->{placeholders} } );
1405				} catch {
1406					die ( defined($sth->errstr) ? $sth->errstr : $@ );
1407				};
1408				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1409			}
1410
1411			# The result hash
1412			my $newdata = {};
1413
1414			# Actually do the query!
1415			try {
1416
1417				my @row = $sth->fetchrow_array();
1418
1419				if (@row) {
1420					$rows = @row;
1421					for my $i ( 0 .. $sth->{NUM_OF_FIELDS}-1 ) {
1422						$result->{$sth->{NAME}->[$i]} = $row[$i];
1423					}
1424				}
1425
1426			} catch {
1427				die $sth->errstr;
1428			};
1429
1430			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1431
1432			# Check for any errors that might have terminated the loop early
1433			if ( $sth->err() ) {
1434				# Premature termination!
1435				die $sth->errstr;
1436			}
1437		} catch {
1438			$self->{output} = $self->make_error( $data->{id}, shift );
1439		};
1440
1441	}
1442
1443	# Check if we got any errors
1444	if (!defined($self->{output})) {
1445		# Make output include the results
1446		$self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1447	}
1448
1449	# Finally, we clean up this statement handle
1450	if (defined($sth)) {
1451		$sth->finish();
1452	}
1453
1454	return;
1455}
1456
1457sub db_keyvalhash {
1458	# Get the dbi handle
1459	my $self = shift;
1460
1461	# Get the input structure
1462	my $data = shift;
1463
1464	# Variables we use
1465	my $sth = undef;
1466	my $result = {};
1467	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		if ($data->{begin_work}) {
1478			$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			if ($data->{no_cache}) {
1485				$sth = $self->{dbh}->prepare( $data->{sql} );
1486			} else {
1487				# We use the prepare_cached method in hopes of hitting a cached one...
1488				$sth = $self->{dbh}->prepare_cached( $data->{sql} );
1489			}
1490
1491			# Check for undef'ness
1492			if (!defined($sth)) {
1493				die 'Did not get a statement handler';
1494			} else {
1495				# Execute the query
1496				try {
1497					$sth->execute( @{ $data->{placeholders} } );
1498				} catch {
1499					die ( defined($sth->errstr) ? $sth->errstr : $@ );
1500				};
1501				die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1502			}
1503
1504			# Actually do the query!
1505			try {
1506				while (my @row = $sth->fetchrow_array()) {
1507					if ($#row < 1) {
1508						die 'You need at least 2 columns selected for a keyvalhash query';
1509					}
1510					if (exists($data->{chunked}) && defined($self->{output})) {
1511						# chunk results ready to send
1512						$self->output();
1513						$result = {};
1514						$rows = 0;
1515					}
1516					$rows++;
1517					$result->{$row[0]} = $row[1];
1518					if (exists($data->{chunked}) && $data->{chunked} == $rows) {
1519						# Make output include the results
1520						$self->{output} = { rows => $rows, result => $result, id => $data->{id}, chunked => $data->{chunked} };
1521					}
1522				}
1523				# in the case that our rows == chunk
1524				$self->{output} = undef;
1525
1526			} catch {
1527				die $sth->errstr;
1528			};
1529
1530			die $self->{dbh}->errstr if ( $self->{dbh}->errstr );
1531
1532			# Check for any errors that might have terminated the loop early
1533			if ( $sth->err() ) {
1534				# Premature termination!
1535				die $sth->errstr;
1536			}
1537		} catch {
1538			$self->{output} = $self->make_error( $data->{id}, shift);
1539		};
1540
1541	}
1542
1543	# Check if we got any errors
1544	if (!defined($self->{output})) {
1545		# Make output include the results
1546		$self->{output} = { rows => $rows, result => $result, id => $data->{id} };
1547		if (exists($data->{chunked})) {
1548			$self->{output}->{last_chunk} = 1;
1549			$self->{output}->{chunked} = $data->{chunked};
1550		}
1551	}
1552
1553	# Finally, we clean up this statement handle
1554	if (defined($sth)) {
1555		$sth->finish();
1556	}
1557
1558	return;
1559}
1560
1561# Prints any output to STDOUT
1562sub output {
1563	my $self = shift;
1564
1565	# Get the data
1566	my $data = shift || undef;
1567
1568	unless (defined($data)) {
1569		$data = $self->{output};
1570		$self->{output} = undef;
1571		# TODO use this at some point
1572		$self->{error} = undef;
1573	}
1574
1575	# Freeze it!
1576	my $outdata = $self->{filter}->put( [ $data ] );
1577
1578	# Print it!
1579	print STDOUT @$outdata;
1580
1581	return;
1582}
1583
15841;
1585
1586__END__
1587
1588=head1 NAME
1589
1590POE::Component::EasyDBI::SubProcess - Backend of POE::Component::EasyDBI
1591
1592=head1 ABSTRACT
1593
1594This module is responsible for implementing the guts of POE::Component::EasyDBI.
1595The fork and the connection to the DBI.
1596
1597=head2 EXPORT
1598
1599Nothing.
1600
1601=head1 SEE ALSO
1602
1603L<POE::Component::EasyDBI>
1604
1605L<DBI>
1606
1607L<POE>
1608L<POE::Wheel::Run>
1609L<POE::Filter::Reference>
1610
1611L<POE::Component::DBIAgent>
1612L<POE::Component::LaDBI>
1613L<POE::Component::SimpleDBI>
1614
1615=head1 AUTHOR
1616
1617David Davis E<lt>xantus@cpan.orgE<gt>
1618
1619=head1 CREDITS
1620
1621Apocalypse E<lt>apocal@cpan.orgE<gt>
1622
1623=head1 COPYRIGHT AND LICENSE
1624
1625Copyright 2003-2004 by David Davis and Teknikill Software
1626
1627This library is free software; you can redistribute it and/or modify
1628it under the same terms as Perl itself.
1629
1630=cut
1631