Eidolon::Driver::DB - Eidolon generic database driver.


Eidolon documentation Contained in the Eidolon distribution.

Index


Code Index:

NAME

Top

Eidolon::Driver::DB - Eidolon generic database driver.

SYNOPSIS

Top

Example database driver:

    package Eidolon::Driver::DB::Example;
    use base qw/Eidolon::Driver::DB/;

    sub new
    {
        my ($class, $self);

        $class = shift;
        $self  = $class->SUPER::new("Example", @_);

        return $self;
    }

    sub call
    {
        my ($self, $function, @params, $query);

        ($self, $function, @params) = @_;
        throw DriverError::DB::SQL($function);

        # never will reach here
        return $self->execute($query, @params);
    }

DESCRIPTION

Top

The Eidolon::Driver::DB is a generic database driver for Eidolon. It declares some functions that are common for all driver types and some abstract methods, that must be overloaded in ancestor classes. All database drivers should subclass this package.

Actually, Eidolon database stack is more high-level abstraction over the DBI package. However, this abstraction is not ORM-like but makes SQL syntax differences between different DBMSs less visible.

To use database drivers you must have DBI and needed DBD packages installed.

METHODS

Top

new($dbd, $db, $user, $password, $host, $port, $cfg)

Class constructor. Sets initial class data: $dbd - DBI driver name, $db - database name, $user - database user name, $password - database password, $host - database host, $port - database port, $cfg - configuration hashref:

auto_fetch

Automatically fetch all query results right after query execution. Default value is 0.

auto_commit

Automatically commit transaction after each SQL query. Default value is 1.

execute($query, @params)

Query execution. Given $query executed with binded @params. If any error occurs, exception is thrown.

execute_prepared(@params)

Prepared query execution. Previously executed query will be executed again with new @params.

fetch()

Returns one row fetched from database or undef if no results remained.

fetch_all()

Returns reference to array of all rows fetched from database after query execution.

free()

Clear in-memory cache of fetched data.

call($function, @params)

Call stored procedure or function with $function as name and @params as parameters. Abstract method, should be overloaded in ancestors.

SEE ALSO

Top

Eidolon, Eidolon::Driver::DB::Exceptions

LICENSE

Top

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

Top

Anton Belousov, <abel@cpan.org>

COPYRIGHT

Top


Eidolon documentation Contained in the Eidolon distribution.

package Eidolon::Driver::DB;
# ==============================================================================
#
#   Eidolon
#   Copyright (c) 2009, Atma 7
#   ---
#   Eidolon/Driver/DB.pm - generic database driver
#
# ==============================================================================

use base qw/Eidolon::Driver/;
use Eidolon::Driver::DB::Exceptions;
use DBI;
use warnings;
use strict;

our $VERSION = "0.02"; # 2009-05-14 05:18:37

# ------------------------------------------------------------------------------
# \% new($dbd, $db, $user, $password, $host, $port, $cfg)
# constructor
# ------------------------------------------------------------------------------
sub new
{
    my ($class, $dbd, $db, $user, $password, $host, $port, $cfg, $self);

    ($class, $dbd, $db, $user, $password, $host, $port, $cfg) = @_;

    # class attributes
    $self = 
    {
        # connection settings
        "dbd"         => $dbd,
        "database"    => $db,
        "user"        => $user,
        "password"    => $password,
        "host"        => $host,
        "port"        => $port,

        # other settings
        "auto_fetch"  => $cfg && exists $cfg->{"auto_fetch"}  ? $cfg->{"auto_fetch"}  : 0,
        "auto_commit" => $cfg && exists $cfg->{"auto_commit"} ? $cfg->{"auto_commit"} : 1,

        # handles
        "dbh"         => undef,
        "sth"         => undef,

        # data
        "query"       => undef,
        "query_count" => 0,
        "rows"        => 0,
        "dataset"     => []
    };

    bless $self, $class;
    $self->_init();

    return $self;
}

# ------------------------------------------------------------------------------
# _init()
# class initialization
# ------------------------------------------------------------------------------
sub _init
{
    my $self = shift;

    eval 
    {
        $self->{"dbh"} = DBI->connect
        (
            "DBI:$self->{'dbd'}:database=$self->{'database'};host=$self->{'host'};port=$self->{'port'}", 

            $self->{"user"},
            $self->{"password"},

            {
                "RaiseError"      => 1,
                "PrintError"      => 0,
                "PrintWarn"       => 0,
                "InactiveDestroy" => 1,
                "AutoCommit"      => $self->{"auto_commit"}
            }
        );
    }; 

    throw DriverError::DB::Connect($@) if ($@);
}

# ------------------------------------------------------------------------------
# \@ execute($query, @params)
# query execution
# ------------------------------------------------------------------------------
sub execute
{
    my ($self, $query, @params, $row);

    ($self, $query, @params) = @_;

    eval 
    { 
        $self->free;

        $self->{"query"} = $query;
        $self->{"query_count"}++;

        $self->{"sth"}  = $self->{"dbh"}->prepare($query);
        $self->{"rows"} = $self->{"sth"}->execute(@params);
    };

    throw DriverError::DB::SQL($query) if ($@);

    if ($self->{"auto_fetch"})
    {
        $self->_fetch_all;
        return $self->{"dataset"};
    }
}

# ------------------------------------------------------------------------------
# \@ execute_prepared(@params)
# execute prepared query
# ------------------------------------------------------------------------------
sub execute_prepared
{
    my ($self, @params, $row);

    ($self, @params) = @_;

    eval
    {
        $self->free;

        $self->{"query_count"}++;
        $self->{"rows"} = $self->{"sth"}->execute(@params);
    };

    throw DriverError::DB::SQL($self->{"query"}) if ($@);

    if ($self->{"auto_fetch"})
    {
        $self->_fetch_all;
        return $self->{"dataset"};
    }
}

# ------------------------------------------------------------------------------
# fetch()
# fetch result
# ------------------------------------------------------------------------------
sub fetch
{
    my ($self, $row);
    
    $self = shift;

    throw DriverError::DB::AlreadyFetched if ($self->{"auto_fetch"});
    $row  = $self->{"sth"}->fetchrow_hashref;

    return $row;
}

# ------------------------------------------------------------------------------
# _fetch_all()
# private version of fetch all results
# ------------------------------------------------------------------------------
sub _fetch_all
{
    my ($self, $row);

    $self = shift;

    while ($row = $self->{"sth"}->fetchrow_hashref)
    {
        push @{ $self->{"dataset"} }, $row;
    }
}

# ------------------------------------------------------------------------------
# fetch_all()
# fetch all results
# ------------------------------------------------------------------------------
sub fetch_all
{
    my $self = shift;

    throw DriverError::DB::AlreadyFetched if ($self->{"auto_fetch"});
    $self->_fetch_all;

    return $self->{"dataset"};
}

# ------------------------------------------------------------------------------
# free()
# free memory
# ------------------------------------------------------------------------------
sub free
{
    my $self = shift;

    $self->{"sth"}->finish  if ($self->{"sth"});

    if ($self->{"dataset"}) 
    {
        undef $self->{"dataset"};
        $self->{"dataset"} = [];
    }
}

# ------------------------------------------------------------------------------
# \@ call($function, @params)
# stored function/procedure call
# ------------------------------------------------------------------------------
sub call
{
    throw CoreError::AbstractMethod;
}

# ------------------------------------------------------------------------------
# DESTROY()
# destructor
# ------------------------------------------------------------------------------
sub DESTROY
{
    $_[0]->{"dbh"}->disconnect if ($_[0]->{"dbh"});
}

1;

__END__