Author: timbo
Date: Mon Feb 12 05:34:03 2007
New Revision: 9082

Modified:
   dbi/trunk/lib/DBI/Gofer/Execute.pm
   dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm

Log:
Add initial dir_config configuration support for mod_perl transport.
Make DBI::Gofer::Export more OO.


Modified: dbi/trunk/lib/DBI/Gofer/Execute.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Execute.pm  (original)
+++ dbi/trunk/lib/DBI/Gofer/Execute.pm  Mon Feb 12 05:34:03 2007
@@ -11,6 +11,7 @@
 use warnings;
 
 use DBI;
+use DBI::Gofer::Request;
 use DBI::Gofer::Response;
 
 use base qw(DBI::Util::_accessor);
@@ -81,16 +82,14 @@
 
 
 sub _connect {
-    my $request = shift;
+    my ($self, $request) = @_;
 
     local $ENV{DBI_AUTOPROXY}; # limit the insanity
 
-    my $connect_args = $request->connect_args;
-    my ($dsn, $u, $p, $attr) = @$connect_args;
+    my ($dsn, $u, $p, $attr) = @{ $request->connect_args };
     # delete attributes we don't want to affect the server-side
     delete @{$attr}{qw(Profile InactiveDestroy Warn HandleError HandleSetErr 
TraceLevel Taint TaintIn TaintOut)};
     my $connect_method = 'connect_cached';
-    #$connect_method = 'connect';
 
     # XXX need way to limit/purge connect cache over time
     my $dbh = DBI->$connect_method($dsn, $u, $p, {
@@ -101,31 +100,32 @@
         RaiseError => 1,
         # ensure this connect_cached doesn't have the same args as the client
         # because that causes subtle issues if in the same process (ie 
transport=null)
-        dbi_go_execute_unique => rand(),
+        dbi_go_execute_unique => __PACKAGE__,
     });
-    die "NOT CONNECTED" if $dbh and not $dbh->{Active};
     #$dbh->trace(0);
     return $dbh;
 }
 
 
