File Coverage

blib/lib/Apache/WeSQL/SqlFunc.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Apache::WeSQL::SqlFunc;
2              
3 1     1   27 use 5.006;
  1         3  
  1         33  
4 1     1   4 use strict;
  1         1  
  1         29  
5 1     1   4 use warnings;
  1         2  
  1         34  
6 1     1   4 use lib(".");
  1         2  
  1         6  
7              
8 1     1   1543 use Apache::Constants qw(:common);
  0            
  0            
9             use Apache::WeSQL;
10             require Exporter;
11              
12             our @ISA = qw(Exporter);
13              
14             # Items to export into callers namespace by default. Note: do not export
15             # names by default without a very good reason. Use EXPORT_OK instead.
16             # Do not simply export all your public functions/methods/constants.
17              
18             # This allows declaration use Apache::WeSQL ':all';
19             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
20             # will save memory.
21             our %EXPORT_TAGS = ( 'all' => [ qw(
22             sqlConnect sqlDisconnect sqlSelect sqlSelectMany
23             sqlPrepareInsert sqlExecuteInsert sqlInsert sqlInsertReturn
24             sqlUpdate sqlDelete sqlGeneric
25             ) ] );
26             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
27             our @EXPORT = qw( );
28              
29             our $VERSION = '0.53';
30              
31             # Preloaded methods go here.
32              
33             ############################################################
34             # sqlGeneric performs a generic SQL query, and returns
35             # a handler to the resulting data
36             ############################################################
37             sub sqlGeneric {
38             my ($dbh, $sql) = @_;
39             $sql ||= "";
40             my $c=${$dbh}->prepare($sql);
41              
42             my $dbtype = 0; #MySQL
43             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
44              
45             &Apache::WeSQL::log_error("$$: sqlGeneric: $sql") if ($Apache::WeSQL::DEBUG);
46              
47             if($c->execute()) {
48             if ($dbtype) { ${$dbh}->commit; }
49             return $c;
50             } else {
51             if ($dbtype) { ${$dbh}->rollback; }
52             $c->finish();
53             &Apache::WeSQL::log_error("$$: sqlGeneric: bad query: $sql: " . ${$dbh}->errstr);
54             return undef;
55             }
56             }
57              
58             ############################################################
59             # sqlPrepareInsert allows a prepare for a SQL 'insert' query
60             # parameter 1: $dbh: database handler
61             # parameter 2: $table: database table
62             # parameter 3: @columns: 'columns' of the SQL statement
63             ############################################################
64             sub sqlPrepareInsert {
65             my $dbh = shift;
66             my ($table, @columns) = @_;
67              
68             # First build the SQL statement
69             my $sql = qq{INSERT INTO $table (};
70             $sql .= join(',',@columns);
71             $sql .= qq{) VALUES (} . "?," x ($#columns+1);
72             chop($sql);
73             $sql .= q{)};
74              
75             &Apache::WeSQL::log_error("$$: sqlPrepareInsert: $sql") if ($Apache::WeSQL::DEBUG);
76              
77             # Then prepare it
78             # my $sth=${$dbh}->prepare_cached($sql) or die "Sql has gone away\n";
79             # Does this help against the weird DBI bug (see sqlExecuteInsert)? WVW 2002-6-4
80             my $sth=${$dbh}->prepare($sql) or die "Sql has gone away\n";
81             return ($sth);
82             }
83              
84             ############################################################
85             # sqlExecuteInsert allows execution of a prepared SQL 'insert' query
86             # parameter 1: $dbh: database handler
87             # parameter 2: $sth: query handler
88             # parameter 3: @values: 'values' of the SQL statement
89             ############################################################
90             sub sqlExecuteInsert {
91             my $dbh = shift;
92             my $sth = shift;
93             my @values = @_;
94             my $dbtype = 0; #MySQL
95             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
96              
97             if ($Apache::WeSQL::DEBUG) {
98             my $logstr = "$$: sqlExecuteInsert: parameters (";
99             foreach (@values) {
100             my $tmp = $_;
101             $tmp = substr($tmp,0,100); #Chop off after 100 chars to keep logs readable
102             $logstr .= "$tmp,";
103             }
104             chop($logstr);
105             $logstr .= ")";
106             &Apache::WeSQL::log_error($logstr);
107             }
108             # We need to reassure that all @values items that contain non-digit characters are actually stored as strings.
109             # This is necessary for values like word.word which seem to be wrongly interpreted by the MySQL code as
110             # dbname.tablename without the following three lines. Why? Beats me. WVW, 2002-02-08
111             # Not necessary anymore after an upgrade from MySQL 3.23.37 and DBI 1.20 to MySQL 3.23.49 and DBI 1.21 ??? WVW, 2002-05-08
112             # Correction, bug persists. Have now removed Msql-mysql perl module and switched to DBD-mysql. Seems to have solved the issue. WVW, 2002-05-12
113             # for (my $cnt = 0; $cnt < $#values; $cnt++) {
114             # $values[$cnt] = ${$dbh}->quote($values[$cnt]) if ($values[$cnt] =~ /\D/);
115             # }
116             if(not $sth->execute(@values)) {
117             $sth->finish;
118             ${$dbh}->rollback if ($dbtype);
119             &Apache::WeSQL::log_error("$$: sqlExecuteInsert: bad query: " . ${$dbh}->errstr);
120             return undef;
121             }
122             $sth->finish;
123              
124             if ($dbtype) { ${$dbh}->commit; }
125             return 1;
126             }
127              
128             ############################################################
129             # sqlInsert allows a SQL 'insert' query
130             # parameter 1: $dbh: database handler
131             # parameter 2: $table: database table
132             # parameter 3: \@columns: 'columns' of the SQL statement
133             # parameter 4: \@values: 'values' of the SQL statement
134             ############################################################
135             sub sqlInsert {
136             my $dbh = shift;
137             my ($table, $colref, $valref)= @_;
138             my $sth = &sqlPrepareInsert($dbh,$table,@{$colref});
139             &sqlExecuteInsert($dbh,$sth,@{$valref});
140             return "";
141             }
142              
143             ############################################################
144             # sqlInsertReturn allows a SQL 'insert' query, and can return (a) column(s) from the just inserted row
145             # parameter 1: $dbh: database handler
146             # parameter 2: $table: database table
147             # parameter 3: \@columns: 'columns' of the SQL statement
148             # parameter 4: \@values: 'values' of the SQL statement
149             # parameter 5: $retcols: comma-separated list of columns whose values should be returned by this sub
150             # parameter 6: $pkey:
151             # MySQL: name of the autoincrement column in this table (default: pkey)
152             # PostgreSQL: name of the SEQUENCE used in this table (default: tablename_pkey_seq)
153             ############################################################
154             sub sqlInsertReturn {
155             my $dbh = shift;
156             my ($table, $colref, $valref, $retcols, $pkey)= @_;
157             &sqlInsert($dbh,$table,$colref,$valref);
158              
159             # Determine the database type
160             my $dbtype = 0; #MySQL
161             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
162              
163             if ($dbtype == 0) {
164             $pkey ||= "pkey";
165             my @r = &sqlSelect($dbh,"SELECT LAST_INSERT_ID()");
166             my @r2 = &sqlSelect($dbh,"SELECT $retcols FROM $table WHERE $pkey=$r[0]");
167             return @r2;
168             } else {
169             my $sequence = $pkey;
170             $sequence ||= "$table" . "_pkey_seq";
171             ($pkey) = $sequence =~ /$table\L_(.*?)_seq/;
172             my @r = &sqlSelect($dbh,"SELECT last_value FROM $sequence");
173             my @r2 = &sqlSelect($dbh,"SELECT $retcols FROM $table WHERE $pkey=$r[0]");
174             return @r2;
175             }
176             }
177              
178             ############################################################
179             # sqlDelete allows a SQL 'delete' query
180             # parameter 1: $dbh: database handler
181             # parameter 2: $table: database table
182             # parameter 3: $where: where-part of the SQL statement
183             # paramater 4: $other: last part of the SQL statement (optional)
184             # Returns: number of rows affected by the delete or undef upon failure
185             ############################################################
186             sub sqlDelete {
187             my $dbh = shift;
188             my ($table, $where, $other)=@_;
189              
190             my $dbtype = 0; #MySQL
191             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
192              
193             my $sql="DELETE FROM $table ";
194             $sql.="WHERE $where " if $where;
195             $sql.="$other" if $other;
196            
197             my $c=${$dbh}->prepare_cached($sql) or die "Sql has gone away\n";
198             if(not $c->execute()) {
199             if ($dbtype) { ${$dbh}->rollback; }
200             &Apache::WeSQL::log_error("$$: sqlDelete: bad query: $sql: " . ${$dbh}->errstr);
201             return undef;
202             }
203             my $rows = $c->rows();
204             $c->finish();
205             if ($dbtype) { ${$dbh}->commit; }
206             return $rows;
207             }
208              
209             ############################################################
210             # sqlUpdate is an easy interface to an UPDATE sql query
211             # parameter 1: $dbh: database handler
212             # parameter 2: $table: database table
213             # parameter 3: $what: what to update
214             # parameter 4: $where: condition
215             # parameter 5: $other: any rest of the sql statement
216             # Returns: number of rows affected by the update or undef upon failure
217             ############################################################
218             sub sqlUpdate {
219             my $dbh = shift;
220             my ($table, $what, $where, $other)=@_;
221              
222             # Determine the database type
223             my $dbtype = 0; #MySQL
224             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
225              
226             my $sql="UPDATE $table ";
227             $sql.="SET $what " if $what;
228             $sql.="WHERE $where " if $where;
229             $sql.="$other" if $other;
230              
231             &Apache::WeSQL::log_error("$$: sqlUpdate: $sql") if ($Apache::WeSQL::DEBUG);
232              
233             my $c=${$dbh}->prepare_cached($sql) or die "Sql has gone away\n";
234             if(not $c->execute()) {
235             if ($dbtype) { ${$dbh}->rollback; }
236             &Apache::WeSQL::log_error("$$: sqlUpdate: bad query: $sql" . ${$dbh}->errstr);
237             return undef;
238             }
239             my $rows = $c->rows();
240             $c->finish();
241             if ($dbtype) { ${$dbh}->commit; }
242             return $rows; #return the number of rows affected by the update
243             }
244              
245             ############################################################
246             # sqlSelect
247             # Takes a select statement and returns the first row of results
248             ############################################################
249              
250             sub sqlSelect {
251             my ($dbh,$sql) = @_;
252             my $c;
253              
254             # Determine the database type
255             my $dbtype = 0; #MySQL
256             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
257              
258             # Save the database from much unnecessary work, we only want the first record returned!
259             $sql .= " LIMIT 1" if (!($sql =~ / LIMIT /i) && ($sql =~ / FROM /i));
260              
261             &Apache::WeSQL::log_error("$$: sqlSelect: $sql") if ($Apache::WeSQL::DEBUG);
262            
263             unless($c=${$dbh}->prepare($sql)) {
264             &Apache::WeSQL::log_error("$$: sqlSelect: error: $sql");
265             return undef;
266             }
267              
268             if(not $c->execute()) {
269             $c->finish();
270             if ($dbtype) { ${$dbh}->rollback; }
271             &Apache::WeSQL::log_error("$$: sqlSelect: bad query: $sql");
272             return undef;
273             }
274             my @r=$c->fetchrow();
275             $c->finish();
276             return @r;
277             }
278              
279             ############################################################
280             # sqlSelectMany
281             # Takes a sql select statement and returns a handle to the results.
282             ############################################################
283              
284             sub sqlSelectMany {
285             my ($dbh,$sql) = (shift,@_);
286             my $c;
287              
288             # Determine the database type
289             my $dbtype = 0; #MySQL
290             $dbtype = 1 if (${$dbh}->{Driver}->{Name} =~ /^Pg/);
291              
292             &Apache::WeSQL::log_error("$$: sqlSelectMany: $sql") if ($Apache::WeSQL::DEBUG);
293              
294             unless($c=${$dbh}->prepare($sql)) {
295             &Apache::WeSQL::log_error("$$: sqlSelectMany: error: $sql");
296             return undef;
297             }
298              
299             if ($c->execute()) {
300             return $c;
301             } else {
302             $c->finish();
303             if ($dbtype) { ${$dbh}->rollback; }
304             &Apache::WeSQL::log_error("$$: sqlSelectMany: bad query: $sql");
305             return undef;
306             }
307             }
308              
309             ########################################################
310             # sqlConnect makes a connection to the database, and returns a reference to the database
311             # handler. Called from Apache::WeSQL::AppHandler
312             ########################################################
313             sub sqlConnect {
314             my ($dsn, $dbuser, $dbpass, $dbtype) = @_;
315              
316             my $dbh;
317             my $autocommit = { AutoCommit => 1 };
318             if ($dbtype == 1) { #PostgreSQL supports transactions, MySQL doesn't
319             $autocommit = { AutoCommit => 0 };
320             }
321              
322             if (!($dbh=DBI->connect($dsn,$dbuser,$dbpass,$autocommit))) {
323             print &Apache::WeSQL::error("Serious problem on the server. Please contact the webmaster.","Could not open database connection: " . ${$dbh}->errstr);
324             exit;
325             }
326            
327             DBI->trace(1) if ($Apache::WeSQL::DEBUG > 1);
328              
329             &Apache::WeSQL::log_error("$$: New connection to $dsn as $dbuser") if ($Apache::WeSQL::DEBUG);
330              
331             return \$dbh;
332             }
333              
334             ########################################################
335             # sqlDisconnect disconnects the database handler
336             ########################################################
337             sub sqlDisconnect {
338             my $dbh = shift;
339             ${$dbh}->disconnect;
340             undef($dbh);
341             }
342              
343             1;
344             __END__