bury dead whitespace
[torrus-plus.git] / src / lib / Torrus / SQL.pm
blobf4ac66196ec46a89bca0ffd6c58f264c54cce73c
1 # Copyright (C) 2005 Stanislav Sinyagin
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
17 # $Id$
18 # Stanislav Sinyagin <ssinyagin@yahoo.com>
20 # Package for RDBMS communication management in Torrus
21 # Classes should inherit Torrus::SQL and execute Torrus::SQL->new(),
22 # and then use methods of DBIx::Abstract.
24 package Torrus::SQL;
26 use strict;
27 use DBI;
28 use DBIx::Abstract;
29 use DBIx::Sequence;
31 use Torrus::Log;
33 our $VERSION = 1.0;
35 my %connectionArgsCache;
37 # Obtain connection attributes for particular class and object subtype.
38 # The attributes are defined in torrus-siteconfig.pl, in a hash
39 # %Torrus::SQL::connections.
40 # For a given Perl class and an optional subtype,
41 # the connection attributes are derived in the following order:
42 # 'Default', 'Default/[subtype]', '[Class]', '[Class]/[subtype]',
43 # 'All/[subtype]'.
44 # For a simple setup, the default attributes are usually defined for
45 # 'Default' key.
46 # The key attributes are: 'dsn', 'username', and 'password'.
47 # Returns a hash reference with the same keys.
49 sub getConnectionArgs
51 my $class = shift;
52 my $objClass = shift;
53 my $subtype = shift;
55 my $cachekey = $objClass . ( defined( $subtype )? '/'.$subtype : '');
56 if( defined( $connectionArgsCache{$cachekey} ) )
58 return $connectionArgsCache{$cachekey};
61 my @lookup = ('Default');
62 if( defined( $subtype ) )
64 push( @lookup, 'Default/' . $subtype );
66 push( @lookup, $objClass );
67 if( defined( $subtype ) )
69 push( @lookup, $objClass . '/' . $subtype, 'All/' . $subtype );
72 my $ret = {};
73 for my $attr ( 'dsn', 'username', 'password' )
75 my $val;
76 for my $key ( @lookup )
78 if( defined( $Torrus::SQL::connections{$key} ) )
80 if( defined( $Torrus::SQL::connections{$key}{$attr} ) )
82 $val = $Torrus::SQL::connections{$key}{$attr};
86 if( not defined( $val ) )
88 die('Undefined attribute in %Torrus::SQL::connections: ' . $attr);
90 $ret->{$attr} = $val;
93 $connectionArgsCache{$cachekey} = $ret;
95 return $ret;
99 my %dbhPool;
101 # For those who want direct DBI manipulation, simply call
102 # Class->dbh($subtype) with optional subtype. Then you don't use
103 # any other methods of Torrus::SQL.
105 sub dbh
107 my $class = shift;
108 my $subtype = shift;
110 my $attrs = Torrus::SQL->getConnectionArgs( $class, $subtype );
112 my $poolkey = $attrs->{'dsn'} . '//' . $attrs->{'username'} . '//' .
113 $attrs->{'password'};
115 my $dbh;
117 if( exists( $dbhPool{$poolkey} ) )
119 $dbh = $dbhPool{$poolkey};
120 if( not $dbh->ping() )
122 $dbh = undef;
123 delete $dbhPool{$poolkey};
127 if( not defined( $dbh ) )
129 $dbh = DBI->connect( $attrs->{'dsn'},
130 $attrs->{'username'},
131 $attrs->{'password'},
132 { 'PrintError' => 0,
133 'AutoCommit' => 0 } );
135 if( not defined( $dbh ) )
137 Error('Error connecting to DBI source ' . $attrs->{'dsn'} . ': ' .
138 $DBI::errstr);
140 else
142 $dbhPool{$poolkey} = $dbh;
146 return $dbh;
152 for my $dbh ( values %dbhPool )
154 $dbh->disconnect();
159 sub new
161 my $class = shift;
162 my $subtype = shift;
164 my $self = {};
166 $self->{'dbh'} = $class->dbh( $subtype );
167 if( not defined( $self->{'dbh'} ) )
169 return
172 $self->{'sql'} = DBIx::Abstract->connect( $self->{'dbh'} );
174 $self->{'subtype'} = $subtype;
175 $self->{'classname'} = $class;
177 bless ($self, $class);
178 return $self;
183 sub sequence
185 my $self = shift;
187 if( not defined( $self->{'sequence'} ) )
189 my $attrs = Torrus::SQL->getConnectionArgs( $self->{'classname'},
190 $self->{'subtype'} );
192 $self->{'sequence'} = DBIx::Sequence->new({
193 dbh => $self->{'dbh'},
194 allow_id_reuse => 1 });
196 return $self->{'sequence'};
200 sub sequenceNext
202 my $self = shift;
204 return $self->sequence()->Next($self->{'classname'});
208 sub fetchall
210 my $self = shift;
211 my $columns = shift;
213 my $ret = [];
214 while( defined( my $row = $self->{'sql'}->fetchrow_arrayref() ) )
216 my $retrecord = {};
217 my $i = 0;
218 for my $col ( @{$columns} )
220 $retrecord->{$col} = $row->[$i++];
222 push( @{$ret}, $retrecord );
225 return $ret;
232 # Local Variables:
233 # mode: perl
234 # indent-tabs-mode: nil
235 # perl-indent-level: 4
236 # End: