CTKlib
view release on metacpan or search on metacpan
lib/CTK/DBI.pm view on Meta::CPAN
=head1 HISTORY
See C<Changes> file
=head1 VARIABLES
=over 4
=item B<$CTK::DBI::CTK_DBI_DEBUG>
Debug mode flag. Default: 0
=item B<$CTK::DBI::CTK_DBI_ERROR>
General error string
=back
=head1 DEPENDENCIES
L<DBI>
=head1 TO DO
See C<TODO> file
=head1 BUGS
* none noted
=head1 SEE ALSO
L<DBI>
=head1 AUTHOR
Serż Minus (Sergey Lepenkov) L<https://www.serzik.com> E<lt>abalama@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright (C) 1998-2022 D&D Corporation. All Rights Reserved
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See C<LICENSE> file and L<https://dev.perl.org/licenses/>
=cut
use vars qw/$VERSION/;
$VERSION = '2.31';
our $CTK_DBI_DEBUG = 0;
our $CTK_DBI_ERROR = "";
use Carp;
use CTK::Util qw( :API );
use CTK::Timeout;
use DBI qw();
# Create global Timeout object
my $to = CTK::Timeout->new();
sub new {
my $class = shift;
my @in = read_attributes([
['DSN','STRING','STR'],
['USER','USERNAME','LOGIN'],
['PASSWORD','PASS'],
['TIMEOUT_CONNECT','CONNECT_TIMEOUT','CNT_TIMEOUT','TIMEOUT_CNT','TO_CONNECT','CONNECT_TO'],
['TIMEOUT_REQUEST','REQUEST_TIMEOUT','REQ_TIMEOUT','TIMEOUT_REQ','TO_REQUEST','REQUEST_TO'],
['ATTRIBUTES','ATTR','ATTRS','ATTRHASH','PARAMS'],
['PREPARE_ATTRIBUTES','PREPARE_ATTR','PREPARE_ATTRS'],
['DEBUG'],
], @_);
if ($in[7]) {
$CTK_DBI_DEBUG = 1;
}
# General arguments
my %args = (
dsn => $in[0] || '',
user => $in[1] // '',
password => $in[2] // '',
connect_to => $in[3] // 0,
request_to => $in[4] // 0,
attr => $in[5] || undef,
prepare_attr=> $in[6] || undef,
debug => $in[7] // 0,
dbh => undef,
error => "", # Ok
);
# Connect
my $_err = "";
$args{dbh} = DBI_CONNECT($args{dsn}, $args{user}, $args{password}, $args{attr}, $args{connect_to}, \$_err);
# Create CTK::DBI object
my $self = bless {%args}, $class;
if ($args{dbh}) { # Ok
_debug(sprintf("--- CTK::DBI CONNECT {%s} ---", $args{dsn}));
} else {
$self->_set_error($_err);
}
return $self;
}
sub _set_error {
my $self = shift;
my $merr = shift;
my $dbh = $self->{dbh};
# Set error string
$self->{error} = "";
if (defined($merr)) {
$self->{error} = $merr;
} else {
if ($dbh && $dbh->can('errstr')) {
$self->{error} = $dbh->errstr // '';
}
unless (length($self->{error})) {
lib/CTK/DBI.pm view on Meta::CPAN
my $sth = $self->execute(@_);
return () unless $sth;
my $rslt = $sth->fetchall_hashref($key_field);
$rslt = {} unless $rslt && ref($rslt) eq 'HASH';
my %result = %$rslt;
$sth->finish;
return %result;
}
sub execute {
my $self = shift;
my $sql = shift // '';
my @inargs = @_;
my $dbh = $self->{dbh} || return;
$self->_set_error(""); # Flush errors first
return $self->_set_error("No statement specified") unless length($sql);
# Prepare
my $prepare_attr = $self->{prepare_attr};
my %attr = ($prepare_attr && ref($prepare_attr) eq 'HASH') ? %$prepare_attr : ();
my $sth_ex = keys(%attr)
? $dbh->prepare($sql, {%attr})
: $dbh->prepare($sql);
unless ($sth_ex) {
return $self->_set_error(sprintf("Can't prepare statement \"%s\": %s", $sql, $dbh->errstr // 'unknown error'));
}
# Execute
my $err = "";
my $retval = $to->timeout_call(sub {
unless ($sth_ex->execute(@inargs)) {
$err = $dbh->errstr || "the DBI::execute method has returned false status";
}
1;
}, $self->{request_to});
unless ($retval) {
$err = $to->error || "unknown error";
}
# Errors
if ($err) {
my @repsrgs = @inargs;
my $argb = "";
$argb = sprintf(" with bind variables: %s", join(", ", map {defined($_) ? sprintf("\"%s\"", $_) : 'undef'} @repsrgs))
if exists($inargs[0]);
return $self->_set_error(sprintf("Can't execute statement \"%s\"%s: %s", $sql, $argb, $err));
}
return $sth_ex;
}
sub DESTROY {
my $self = shift;
$self->disconnect();
}
sub DBI_CONNECT {
# $dbh = DBI_CONNECT($dsn, $user, $password, $attr, $timeout, \$error)
my $db_dsn = shift || ''; # DSN
my $db_user = shift // ''; # DB Username
my $db_password = shift // ''; # DB Password
my $db_attr = shift || {}; # Attributes DBD::* (hash-ref) E.g., {ORACLE_enable_utf8 => 1}
my $db_tocnt = shift // 0; # Timeout value
my $rerr = shift; # Reference to error scalar
$rerr = \$CTK_DBI_ERROR unless $rerr && ref($rerr) eq 'SCALAR';
my $dbh;
# Connect
my $err = "";
my $retval = $to->timeout_call(sub {
$dbh = DBI->connect($db_dsn, "$db_user", "$db_password", $db_attr);
unless ($dbh) {
$err = $DBI::errstr || "the DBI::connect method has returned false status";
}
1;
}, $db_tocnt);
unless ($retval) {
$err = $to->error || "unknown error";
}
# Errors
if ($err) {
$$rerr = sprintf("Can't connect to \"%s\", %s", $db_dsn, $err);
}
# DBI handler or undef
return $dbh;
}
sub _debug { $CTK_DBI_DEBUG ? carp(@_) : 1 }
1;
__END__
( run in 1.627 second using v1.01-cache-2.11-cpan-2398b32b56e )