[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3-unattended/var/se3/unattended/install/linuxaux/opt/perl/lib/site_perl/5.10.0/i586-linux-thread-multi/DBD/ -> Gofer.pm (source)

   1  {
   2      package DBD::Gofer;
   3  
   4      use strict;
   5  
   6      require DBI;
   7      require DBI::Gofer::Request;
   8      require DBI::Gofer::Response;
   9      require Carp;
  10  
  11      our $VERSION = sprintf("0.%06d", q$Revision: 11565 $ =~ /(\d+)/o);
  12  
  13  #   $Id: Gofer.pm 11565 2008-07-22 20:17:33Z timbo $
  14  #
  15  #   Copyright (c) 2007, Tim Bunce, Ireland
  16  #
  17  #   You may distribute under the terms of either the GNU General Public
  18  #   License or the Artistic License, as specified in the Perl README file.
  19  
  20  
  21  
  22      # attributes we'll allow local STORE
  23      our %xxh_local_store_attrib = map { $_=>1 } qw(
  24          Active
  25          CachedKids
  26          Callbacks
  27          DbTypeSubclass
  28          ErrCount Executed
  29          FetchHashKeyName
  30          HandleError HandleSetErr
  31          InactiveDestroy
  32          PrintError PrintWarn
  33          Profile
  34          RaiseError
  35          RootClass
  36          ShowErrorStatement
  37          Taint TaintIn TaintOut
  38          TraceLevel
  39          Warn
  40          dbi_quote_identifier_cache
  41          dbi_connect_closure
  42          dbi_go_execute_unique
  43      );
  44      our %xxh_local_store_attrib_if_same_value = map { $_=>1 } qw(
  45          Username
  46          dbi_connect_method
  47      );
  48  
  49      our $drh = undef;    # holds driver handle once initialised
  50      our $methods_already_installed;
  51  
  52      sub driver{
  53          return $drh if $drh;
  54  
  55          DBI->setup_driver('DBD::Gofer');
  56  
  57          unless ($methods_already_installed++) {
  58              my $opts = { O=> 0x0004 }; # IMA_KEEP_ERR
  59              DBD::Gofer::db->install_method('go_dbh_method', $opts);
  60              DBD::Gofer::st->install_method('go_sth_method', $opts);
  61              DBD::Gofer::st->install_method('go_clone_sth',  $opts);
  62              DBD::Gofer::db->install_method('go_cache',      $opts);
  63              DBD::Gofer::st->install_method('go_cache',      $opts);
  64          }
  65  
  66          my($class, $attr) = @_;
  67          $class .= "::dr";
  68          ($drh) = DBI::_new_drh($class, {
  69              'Name' => 'Gofer',
  70              'Version' => $VERSION,
  71              'Attribution' => 'DBD Gofer by Tim Bunce',
  72          });
  73  
  74          $drh;
  75      }
  76  
  77  
  78      sub CLONE {
  79          undef $drh;
  80      }
  81  
  82  
  83      sub go_cache {
  84          my $h = shift;
  85          $h->{go_cache} = shift if @_;
  86          # return handle's override go_cache, if it has one
  87          return $h->{go_cache} if defined $h->{go_cache};
  88          # or else the transports default go_cache
  89          return $h->{go_transport}->{go_cache};
  90      }
  91  
  92  
  93      sub set_err_from_response { # set error/warn/info and propagate warnings
  94          my $h = shift;
  95          my $response = shift;
  96          if (my $warnings = $response->warnings) {
  97              warn $_ for @$warnings;
  98          }
  99          return $h->set_err($response->err_errstr_state);
 100      }
 101  
 102  
 103      sub install_methods_proxy {
 104          my ($installed_methods) = @_;
 105          while ( my ($full_method, $attr) = each %$installed_methods ) {
 106              # need to install both a DBI dispatch stub and a proxy stub
 107              # (the dispatch stub may be already here due to local driver use)
 108  
 109              DBI->_install_method($full_method, "", $attr||{})
 110                  unless defined &{$full_method};
 111  
 112              # now install proxy stubs on the driver side
 113              $full_method =~ m/^DBI::(\w\w)::(\w+)$/
 114                  or die "Invalid method name '$full_method' for install_method";
 115              my ($type, $method) = ($1, $2);
 116              my $driver_method = "DBD::Gofer::$type}::$method}";
 117              next if defined &{$driver_method};
 118              my $sub;
 119              if ($type eq 'db') {
 120                  $sub = sub { return shift->go_dbh_method(undef, $method, @_) };
 121              }
 122              else {
 123                  $sub = sub { shift->set_err($DBI::stderr, "Can't call \$$type}h->$method when using DBD::Gofer"); return; };
 124              }
 125              no strict 'refs';
 126              *$driver_method = $sub;
 127          }
 128      }
 129  }
 130  
 131  
 132  {   package DBD::Gofer::dr; # ====== DRIVER ======
 133  
 134      $imp_data_size = 0;
 135      use strict;
 136  
 137      sub connect_cached {
 138          my ($drh, $dsn, $user, $auth, $attr)= @_;
 139          $attr ||= {};
 140          return $drh->SUPER::connect_cached($dsn, $user, $auth, {
 141              (%$attr),
 142              go_connect_method => $attr->{go_connect_method} || 'connect_cached',
 143          });
 144      }
 145  
 146  
 147      sub connect {
 148          my($drh, $dsn, $user, $auth, $attr)= @_;
 149          my $orig_dsn = $dsn;
 150  
 151          # first remove dsn= and everything after it
 152          my $remote_dsn = ($dsn =~ s/;?\bdsn=(.*)$// && $1)
 153              or return $drh->set_err($DBI::stderr, "No dsn= argument in '$orig_dsn'");
 154  
 155          if ($attr->{go_bypass}) { # don't use DBD::Gofer for this connection
 156              # useful for testing with DBI_AUTOPROXY, e.g., t/03handle.t
 157              return DBI->connect($remote_dsn, $user, $auth, $attr);
 158          }
 159  
 160          my %go_attr;
 161          # extract any go_ attributes from the connect() attr arg
 162          for my $k (grep { /^go_/ } keys %$attr) {
 163              $go_attr{$k} = delete $attr->{$k};
 164          }
 165          # then override those with any attributes embedded in our dsn (not remote_dsn)
 166          for my $kv (grep /=/, split /;/, $dsn, -1) {
 167              my ($k, $v) = split /=/, $kv, 2;
 168              $go_attr{ "go_$k" } = $v;
 169          }
 170  
 171          if (not ref $go_attr{go_policy}) { # if not a policy object already
 172              my $policy_class = $go_attr{go_policy} || 'classic';
 173              $policy_class = "DBD::Gofer::Policy::$policy_class"
 174                  unless $policy_class =~ /::/;
 175              _load_class($policy_class)
 176                  or return $drh->set_err($DBI::stderr, "Can't load $policy_class: $@");
 177              # replace policy name in %go_attr with policy object
 178              $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
 179                  or return $drh->set_err($DBI::stderr, "Can't instanciate $policy_class: $@");
 180          }
 181          # policy object is left in $go_attr{go_policy} so transport can see it
 182          my $go_policy = $go_attr{go_policy};
 183  
 184          if ($go_attr{go_cache} and not ref $go_attr{go_cache}) { # if not a cache object already
 185              my $cache_class = $go_attr{go_cache};
 186              $cache_class = "DBI::Util::CacheMemory" if $cache_class eq '1';
 187              _load_class($cache_class)
 188                  or return $drh->set_err($DBI::stderr, "Can't load $cache_class $@");
 189              $go_attr{go_cache} = eval { $cache_class->new() }
 190                  or $drh->set_err(0, "Can't instanciate $cache_class: $@"); # warning
 191          }
 192  
 193          # delete any other attributes that don't apply to transport
 194          my $go_connect_method = delete $go_attr{go_connect_method};
 195  
 196          my $transport_class = delete $go_attr{go_transport}
 197              or return $drh->set_err($DBI::stderr, "No transport= argument in '$orig_dsn'");
 198          $transport_class = "DBD::Gofer::Transport::$transport_class"
 199              unless $transport_class =~ /::/;
 200          _load_class($transport_class)
 201              or return $drh->set_err($DBI::stderr, "Can't load $transport_class: $@");
 202          my $go_transport = eval { $transport_class->new(\%go_attr) }
 203              or return $drh->set_err($DBI::stderr, "Can't instanciate $transport_class: $@");
 204  
 205          my $request_class = "DBI::Gofer::Request";
 206          my $go_request = eval {
 207              my $go_attr = { %$attr };
 208              # XXX user/pass of fwd server vs db server ? also impact of autoproxy
 209              if ($user) {
 210                  $go_attr->{Username} = $user;
 211                  $go_attr->{Password} = $auth;
 212              }
 213              # delete any attributes we can't serialize (or don't want to)
 214              delete @{$go_attr}{qw(Profile HandleError HandleSetErr Callbacks)};
 215              # delete any attributes that should only apply to the client-side
 216              delete @{$go_attr}{qw(RootClass DbTypeSubclass)};
 217  
 218              $go_connect_method ||= $go_policy->connect_method($remote_dsn, $go_attr) || 'connect';
 219              $request_class->new({
 220                  dbh_connect_call => [ $go_connect_method, $remote_dsn, $user, $auth, $go_attr ],
 221              })
 222          } or return $drh->set_err($DBI::stderr, "Can't instanciate $request_class: $@");
 223  
 224          my ($dbh, $dbh_inner) = DBI::_new_dbh($drh, {
 225              'Name' => $dsn,
 226              'USER' => $user,
 227              go_transport => $go_transport,
 228              go_request => $go_request,
 229              go_policy => $go_policy,
 230          });
 231  
 232          # mark as inactive temporarily for STORE. Active not set until connected() called.
 233          $dbh->STORE(Active => 0);
 234  
 235          # should we ping to check the connection
 236          # and fetch dbh attributes
 237          my $skip_connect_check = $go_policy->skip_connect_check($attr, $dbh);
 238          if (not $skip_connect_check) {
 239              if (not $dbh->go_dbh_method(undef, 'ping')) {
 240                  return undef if $dbh->err; # error already recorded, typically
 241                  return $dbh->set_err($DBI::stderr, "ping failed");
 242              }
 243          }
 244  
 245          return $dbh;
 246      }
 247  
 248      sub _load_class { # return true or false+$@
 249          my $class = shift;
 250          (my $pm = $class) =~ s{::}{/}g;
 251          $pm .= ".pm";
 252          return 1 if eval { require $pm };
 253          delete $INC{$pm}; # shouldn't be needed (perl bug?) and assigning undef isn't enough
 254          undef; # error in $@
 255      }
 256  
 257  }
 258  
 259  
 260  {   package DBD::Gofer::db; # ====== DATABASE ======
 261      $imp_data_size = 0;
 262      use strict;
 263      use Carp qw(carp croak);
 264  
 265      my %dbh_local_store_attrib = %DBD::Gofer::xxh_local_store_attrib;
 266  
 267      sub connected {
 268          shift->STORE(Active => 1);
 269      }
 270  
 271      sub go_dbh_method {
 272          my $dbh = shift;
 273          my $meta = shift;
 274          # @_ now contains ($method_name, @args)
 275  
 276          my $request = $dbh->{go_request};
 277          $request->init_request([ wantarray, @_ ], $dbh);
 278          ++$dbh->{go_request_count};
 279  
 280          my $go_policy = $dbh->{go_policy};
 281          my $dbh_attribute_update = $go_policy->dbh_attribute_update();
 282          $request->dbh_attributes( $go_policy->dbh_attribute_list() )
 283              if $dbh_attribute_update eq 'every'
 284              or $dbh->{go_request_count}==1;
 285  
 286          $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
 287              if $meta->{go_last_insert_id_args};
 288  
 289          my $transport = $dbh->{go_transport}
 290              or return $dbh->set_err($DBI::stderr, "Not connected (no transport)");
 291  
 292          local $transport->{go_cache} = $dbh->{go_cache}
 293              if defined $dbh->{go_cache};
 294  
 295          my ($response, $retransmit_sub) = $transport->transmit_request($request);
 296          $response ||= $transport->receive_response($request, $retransmit_sub);
 297          $dbh->{go_response} = $response
 298              or die "No response object returned by $transport";
 299  
 300          die "response '$response' returned by $transport is not a response object"
 301              unless UNIVERSAL::isa($response,"DBI::Gofer::Response");
 302  
 303          if (my $dbh_attributes = $response->dbh_attributes) {
 304  
 305              # XXX installed_methods piggbacks on dbh_attributes for now
 306              if (my $installed_methods = delete $dbh_attributes->{dbi_installed_methods}) {
 307                  DBD::Gofer::install_methods_proxy($installed_methods)
 308                      if $dbh->{go_request_count}==1;
 309              }
 310  
 311              # XXX we don't STORE here, we just stuff the value into the attribute cache
 312              $dbh->{$_} = $dbh_attributes->{$_}
 313                  for keys %$dbh_attributes;
 314          }
 315  
 316          my $rv = $response->rv;
 317          if (my $resultset_list = $response->sth_resultsets) {
 318              # dbh method call returned one or more resultsets
 319              # (was probably a metadata method like table_info)
 320              #
 321              # setup an sth but don't execute/forward it
 322              my $sth = $dbh->prepare(undef, { go_skip_prepare_check => 1 });
 323              # set the sth response to our dbh response
 324              (tied %$sth)->{go_response} = $response;
 325              # setup the sth with the results in our response
 326              $sth->more_results;
 327              # and return that new sth as if it came from original request
 328              $rv = [ $sth ];
 329          }
 330          elsif (!$rv) { # should only occur for major transport-level error
 331              #carp("no rv in response { @{[ %$response ]} }");
 332              $rv = [ ];
 333          }
 334  
 335          DBD::Gofer::set_err_from_response($dbh, $response);
 336  
 337          return (wantarray) ? @$rv : $rv->[0];
 338      }
 339  
 340  
 341      # Methods that should be forwarded but can be cached
 342      for my $method (qw(
 343          tables table_info column_info primary_key_info foreign_key_info statistics_info
 344          data_sources type_info_all get_info
 345          parse_trace_flags parse_trace_flag
 346          func
 347      )) {
 348          my $policy_name = "cache_$method";
 349          my $super_name  = "SUPER::$method";
 350          my $sub = sub {
 351              my $dbh = shift;
 352              my $rv;
 353  
 354              # if we know the remote side doesn't override the DBI's default method
 355              # then we might as well just call the DBI's default method on the client
 356              # (which may, in turn, call other methods that are forwarded, like get_info)
 357              if ($dbh->{dbi_default_methods}{$method} && $dbh->{go_policy}->skip_default_methods()) {
 358                  $dbh->trace_msg("    !! $method: using local default as remote method is also default\n");
 359                  return $dbh->$super_name(@_);
 360              }
 361  
 362              my $cache;
 363              my $cache_key;
 364              if (my $cache_it = $dbh->{go_policy}->$policy_name(undef, $dbh, @_)) {
 365                  $cache = $dbh->{go_meta_cache} ||= {}; # keep separate from go_cache
 366                  $cache_key = sprintf "%s_wa%d(%s)", $policy_name, wantarray||0,
 367                      join(",\t", map { # XXX basic but sufficient for now
 368                           !ref($_)            ? DBI::neat($_,1e6)
 369                          : ref($_) eq 'ARRAY' ? DBI::neat_list($_,1e6,",\001")
 370                          : ref($_) eq 'HASH'  ? do { my @k = sort keys %$_; DBI::neat_list([@k,@{$_}{@k}],1e6,",\002") }
 371                          : do { warn "unhandled argument type ($_)"; $_ }
 372                      } @_);
 373                  if ($rv = $cache->{$cache_key}) {
 374                      $dbh->trace_msg("$method(@_) returning previously cached value ($cache_key)\n",4);
 375                      my @cache_rv = @$rv;
 376                      # if it's an sth we have to clone it
 377                      $cache_rv[0] = $cache_rv[0]->go_clone_sth if UNIVERSAL::isa($cache_rv[0],'DBI::st');
 378                      return (wantarray) ? @cache_rv : $cache_rv[0];
 379                  }
 380              }
 381  
 382              $rv = [ (wantarray)
 383                  ?       ($dbh->go_dbh_method(undef, $method, @_))
 384                  : scalar $dbh->go_dbh_method(undef, $method, @_)
 385              ];
 386  
 387              if ($cache) {
 388                  $dbh->trace_msg("$method(@_) caching return value ($cache_key)\n",4);
 389                  my @cache_rv = @$rv;
 390                  # if it's an sth we have to clone it
 391                  #$cache_rv[0] = $cache_rv[0]->go_clone_sth
 392                  #   if UNIVERSAL::isa($cache_rv[0],'DBI::st');
 393                  $cache->{$cache_key} = \@cache_rv
 394                      unless UNIVERSAL::isa($cache_rv[0],'DBI::st'); # XXX cloning sth not yet done
 395              }
 396  
 397              return (wantarray) ? @$rv : $rv->[0];
 398          };
 399          no strict 'refs';
 400          *$method = $sub;
 401      }
 402  
 403  
 404      # Methods that can use the DBI defaults for some situations/drivers
 405      for my $method (qw(
 406          quote quote_identifier
 407      )) {    # XXX keep DBD::Gofer::Policy::Base in sync
 408          my $policy_name = "locally_$method";
 409          my $super_name  = "SUPER::$method";
 410          my $sub = sub {
 411              my $dbh = shift;
 412  
 413              # if we know the remote side doesn't override the DBI's default method
 414              # then we might as well just call the DBI's default method on the client
 415              # (which may, in turn, call other methods that are forwarded, like get_info)
 416              if ($dbh->{dbi_default_methods}{$method} && $dbh->{go_policy}->skip_default_methods()) {
 417                  $dbh->trace_msg("    !! $method: using local default as remote method is also default\n");
 418                  return $dbh->$super_name(@_);
 419              }
 420  
 421              # false:    use remote gofer
 422              # 1:        use local DBI default method
 423              # code ref: use the code ref
 424              my $locally = $dbh->{go_policy}->$policy_name($dbh, @_);
 425              if ($locally) {
 426                  return $locally->($dbh, @_) if ref $locally eq 'CODE';
 427                  return $dbh->$super_name(@_);
 428              }
 429              return $dbh->go_dbh_method(undef, $method, @_); # propagate context
 430          };
 431          no strict 'refs';
 432          *$method = $sub;
 433      }
 434  
 435  
 436      # Methods that should always fail
 437      for my $method (qw(
 438          begin_work commit rollback
 439      )) {
 440          no strict 'refs';
 441          *$method = sub { return shift->set_err($DBI::stderr, "$method not available with DBD::Gofer") }
 442      }
 443  
 444  
 445      sub do {
 446          my ($dbh, $sql, $attr, @args) = @_;
 447          delete $dbh->{Statement}; # avoid "Modification of non-creatable hash value attempted"
 448          $dbh->{Statement} = $sql; # for profiling and ShowErrorStatement
 449          my $meta = { go_last_insert_id_args => $attr->{go_last_insert_id_args} };
 450          return $dbh->go_dbh_method($meta, 'do', $sql, $attr, @args);
 451      }
 452  
 453      sub ping {
 454          my $dbh = shift;
 455          return $dbh->set_err(0, "can't ping while not connected") # warning
 456              unless $dbh->SUPER::FETCH('Active');
 457          my $skip_ping = $dbh->{go_policy}->skip_ping();
 458          return ($skip_ping) ? 1 : $dbh->go_dbh_method(undef, 'ping', @_);
 459      }
 460  
 461      sub last_insert_id {
 462          my $dbh = shift;
 463          my $response = $dbh->{go_response} or return undef;
 464          return $response->last_insert_id;
 465      }
 466  
 467      sub FETCH {
 468          my ($dbh, $attrib) = @_;
 469  
 470          # FETCH is effectively already cached because the DBI checks the
 471          # attribute cache in the handle before calling FETCH
 472          # and this FETCH copies the value into the attribute cache
 473  
 474          # forward driver-private attributes (except ours)
 475          if ($attrib =~ m/^[a-z]/ && $attrib !~ /^go_/) {
 476              my $value = $dbh->go_dbh_method(undef, 'FETCH', $attrib);
 477              $dbh->{$attrib} = $value; # XXX forces caching by DBI
 478              return $dbh->{$attrib} = $value;
 479          }
 480  
 481          # else pass up to DBI to handle
 482          return $dbh->SUPER::FETCH($attrib);
 483      }
 484  
 485      sub STORE {
 486          my ($dbh, $attrib, $value) = @_;
 487          if ($attrib eq 'AutoCommit') {
 488              croak "Can't enable transactions when using DBD::Gofer" if !$value;
 489              return $dbh->SUPER::STORE($attrib => ($value) ? -901 : -900);
 490          }
 491          return $dbh->SUPER::STORE($attrib => $value)
 492              # we handle this attribute locally
 493              if $dbh_local_store_attrib{$attrib}
 494              # or it's a private_ (application) attribute
 495              or $attrib =~ /^private_/
 496              # or not yet connected (ie being called by DBI->connect)
 497              or not $dbh->FETCH('Active');
 498  
 499          return $dbh->SUPER::STORE($attrib => $value)
 500              if $DBD::Gofer::xxh_local_store_attrib_if_same_value{$attrib}
 501              && do { # values are the same
 502                  my $crnt = $dbh->FETCH($attrib);
 503                  local $^W;
 504                  (defined($value) ^ defined($crnt))
 505                      ? 0 # definedness differs
 506                      : $value eq $crnt;
 507              };
 508  
 509          # dbh attributes are set at connect-time - see connect()
 510          carp("Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer") if $dbh->FETCH('Warn');
 511          return $dbh->set_err($DBI::stderr, "Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer");
 512      }
 513  
 514      sub disconnect {
 515          my $dbh = shift;
 516          $dbh->{go_transport} = undef;
 517          $dbh->STORE(Active => 0);
 518      }
 519  
 520      sub prepare {
 521          my ($dbh, $statement, $attr)= @_;
 522  
 523          return $dbh->set_err($DBI::stderr, "Can't prepare when disconnected")
 524              unless $dbh->FETCH('Active');
 525  
 526          $attr = { %$attr } if $attr; # copy so we can edit
 527  
 528          my $policy     = delete($attr->{go_policy}) || $dbh->{go_policy};
 529          my $lii_args   = delete $attr->{go_last_insert_id_args};
 530          my $go_prepare = delete($attr->{go_prepare_method})
 531                        || $dbh->{go_prepare_method}
 532                        || $policy->prepare_method($dbh, $statement, $attr)
 533                        || 'prepare'; # e.g. for code not using placeholders
 534          my $go_cache = delete $attr->{go_cache};
 535          # set to undef if there are no attributes left for the actual prepare call
 536          $attr = undef if $attr and not %$attr;
 537  
 538          my ($sth, $sth_inner) = DBI::_new_sth($dbh, {
 539              Statement => $statement,
 540              go_prepare_call => [ 0, $go_prepare, $statement, $attr ],
 541              # go_method_calls => [], # autovivs if needed
 542              go_request => $dbh->{go_request},
 543              go_transport => $dbh->{go_transport},
 544              go_policy => $policy,
 545              go_last_insert_id_args => $lii_args,
 546              go_cache => $go_cache,
 547          });
 548          $sth->STORE(Active => 0);
 549  
 550          my $skip_prepare_check = $policy->skip_prepare_check($attr, $dbh, $statement, $attr, $sth);
 551          if (not $skip_prepare_check) {
 552              $sth->go_sth_method() or return undef;
 553          }
 554  
 555          return $sth;
 556      }
 557  
 558      sub prepare_cached {
 559          my ($dbh, $sql, $attr, $if_active)= @_;
 560          $attr ||= {};
 561          return $dbh->SUPER::prepare_cached($sql, {
 562              %$attr,
 563              go_prepare_method => $attr->{go_prepare_method} || 'prepare_cached',
 564          }, $if_active);
 565      }
 566  
 567      *go_cache = \&DBD::Gofer::go_cache;
 568  }
 569  
 570  
 571  {   package DBD::Gofer::st; # ====== STATEMENT ======
 572      $imp_data_size = 0;
 573      use strict;
 574  
 575      my %sth_local_store_attrib = (%DBD::Gofer::xxh_local_store_attrib, NUM_OF_FIELDS => 1);
 576  
 577      sub go_sth_method {
 578          my ($sth, $meta) = @_;
 579  
 580          if (my $ParamValues = $sth->{ParamValues}) {
 581              my $ParamAttr = $sth->{ParamAttr};
 582              # XXX the sort here is a hack to work around a DBD::Sybase bug
 583              # but only works properly for params 1..9
 584              # (reverse because of the unshift)
 585              my @params = reverse sort keys %$ParamValues;
 586              if (@params > 9 && ($sth->{Database}{go_dsn}||'') =~ /dbi:Sybase/) {
 587                  # if more than 9 then we need to do a proper numeric sort
 588                  # also warn to alert user of this issue
 589                  warn "Sybase param binding order hack in use";
 590                  @params = sort { $b <=> $a } @params;
 591              }
 592              for my $p (@params) {
 593                  # unshift to put binds before execute call
 594                  unshift @{ $sth->{go_method_calls} },
 595                      [ 'bind_param', $p, $ParamValues->{$p}, $ParamAttr->{$p} ];
 596              }
 597          }
 598  
 599          my $dbh = $sth->{Database} or die "panic";
 600          ++$dbh->{go_request_count};
 601  
 602          my $request = $sth->{go_request};
 603          $request->init_request($sth->{go_prepare_call}, $sth);
 604          $request->sth_method_calls(delete $sth->{go_method_calls})
 605              if $sth->{go_method_calls};
 606          $request->sth_result_attr({}); # (currently) also indicates this is an sth request
 607  
 608          $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
 609              if $meta->{go_last_insert_id_args};
 610  
 611          my $go_policy = $sth->{go_policy};
 612          my $dbh_attribute_update = $go_policy->dbh_attribute_update();
 613          $request->dbh_attributes( $go_policy->dbh_attribute_list() )
 614              if $dbh_attribute_update eq 'every'
 615              or $dbh->{go_request_count}==1;
 616  
 617          my $transport = $sth->{go_transport}
 618              or return $sth->set_err($DBI::stderr, "Not connected (no transport)");
 619  
 620          local $transport->{go_cache} = $sth->{go_cache}
 621              if defined $sth->{go_cache};
 622  
 623          my ($response, $retransmit_sub) = $transport->transmit_request($request);
 624          $response ||= $transport->receive_response($request, $retransmit_sub);
 625          $sth->{go_response} = $response
 626              or die "No response object returned by $transport";
 627          $dbh->{go_response} = $response; # mainly for last_insert_id
 628  
 629          if (my $dbh_attributes = $response->dbh_attributes) {
 630              # XXX we don't STORE here, we just stuff the value into the attribute cache
 631              $dbh->{$_} = $dbh_attributes->{$_}
 632                  for keys %$dbh_attributes;
 633              # record the values returned, so we know that we have fetched
 634              # values are which we have fetched (see dbh->FETCH method)
 635              $dbh->{go_dbh_attributes_fetched} = $dbh_attributes;
 636          }
 637  
 638          my $rv = $response->rv; # may be undef on error
 639          if ($response->sth_resultsets) {
 640              # setup first resultset - including sth attributes
 641              $sth->more_results;
 642          }
 643          else {
 644              $sth->STORE(Active => 0);
 645              $sth->{go_rows} = $rv;
 646          }
 647          # set error/warn/info (after more_results as that'll clear err)
 648          DBD::Gofer::set_err_from_response($sth, $response);
 649  
 650          return $rv;
 651      }
 652  
 653  
 654      sub bind_param {
 655          my ($sth, $param, $value, $attr) = @_;
 656          $sth->{ParamValues}{$param} = $value;
 657          $sth->{ParamAttr}{$param}   = $attr
 658              if defined $attr; # attr is sticky if not explicitly set
 659          return 1;
 660      }
 661  
 662  
 663      sub execute {
 664          my $sth = shift;
 665          $sth->bind_param($_, $_[$_-1]) for (1..@_);
 666          push @{ $sth->{go_method_calls} }, [ 'execute' ];
 667          my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} };
 668          return $sth->go_sth_method($meta);
 669      }
 670  
 671  
 672      sub more_results {
 673          my $sth = shift;
 674  
 675          $sth->finish;
 676  
 677          my $response = $sth->{go_response} or do {
 678              # e.g., we haven't sent a request yet (ie prepare then more_results)
 679              $sth->trace_msg("    No response object present", 3);
 680              return;
 681          };
 682  
 683          my $resultset_list = $response->sth_resultsets
 684              or return $sth->set_err($DBI::stderr, "No sth_resultsets");
 685  
 686          my $meta = shift @$resultset_list
 687              or return undef; # no more result sets
 688          #warn "more_results: ".Data::Dumper::Dumper($meta);
 689  
 690          # pull out the special non-atributes first
 691          my ($rowset, $err, $errstr, $state)
 692              = delete @{$meta}{qw(rowset err errstr state)};
 693  
 694          # copy meta attributes into attribute cache
 695          my $NUM_OF_FIELDS = delete $meta->{NUM_OF_FIELDS};
 696          $sth->STORE('NUM_OF_FIELDS', $NUM_OF_FIELDS);
 697          # XXX need to use STORE for some?
 698          $sth->{$_} = $meta->{$_} for keys %$meta;
 699  
 700          if (($NUM_OF_FIELDS||0) > 0) {
 701              $sth->{go_rows}           = ($rowset) ? @$rowset : -1;
 702              $sth->{go_current_rowset} = $rowset;
 703              $sth->{go_current_rowset_err} = [ $err, $errstr, $state ]
 704                  if defined $err;
 705              $sth->STORE(Active => 1) if $rowset;
 706          }
 707  
 708          return $sth;
 709      }
 710  
 711  
 712      sub go_clone_sth {
 713          my ($sth1) = @_;
 714          # clone an (un-fetched-from) sth - effectively undoes the initial more_results
 715          # not 100% so just for use in caching returned sth e.g. table_info
 716          my $sth2 = $sth1->{Database}->prepare($sth1->{Statement}, { go_skip_prepare_check => 1 });
 717          $sth2->STORE($_, $sth1->{$_}) for qw(NUM_OF_FIELDS Active);
 718          my $sth2_inner = tied %$sth2;
 719          $sth2_inner->{$_} = $sth1->{$_} for qw(NUM_OF_PARAMS FetchHashKeyName);
 720          die "not fully implemented yet";
 721          return $sth2;
 722      }
 723  
 724  
 725      sub fetchrow_arrayref {
 726          my ($sth) = @_;
 727          my $resultset = $sth->{go_current_rowset} || do {
 728              # should only happen if fetch called after execute failed
 729              my $rowset_err = $sth->{go_current_rowset_err}
 730                  || [ 1, 'no result set (did execute fail)' ];
 731              return $sth->set_err( @$rowset_err );
 732          };
 733          return $sth->_set_fbav(shift @$resultset) if @$resultset;
 734          $sth->finish;     # no more data so finish
 735          return undef;
 736      }
 737      *fetch = \&fetchrow_arrayref; # alias
 738  
 739  
 740      sub fetchall_arrayref {
 741          my ($sth, $slice, $max_rows) = @_;
 742          my $resultset = $sth->{go_current_rowset} || do {
 743              # should only happen if fetch called after execute failed
 744              my $rowset_err = $sth->{go_current_rowset_err}
 745                  || [ 1, 'no result set (did execute fail)' ];
 746              return $sth->set_err( @$rowset_err );
 747          };
 748          my $mode = ref($slice) || 'ARRAY';
 749          return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
 750              if ref($slice) or defined $max_rows;
 751          $sth->finish;     # no more data after this so finish
 752          return $resultset;
 753      }
 754  
 755  
 756      sub rows {
 757          return shift->{go_rows};
 758      }
 759  
 760  
 761      sub STORE {
 762          my ($sth, $attrib, $value) = @_;
 763  
 764          return $sth->SUPER::STORE($attrib => $value)
 765              if $sth_local_store_attrib{$attrib} # handle locally
 766              # or it's a private_ (application) attribute
 767              or $attrib =~ /^private_/;
 768  
 769          # otherwise warn but do it anyway
 770          # this will probably need refining later
 771          my $msg = "Altering \$sth->{$attrib} won't affect proxied handle";
 772          Carp::carp($msg) if $sth->FETCH('Warn');
 773  
 774          # XXX could perhaps do
 775          #   push @{ $sth->{go_method_calls} }, [ 'STORE', $attrib, $value ]
 776          #       if not $sth->FETCH('Executed');
 777          # but how to handle repeat executions? How to we know when an
 778          # attribute is being set to affect the current resultset or the
 779          # next execution?
 780          # Could just always use go_method_calls I guess.
 781  
 782          # do the store locally anyway, just in case
 783          $sth->SUPER::STORE($attrib => $value);
 784  
 785          return $sth->set_err($DBI::stderr, $msg);
 786      }
 787  
 788      # sub bind_param_array
 789      # we use DBI's default, which sets $sth->{ParamArrays}{$param} = $value
 790      # and calls bind_param($param, undef, $attr) if $attr.
 791  
 792      sub execute_array {
 793          my $sth = shift;
 794          my $attr = shift;
 795          $sth->bind_param_array($_, $_[$_-1]) for (1..@_);
 796          push @{ $sth->{go_method_calls} }, [ 'execute_array', $attr ];
 797          return $sth->go_sth_method($attr);
 798      }
 799  
 800      *go_cache = \&DBD::Gofer::go_cache;
 801  }
 802  
 803  1;
 804  
 805  __END__
 806  
 807  =head1 NAME
 808  
 809  DBD::Gofer - A stateless-proxy driver for communicating with a remote DBI
 810  
 811  =head1 SYNOPSIS
 812  
 813    use DBI;
 814  
 815    $original_dsn = "dbi:..."; # your original DBI Data Source Name
 816  
 817    $dbh = DBI->connect("dbi:Gofer:transport=$transport;...;dsn=$original_dsn",
 818                        $user, $passwd, \%attributes);
 819  
 820    ... use $dbh as if it was connected to $original_dsn ...
 821  
 822  
 823  The C<transport=$transport> part specifies the name of the module to use to
 824  transport the requests to the remote DBI. If $transport doesn't contain any
 825  double colons then it's prefixed with C<DBD::Gofer::Transport::>.
 826  
 827  The C<dsn=$original_dsn> part I<must be the last element> of the DSN because
 828  everything after C<dsn=> is assumed to be the DSN that the remote DBI should
 829  use.
 830  
 831  The C<...> represents attributes that influence the operation of the Gofer
 832  driver or transport. These are described below or in the documentation of the
 833  transport module being used.
 834  
 835  =head1 DESCRIPTION
 836  
 837  DBD::Gofer is a DBI database driver that forwards requests to another DBI
 838  driver, usually in a seperate process, often on a separate machine. It tries to
 839  be as transparent as possible so it appears that you are using the remote
 840  driver directly.
 841  
 842  DBD::Gofer is very similar to DBD::Proxy. The major difference is that with
 843  DBD::Gofer no state is maintained on the remote end. That means every
 844  request contains all the information needed to create the required state. (So,
 845  for example, every request includes the DSN to connect to.) Each request can be
 846  sent to any available server. The server executes the request and returns a
 847  single response that includes all the data.
 848  
 849  This is very similar to the way http works as a stateless protocol for the web.
 850  Each request from your web browser can be handled by a different web server process.
 851  
 852  =head2 Use Cases
 853  
 854  This may seem like pointless overhead but there are situations where this is a
 855  very good thing. Let's consider a specific case.
 856  
 857  Imagine using DBD::Gofer with an http transport. Your application calls
 858  connect(), prepare("select * from table where foo=?"), bind_param(), and execute().
 859  At this point DBD::Gofer builds a request containing all the information
 860  about the method calls. It then uses the httpd transport to send that request
 861  to an apache web server.
 862  
 863  This 'dbi execute' web server executes the request (using DBI::Gofer::Execute
 864  and related modules) and builds a response that contains all the rows of data,
 865  if the statement returned any, along with all the attributes that describe the
 866  results, such as $sth->{NAME}. This response is sent back to DBD::Gofer which
 867  unpacks it and presents it to the application as if it had executed the
 868  statement itself.
 869  
 870  =head2 Advantages
 871  
 872  Okay, but you still don't see the point? Well let's consider what we've gained:
 873  
 874  =head3 Connection Pooling and Throttling
 875  
 876  The 'dbi execute' web server leverages all the functionality of web
 877  infrastructure in terms of load balancing, high-availability, firewalls, access
 878  management, proxying, caching.
 879  
 880  At its most basic level you get a configurable pool of persistent database connections.
 881  
 882  =head3 Simple Scaling
 883  
 884  Got thousands of processes all trying to connect to the database? You can use
 885  DBD::Gofer to connect them to your smaller pool of 'dbi execute' web servers instead.
 886  
 887  =head3 Caching
 888  
 889  Client-side caching is as simple as adding "C<cache=1>" to the DSN.
 890  This feature alone can be worth using DBD::Gofer for.
 891  
 892  =head3 Fewer Network Round-trips
 893  
 894  DBD::Gofer sends as few requests as possible (dependent on the policy being used).
 895  
 896  =head3 Thin Clients / Unsupported Platforms
 897  
 898  You no longer need drivers for your database on every system.  DBD::Gofer is pure perl.
 899  
 900  =head1 CONSTRAINTS
 901  
 902  There are some natural constraints imposed by the DBD::Gofer 'stateless' approach.
 903  But not many:
 904  
 905  =head2 You can't change database handle attributes after connect()
 906  
 907  You can't change database handle attributes after you've connected.
 908  Use the connect() call to specify all the attribute settings you want.
 909  
 910  This is because it's critical that when a request is complete the database
 911  handle is left in the same state it was when first connected.
 912  
 913  An exception is made for attributes with names starting "C<private_>":
 914  They can be set after connect() but the change is only applied locally.
 915  
 916  =head2 You can't change statement handle attributes after prepare()
 917  
 918  You can't change statment handle attributes after prepare.
 919  
 920  An exception is made for attributes with names starting "C<private_>":
 921  They can be set after prepare() but the change is only applied locally.
 922  
 923  =head2 You can't use transactions
 924  
 925  AutoCommit only. Transactions aren't supported.
 926  
 927  (In theory transactions could be supported when using a transport that
 928  maintains a connection, like C<stream> does. If you're interested in this
 929  please get in touch via dbi-dev@perl.org)
 930  
 931  =head2 You can't call driver-private sth methods
 932  
 933  But that's rarely needed anyway.
 934  
 935  =head1 GENERAL CAVEATS
 936  
 937  A few important things to keep in mind when using DBD::Gofer:
 938  
 939  =head2 Temporary tables, locks, and other per-connection persistent state
 940  
 941  You shouldn't expect any per-session state to persist between requests.
 942  This includes locks and temporary tables.
 943  
 944  Because the server-side may execute your requests via a different
 945  database connections, you can't rely on any per-connection persistent state,
 946  such as temporary tables, being available from one request to the next.
 947  
 948  This is an easy trap to fall into. A good way to check for this is to test your
 949  code with a Gofer policy package that sets the C<connect_method> policy to
 950  'connect' to force a new connection for each request. The C<pedantic> policy does this.
 951  
 952  =head2 Driver-private Database Handle Attributes
 953  
 954  Some driver-private dbh attributes may not be available if the driver has not
 955  implemented the private_attribute_info() method (added in DBI 1.54).
 956  
 957  =head2 Driver-private Statement Handle Attributes
 958  
 959  Driver-private sth attributes can be set in the prepare() call. TODO
 960  
 961  Some driver-private dbh attributes may not be available if the driver has not
 962  implemented the private_attribute_info() method (added in DBI 1.54).
 963  
 964  =head2 Multiple Resultsets
 965  
 966  Multiple resultsets are supported only if the driver supports the more_results() method
 967  (an exception is made for DBD::Sybase).
 968  
 969  =head2 Statement activity that also updates dbh attributes
 970  
 971  Some drivers may update one or more dbh attributes after performing activity on
 972  a child sth.  For example, DBD::mysql provides $dbh->{mysql_insertid} in addition to
 973  $sth->{mysql_insertid}. Currently mysql_insertid is supported via a hack but a
 974  more general mechanism is needed for other drivers to use.
 975  
 976  =head2 Methods that report an error always return undef
 977  
 978  With DBD::Gofer, a method that sets an error always return an undef or empty list.
 979  That shouldn't be a problem in practice because the DBI doesn't define any
 980  methods that return meaningful values while also reporting an error.
 981  
 982  =head2 Subclassing only applies to client-side
 983  
 984  The RootClass and DbTypeSubclass attributes are not passed to the Gofer server.
 985  
 986  =head1 CAVEATS FOR SPECIFIC METHODS
 987  
 988  =head2 last_insert_id
 989  
 990  To enable use of last_insert_id you need to indicate to DBD::Gofer that you'd
 991  like to use it.  You do that my adding a C<go_last_insert_id_args> attribute to
 992  the do() or prepare() method calls. For example:
 993  
 994      $dbh->do($sql, { go_last_insert_id_args => [...] });
 995  
 996  or
 997  
 998      $sth = $dbh->prepare($sql, { go_last_insert_id_args => [...] });
 999  
