DBI

 view release on metacpan or  search on metacpan

ChangeLog  view on Meta::CPAN

        thanks to pali #55

1.637 - 2017-08-16, Tim Bunce

    Fix use of externally controlled format string (CWE-134) thanks to pali #44
        This could cause a crash if, for example, a db error contained a %.
        https://cwe.mitre.org/data/definitions/134.html
    Fix extension detection for DBD::File related drivers
    Fix tests for perl without dot in @INC RT#120443
    Fix loss of error message on parent handle, thanks to charsbar #34
    Fix disappearing $_ inside callbacks, thanks to robschaber #47
    Fix dependency on Storable for perl older than 5.8.9

    Allow objects to be used as passwords without throwing an error, thanks to demerphq #40
    Allow $sth NAME_* attributes to be set from Perl code, re #45
    Added support for DBD::XMLSimple thanks to nigelhorne #38

    Documentation updates:
    Improve examples using eval to be more correct, thanks to pali #39
    Add cautionary note to prepare_cached docs re refs in %attr #46
    Small POD changes (Getting Help -> Online) thanks to openstrike #33

ChangeLog  view on Meta::CPAN

    Added note to AutoInactiveDestroy docs strongly recommending that it
        is enabled in all new code.

1.631 - 2014-01-20, Tim Bunce

NOTE: This release changes the handle passed to Callbacks from being an 'inner'
handle to being an 'outer' handle. If you have code that makes use of Callbacks,
ensure that you understand what this change means and review your callback code.

    Fixed err_hash handling of integer err RT#92172 [Dagfinn Ilmari]
    Fixed use of \Q vs \E in t/70callbacks.t

    Changed the handle passed to Callbacks from being an 'inner'
        handle to being an 'outer' handle.

    Improved reliability of concurrent testing
        PR#8 [Peter Rabbitson]
    Changed optional dependencies to "suggest"
        PR#9 [Karen Etheridge]
    Changed to avoid mg_get in neatsvpv during global destruction
        PR#10 [Matt Phillips]

ChangeLog  view on Meta::CPAN

    Extended ReadOnly attribute docs for when the driver cannot
      ensure read only [Martin J. Evans]
    Corrected SQL_BIGINT docs to say ODBC value is used PR#5 [ilmari]

There was no DBI 1.629 release.

1.628 - 2013-07-22, Tim Bunce

    Fixed missing fields on partial insert via DBI::DBD::SqlEngine
        engines (DBD::CSV, DBD::DBM etc.) [H.Merijn Brand, Jens Rehsack]
    Fixed stack corruption on callbacks RT#85562 RT#84974 [Aaron Schweiger]
    Fixed DBI::SQL::Nano_::Statement handling of "0" [Jens Rehsack]
    Fixed exit op precedence in test RT#87029 [Reni Urban]

    Added support for finding tables in multiple directories
        via new DBD::File f_dir_search attribute [H.Merijn Brand]
    Enable compiling by C++ RT#84285 [Kurt Jaeger]

    Typo fixes in pod and comment [David Steinbrunner]
    Change DBI's docs to refer to git not svn [H.Merijn Brand]
    Clarify bind_col TYPE attribute is sticky [Martin J. Evans]

DBI.pm  view on Meta::CPAN

  };

The callback would then be executed when you called the C<prepare()> method:

  $dbh->prepare('SELECT 1');

And the output of course would be:

  Preparing q{SELECT 1}

Because callbacks are executed I<before> the methods
they're associated with, you can modify the arguments before they're passed on
to the method call. For example, to make sure that all calls to C<prepare()>
are immediately prepared by L<DBD::Pg>, add a callback that makes sure that
the C<pg_prepare_now> attribute is always set:

  my $dbh = DBI->connect($dsn, $username, $auth, {
      Callbacks => {
          prepare => sub {
              $_[2] ||= {};
              $_[2]->{pg_prepare_now} = 1;
              return; # must return nothing
          },
      }
  });

Note that we are editing the contents of C<@_> directly. In this case we've
created the attributes hash if it's not passed to the C<prepare> call.

