DBIx::Connector::Driver - Database-specific connection interface


DBIx-Connector documentation Contained in the DBIx-Connector distribution.

Index


Code Index:

Name

Top

DBIx::Connector::Driver - Database-specific connection interface

Description

Top

Some of the things that DBIx::Connector does are implemented differently by different drivers, or the official interface provided by the DBI may not be implemented for a particular driver. The driver-specific code therefore is encapsulated in this separate driver class.

Most of the DBI drivers work uniformly, so in most cases the implementation provided here in DBIx::Connector::Driver will work just fine. It's only when something is different that a driver subclass needs to be added. In such a case, the subclass's name is the same as the DBI driver. For example the driver for DBD::Pg is DBIx::Connector::Driver::Pg and the driver for DBD::mysql is DBIx::Connector::Driver::mysql.

If you're just a user of DBIx::Connector, you can ignore the driver classes. DBIx::Connector uses them internally to do its magic, so you needn't worry about them.

Interface

Top

In case you need to implement a driver, here's the interface you can modify.

Constructor

new

  my $driver = DBIx::Connector::Driver->new( $driver );

Constructs and returns a driver object. Each driver class is implemented as a singleton, so the same driver object is always returned for the same driver. The driver parameter should be a Perl DBI driver name, such as Pg for DBD::Pg or SQLite for DBD::SQLite. If a subclass has been defined for $driver, then the object will be of that class. Otherwise it will be an instance of the driver base class.

Instance Methods

ping

  $driver->ping($dbh);

Calls $dbh->ping. Override if for some reason the DBI driver doesn't do it right.

begin_work

  $driver->begin_work($dbh);

Calls $dbh->begin_work. Override if for some reason the DBI driver doesn't do it right.

commit

  $driver->commit($dbh);

Calls $dbh->commit. Override if for some reason the DBI driver doesn't do it right.

rollback

  $driver->rollback($dbh);

Calls $dbh->rollback. Override if for some reason the DBI driver doesn't do it right.

savepoint

  $driver->savepoint($dbh, $name);

A no-op. Override if your database does in fact support savepoints. The driver subclass should create a savepoint with the given $name. See the implementations in DBIx::Connector::Driver::Pg and DBIx::Connector::Driver::Oracle for examples.

release

  $driver->release($dbh, $name);

A no-op. Override if your database does in fact support savepoints. The driver subclass should release the savepoint with the given $name. See the implementations in DBIx::Connector::Driver::Pg and DBIx::Connector::Driver::Oracle for examples.

rollback_to

  $driver->rollback_to($dbh, $name);

A no-op. Override if your database does in fact support savepoints. The driver subclass should rollback to the savepoint with the given $name. See the implementations in DBIx::Connector::Driver::Pg and DBIx::Connector::Driver::Oracle for examples.

Authors

Top

This module was written and is maintained by:

David E. Wheeler <david@kineticode.com>

It is based on code written by:

Matt S. Trout <mst@shadowcatsystems.co.uk>
Peter Rabbitson <rabbit+dbic@rabbit.us>

Copyright and License

Top


DBIx-Connector documentation Contained in the DBIx-Connector distribution.

package DBIx::Connector::Driver;

use strict;
use warnings;
our $VERSION = '0.45';

DRIVERS: {
    my %DRIVERS;

    sub new {
        my ($class, $driver) = @_;
        return $DRIVERS{$driver} ||= do {
            my $subclass = __PACKAGE__ . "::$driver";
            eval "require $subclass";
            $class = $subclass unless $@;
            bless { driver => $driver } => $class;
        };
    }
}

sub _connect {
    my ($self, $dbh, $dsn, $username, $password, $attrs) = @_;
    $dbh;
}

sub ping {
    my ($self, $dbh) = @_;
    $dbh->ping;
}

sub begin_work {
    my ($self, $dbh) = @_;
    $dbh->begin_work;
}

sub commit {
    my ($self, $dbh) = @_;
    $dbh->commit;
}

sub rollback {
    my ($self, $dbh) = @_;
    $dbh->rollback;
}

sub _rollback {
    my ($self, $dbh, $err) = @_;
    local $@;
    eval { $dbh->rollback };
    return $@ ? DBIx::Connector::TxnRollbackError->new(
        error          => $err,
        rollback_error => $@,
    ) : $err;
}

sub _rollback_and_release {
    my ($self, $dbh, $name, $err) = @_;
    local $@;
    eval {
        $self->rollback_to($dbh, $name);
        $self->rollback_release($dbh, $name);
    };
    return $@ ? DBIx::Connector::SvpRollbackError->new(
        error          => $err,
        rollback_error => $@,
    ) : $err;
}

sub savepoint {
    my ($self, $dbh, $name) = @_;
}

sub release {
    my ($self, $dbh, $name) = @_;
}

sub rollback_to {
    my ($self, $dbh, $name) = @_;
}

ROLLBACKERR: {
    package DBIx::Connector::RollbackError;
    # an exception is always true
    use overload bool => sub {1}, '""' => 'as_string', fallback => 1;

    sub new       { my $c = shift; bless {@_} => $c; }
    sub error     { shift->{error} }
    sub rollback_error { shift->{rollback_error} }
    sub as_string {
        my $self = shift;
        my $label = $self->_label;
        return "$label aborted: " . $self->error
            . "$label rollback failed: " . $self->rollback_error;
    }

    package DBIx::Connector::TxnRollbackError;
    our @ISA = ('DBIx::Connector::RollbackError');
    sub _label    { 'Transaction' }

    package DBIx::Connector::SvpRollbackError;
    our @ISA = ('DBIx::Connector::RollbackError');
    sub _label    { 'Savepoint' }
}

1;
__END__