=head1 NAME
AnyEvent::DBI::Slave - implement AnyEvent::DBI child/server processes
=head1 SYNOPSIS
# this module is normally loaded automatically
=head1 DESCRIPTION
This module contains the code that implements the DBI server part of
C<AnyEvent::DBI>. It is normally loaded automatically into each child
process, but can be loaded explicitly to save memory or startup time
(search for C<AnyEvent::DBI::Slave> in the L<AnyEvent::DBI> manpage).
=cut
package AnyEvent::DBI::Slave;
use common::sense;
use DBI ();
use Convert::Scalar ();
use CBOR::XS ();
use AnyEvent ();
our $VERSION = '3.04';
# this is the forked server code, could/should be bundled as it's own file
our $DBH;
our $STH;
sub req_pid {
[1, $$]
}
sub req_open {
my (undef, $dbi, $user, $pass, %attr) = @{+shift};
$DBH = DBI->connect ($dbi, $user, $pass, \%attr) or die $DBI::errstr;
[1, 1]
}
sub req_attr {
my (undef, $attr_name, @attr_val) = @{+shift};
$DBH->{$attr_name} = $attr_val[0]
if @attr_val;
[1, $DBH->{$attr_name}]
}
sub req_exec {
my (undef, $st, @args) = @{+shift};
$STH = $DBH->prepare_cached ($st, undef, 1)
or die [$DBI::errstr];
my $rv = $STH->execute (@args)
or die [$STH->errstr];
[1, $STH->{NUM_OF_FIELDS} ? $STH->fetchall_arrayref : undef, $rv]
}
sub req_stattr {
my (undef, $attr_name) = @{+shift};
[1, $STH->{$attr_name}]
}
sub req_begin_work {
[1, $DBH->begin_work || die [$DBI::errstr]]
}
sub req_commit {
[1, $DBH->commit || die [$DBI::errstr]]
}
sub req_rollback {
[1, $DBH->rollback || die [$DBI::errstr]]
}
sub req_func {
my (undef, $arg_string, $function) = @{+shift};
my @args = eval $arg_string;
die "error evaling \$dbh->func() arg_string: $@"
if $@;
my $rc = $DBH->func (@args, $function);
return [1, $rc, $DBI::err, $DBI::errstr];
}
sub serve($$) {
my ($fork_fh, $version, $fh) = @_;
$0 = "dbi slave";
close $fork_fh;
if ($VERSION != $version) {
Convert::Scalar::write_all $fh, CBOR::XS::encode_cbor
[undef, "AnyEvent::DBI version mismatch ($VERSION vs. $version)"];
return;
}
eval {
my $cbor = new CBOR::XS;
my $rbuf;
while (Convert::Scalar::extend_read $fh, $rbuf, 16000) {
for my $req ($cbor->incr_parse_multiple ($rbuf)) {
my $wbuf = eval { CBOR::XS::encode_cbor $req->[0]($req) };
$wbuf = CBOR::XS::encode_cbor [undef, ref $@ ? ("$@->[0]", $@->[1]) : ("$@", 1)]
if $@;
Convert::Scalar::write_all $fh, $wbuf
or die "unable to write results";
}
}
};
}
=head1 SEE ALSO
L<AnyEvent::DBI>.
=head1 AUTHOR AND CONTACT
Marc Lehmann <schmorp@schmorp.de> (current maintainer)
http://home.schmorp.de/
Adam Rosenstein <adam@redcondor.com>
http://www.redcondor.com/
=cut
1