You can also prevent the associated method from ever executing. While a
callback executes, C<$_> holds the method name. (This allows multiple callbacks
to share the same code reference and still know what method was called.)
To prevent the method from
executing, simply C<undef $_>. For example, if you wanted to disable calls to
C<ping()>, you could do this:

  $dbh->{Callbacks} = {
      ping => sub {
          # tell dispatch to not call the method:
          undef $_;
          # return this value instead:

DBI.pm  view on Meta::CPAN

attributes to C<connect()>. Callbacks can also be applied to a statement
methods on a statement handle. For example:

  $sth->{Callbacks} = {
      execute => sub {
          print "Executing ", shift->{Statement}, "\n";
      }
  };

The C<Callbacks> attribute of a database handle isn't copied to any statement
handles it creates. So setting callbacks for a statement handle requires you to
set the C<Callbacks> attribute on the statement handle yourself, as in the
example above, or use the special C<ChildCallbacks> key described below.

B<Special Keys in Callbacks Attribute>

In addition to DBI handle method names, the C<Callbacks> hash reference
supports four additional keys.

The first is the C<ChildCallbacks> key. When a statement handle is created from
a database handle the C<ChildCallbacks> key of the database handle's
C<Callbacks> attribute, if any, becomes the new C<Callbacks> attribute of the
statement handle.
This allows you to define callbacks for all statement handles created from a
database handle. For example, if you wanted to count how many times C<execute>
was called in your application, you could write:

  my $exec_count = 0;
  my $dbh = DBI->connect( $dsn, $username, $auth, {
      Callbacks => {
          ChildCallbacks => {
              execute => sub { $exec_count++; return; }
          }
      }
  });

  END {
      print "The execute method was called $exec_count times\n";
  }

The other three special keys are C<connect_cached.new>,
C<connect_cached.connected>, and C<connect_cached.reused>. These keys define
callbacks that are called when C<connect_cached()> is called, but allow
different behaviors depending on whether a new handle is created or a handle
is returned. The callback is invoked with these arguments:
C<$dbh, $dsn, $user, $auth, $attr>.

For example, some applications uses C<connect_cached()> to connect with
C<AutoCommit> enabled and then disable C<AutoCommit> temporarily for
transactions. If C<connect_cached()> is called during a transaction, perhaps in
a utility method, then it might select the same cached handle and then force
C<AutoCommit> on, forcing a commit of the transaction. See the L</connect_cached>
documentation for one way to deal with that. Here we'll describe an alternative
approach using a callback.

Because the C<connect_cached.new> and C<connect_cached.reused> callbacks are
invoked before C<connect_cached()> has applied the connect attributes, you can
use them to edit the attributes that will be applied. To prevent a cached
handle from having its transactions committed before it's returned, you can
eliminate the C<AutoCommit> attribute in a C<connect_cached.reused> callback,
like so:

  my $cb = {
      'connect_cached.reused' => sub { delete $_[4]->{AutoCommit} },
  };

DBI.pm  view on Meta::CPAN

          RaiseError => 1,
          AutoCommit => 1,
          Callbacks  => $cb,
      });
  }

The upshot is that new database handles are created with C<AutoCommit>
enabled, while cached database handles are left in whatever transaction state
they happened to be in when retrieved from the cache.

Note that we've also used a lexical for the callbacks hash reference. This is
because C<connect_cached()> returns a new database handle if any of the
attributes passed to is have changed. If we used an inline hash reference,
C<connect_cached()> would return a new database handle every time. Which would
rather defeat the purpose.

A more common application for callbacks is setting connection state only when
a new connection is made (by connect() or connect_cached()). Adding a callback
to the connected method (when using C<connect>) or via
C<connect_cached.connected> (when useing connect_cached()>) makes this easy.
The connected() method is a no-op by default (unless you subclass the DBI and
change it). The DBI calls it to indicate that a new connection has been made
and the connection attributes have all been set. You can give it a bit of
added functionality by applying a callback to it. For example, to make sure
that MySQL understands your application's ANSI-compliant SQL, set it up like
so:

DBI.pm  view on Meta::CPAN

      'connect_cached.connected' => sub {
          shift->do('SET timezone = UTC');
      }
  };

  sub dbh {
      my $self = shift;
      DBI->connect_cached( $dsn, $username, $auth, { Callbacks => $cb });
  }

One significant limitation with callbacks is that there can only be one per
method per handle. This means it's easy for one use of callbacks to interfere
with, or typically simply overwrite, another use of callbacks. For this reason
modules using callbacks should document the fact clearly so application authors
can tell if use of callbacks by the module will clash with use of callbacks by
the application.