-sub _reset_dbh {
-    my ($dbh) = @_;
+sub reset_dbh {
+    my ($self, $dbh) = @_;
     $dbh->set_err(undef, undef); # clear any error state
 }
 
 
-sub _new_response_with_err {
-    my ($rv) = @_;
+sub new_response_with_err {
+    my ($self, $rv, $eval_error) = @_;
+    # capture err+errstr etc and merge in $eval_error ($@)
 
     my ($err, $errstr, $state) = ($DBI::err, $DBI::errstr, $DBI::state);
 
     # if we caught an exception and there's either no DBI error, or the
     # exception itself doesn't look like a DBI exception, then append the
     # exception to errstr
-    if ($@ and !$errstr || $@ !~ /^DBD::/) {
+    if ($eval_error and (!$errstr || $eval_error !~ /^DBD::/)) {
+        chomp $eval_error;
         $err ||= 1;
-        $errstr = ($errstr) ? "$errstr; $@" : $@;
+        $errstr = ($errstr) ? "$errstr; $eval_error" : $eval_error;
     }
 
     my $response = DBI::Gofer::Response->new({
@@ -141,21 +141,16 @@
 
 sub execute_request {
     my ($self, $request) = @_;
-    DBI->trace_msg("-----> execute_request\n");
+    # should never throw an exception
     my @warnings;
     local $SIG{__WARN__} = sub { push @warnings, @_ };
-    # guaranteed not to throw an exception
+    DBI->trace_msg("-----> execute_request\n");
     my $response = eval {
         ($request->is_sth_request)
-            ? execute_sth_request($request)
-            : execute_dbh_request($request);
+            ? $self->execute_sth_request($request)
+            : $self->execute_dbh_request($request);
     };
-    if ($@) {
-        chomp $@;
-        $response = DBI::Gofer::Response->new({
-            err => 1, errstr => $@, state  => '',
-        });
-    }
+    $response = $self->new_response_with_err(undef, $@) if $@;
     $response->warnings([EMAIL PROTECTED]) if @warnings;
     DBI->trace_msg("<----- execute_request\n");
     return $response;
@@ -163,10 +158,10 @@
 
 
 sub execute_dbh_request {
-    my $request = shift;
+    my ($self, $request) = @_;
     my $dbh;
     my $rv_ref = eval {
-        $dbh = _connect($request);
+        $dbh = $self->_connect($request);
         my $meth = $request->dbh_method_name;
         my $args = $request->dbh_method_args;
         my @rv = ($request->dbh_wantarray)
@@ -174,35 +169,35 @@
             : scalar $dbh->$meth(@$args);
         [EMAIL PROTECTED];
     };
-    my $response = _new_response_with_err($rv_ref);
+    my $response = $self->new_response_with_err($rv_ref, $@);
     if ($dbh) {
         $response->last_insert_id = $dbh->last_insert_id( @{ 
$request->dbh_last_insert_id_args })
             if $rv_ref && $request->dbh_last_insert_id_args;
-        _reset_dbh($dbh);
+        $self->reset_dbh($dbh);
     }
     if ($rv_ref and UNIVERSAL::isa($rv_ref->[0],'DBI::st')) {
-        my $rv = $rv_ref->[0];
         # dbh_method_call was probably a metadata method like table_info
         # that returns a statement handle, so turn the $sth into resultset
-        $response->sth_resultsets( _gather_sth_resultsets($rv, $request) );
-        $response->rv("(sth)");
+        my $rv = $rv_ref->[0];
+        $response->sth_resultsets( $self->gather_sth_resultsets($rv, $request) 
);
+        $response->rv("(sth)"); # don't try to return actual sth
     }
     return $response;
 }
 
 
 sub execute_sth_request {
-    my $request = shift;
+    my ($self, $request) = @_;
     my $dbh;
     my $sth;
 
     my $rv = eval {
-        $dbh = _connect($request);
+        $dbh = $self->_connect($request);
 
         my $meth = $request->dbh_method_name;
         my $args = $request->dbh_method_args;
         $sth = $dbh->$meth(@$args);
-        my $last = '(sth)'; # a true value
+        my $last = '(sth)'; # a true value (don't try to return actual sth)
 
         # execute methods on the sth, e.g., bind_param & execute
         for my $meth_call (@{ $request->sth_method_calls }) {
@@ -211,22 +206,22 @@
         }
         $last;
     };
-    my $response = _new_response_with_err($rv);
+    my $response = $self->new_response_with_err($rv, $@);
 
     # even if the eval failed we still want to try to gather attribute values
-    $response->sth_resultsets( _gather_sth_resultsets($sth, $request) ) if 
$sth;
+    $response->sth_resultsets( $self->gather_sth_resultsets($sth, $request) ) 
if $sth;
 
     # XXX would be nice to be able to support streaming of results
     # which would reduce memory usage and latency for large results
 
-    _reset_dbh($dbh) if $dbh;
+    $self->reset_dbh($dbh) if $dbh;
 
     return $response;
 }
 
 
-sub _gather_sth_resultsets {
-    my ($sth, $request) = @_;
+sub gather_sth_resultsets {
+    my ($self, $sth, $request) = @_;
     return eval {
         my $driver_name = $sth->{Database}{Driver}{Name};
         my $extra_sth_attr = $extra_attr{$driver_name}{sth} || [];
@@ -242,7 +237,7 @@
 
         my $rs_list = [];
         do {
-            my $rs = fetch_result_set($sth, $sth_attr);
+            my $rs = $self->fetch_result_set($sth, $sth_attr);
             push @$rs_list, $rs;
         } while $sth->more_results
              || $sth->{syb_more_results};
@@ -253,7 +248,7 @@
 
 
 sub fetch_result_set {
-    my ($sth, $extra_sth_attr) = @_;
+    my ($self, $sth, $extra_sth_attr) = @_;
     my %meta;
     while ( my ($attr,$use) = each %$extra_sth_attr ) {
         next unless $use;

Modified: dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       (original)
+++ dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       Mon Feb 12 05:34:03 2007
@@ -12,21 +12,69 @@
 our $VERSION = sprintf("0.%06d", q$Revision$ =~ /(\d+)/o);
 
 my $transport = __PACKAGE__->new();
-my $executor  = DBI::Gofer::Execute->new();
 
+my %executor_configs;
+my %executor_cache;
 
-sub handler {
+
+sub handler ($$) {
+    my $self = shift;
     my $r = shift;
-    my $r_dir_config = $r->dir_config; # cache it as it's relatively expensive
 
-    $r->read(my $frozen_request, $r->header_in('Content-length'));
+    my $executor = $executor_cache{ $r->uri } ||= $self->executor_for_uri($r);
 
+    $r->read(my $frozen_request, $r->header_in('Content-length'));
     my $request = $transport->thaw_data($frozen_request);
+
     my $response = $executor->execute_request( $request );
 
     my $frozen_response = $transport->freeze_data($response);
-
     print $frozen_response;
 
     return Apache::Constants::OK;
 }
+
+
+sub executor_for_uri {
+    my ($self, $r) = @_;
+    my $uri = $r->uri;
+    my $r_dir_config = $r->dir_config;
+
+    my @location_configs = $r_dir_config->get('GoferConfig');
+    push @location_configs, 'default' unless @location_configs;
+
+    # merge all configs for this location in sequence ('closest' last)
+    my %merged_config;
+    for my $config_name ( @location_configs ) {
+        my $config = $executor_configs{$config_name};
+        if (!$config) {
+            # die if an unknown config is requested but not defined
+            # (don't die for 'default' unless it was explicitly requested)
+            die "$uri: GoferConfig '$config_name' not defined"
+                unless $config_name eq 'default'
+                   and !$r_dir_config->get('GoferConfig');
+            next;
+        }
+        for my $type (qw(require default force)) {
+            my $type_config = $config->{$type};
+            next if !$type_config or !%$type_config;
+            warn "$uri: GoferConfig $config_name $type (@{[ %$type_config 
]})\n";
+            my $merged = $merged_config{$type} ||= {};
+            $merged->{$_} = $type_config->{$_} for keys %$type_config;
+        }
+    }
+    my $executor = DBI::Gofer::Execute->new(\%merged_config);
+    return $executor;
+}
+
+
+sub configuration { # one-time setup from httpd.conf
+    my ($self, $configs) = @_;
+    %executor_configs = %$configs;
+}
+
+1;
+
+__END__
+
+also need a CGI/FastCGI transport

Reply via email to