my $mplx_trace = 0; # vim:ts=4 { package DBD::Multiplex; require DBI; require Carp; @EXPORT = (); $VERSION = substr(q$Revision: 1.2 $, 9,-1) -1; # $Id: Multiplex.pm,v 1.2 1999/07/29 00:11:57 timbo Exp $ # # Copyright (c) 1999, Tim Bunce & Thomas Kishel # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the Perl README file. $drh = undef; # holds driver handle once initialised $err = 0; # The $DBI::err value sub driver { return $drh if $drh; my($class, $attr) = @_; $class .= "::dr"; ($drh) = DBI::_new_drh($class, { 'Name' => 'Multiplex', 'Version' => $VERSION, 'Attribution' => 'DBD Multiplex by Tim Bunce & Thomas Kishel', }); return $drh; } # functions for calling a method for each child handle sub mplx_do_calls { # 'bottom-level' support function to do the calls my ($method, $handles, $wantarray, $opts) = (shift,shift,shift,shift); my $errh = $opts->{errh}; # handle to record error on my $stop = $opts->{stop_on}||'';# stop on first 'err' or 'ok' else do all my $trace= $opts->{trace}; my @results; my @errors; # sparse array paralleling $results[0..n] warn "mplx_do_calls $method for (@$handles)" if $trace; foreach my $h (@$handles) { # child handle push @results, ($wantarray) ? [ $h->$method(@_) ] : [ scalar $h->$method(@_) ]; if (my $err = $h->err) { my $errstr = $h->errstr; $errors[ @results-1 ] = [ $err, $errstr ]; DBI::set_err($errh, $err, $errstr) if $errh; warn "mplx_do_calls $h->$method ERROR: $err, $errstr" if $trace; last if $stop eq 'err'; } else { warn "mplx_do_calls $h->$method OK: @{ $results[-1] }" if $trace; last if $stop eq 'ok'; } } return (\@results, \@errors); } # XXX need variants/flags for # - call-each-till-first-success-then-stop # - call-all-return-first-success-else-error # - call-all-return-most-common-result (eg three-way-voting etc) # In some cases the default behaviour may depend on the method being called. # In others the application may want to override that for specific cases # (using \%attrib) sub mplx_method_all { my $method = shift; my $ph = shift; my $handles = $ph->{mplx_h} || die; my %opts = ( errh => $ph, stop_on => 'err', trace => $mplx_trace ); my ($results, $errors) = mplx_do_calls($method, $handles, wantarray, \%opts, @_); my $result = $results->[0]; # pick results to return return $result->[0] unless wantarray; return @$result; } } { package DBD::Multiplex::dr; # ====== DRIVER ====== $imp_data_size = 0; sub connect { my ($drh, $dsn, $user, $auth, $attr) = @_; # XXX parse $dsn and make multiple connects # need to define good syntax my $dbh1 = DBI->connect($dsn, $user, $auth, $attr); return DBI::set_err($drh, $DBI::err, $DBI::errstr) unless $dbh1; my ($this) = DBI::_new_dbh($drh, { Name => $dsn, User => $user, mplx_h => [ $dbh1 ], }); return $this; } sub disconnect_all { } sub DESTROY { } } { package DBD::Multiplex::db; # ====== DATABASE ====== $imp_data_size = 0; use strict; sub prepare { my $dbh = shift; my ($statement, $attribs) = @_; my $handles = $dbh->{mplx_h} || die; my %opts = ( errh => $dbh ); my ($results, $errors) = DBD::Multiplex::mplx_do_calls('prepare', $handles, wantarray, \%opts, @_); return if @$errors; my ($outer, $sth) = DBI::_new_sth($dbh, { 'Statement' => $statement, mplx_h => [ map { $_->[0] } @$results ], }); $outer; } # XXX replace this with dynamic info from updated DBI # XXX needs expanding manually in the short term use subs qw(FETCH STORE DESTROY); sub AUTOLOAD { my $method = $DBD::Multiplex::db::AUTOLOAD; $method =~ s/^DBD::Multiplex::db:://; warn "db AUTOLOAD $method(@_)" if $mplx_trace; my @results = (wantarray) ? ( DBD::Multiplex::mplx_method_all($method, @_)) : (scalar DBD::Multiplex::mplx_method_all($method, @_)); return $results[0] unless wantarray; return @results; } } { package DBD::Multiplex::st; # ====== STATEMENT ====== $imp_data_size = 0; use strict; # XXX replace this with dynamic info from updated DBI # XXX needs expanding manually in the short term use subs qw(execute fetch fetchrow_arrayref finish STORE FETCH DESTROY); sub AUTOLOAD { my $method = $DBD::Multiplex::st::AUTOLOAD; $method =~ s/^DBD::Multiplex::st:://; warn "st AUTOLOAD $method(@_)" if $mplx_trace; my @results = (wantarray) ? ( DBD::Multiplex::mplx_method_all($method, @_)) : (scalar DBD::Multiplex::mplx_method_all($method, @_)); return $results[0] unless wantarray; return @results; } } 1; __END__ =head1 NAME DBD::Multiplex - A DBI driver multiplexer =head1 SYNOPSIS use DBI; $dbh = DBI->connect("dbi:Multiplex:dsn", $user, $passwd); # See the DBI module documentation for full details =head1 DESCRIPTION To be written =cut