You might be able to work around this issue by taking a copy of the original
callback and calling it within your own. For example:

  my $prev_cb = $h->{Callbacks}{method_name};
  $h->{Callbacks}{method_name} = sub {
    if ($prev_cb) {
        my @result = $prev_cb->(@_);
	return @result if not $_; # $prev_cb vetoed call

DBI.xs  view on Meta::CPAN

            if (imp_xxh && DBIc_THR_USER(imp_xxh) != my_perl) {
                goto is_DESTROY_wrong_thread;
            }
#endif
            if (imp_xxh && DBIc_TYPE(imp_xxh) <= DBIt_DB)
                clear_cached_kids(aTHX_ mg->mg_obj, imp_xxh, meth_name, trace_level);
            /* XXX might be better to move this down to after call_depth has been
             * incremented and then also SvREFCNT_dec(mg->mg_obj) to force an immediate
             * DESTROY of the inner handle if there are no other refs to it.
             * That way the inner DESTROY is properly flagged as a nested call,
             * and the outer DESTROY gets profiled more accurately, and callbacks work.
             */
            if (trace_level >= 3) {
                PerlIO_printf(DBILOGFP,
                    "%c   <> DESTROY(%s) ignored for outer handle (inner %s has ref cnt %ld)\n",
                    (PL_dirty?'!':' '), neatsvpv(h,0), neatsvpv(mg->mg_obj,0),
                    (long)SvREFCNT(SvRV(mg->mg_obj))
                );
            }
            /* for now we ignore it since it'll be followed soon by     */
            /* a destroy of the inner hash and that'll do the real work */

MANIFEST  view on Meta::CPAN

t/43prof_env.t
t/48dbi_dbd_sqlengine.t         Tests for DBI::DBD::SqlEngine
t/49dbd_file.t			DBD::File API and very basic tests
t/50dbm_simple.t		simple DBD::DBM tests
t/51dbm_file.t			extended DBD::File tests (through DBD::DBM)
t/52dbm_complex.t		Complex DBD::DBM tests with SQL::Statement
t/53sqlengine_adv.t
t/54_dbd_mem.t
t/60preparse.t
t/65transact.t
t/70callbacks.t
t/72childhandles.t
t/73cachedkids.t
t/80proxy.t
t/85gofer.t
t/86gofer_fail.t
t/87gofer_cache.t
t/90sql_type_cast.t
t/91_store_warning.t
t/lib.pl		Utility functions for test scripts
typemap

lib/DBI/Changes.pm  view on Meta::CPAN

        thanks to pali #55

=head2 Changes in DBI 1.637 - 16 Aug 2017

    Fix use of externally controlled format string (CWE-134) thanks to pali #44
        This could cause a crash if, for example, a db error contained a %.
        https://cwe.mitre.org/data/definitions/134.html
    Fix extension detection for DBD::File related drivers
    Fix tests for perl without dot in @INC RT#120443
    Fix loss of error message on parent handle, thanks to charsbar #34
    Fix disappearing $_ inside callbacks, thanks to robschaber #47
    Fix dependency on Storable for perl older than 5.8.9

    Allow objects to be used as passwords without throwing an error, thanks to demerphq #40
    Allow $sth NAME_* attributes to be set from Perl code, re #45
    Added support for DBD::XMLSimple thanks to nigelhorne #38

    Documentation updates:
    Improve examples using eval to be more correct, thanks to pali #39
    Add cautionary note to prepare_cached docs re refs in %attr #46
    Small POD changes (Getting Help -> Online) thanks to openstrike #33

lib/DBI/Changes.pm  view on Meta::CPAN

    Added note to AutoInactiveDestroy docs strongly recommending that it
        is enabled in all new code.

=head2 Changes in DBI 1.631 - 20 Jan 2014

NOTE: This release changes the handle passed to Callbacks from being an 'inner'
handle to being an 'outer' handle. If you have code that makes use of Callbacks,
ensure that you understand what this change means and review your callback code.

    Fixed err_hash handling of integer err RT#92172 [Dagfinn Ilmari]
    Fixed use of \Q vs \E in t/70callbacks.t

    Changed the handle passed to Callbacks from being an 'inner'
        handle to being an 'outer' handle.

    Improved reliability of concurrent testing
        PR#8 [Peter Rabbitson]
    Changed optional dependencies to "suggest"
        PR#9 [Karen Etheridge]
    Changed to avoid mg_get in neatsvpv during global destruction
        PR#10 [Matt Phillips]

lib/DBI/Changes.pm  view on Meta::CPAN

    Extended ReadOnly attribute docs for when the driver cannot
      ensure read only [Martin J. Evans]
    Corrected SQL_BIGINT docs to say ODBC value is used PR#5 [ilmari]

There was no DBI 1.629 release.

=head2 Changes in DBI 1.628 - 22 Jul 2013

    Fixed missing fields on partial insert via DBI::DBD::SqlEngine
        engines (DBD::CSV, DBD::DBM etc.) [H.Merijn Brand, Jens Rehsack]
    Fixed stack corruption on callbacks RT#85562 RT#84974 [Aaron Schweiger]
    Fixed DBI::SQL::Nano_::Statement handling of "0" [Jens Rehsack]
    Fixed exit op precedence in test RT#87029 [Reni Urban]

    Added support for finding tables in multiple directories
        via new DBD::File f_dir_search attribute [H.Merijn Brand]
    Enable compiling by C++ RT#84285 [Kurt Jaeger]

    Typo fixes in pod and comment [David Steinbrunner]
    Change DBI's docs to refer to git not svn [H.Merijn Brand]
    Clarify bind_col TYPE attribute is sticky [Martin J. Evans]

lib/DBI/DBD.pm  view on Meta::CPAN

C structures.

=item *

Some methods are typically moved to the XS code, in particular
C<prepare()>, C<execute()>, C<disconnect()>, C<disconnect_all()> and the
C<STORE()> and C<FETCH()> methods.

=item *

Other methods are still part of F<Driver.pm>, but have callbacks to
the XS code.

=item *

If the driver-specific parts of the I<imp_drh_t> structure need to be
formally initialized (which does not seem to be a common requirement),
then you need to add a call to an appropriate XS function in the driver
method of C<DBD::Driver::driver()>, and you define the corresponding function
in F<Driver.xs>, and you define the C code in F<dbdimp.c> and the prototype in
F<dbdimp.h>.

lib/DBI/Gofer/Execute.pm  view on Meta::CPAN

    };

    # XXX implement our own private connect_cached method? (with rate-limited ping)
    my $dbh = DBI->$connect_method($dsn, undef, undef, $connect_attr);

    $dbh->{ShowErrorStatement} = 1 if $local_log;

    # XXX should probably just be a Callbacks => arg to connect_cached
    # with a cache of pre-built callback hooks (memoized, without $self)
    if (my $random = $self->{forced_gofer_random} || $ENV{DBI_GOFER_RANDOM}) {
        $self->_install_rand_callbacks($dbh, $random);
    }

    my $CK = $dbh->{CachedKids};
    if ($CK && keys %$CK > $self->{max_cached_sth_per_dbh}) {
        %$CK = (); #  clear all statement handles
    }

    #$dbh->trace(0);
    $current_dbh = $dbh;
    return $dbh;

lib/DBI/Gofer/Execute.pm  view on Meta::CPAN

        my $imp_sub = $ImplementorClass->can($method) || 42;
        next if $imp_sub != $dbi_sub;
        #warn("default $method\n");
        $default_methods{$method} = 1;
    }
    return \%default_methods;
}


