SAL-DBI
From GTALUG
Sitemap > Culture > Psema4 > SAL > SAL-DBI
package SAL::DBI;
# This script is licensed under the FDL (Free Document License)
# The complete license text can be found at http://www.gnu.org/copyleft/fdl.html
# Contains excerpts from various man pages, tutorials and books on perl
# DBI ABSTRACTION
use strict;
use DBI;
use Carp;
BEGIN {
use Exporter ();
our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
$VERSION = 3.0;
@ISA = qw(Exporter);
@EXPORT = qw();
%EXPORT_TAGS = ();
@EXPORT_OK = qw();
}
our @EXPORT_OK;
END { }
our %DBI = (
######################################
'connection' => {
# Shared
'type' => '',
'dbh' => '',
'sth' => '',
'user' => '',
'passwd' => '',
# For MySQL
'server' => '',
'database' => '',
# For ODBC
'dsn' => '',
# For SQLite
'dbfile' => ''
},
######################################
'fields' => (
{
'name' => '',
'label' => '',
'type' => '',
'visible' => 0,
'header' => 0,
'writeable' => 0,
'css' => '',
'precision' => '',
'commify' => '',
'align' => '',
'prefix' => '',
'postfix' => '',
}
),
######################################
'data' => [],
######################################
'internal' => {
'width' => '',
'height' => '',
},
######################################
);
# Setup accessors via closure (from perltooc manpage)
sub _classobj {
my $obclass = shift || __PACKAGE__;
my $class = ref($obclass) || $obclass;
no strict "refs";
return \%$class;
}
for my $datum (keys %{ _classobj() }) {
no strict "refs";
*$datum = sub {
my $self = shift->_classobj();
$self->{$datum} = shift if @_;
return $self->{$datum};
}
}
##########################################################################################################################
# Constructors (Public)
sub new {
my $obclass = shift || __PACKAGE__;
my $class = ref($obclass) || $obclass;
my $self = {};
bless($self, $class);
return $self;
}
sub spawn_mysql {
my $obclass = shift || __PACKAGE__;
my $class = ref($obclass) || $obclass;
my $db_type = 'mysql';
my $db_server = shift || '(undefined)';
my $db_user = shift || '(undefined)';
my $db_passwd = shift || '(undefined)';
my $db_database = shift || '(undefined)';
my $self = {};
$self->{connection}{type} = $db_type;
$self->{connection}{server} = $db_server;
$self->{connection}{user} = $db_user;
$self->{connection}{passwd} = $db_passwd;
$self->{connection}{database} = $db_database;
bless($self, $class);
# make the connection
$self->{connection}{dbh} = DBI->connect("DBI:mysql:$db_database:$db_server",$db_user,$db_passwd) || confess($DBI::errstr);
return $self;
}
sub spawn_odbc {
my $obclass = shift || __PACKAGE__;
my $class = ref($obclass) || $obclass;
my $db_type = 'odbc';
my $db_dsn = shift || '';
my $db_user = shift || '';
my $db_passwd = shift || '';
my $self = {};
$self->{connection}{type} = $db_type;
$self->{connection}{dsn} = $db_dsn;
$self->{connection}{user} = $db_user;
$self->{connection}{passwd} = $db_passwd;
bless($self, $class);
# make the connection
$self->{connection}{dbh} = DBI->connect("DBI:ODBC:$db_dsn",$db_user,$db_passwd) || confess($DBI::errstr);
return $self;
}
sub spawn_sqlite {
my $obclass = shift || __PACKAGE__;
my $class = ref($obclass) || $obclass;
my $db_type = 'sqlite';
my $db_server = '';
my $db_user = '';
my $db_passwd = '';
my $db_database = shift || '(undefined)';
my $self = {};
$self->{connection}{type} = $db_type;
$self->{connection}{server} = $db_server;
$self->{connection}{user} = $db_user;
$self->{connection}{passwd} = $db_passwd;
$self->{connection}{database} = $db_database;
bless($self, $class);
# make the connection
$self->{connection}{dbh} = DBI->connect("DBI:SQLite:dbname=$db_database",$db_user,$db_passwd) || confess($DBI::errstr);
return $self;
}
##########################################################################################################################
# Destructor (Public)
sub destruct {
my $self = shift;
if(defined($self->{connection}{dbh})) {
$self->{connection}{dbh}->disconnect();
}
}
##########################################################################################################################
# Public Methods
sub do {
my ($self, $statement) = @_;
my $rv = $self->{connection}{dbh}->do($statement);
return $rv;
}
sub execute {
my ($self, $statement, @params) = @_;
my $table = $self->_extract_table($statement);
# From the section "Outline Usage" of the DBI pod (http://search.cpan.org/~timb/DBI-1.43/DBI.pm)
# This should probably be it's own function... Note also the way placeholders are used...
$self->{connection}{sth} = $self->{connection}{dbh}->prepare($statement) || confess("Can't Prepare SQL Statement: " . $self->{connection}{dbh}->errstr);
#
$self->{connection}{sth}->execute(@params) || confess("Can't Execute SQL Statement: " . $self->{connection}{sth}->errstr . "\n\nSQL Statement:\n$statement\nParams:\n@params\n\n");
$self->{data} = $self->{connection}{sth}->fetchall_arrayref();
# get the width and height (aka metrics) of the returned data set...
my $width = $#{$self->{data}[0]};
my $height = $self->{connection}{sth}->rows();
$self->{internal}{width} = $width;
$self->{internal}{height} = $height;
foreach my $column (0..$width) {
$self->{fields}[$column]{visible} = 1;
$self->{fields}[$column]{header} = 1;
$self->{fields}[$column]{writeable} = 0;
}
$self->_get_labels($table);
return ($width, $height);
}
sub get_column {
my $self = shift;
my $column = shift;
my @data;
for (my $i=0; $i <= $self->{internal}{height}; $i++) {
push (@data, $self->{data}->[$i][$column]);
}
return @data;
}
sub get_row {
my $self = shift;
my $row = shift;
my @data;
for (my $i=0; $i <= $self->{internal}{width}; $i++) {
push (@data, $self->{data}->[$row][$i]);
}
return @data;
}
sub get_labels {
my $self = shift;
my @data;
for (my $i=0; $i <= $self->{internal}{width}; $i++) {
push (@data, $self->{fields}->[$i]->{label});
}
return @data;
}
sub clean_times {
my $self = shift;
my $col = shift || '0';
for (my $i=0; $i < $self->{internal}{height}; $i++) {
$self->{data}->[$i][$col] =~ s/\s+\d\d:\d\d:\d\d.*$//;
}
}
sub short_dates {
my $self = shift;
my $col = shift || '0';
for (my $i=0; $i < $self->{internal}{height}; $i++) {
$self->{data}->[$i][$col] =~ s/\d\d(\d\d)-(\d\d)-(\d\d)/$2-$3-$1/;
}
}
##########################################################################################################################
# Private Methods
sub _get_labels {
my $self = shift;
my $table = shift;
my $tmp;
my $query;
my @labels = ();
if ($self->{connection}{type} eq 'mysql') {
$query = "SHOW COLUMNS FROM $table"; # cant use ? placeholder (embeds in single quotes)
$self->{connection}{sth} = $self->{connection}{dbh}->prepare($query) || confess($self->{connection}{dbh}->errstr);
$self->{connection}{sth}->execute() || confess($self->{connection}{sth}->errstr);
} elsif ($self->{connection}{type} eq 'odbc') {
$query = 'SELECT column_name, data_type FROM information_schema.columns WHERE table_name=?';
$self->{connection}{sth} = $self->{connection}{dbh}->prepare($query) || confess($self->{connection}{dbh}->errstr);
$self->{connection}{sth}->execute($table) || confess($self->{connection}{sth}->errstr);
} elsif ($self->{connection}{type} eq 'sqlite') {
$query = "PRAGMA table_info($table)";
$self->{connection}{sth} = $self->{connection}{dbh}->prepare($query) || confess($self->{connection}{dbh}->errstr);
$self->{connection}{sth}->execute() || confess($self->{connection}{sth}->errstr);
}
$tmp = $self->{connection}{sth}->fetchall_arrayref();
if (defined($tmp)) {
my $num_rows = $#{$tmp};
my $column = 0;
for my $row (0..$num_rows) {
if ($self->{connection}{type} ne 'sqlite') {
my $name = $tmp->[$row][0];
my $type = $tmp->[$row][1];
$self->{fields}[$column]{label} = $name;
$self->{fields}[$column]{name} = $name;
$self->{fields}[$column]{type} = $type;
$column++;
} else {
my $name = $tmp->[$row][1];
my $type = $tmp->[$row][3];
$self->{fields}[$column]{label} = $name;
$self->{fields}[$column]{name} = $name;
$self->{fields}[$column]{type} = $type;
$column++;
}
}
}
}
sub _extract_table {
my $self = shift;
my $statement = shift;
my $table;
# Add a space so that the regex below does not fail on statements like:
# "SELECT * FROM some_table"
$statement .= ' ';
if ($statement =~ /^SELECT\s+(.*)\s+FROM\s+(\w+)\s+(.*)/) {
$table = $2;
} else {
$table = 'undefined_tablename';
}
return $table;
}
1;
=pod
=head1 Name
SAL::DBI
=head1 Synopsis
=head1 Methods
=head2 Constructors
new()
spawn_mysql()
spawn_odbc()
spawn_sqlite()
=head2 Destructor
destruct()
=head2 Eponymous Hash
=head2 Public
do()
execute()
get_column()
get_row()
get_labels()
clean_times()
short_dates()
=head1 See Also
SAL::DBI, SAL::Graph, SAL::WebDDR, SAL::WebApplication
=cut

