NAME
POE::Component::LaDBI - POE Component that spawns a perl subprocess to handle non-blocking access to the DBI API.
SYNOPSIS
use POE::Component::LaDBI;
$h->{ladbi} = POE::Component::LaDBI->create ( Alias => 'ladbi' );
$k->post(ladbi => 'connect', SuccessEvent => 'connected', FailureEvent => 'connect_failed', Args => ["dbi:Pg:dbname=$dbname", $user, $passwd]);
$k->post(ladbi => 'disconnect', SuccessEvent => 'disconnected', FailureEvent => 'disconnect_failed', HandleId => $dbh_id);
$k->post('ladbi' => 'prepare', SuccessEvent => 'prepared', FailureEvent => 'prepare_failed', HandleId => $dbh_id, Args => [$sql]);
$k->post('ladbi' => 'finish', SuccessEvent => 'finished', FailureEvent => 'finish_failed', HandleId => $sth_id);
$k->post('ladbi' => 'execute', SuccessEvent => 'executed', FailureEvent => 'execute_failed', HandleId => $sth_id, Args => [$bind_val0, $bind_val1, ...]);
$k->post('ladbi' => 'rows', SuccessEvent => 'rows_found', FailureEvent => 'rows_failed', HandleId => $sth_id);
$k->post('ladbi' => 'fetchrow', SuccessEvent => 'row_fetched', FailureEvent => 'fetch_failed', HandleId => $sth_id);
$k->post('ladbi' => 'fetchrow_hash', SuccessEvent => 'row_fetched', FailureEvent => 'fetch_failed', HandleId => $sth_id);
$k->post('ladbi' => 'fetchall', SuccessEvent => 'all_fetched', FailureEvent => 'fetchall_failed', HandleId => $sth_id, Args => [ @optional_indicies ] );
$k->post('ladbi' => 'fetchall_hash', SuccessEvent => 'all_fetched', FailureEvent => 'fetchall_failed', HandleId => $sth_id, Args => [ @optional_keys ] );
$k->post('ladbi' => 'ping', SuccessEvent => 'check_ping_results', FailureEvent => 'ping_failed', HandleId => $dbh_id);
$k->post('ladbi' => 'do', SuccessEvent => 'check_do_results', FailureEvent => 'do_failed', HandleId => $dbh_id, Args => [ $sql, $attr_hashref, @bind_values ]);
$k->post('ladbi' => 'begin_work', SuccessEvent => 'check_transactions_enabled', FailureEvent => 'begin_work_failed', HandleId => $dbh_id);
$k->post('ladbi' => 'commit', SuccessEvent => 'check_commit', FailureEvent => 'commit_failed', HandleId => $dbh_id);
$k->post('ladbi' => 'rollback', SuccessEvent => 'check_rollback', FailureEvent => 'rollback_failed', HandleId => $dbh_id);
$k->post('ladbi' => 'selectall', SuccessEvent => 'check_results', FailureEvent => 'selectall_failed', HandleId => $dbh_id, Args => [ $sql ]);
$k->post('ladbi' => 'selectall_hash', SuccessEvent => 'check_results', FailureEvent => 'selectall_failed', HandleId => $dbh_id, Args => [ $sql, $key_field ]);
$k->post('ladbi' => 'selectcol', SuccessEvent => 'check_results', FailureEvent => 'selectcol_failed', HandleId => $dbh_id, Args => [ $sql, $attr_hashref ]);
$k->post('ladbi' => 'selectrow', SuccessEvent => 'check_results', FailureEvent => 'selectrow_failed', HandleId => $dbh_id, Args => [ $sql, $attr_hashref ]);
$k->post('ladbi' => 'quote', SuccessEvent => 'use_quote_results', FailureEvent => 'quote_failed', HandleId => $dbh_id, Args => [ $value ]);
DESCRIPTION
All events have the same handler. This is because the handler merely creates a request message and sends it to the perl sub-process which is doing the actuall DBI calls.
The handler takes the same arguments. Not all events use the all the argument fields. The arguments fields/keys are:
SuccessEvent
-
All
POE::Component::LaDBI
events requireSuccessEvent
.The
SuccessEvent
is fired off if the DBI call returned successfully. "Returning Successfully" means that no exeption was called (as theRaiseError
attribute might cause) AND that the return value from the DBI call was adefined()
value.However a
SuccessEvent
does not mean that the SQL completed in what you might commonly think of as a successful manner. For instance, a SELECT statement might not return anything. In that case, the returned data will be an empty array ref. Further, somecalls, while well formed, will return an error because that feature (like transactions ala$dbh->begin_work
) are not implemented in your DBI driver.The handler for the
SuccessEvent
is invoked the following arguments.sub success_event_handler { ... my ($handle_id, $datatype, $data) = @_[ARG0,ARG1,ARG2]; ... }
$handle_id
-
This is a cookie representing a DBI handle object. There are two kinds of DBI handle objects, database handles and statement handles. You use
$handle_id
to refer to a DBI handle object you want to call methods on.Both,
connect
andprepare
generate new handle ids. TheSuccessEvent
called by theconnect
handler is passed a new database handle id. The same is true forprepare
but the$handle_id
represents a DBI statement handler object instead.All other
POE::Component::LaDBI
events just return the$handle_id
that was used to invoke them. For exmple, theexecute
event requires a statement handle id. When theSuccessEvent
for thatexecute
is called it just returns the same statement handle id. $datatype
-
The value of
$datatype
is a string that tells you what kind of data structure is contained in$data
.$data
can be a return code 'RC', a return value 'RV', an array ref of array refs 'TABLE', a hash ref of hash refs 'NAMED_TABLE', an array ref representing a row 'ROW', a hash ref representing a row 'NAMED_ROW', an array ref representing a column 'COLUMN', or a string meant to represent a part of a SQL statement 'SQL' (like from$dbh-
quote()>).Here is a some rough descriptions of the format of the values of
$datatype
:TABLE
-
Data is an array ref of array refs to scalars.
Data = [ [row0col0, row0col1, ...], [row1col0, row1col1, ...], ... ]
NAMED_TABLE
-
This one is odd. See the description of
selectall_hashref()
in DBI. For*_hashref()
calls in DBI you have to provide the database table field which will be the hash key into this hash table. The values corresponding to each key is a hash of the rows returned from the select or fetch. I did not invent this and do not quite understand why is is this way.Data = { row0colX_val => {col0_name => row0_val, col1_name => row0_val, ...}, row1colX_val => {col0_name => row1_val, col1_name => row1_val, ...}, ... }
ROW
-
Data is an array ref of scalars.
Data = [ elt0, elt1, ... ]
NAMED_ROW
-
Data is an hash ref containing name-value pairs of each data item in the row; the name is the column name, the value is the column value.
Data = { col0_name => elt0, col1_name => elt1, ... }
COLUMN
-
Data = [ elt0, elt1, ... ]
RC
-
Return code is a scalar valude returned from the DBI call.
Data = $rc
RV
-
Return Value is a scalar value returned from the DBI call.
Data = $rv
SQL
-
This is the data type for the return value from DBI::quote() call.
Data = $sql_string
$data
-
This is scalar value or a reference to a more complex data structure (see above).
Some calls may return successfully with $data a defined value, yet $data may be a "zero-but-true" value. For example look at the DBI description of
$dbh->ping
.
FailureEvent
-
All
POE::Component::LaDBI
events requireFailureEvent
.When
FailureEvent
is invoked, it can be for several different reasons.One common reason is that your SQL is malformed. This one gets me all the time.
Another common reason is that you did not provide the correct arguements to the
POE::Component::LaDBI
event. The arguements you provide in theArgs
field are passed literally to the DBI call. Bad arguements, or the wrong number, will cause the DBI call to throw an execption.Another reason might be that you are using an invalid
$handle_id
. The$handle_id
might be invalid because it is garbled, or it has be deleted due to a previous use ofdisconnect
orfinish
.Finnally, it might just be that something bad happened internally to
POE::Component::LaDBI::Engine
orDBI
itself.A
FailureEvent
is provided the following arguments.sub failure_event { ... my ($handle_id, $errtype, $errstr, $err) = @_[ARG0..ARG3]; ... }
The argument
$handle_id
is eitherundef
, a statement handle, or a database handle, depending on the type of requested event.The argument
$errtype
can be 'SHUTDOWN', 'ERROR', 'EXCEPTION', 'INVALID_REQUEST'.The
$errtype eq 'EXCEPTION'
results from the fact that all the actual DBI command are wrapped in andeval {}
and the$@
checked. In this case,$errstr
is set to$@
and$err
is undefined.The
$errtype eq 'ERROR'
results from the fact that the results of the DBI command is checked forundef
. Then the appropriate DBI$DBI::errstr
and$DBI::err
are passed back as$errstr
and$err
respectively.The
$errtype eq 'SHUTDOWN'
results from abnomal termination of thePOE::Component::LaDBI
session.$err
is set to the cause and$errstr
is set to a string explanation of the cause.$errstr
can be 'signal' or a POE::Wheel::Run operation. And$err
is set to the signal type or wheel operation string value of$!
.The
$errtype eq 'INVALID_REQUEST'
means thatPOE::Component::LaDBI
failed to instantiate aPOE::Component::LaDBI::Request
object. Hence, nothing was sent to the sub-process runningPOE::Component::LaDBI::Engine
for execution.The
$errtype eq 'INVALIE_HANDLE_ID'
means that aPOE::Component::LaDBI::Request
object was create and the message sent to the sub-process, but thePOE::Component::LaDBI::Engine
object in the sub-process did not have a record of that handle id. HandleId
-
This is either a database handle id, a statement handle id to use, or
undef
if a DBI handle type is not required for the LaDBI command. Args
-
This is always an array ref. The array is exact the arguemnts to pass to the appropriate DBI method. You are required to pass the correct ones, else you will recieve a
FailureEvent
, probably ofEXCEPTION
type.
EXAMPLE
use strict;
use warnings;
use POE;
use POE::Component::LaDBI;
my $LADBI_ALIAS = 'ladbi';
my $DSN = 'dbi:Pg:dbname=test';
my $USER = 'dbuser';
my $PASSWD = 'secret';
my $SQL = "SELECT * FROM contacts";
POE::Component::LaDBI->create(Alias => $LADBI_ALIAS)
or die "Failed to create a POE::Component::LaDBI session\n";
POE::Session->create
(args => [$DSN, $USER, $PASSWD, $SQL],
inline_states =>
{
_start => sub {
my ($dsn, $user, $passwd, $sql) = @_[ARG0..ARG3];
print STDERR "_start: args=($dsn,$user,$passwd)\n";
$_[HEAP]->{sql} = $sql;
$_[KERNEL]->post($LADBI_ALIAS => 'connect',
SuccessEvent => 'selectall',
FailureEvent => 'dberror',
Args => [ $dsn, $user, $passwd ]);
},
_stop => sub {
print STDERR "_stop: client session ended.\n";
},
shutdown => sub {
print STDERR "shutdown: sending shutodnw to $LADBI_ALIAS\n";
$_[KERNEL]->post($LADBI_ALIAS => 'shutdown');
},
selectall => sub {
my ($dbh_id, $datatype, $data) = @_[ARG0..ARG2];
$_[HEAP]->{dbh_id} = $dbh_id;
print STDERR "selectall: dbh_id=$dbh_id\n";
$_[KERNEL]->post($LADBI_ALIAS => 'selectall',
SuccessEvent => 'display_results',
FailureEvent => 'dberror',
HandleId => $dbh_id,
Args => [ $_[HEAP]->{sql} ] );
},
display_results => sub {
my ($dbh_id, $datatype, $data) = @_[ARG0..ARG2];
print STDERR "display_results: dbh_id=$dbh_id\n";
for my $row ( @$data ) {
print join(',', @$row), "\n";
}
$_[KERNEL]->post($LADBI_ALIAS => 'disconnect',
SuccessEvent => 'shutdown',
FailureEvent => 'dberror',
HandleId => $dbh_id);
},
dberror => sub {
my ($dbh_id, $errtype, $errstr, $err) = @_[ARG0..ARG3];
print STDERR "dberror: dbh_id = $dbh_id\n";
print STDERR "dberror: errtype = $errtype\n";
print STDERR "dberror: errstr = $errstr\n";
print STDERR "dberror: err = $err\n" if $errtype eq 'ERROR';
$_[KERNEL]->yield('shutdown');
}
} #end: inline_states
) #end: POE::Session->create()
or die "Failed to instantiate POE::Session\n";
$poe_kernel->run();
exit 0;
__END__
DEBUGGING
If the environment variable LADBI_DEBUG is set to a true value (perl-wise), or the ':DEBUG' symbol is in the use statement import list (eg use POE::Component::LaDBI qw(:DEBUG)
), then debugging will be turned on.
When debuggind is turned on, POE::Component::LaDBI->run() will open and log messages to a file whos name is indicated in $POE::Component::LaDBI::DEBUG_FILE.
The debug log is set to 'ladbi_run.log' by default.
EXPORT
None by default.
AUTHOR
Sean M. Egan, <seanegan@bigfoot.com>
SEE ALSO
perl, POE, DBI, POE::Component::LaDBI::Engine, POE::Component::LaDBI::Request, POE::Component::LaDBI::Response