# XXX would be nice to make this a generic DBI module
sub _install_rand_callbacks {
    my ($self, $dbh, $dbi_gofer_random) = @_;

    my $callbacks = $dbh->{Callbacks} || {};
    my $prev      = $dbh->{private_gofer_rand_fail_callbacks} || {};

    # return if we've already setup this handle with callbacks for these specs
    return if (($callbacks->{_dbi_gofer_random_spec}||'') eq $dbi_gofer_random);
    #warn "$dbh # $callbacks->{_dbi_gofer_random_spec}";
    $callbacks->{_dbi_gofer_random_spec} = $dbi_gofer_random;

    my ($fail_percent, $fail_err, $delay_percent, $delay_duration, %spec_part, @spec_note);
    my @specs = split /,/, $dbi_gofer_random;
    for my $spec (@specs) {
        if ($spec =~ m/^fail=(-?[.\d]+)%?$/) {
            $fail_percent = $1;
            $spec_part{fail} = $spec;
            next;
        }
        if ($spec =~ m/^err=(-?\d+)$/) {

lib/DBI/Gofer/Execute.pm  view on Meta::CPAN

            $delay_percent  = $2;
            $spec_part{delay} = $spec;
            next;
        }
        elsif ($spec !~ m/^(\w+|\*)$/) {
            warn "Ignored DBI_GOFER_RANDOM item '$spec' which isn't a config or a dbh method name";
            next;
        }

        my $method = $spec;
        if ($callbacks->{$method} && $prev->{$method} && $callbacks->{$method} != $prev->{$method}) {
            warn "Callback for $method method already installed so DBI_GOFER_RANDOM callback not installed\n";
            next;
        }
        unless (defined $fail_percent or defined $delay_percent) {
            warn "Ignored DBI_GOFER_RANDOM item '$spec' because not preceded by 'fail=N' and/or 'delayN=N'";
            next;
        }

        push @spec_note, join(",", values(%spec_part), $method);
        $callbacks->{$method} = $self->_mk_rand_callback($method, $fail_percent, $delay_percent, $delay_duration, $fail_err);
    }
    warn "DBI_GOFER_RANDOM failures/delays enabled: @spec_note\n"
        if @spec_note;
    $dbh->{Callbacks} = $callbacks;
    $dbh->{private_gofer_rand_fail_callbacks} = $callbacks;
}

