/usr/local/CPAN/dbMan/DBIx/dbMan/DBI.pm
package DBIx::dbMan::DBI;
use strict;
use locale;
use vars qw/$AUTOLOAD/;
use POSIX;
use DBIx::dbMan::Config;
use DBI;
our $VERSION = '0.08';
1;
sub new {
my $class = shift;
my $obj = bless { @_ }, $class;
$obj->clear_all_connections;
$obj->load_connections;
return $obj;
}
sub connectiondir {
my $obj = shift;
return $ENV{DBMAN_CONNECTIONDIR} if $ENV{DBMAN_CONNECTIONDIR};
return $obj->{-config}->connection_dir if $obj->{-config}->connection_dir;
mkdir $ENV{HOME}.'/.dbman/connections' unless -d $ENV{HOME}.'/.dbman/connections';
return $ENV{HOME}.'/.dbman/connections';
}
sub clear_all_connections {
my $obj = shift;
$obj->{connections} = {};
}
sub load_connections {
my $obj = shift;
my $cdir = $obj->connectiondir;
return -1 unless -d $cdir;
opendir D,$cdir;
$obj->load_connection($_) for grep !/^\.\.?/,readdir D;
closedir D;
my $current = '';
$current = $obj->{-config}->current_connection if $obj->{-config}->current_connection;
$obj->{-interface}->add_to_actionlist({ action => 'CONNECTION',
operation => 'use', what => $current });
}
sub load_connection {
my ($obj,$name) = @_;
my $cdir = $obj->connectiondir;
return -1 unless -d $cdir;
$cdir =~ s/\/$//;
return -2 unless -f "$cdir/$name";
CORE::open F,"$cdir/$name" or return -2;
CORE::close F;
my $lcfg = new DBIx::dbMan::Config -file => "$cdir/$name";
my %connection;
$connection{$_} = $lcfg->$_ for $lcfg->all_tags;
$obj->{connections}->{$name} = \%connection;
$obj->{-interface}->add_to_actionlist({ action => 'CONNECTION',
operation => 'open', what => $name }) if lc $lcfg->auto_login eq 'yes';
}
sub open {
my ($obj,$name) = @_;
return -3 unless exists $obj->{connections}->{$name};
return -4 if $obj->{connections}->{$name}->{-logged};
return -1 unless grep { $_ eq $obj->{connections}->{$name}->{driver} } $obj->driverlist;
my $dbi = DBI->connect('dbi:'.$obj->{connections}->{$name}->{driver}.
':'.$obj->{connections}->{$name}->{dsn},
$obj->{connections}->{$name}->{login},
$obj->{connections}->{$name}->{password},
{ PrintError => 0, RaiseError => 0, AutoCommit => 1, LongTruncOk => 1 });
return -2 unless defined $dbi;
$obj->{connections}->{$name}->{-dbi} = $dbi;
$obj->{connections}->{$name}->{-logged} = 1;
$obj->{-interface}->add_to_actionlist({ action => 'AUTO_SQL', connection => $name });
return 0;
}
sub driverlist {
my $obj = shift;
return DBI->available_drivers;
}
sub close {
my ($obj,$name) = @_;
return -1 unless exists $obj->{connections}->{$name};
return -2 unless $obj->{connections}->{$name}->{-logged};
$obj->set_current() if $obj->{current} eq $name;
$obj->discard_profile_data();
delete $obj->{connections}->{$name}->{-logged};
$obj->{connections}->{$name}->{-dbi}->disconnect();
undef $obj->{connections}->{$name}->{-dbi};
return 0;
}
sub close_all {
my $obj = shift;
for my $name (keys %{$obj->{connections}}) {
if ($obj->{connections}->{$name}->{-logged}) {
$obj->close($name);
$obj->{-interface}->print("Disconnected from $name.\n");
# we can't move this message to extension - close_all called when
# destroying DBI object (handle event collapsed :(, no OUTPUT event exist)
}
}
}
sub DESTROY {
my $obj = shift;
$obj->close_all;
}
sub list {
my ($obj,$what) = @_;
my @returned = ();
for my $name (keys %{$obj->{connections}}) {
my %r = %{$obj->{connections}->{$name}};
next if ($what eq 'inactive' and $r{-logged}) || ($what eq 'active' and ! $r{-logged});
$r{name} = $name;
push @returned, \%r;
}
return [ sort { $a->{name} cmp $b->{name} } @returned ];
}
sub autosql {
my $obj = shift;
return -1 unless $obj->{current};
return -2 unless exists $obj->{connections}->{$obj->{current}};
return $obj->{connections}->{$obj->{current}}->{autosql};
}
sub silent_autosql {
my $obj = shift;
return -1 unless $obj->{current};
return -2 unless exists $obj->{connections}->{$obj->{current}};
return $obj->{connections}->{$obj->{current}}->{silent_autosql};
}
sub set_current {
my ($obj,$name) = @_;
return 9999 if $obj->{current} eq $name;
unless ($name) { delete $obj->{current}; return 1; }
return -1 unless exists $obj->{connections}->{$name};
return -2 unless $obj->{connections}->{$name}->{-logged};
$obj->{current} = $name;
return 0;
}
sub current {
my $obj = shift;
return $obj->{current};
}
sub drop_connection {
my ($obj,$name) = @_;
return -1 unless exists $obj->{connections}->{$name};
$obj->close($name) if $obj->{connections}->{$name}->{-logged};
delete $obj->{connections}->{$name};
return 0;
}
sub create_connection {
my ($obj,$name,$p) = @_;
my %parms = %$p;
return -1 if exists $obj->{connections}->{$name};
$obj->{connections}->{$name} = \%parms;
return 100+$obj->open($name) if lc $parms{auto_login} eq 'yes';
return 0;
}
sub save_connection {
my $obj = shift;
my $name = shift;
return -1 unless exists $obj->{connections}->{$name};
my $cdir = $obj->connectiondir;
mkdir $cdir unless -d $cdir;
return -1 unless -d $cdir;
$cdir =~ s/\/$//;
CORE::open F,">$cdir/$name" or return -2;
for (qw/driver dsn login password auto_login/) {
print F "$_ ".$obj->{connections}->{$name}->{$_}."\n"
if exists $obj->{connections}->{$name}->{$_}
and $obj->{connections}->{$name}->{$_} ne '';
}
CORE::close F;
chmod 0600,"$cdir/$name";
return 0;
}
sub destroy_connection {
my $obj = shift;
my $name = shift;
my $cdir = $obj->connectiondir;
return -1 unless -d $cdir;
$cdir =~ s/\/$//;
return 1 unless -e "$cdir/$name";
unlink "$cdir/$name";
return -2 if -e "$cdir/$name";
return 0;
}
sub is_permanent_connection {
my $obj = shift;
my $name = shift;
my $cdir = $obj->connectiondir;
return 0 unless -d $cdir;
$cdir =~ s/\/$//;
return -e "$cdir/$name";
}
sub trans_begin {
my $obj = shift;
return -1 unless $obj->{current};
$obj->{connections}->{$obj->{current}}->{-dbi}->{AutoCommit} = 0;
}
sub longreadlen {
my $obj = shift;
my $long = shift;
$obj->{connections}->{$obj->{current}}->{-dbi}->{LongReadLen} = $long if $long;
return $obj->{connections}->{$obj->{current}}->{-dbi}->{LongReadLen};
}
sub trans_end {
my $obj = shift;
return -1 unless $obj->{current};
$obj->{connections}->{$obj->{current}}->{-dbi}->{AutoCommit} = 1;
}
sub in_transaction {
my $obj = shift;
return 0 unless $obj->{current};
return not $obj->{connections}->{$obj->{current}}->{-dbi}->{AutoCommit};
}
sub driver {
my $obj = shift;
return undef unless $obj->{current};
return $obj->{connections}->{$obj->{current}}->{driver};
}
sub login {
my $obj = shift;
return undef unless $obj->{current};
return $obj->{connections}->{$obj->{current}}->{login};
}
sub AUTOLOAD {
my $obj = shift;
$AUTOLOAD =~ s/^DBIx::dbMan::DBI:://g;
return undef unless $obj->{current};
return undef unless exists $obj->{connections}->{$obj->{current}};
return undef unless $obj->{connections}->{$obj->{current}}->{-logged};
return undef unless defined $obj->{connections}->{$obj->{current}}->{-dbi};
my $dbi = $obj->{connections}->{$obj->{current}}->{-dbi};
return $dbi->$AUTOLOAD(@_);
}
sub set {
my ($obj,$var,$val) = @_;
return unless $obj->{current};
$obj->{connections}->{$obj->{current}}->{-dbi}->{$var} = $val;
}
sub get {
my ($obj,$var) = @_;
return undef unless $obj->{current};
return $obj->{connections}->{$obj->{current}}->{-dbi}->{$var};
}
sub discard_profile_data {
my $obj = shift;
return unless $obj->{current};
# $obj->{connections}->{$obj->{current}}->{-dbi}->{Profile}->{Data} = undef;
}