File Coverage

blib/lib/BW/DB.pm
Criterion Covered Total %
statement 15 137 10.9
branch 0 100 0.0
condition 0 23 0.0
subroutine 5 26 19.2
pod 8 20 40.0
total 28 306 9.1


line stmt bran cond sub pod time code
1             # BW::DB.pm
2             # Normalized database routines
3             # with support for MySQL and SQLite
4             #
5             # by Bill Weinman - http://bw.org/
6             # Copyright (c) 1995-2010 The BearHeart Group, LLC
7             #
8             # See HISTORY file.
9             #
10              
11             package BW::DB;
12 1     1   30394 use strict;
  1         3  
  1         37  
13 1     1   4 use warnings;
  1         2  
  1         49  
14              
15 1     1   4 use base qw( BW::Base );
  1         6  
  1         751  
16 1     1   2457 use BW::Constants;
  1         2  
  1         60  
17 1     1   5 use DBI;
  1         2  
  1         2039  
18              
19             our $VERSION = "1.1.1";
20              
21             sub _init
22             {
23 0     0     my $self = shift;
24 0           $self->SUPER::_init(@_);
25              
26 0 0 0       if ( $self->{connect} or $self->{dsn} or $self->{database} or $self->{dbengine} ) {
      0        
      0        
27 0           $self->init_db;
28             }
29              
30 0           return SUCCESS;
31             }
32              
33             # _setter_getter entry points
34 0     0 1   sub connect { BW::Base::_setter_getter(@_); }
35 0     0 0   sub database { BW::Base::_setter_getter(@_); }
36 0     0 0   sub dbname { BW::Base::_setter_getter(@_); }
37 0     0 0   sub host { BW::Base::_setter_getter(@_); }
38 0     0 0   sub port { BW::Base::_setter_getter(@_); }
39 0     0 0   sub socket { BW::Base::_setter_getter(@_); }
40 0     0 0   sub user { BW::Base::_setter_getter(@_); }
41 0     0 0   sub password { BW::Base::_setter_getter(@_); }
42 0     0 0   sub dsn { BW::Base::_setter_getter(@_); }
43 0     0 0   sub dbh { BW::Base::_setter_getter(@_); }
44 0     0 0   sub dbengine { BW::Base::_setter_getter(@_); } # may be 'mysql' or 'SQLite'
45              
46             # setup the database connection
47             sub init_db
48             {
49 0     0 0   my $sn = 'init_db';
50 0           my $self = shift;
51              
52 0           my ( $dsn, $dbengine, $dbname, $database, $host, $port, $socket, $user, $password );
53 0   0       $dbengine = $self->{dbengine} || 'mysql'; # default to mysql for backward compatibility
54              
55 0 0         if ( $self->connect ) {
    0          
    0          
    0          
56 0           my @dsnarray = split( /:/, $self->{connect} );
57 0 0         if( scalar @dsnarray == 2 ) {
58 0           ( $dbengine, $dbname ) = @dsnarray;
59             } else {
60 0           ( $database, $host, $port, $user, $password ) = split( /:/, $self->{connect} );
61             }
62             } elsif ( $self->{dsn} ) {
63 0           $dsn = $self->{dsn};
64             } elsif ( $self->{dbname} ) {
65 0           $dbengine = 'SQLite';
66 0           $dbname = $self->{dbname};
67             } elsif ( $self->{database} ) {
68 0           $database = $self->{database};
69 0           $host = $self->{host};
70 0           $port = $self->{port};
71 0           $socket = $self->{socket};
72             }
73              
74 0 0         if(lc $dbengine eq 'sqlite') { $dbengine = 'SQLite' }; # correct any miscapitalization
  0            
75              
76 0 0         $self->dbengine($dbengine) if $dbengine; # use the setters
77 0 0         $self->dbname($dbname) if $dbname;
78              
79 0 0         $user = $self->{user} if $self->{user};
80 0 0         $password = $self->{password} if $self->{password};
81 0 0         $dsn = "DBI:${dbengine}" unless $dsn;
82 0 0         $dsn .= ":database=$database" if $database;
83 0 0         $dsn .= ":dbname=$dbname" if $dbname;
84 0 0         $dsn .= ";host=$host" if $host;
85 0 0         $dsn .= ";port=$port" if $port;
86 0 0         $dsn .= ";mysql_socket=$socket" if $socket;
87              
88 0           $self->{dbh} = DBI->connect( $dsn, $user, $password, { PrintError => 0 } );
89 0 0         return $self->_error("$sn: DBI connect error: $DBI::errstr") if $DBI::errstr;
90 0 0         return $self->_error("$sn: database not connected") unless $self->{dbh};
91             }
92              
93             # sql_do ( $query, @bind_values )
94             # returns number of rows affected
95             # use for non-SELECT ad-hoc queries
96             sub sql_do
97             {
98 0     0 1   my $sn = 'sql_do';
99 0           my $self = shift;
100 0 0         my $query = shift or return VOID;
101 0           my @bind_values = @_;
102              
103 0 0         $self->init_db() unless $self->{dbh};
104 0 0         return $self->_error("Database not connected.") unless $self->{dbh};
105              
106 0           my $rc = $self->{dbh}->do( $query, undef, @bind_values );
107 0 0         if ($DBI::err) {
108 0           return $self->_error("$sn: DBI: $DBI::errstr");
109             } else {
110 0           return $rc;
111             }
112             }
113              
114             # sql_select ( $query, @bind_values )
115             # returns arrayref of hashrefs or FAILURE
116             # hash keys are equiv of column (or query) names
117             sub sql_select
118             {
119 0     0 1   my $sn = 'sql_select';
120 0           my $self = shift;
121 0 0         my $query = shift or return VOID;
122 0           my @bind_values = @_;
123              
124 0 0         $self->init_db() unless $self->{dbh};
125 0 0         return $self->_error("$sn: Database not connected.") unless $self->{dbh};
126              
127 0           my $rc = $self->{dbh}->selectall_arrayref( $query, { Slice => {} }, @bind_values );
128 0 0 0       if ($DBI::err) {
    0          
129 0           return $self->_error("$sn: DBI: $DBI::errstr");
130             } elsif ( $rc && ref($rc) eq 'ARRAY' ) {
131 0           return $rc;
132             } else {
133 0           return FAILURE;
134             }
135             }
136              
137             # sql_select_column ( $query, @bind_values )
138             # returns arrayref of values (scalars) or FAILURE
139             sub sql_select_column
140             {
141 0     0 1   my $sn = 'sql_select_column';
142 0           my $self = shift;
143 0 0         my $query = shift or return VOID;
144 0           my @bind_values = @_;
145              
146 0 0         $self->init_db() unless $self->{dbh};
147 0 0         return $self->_error("$sn: Database not connected.") unless $self->{dbh};
148              
149 0           my $rc = $self->{dbh}->selectcol_arrayref( $query, undef, @bind_values );
150 0 0 0       if ($DBI::err) {
    0          
151 0           return $self->_error("$sn: DBI: $DBI::errstr");
152             } elsif ( $rc && ref($rc) eq 'ARRAY' ) {
153 0           return $rc;
154             } else {
155 0           return FAILURE;
156             }
157             }
158              
159             # sql_select_value ( $query, @bind_values )
160             # returns scalar value or FAILURE
161             sub sql_select_value
162             {
163 0     0 1   my $sn = 'sql_select_value';
164 0           my $self = shift;
165 0 0         my $query = shift or return VOID;
166 0           my @bind_values = @_;
167              
168 0 0         $self->init_db() unless $self->{dbh};
169 0 0         return $self->_error("$sn: Database not connected.") unless $self->{dbh};
170              
171 0           my $rc = $self->{dbh}->selectcol_arrayref( $query, { MaxRows => 1 }, @bind_values );
172 0 0 0       if ($DBI::err) {
    0          
173 0           return $self->_error("$sn: DBI: $DBI::errstr");
174             } elsif ( $rc && ref($rc) eq 'ARRAY' ) {
175 0           return $rc->[0];
176             } else {
177 0           return FAILURE;
178             }
179             }
180              
181             # insert( table, { name => value, ... } )
182             # returns SUCCESS or FAILURE
183             sub insert
184             {
185 0     0 1   my $sn = 'insert';
186 0 0         my $self = shift or return undef;
187 0 0         my $table = shift or return undef;
188 0 0         my $nvpairs = shift or return undef;
189 0           my @cols;
190             my @vals;
191              
192 0 0         $self->init_db() unless $self->{dbh};
193 0 0         return $self->_error("$sn: Database not connected.") unless $self->{dbh};
194              
195 0           foreach my $k ( keys %{$nvpairs} ) {
  0            
196 0           push @cols, $k;
197 0           push @vals, $nvpairs->{$k};
198             }
199 0 0 0       return FAILURE unless ( @cols and @vals );
200              
201 0           my $query =
202             "INSERT INTO $table (" .
203             join( ', ', @cols ) .
204             ") VALUES (" .
205             join( ', ', ('?') x @vals ) .
206             ")";
207              
208 0 0         $self->{dbh}->do( $query, undef, @vals ) or return $self->_error("$sn: $DBI::errstr");
209 0           return SUCCESS;
210             }
211              
212             # insert_id
213             # returns the insert id from the last insert operation
214             sub insert_id
215             {
216 0     0 1   my $self = shift;
217 0           return $self->{dbh}->last_insert_id( '', '', '', '' ); # use the DBI function
218             }
219              
220             sub table_exists
221             {
222 0     0 1   my $sn = 'table_exists';
223 0           my $self = shift;
224 0 0         my $table_name = shift or return $self->_error("no table name");
225              
226 0 0         if($self->{dbengine} eq 'SQLite') {
    0          
227 0           my $rc = $self->sql_select( "pragma table_info($table_name)" );
228 0           return scalar @$rc; # pragma returns no rows if table doesn't exist
229             } elsif($self->{dbengine} eq 'mysql') {
230 0           my $rc = $self->sql_select("describe $table_name");
231 0 0         if ( $self->error ) {
232 0           return FALSE;
233             } else {
234 0           return TRUE;
235             }
236             }
237             }
238              
239             # create an sql date from a unix epoch date
240             sub sql_date
241             {
242 0     0 0   my ( $self, $t ) = @_;
243 0 0         $t = time unless defined $t;
244              
245 0           my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday ) = gmtime($t);
246 0           my $tstr = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec );
247 0           return $tstr;
248             }
249              
250             1;
251              
252             __END__