my %_mk_rand_callback_seqn;

sub _mk_rand_callback {
    my ($self, $method, $fail_percent, $delay_percent, $delay_duration, $fail_err) = @_;
    my ($fail_modrate, $delay_modrate);
    $fail_percent  ||= 0;  $fail_modrate  = int(1/(-$fail_percent )*100) if $fail_percent;
    $delay_percent ||= 0;  $delay_modrate = int(1/(-$delay_percent)*100) if $delay_percent;
    # note that $method may be "*" but that's not recommended or documented or wise

t/70callbacks.t  view on Meta::CPAN

is ref $attr, 'HASH', 'param modified by callback - not recommended!';

ok !eval { $dbh->disconnect };
ok $@, "You can't disconnect that easily!\n";

$dbh->{Callbacks} = undef;
ok $dbh->ping;
is $called{ping}, 2; # no change


# --- test skipping dispatch and fallback callbacks

$dbh->{Callbacks} = {
    ping => sub {
        undef $_;   # tell dispatch to not call the method
        return "42 bells";
    },
    data_sources => sub {
        my ($h, $values_to_return) = @_;
        undef $_;   # tell dispatch to not call the method
        my @ret = 11..10+($values_to_return||0);

t/70callbacks.t  view on Meta::CPAN

                is $auth, 'p', 'pass';
                $called{connected}++;
                return;
            },
        }
    }
);

%called = ();

ok $dbh = DBI->connect(@args), "Create handle with callbacks";
is keys %called, 0, 'no callback for plain connect';

ok $dbh = DBI->connect_cached(@args), "Create handle with callbacks";
is $called{new}, 1, "connect_cached.new called";
is $called{cached}, undef, "connect_cached.reused not yet called";
is $called{connected}, 1, "connect_cached.connected called";

ok $dbh = DBI->connect_cached(@args), "Create handle with callbacks";
is $called{cached}, 1, "connect_cached.reused called";
is $called{new}, 1, "connect_cached.new not called again";
is $called{connected}, 1, "connect_cached.connected not called called";


# --- test ChildCallbacks.
%called = ();
$args[-1] = {
    Callbacks => my $dbh_callbacks = {
        ping => sub { $called{ping}++; return; },
        ChildCallbacks => my $sth_callbacks = {
            execute => sub { $called{execute}++; return; },
            fetch   => sub { $called{fetch}++; return; },
        }
    }
};

ok $dbh = DBI->connect(@args), "Create handle with ChildCallbacks";
ok $dbh->ping, 'Ping';
is $called{ping}, 1, 'Ping callback should have been called';
ok my $sth = $dbh->prepare('SELECT name from t'), 'Prepare a statement handle (child)';
ok $sth->{Callbacks}, 'child should have Callbacks';
is $sth->{Callbacks}, $sth_callbacks, "child Callbacks should be ChildCallbacks of parent"
    or diag "(dbh Callbacks is $dbh_callbacks)";
ok $sth->execute, 'Execute';
is $called{execute}, 1, 'Execute callback should have been called';
ok $sth->fetch, 'Fetch';
is $called{fetch}, 1, 'Fetch callback should have been called';

# stress test for stack reallocation and mark handling -- RT#86744
my $stress_count = 3000;
my $place_holders = join(',', ('?') x $stress_count);
my @params = ('t') x $stress_count;
my $stress_dbh = DBI->connect( 'DBI:NullP:test');



( run in 0.319 second using v1.01-cache-2.11-cpan-9b1e4054eb1 )