/usr/local/CPAN/Perlbug/Perlbug/Interface/Tk.pm
#!/pro/bin/perl -w
package Perlbug::Interface::Tk;
use strict;
use vars qw($VERSION @ISA);
$VERSION = do { my @r = (q$Revision: 1.8 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
$|=1;
use DBI;
use Carp;
use Exporter;
use vars qw(@ISA @EXPORT);
@ISA = ("Exporter", scalar caller);
@EXPORT = qw(
DBDlogon DBDlogoff
describe
prepar prepex
getrow getrows
local_sql sql_into
);
umask 0;
my $dbtype;
my $dbh; # Everyone else uses prepex () or do ()
my $dbh_st;
$SIG{__DIE__} = sub {
$_[0] =~ m/^DBD::/ or return;
$dbh && ($dbh->err || $dbh->state) or return;
my ($depth, $file, $line) = (1, __FILE__);
while ($file =~ m:/Tk.pm$:) { ($line, $file) = (caller ($depth++))[2, 1] }
printf STDERR "DBI:DBD Failure from line %d in %s\n", $line, $file;
$dbh->err and print STDERR " err:\t", $dbh->err, "\n";
$dbh->errstr and print STDERR " errstr:\t", $dbh->errstr, "\n";
$dbh->state and print STDERR " state:\t", $dbh->state, "\n";
if ($DBI::lasth) {
my $s = $DBI::lasth->{Type} eq "st" ? $DBI::lasth->{Statement} : $dbh_st;
print STDERR " ", (join "\n " =>
"--------",
split (m/\n/ => $s),
"--------"), "\n";
}
die "";
}; # __DIE__
### SQL utils #################################################################
sub DBDlogon (;$$) # Default Read-Only
{
$dbh and return $dbh;
my $wr = 0;
my %attr = (
RaiseError => 1,
PrintError => 1,
AutoCommit => 0,
ChopBlanks => 1,
);
$DBI::VERSION >= "1.15" and $attr{ShowErrorStatement} = 1;
@_ && !ref $_[0] and $wr = shift;
if (@_ && ref $_[0]) {
my $r = shift;
foreach my $attr (keys %$r) { $attr{$attr} = $r->{$attr} }
}
if (exists $ENV{ORACLE_HOME} && -d $ENV{ORACLE_HOME}) {
my ($dbu, $dbp) = split m:/: => $ENV{DBUSER};
$dbh = DBI->connect ("DBI:Oracle:", $dbu, $dbp, \%attr) or
croak "connect: $!";
$wr or $dbh->do ("set transaction read only");
$dbtype = "Oracle";
}
else {
my $db = exists $ENV{MYSQLDB} ? $ENV{MYSQLDB} : "perlbug";
delete $attr{AutoCommit}; # MySQL still croaks on this one
$dbh = DBI->connect ("DBI:mysql:database=$db", $ENV{LOGNAME}, undef, \%attr) or
croak "connect: $!";
$dbtype = "mysql";
}
$dbh;
} # DBDlogon
sub DBDlogoff ()
{
$dbh and $dbh->disconnect;
$dbh = undef;
} # DBDlogoff
# prepar () / prepex () serve two purposes:
# 1. Ease passed statement to allow statement lines in array
# 2. Hide $dbh to the outside world
# 3. Enable immediate column binding
# 4. Combine the ever occuring execute method after the prepare
# We do not have to check anything, since RaiseError is on
sub prepar (@)
{
$dbh or DBDlogon ();
my (@st, @bc);
for (@_) { ref $_ ? push @bc, $_ : push @st, $_ }
$dbh_st = join "\n", @st;
my $sth = $dbh->prepare ($dbh_st);
# MySQL does not support bind before execute.
if (@bc) {
$dbtype eq "mysql" and $sth->execute ((undef) x $sth->{NUM_OF_PARAMS});
$sth->bind_columns (@bc);
$dbtype eq "mysql" and $sth->finish;
}
$sth;
} # prepar
sub prepex (@)
{
my $sth = prepar (@_);
$sth->execute;
$sth;
} # prepex
sub getrow (@)
{
$dbh or DBDlogon ();
$dbh_st = join "\n", @_;
$dbh->selectrow_array ($dbh_st);
} # getrow
sub getrows (@)
{
my $sth = prepex (@_);
$sth->getrows;
} # getrows
sub describe ($)
{
$dbh or DBDlogon ();
my $sth = prepex ("select * from $_[0] where 0 = 1");
my @desc;
my @name = @{$sth->{NAME}};
foreach my $i (0 .. $#name) {
foreach my $col (qw( NAME TYPE PRECISION SCALE NULLABLE )) {
$desc[$i]{$col} = $sth->{$col}[$i];
}
}
@desc;
} # describe
### ###########################################################################
# Next two are to prevent DB's like Oracle to convert empty strings to NULL
sub DBI::st::insert ($@)
{
my $sth = shift;
$sth->execute (map { defined ($_) && $_ eq "" ? " " : $_ } @_);
} # insert
sub DBI::st::update ($@)
{
my $sth = shift;
$sth->execute (map { defined ($_) && $_ eq "" ? " " : $_ } @_);
} # update
sub DBI::st::getrows ($@)
{
my $sth = shift;
my @r = ();
$sth->execute (@_);
while (my @f = $sth->fetchrow_array) {
push @r, @f == 1 ? $f[0] : [ @f ];
}
@r;
} # getrows