1000  The array reference should contains the args that you want passed to the
1001  last_insert_id() method.
1002  
1003  =head2 execute_for_fetch
1004  
1005  The array methods bind_param_array() and execute_array() are supported.
1006  When execute_array() is called the data is serialized and executed in a single
1007  round-trip to the Gofer server. This makes it very fast, but requires enough
1008  memory to store all the serialized data.
1009  
1010  The execute_for_fetch() method currently isn't optimised, it uses the DBI
1011  fallback behaviour of executing each tuple individually.
1012  (It could be implemented as a wrapper for execute_array() - patches welcome.)
1013  
1014  =head1 TRANSPORTS
1015  
1016  DBD::Gofer doesn't concern itself with transporting requests and responses to and fro.
1017  For that it uses special Gofer transport modules.
1018  
1019  Gofer transport modules usually come in pairs: one for the 'client' DBD::Gofer
1020  driver to use and one for the remote 'server' end. They have very similar names:
1021  
1022      DBD::Gofer::Transport::<foo>
1023      DBI::Gofer::Transport::<foo>
1024  
1025  Sometimes the transports on the DBD and DBI sides may have different names. For
1026  example DBD::Gofer::Transport::http is typically used with DBI::Gofer::Transport::mod_perl
1027  (DBD::Gofer::Transport::http and DBI::Gofer::Transport::mod_perl modules are
1028  part of the GoferTransport-http distribution).
1029  
1030  =head2 Bundled Transports
1031  
1032  Several transport modules are provided with DBD::Gofer:
1033  
1034  =head3 null
1035  
1036  The null transport is the simplest of them all. It doesn't actually transport the request anywhere.
1037  It just serializes (freezes) the request into a string, then thaws it back into
1038  a data structure before passing it to DBI::Gofer::Execute to execute. The same
1039  freeze and thaw is applied to the results.
1040  
1041  The null transport is the best way to test if your application will work with Gofer.
1042  Just set the DBI_AUTOPROXY environment variable to "C<dbi:Gofer:transport=null;policy=pedantic>"
1043  (see L</Using DBI_AUTOPROXY> below) and run your application, or ideally its test suite, as usual.
1044  
1045  It doesn't take any parameters.
1046  
1047  =head3 pipeone
1048  
1049  The pipeone transport launches a subprocess for each request. It passes in the
1050  request and reads the response.
1051  
1052  The fact that a new subprocess is started for each request ensures that the
1053  server side is truly stateless. While this does make the transport I<very> slow,
1054  it is useful as a way to test that your application doesn't depend on
1055  per-connection state, such as temporary tables, persisting between requests.
1056  
1057  It's also useful both as a proof of concept and as a base class for the stream
1058  driver.
1059  
1060  =head3 stream
1061  
1062  The stream driver also launches a subprocess and writes requests and reads
1063  responses, like the pipeone transport.  In this case, however, the subprocess
1064  is expected to handle more that one request. (Though it will be automitically
1065  restarted if it exits.)
1066  
1067  This is the first transport that is truly useful because it can launch the
1068  subprocess on a remote machine using C<ssh>. This means you can now use DBD::Gofer
1069  to easily access any databases that's accessible from any system you can login to.
1070  You also get all the benefits of ssh, including encryption and optional compression.
1071  
1072  See L</Using DBI_AUTOPROXY> below for an example.
1073  
1074  =head2 Other Transports
1075  
1076  Implementing a Gofer transport is I<very> simple, and more transports are very welcome.
1077  Just take a look at any existing transports that are similar to your needs.
1078  
1079  =head3 http
1080  
1081  See the GoferTransport-http distribution on CPAN: http://search.cpan.org/dist/GoferTransport-http/
1082  
1083  =head3 Gearman
1084  
1085  I know Ask Bjørn Hansen has implemented a transport for the C<gearman> distributed
1086  job system, though it's not on CPAN at the time of writing this.
1087  
1088  =head1 CONNECTING
1089  
1090  Simply prefix your existing DSN with "C<dbi:Gofer:transport=$transport;dsn=>"
1091  where $transport is the name of the Gofer transport you want to use (see L</TRANSPORTS>).
1092  The C<transport> and C<dsn> attributes must be specified and the C<dsn> attributes must be last.
1093  
1094  Other attributes can be specified in the DSN to configure DBD::Gofer and/or the
1095  Gofer transport module being used. The main attributes after C<transport>, are
1096  C<url> and C<policy>. These and other attributes are described below.
1097  
1098  =head2 Using DBI_AUTOPROXY
1099  
1100  The simplest way to try out DBD::Gofer is to set the DBI_AUTOPROXY environment variable.
1101  In this case you don't include the C<dsn=> part. For example:
1102  
1103      export DBI_AUTOPROXY="dbi:Gofer:transport=null"
1104  
1105  or, for a more useful example, try:
1106  
1107      export DBI_AUTOPROXY="dbi:Gofer:transport=stream;url=ssh:user@example.com"
1108  
1109  =head2 Connection Attributes
1110  
1111  These attributes can be specified in the DSN. They can also be passed in the
1112  \%attr parameter of the DBI connect method by adding a "C<go_>" prefix to the name.
1113  
1114  =head3 transport
1115  
1116  Specifies the Gofer transport class to use. Required. See L</TRANSPORTS> above.
1117  
1118  If the value does not include C<::> then "C<DBD::Gofer::Transport::>" is prefixed.
1119  
1120  The transport object can be accessed via $h->{go_transport}.
1121  
1122  =head3 dsn
1123  
1124  Specifies the DSN for the remote side to connect to. Required, and must be last.
1125  
1126  =head3 url
1127  
1128  Used to tell the transport where to connect to. The exact form of the value depends on the transport used.
1129  
1130  =head3 policy
1131  
1132  Specifies the policy to use. See L</CONFIGURING BEHAVIOUR POLICY>.
1133  
1134  If the value does not include C<::> then "C<DBD::Gofer::Policy>" is prefixed.
1135  
1136  The policy object can be accessed via $h->{go_policy}.
1137  
1138  =head3 timeout
1139  
1140  Specifies a timeout, in seconds, to use when waiting for responses from the server side.
1141  
1142  =head3 retry_limit
1143  
1144  Specifies the number of times a failed request will be retried. Default is 0.
1145  
1146  =head3 retry_hook
1147  
1148  Specifies a code reference to be called to decide if a failed request should be retried.
1149  The code reference is called like this:
1150  
1151    $transport = $h->{go_transport};
1152    $retry = $transport->go_retry_hook->($request, $response, $transport);
1153  
1154  If it returns true then the request will be retried, upto the C<retry_limit>.
1155  If it returns a false but defined value then the request will not be retried.
1156  If it returns undef then the default behaviour will be used, as if C<retry_hook>
1157  had not been specified.
1158  
1159  The default behaviour is to retry requests where $request->is_idempotent is true,
1160  or the error message matches C</induced by DBI_GOFER_RANDOM/>.
1161      
1162  =head3 cache
1163  
1164  Specifies that client-side caching should be performed.  The value is the name
1165  of a cache class to use.
1166  
1167  Any class implementing get($key) and set($key, $value) methods can be used.
1168  That includes a great many powerful caching classes on CPAN, including the
1169  Cache and Cache::Cache distributions.
1170  
1171  You can use "C<cache=1>" is a shortcut for "C<cache=DBI::Util::CacheMemory>".
1172  See L<DBI::Util::CacheMemory> for a description of this simple fast default cache.
1173  
1174  The cache object can be accessed via $h->go_cache. For example:
1175  
1176      $dbh->go_cache->clear; # free up memory being used by the cache
1177  
1178  The cache keys are the frozen (serialized) requests, and the values are the
1179  frozen responses.
1180  
1181  The default behaviour is to only use the cache for requests where
1182  $request->is_idempotent is true (i.e., the dbh has the ReadOnly attribute set
1183  or the SQL statement is obviously a SELECT without a FOR UPDATE clause.)
1184  
1185  For even more control you can use the C<go_cache> attribute to pass in an
1186  instanciated cache object. Individual methods, including prepare(), can also
1187  specify alternative caches via the C<go_cache> attribute. For example, to
1188  specify no caching for a particular query, you could use
1189  
1190      $sth = $dbh->prepare( $sql, { go_cache => 0 } );
1191  
1192  This can be used to implement different caching policies for different statements.
1193  
1194  It's interesting to note that DBD::Gofer can be used to add client-side caching
1195  to any (gofer compatible) application, with no code changes and no need for a
1196  gofer server.  Just set the DBI_AUTOPROXY environment variable like this:
1197  
1198      DBI_AUTOPROXY='dbi:Gofer:transport=null;cache=1'
1199  
1200  =head1 CONFIGURING BEHAVIOUR POLICY
1201  
1202  DBD::Gofer supports a 'policy' mechanism that allows you to fine-tune the number of round-trips to the Gofer server.
1203  The policies are grouped into classes (which may be subclassed) and referenced by the name of the class.
1204  
1205  The L<DBD::Gofer::Policy::Base> class is the base class for all the policy
1206  packages and describes all the available policies.
1207  
1208  Three policy packages are supplied with DBD::Gofer:
1209  
1210  L<DBD::Gofer::Policy::pedantic> is most 'transparent' but slowest because it
1211  makes more  round-trips to the Gofer server.
1212  
1213  L<DBD::Gofer::Policy::classic> is a reasonable compromise - it's the default policy.
1214  
1215  L<DBD::Gofer::Policy::rush> is fastest, but may require code changes in your applications.
1216  
1217  Generally the default C<classic> policy is fine. When first testing an existing
1218  application with Gofer it is a good idea to start with the C<pedantic> policy
1219  first and then switch to C<classic> or a custom policy, for final testing.
1220  
1221  
1222  =head1 AUTHOR
1223  
1224  Tim Bunce, L<http://www.tim.bunce.name>
1225  
1226  =head1 LICENCE AND COPYRIGHT
1227  
1228  Copyright (c) 2007, Tim Bunce, Ireland. All rights reserved.
1229  
1230  This module is free software; you can redistribute it and/or
1231  modify it under the same terms as Perl itself. See L<perlartistic>.
1232  
1233  =head1 ACKNOWLEDGEMENTS
1234  
1235  The development of DBD::Gofer and related modules was sponsored by
1236  Shopzilla.com (L<http://Shopzilla.com>), where I currently work.
1237  
1238  =head1 SEE ALSO
1239  
1240  L<DBI::Gofer::Request>, L<DBI::Gofer::Response>, L<DBI::Gofer::Execute>.
1241  
1242  L<DBI::Gofer::Transport::Base>, L<DBD::Gofer::Policy::Base>.
1243  
1244  L<DBI>
1245  
1246  =head1 Caveats for specific drivers
1247  
1248  This section aims to record issues to be aware of when using Gofer with specific drivers.
1249  It usually only documents issues that are not natural consequences of the limitations
1250  of the Gofer approach - as documented avove.
1251  
1252  =head1 TODO
1253  
1254  This is just a random brain dump... (There's more in the source of the Changes file, not the pod)
1255  
1256  Document policy mechanism
1257  
1258  Add mechanism for transports to list config params and for Gofer to apply any that match (and warn if any left over?)
1259  
1260  Driver-private sth attributes - set via prepare() - change DBI spec
1261  
1262  add hooks into transport base class for checking & updating a result set cache
1263     ie via a standard cache interface such as:
1264     http://search.cpan.org/~robm/Cache-FastMmap/FastMmap.pm
1265     http://search.cpan.org/~bradfitz/Cache-Memcached/lib/Cache/Memcached.pm
1266     http://search.cpan.org/~dclinton/Cache-Cache/
1267     http://search.cpan.org/~cleishman/Cache/
1268  Also caching instructions could be passed through the httpd transport layer
1269  in such a way that appropriate http cache headers are added to the results
1270  so that web caches (squid etc) could be used to implement the caching.
1271  (MUST require the use of GET rather than POST requests.)
1272  
1273  Rework handling of installed_methods to not piggback on dbh_attributes?
1274  
1275  Perhaps support transactions for transports where it's possible (ie null and stream)?
1276  Would make stream transport (ie ssh) more useful to more people.
1277  
1278  Make sth_result_attr more like dbh_attributes (using '*' etc)
1279  
1280  Add @val = FETCH_many(@names) to DBI in C and use in Gofer/Execute?
1281  
1282  Implement _new_sth in C.
1283  
1284  =cut


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1