X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=torrus%2Fperllib%2FTorrus%2FSQL.pm;fp=torrus%2Fperllib%2FTorrus%2FSQL.pm;h=de54cacee09249478c2233e30d125dcd0a7a1df3;hb=74e058c8a010ef6feb539248a550d0bb169c1e94;hp=0000000000000000000000000000000000000000;hpb=35359a73152b3d7a9ad5e3d37faf81f6fedb76e8;p=freeside.git diff --git a/torrus/perllib/Torrus/SQL.pm b/torrus/perllib/Torrus/SQL.pm new file mode 100644 index 000000000..de54cacee --- /dev/null +++ b/torrus/perllib/Torrus/SQL.pm @@ -0,0 +1,234 @@ +# Copyright (C) 2005 Stanislav Sinyagin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +# $Id: SQL.pm,v 1.1 2010-12-27 00:03:38 ivan Exp $ +# Stanislav Sinyagin + +# Package for RDBMS communication management in Torrus +# Classes should inherit Torrus::SQL and execute Torrus::SQL->new(), +# and then use methods of DBIx::Abstract. + +package Torrus::SQL; + +use strict; +use DBI; +use DBIx::Abstract; +use DBIx::Sequence; + +use Torrus::Log; + +my %connectionArgsCache; + +# Obtain connection attributes for particular class and object subtype. +# The attributes are defined in torrus-siteconfig.pl, in a hash +# %Torrus::SQL::connections. +# For a given Perl class and an optional subtype, +# the connection attributes are derived in the following order: +# 'Default', 'Default/[subtype]', '[Class]', '[Class]/[subtype]', +# 'All/[subtype]'. +# For a simple setup, the default attributes are usually defined for +# 'Default' key. +# The key attributes are: 'dsn', 'username', and 'password'. +# Returns a hash reference with the same keys. + +sub getConnectionArgs +{ + my $class = shift; + my $objClass = shift; + my $subtype = shift; + + my $cachekey = $objClass . ( defined( $subtype )? '/'.$subtype : ''); + if( defined( $connectionArgsCache{$cachekey} ) ) + { + return $connectionArgsCache{$cachekey}; + } + + my @lookup = ('Default'); + if( defined( $subtype ) ) + { + push( @lookup, 'Default/' . $subtype ); + } + push( @lookup, $objClass ); + if( defined( $subtype ) ) + { + push( @lookup, $objClass . '/' . $subtype, 'All/' . $subtype ); + } + + my $ret = {}; + foreach my $attr ( 'dsn', 'username', 'password' ) + { + my $val; + foreach my $key ( @lookup ) + { + if( defined( $Torrus::SQL::connections{$key} ) ) + { + if( defined( $Torrus::SQL::connections{$key}{$attr} ) ) + { + $val = $Torrus::SQL::connections{$key}{$attr}; + } + } + } + if( not defined( $val ) ) + { + die('Undefined attribute in %Torrus::SQL::connections: ' . $attr); + } + $ret->{$attr} = $val; + } + + $connectionArgsCache{$cachekey} = $ret; + + return $ret; +} + + +my %dbhPool; + +# For those who want direct DBI manipulation, simply call +# Class->dbh($subtype) with optional subtype. Then you don't use +# any other methods of Torrus::SQL. + +sub dbh +{ + my $class = shift; + my $subtype = shift; + + my $attrs = Torrus::SQL->getConnectionArgs( $class, $subtype ); + + my $poolkey = $attrs->{'dsn'} . '//' . $attrs->{'username'} . '//' . + $attrs->{'password'}; + + my $dbh; + + if( exists( $dbhPool{$poolkey} ) ) + { + $dbh = $dbhPool{$poolkey}; + if( not $dbh->ping() ) + { + $dbh = undef; + delete $dbhPool{$poolkey}; + } + } + + if( not defined( $dbh ) ) + { + $dbh = DBI->connect( $attrs->{'dsn'}, + $attrs->{'username'}, + $attrs->{'password'}, + { 'PrintError' => 0, + 'AutoCommit' => 0 } ); + + if( not defined( $dbh ) ) + { + Error('Error connecting to DBI source ' . $attrs->{'dsn'} . ': ' . + $DBI::errstr); + } + else + { + $dbhPool{$poolkey} = $dbh; + } + } + + return $dbh; +} + + +END +{ + foreach my $dbh ( values %dbhPool ) + { + $dbh->disconnect(); + } +} + + +sub new +{ + my $class = shift; + my $subtype = shift; + + my $self = {}; + + $self->{'dbh'} = $class->dbh( $subtype ); + if( not defined( $self->{'dbh'} ) ) + { + return undef; + } + + $self->{'sql'} = DBIx::Abstract->connect( $self->{'dbh'} ); + + $self->{'subtype'} = $subtype; + $self->{'classname'} = $class; + + bless ($self, $class); + return $self; +} + + + +sub sequence +{ + my $self = shift; + + if( not defined( $self->{'sequence'} ) ) + { + my $attrs = Torrus::SQL->getConnectionArgs( $self->{'classname'}, + $self->{'subtype'} ); + + $self->{'sequence'} = DBIx::Sequence->new({ + dbh => $self->{'dbh'}, + allow_id_reuse => 1 }); + } + return $self->{'sequence'}; +} + + +sub sequenceNext +{ + my $self = shift; + + return $self->sequence()->Next($self->{'classname'}); +} + + +sub fetchall +{ + my $self = shift; + my $columns = shift; + + my $ret = []; + while( defined( my $row = $self->{'sql'}->fetchrow_arrayref() ) ) + { + my $retrecord = {}; + my $i = 0; + foreach my $col ( @{$columns} ) + { + $retrecord->{$col} = $row->[$i++]; + } + push( @{$ret}, $retrecord ); + } + + return $ret; +} + + +1; + + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# perl-indent-level: 4 +# End: