File Coverage

blib/lib/DBIx/SimplePerl.pm
Criterion Covered Total %
statement 33 421 7.8
branch 0 252 0.0
condition 0 30 0.0
subroutine 11 29 37.9
pod 7 14 50.0
total 51 746 6.8


line stmt bran cond sub pod time code
1             package DBIx::SimplePerl;
2              
3 1     1   35394 use base qw(Class::Accessor);
  1         2  
  1         1076  
4              
5 1     1   2459 use 5.008;
  1         3  
  1         35  
6 1     1   6 use strict;
  1         7  
  1         36  
7 1     1   5 use warnings;
  1         2  
  1         31  
8 1     1   5 no strict "subs";
  1         2  
  1         28  
9 1     1   6 no strict "refs";
  1         1  
  1         28  
10 1     1   2769 use DBI;
  1         17681  
  1         73  
11 1     1   982 use POSIX qw(strftime ceil);
  1         7544  
  1         10  
12 1     1   1013 use Data::Dumper;
  1         2  
  1         41  
13              
14 1     1   4 use constant true => (1==1);
  1         1  
  1         53  
15 1     1   4 use constant false => (1==0);
  1         2  
  1         5243  
16              
17             our $VERSION = '1.95';
18              
19              
20             # Preloaded methods go here.
21             =pod
22             =head1 NAME
23              
24             DBIx::SimplePerl - Perlish access to DBI
25              
26             =head1 ABSTRACT
27              
28              
29             This module provides DBIx::SimplePerl which is a highly (over)simplified
30             interface to DBI. The point of DBIx::SimplePerl is that end programmers
31             who want to write their programs which access simple databases in
32             Perl, should be able to write their programs in Perl and not Perl +
33             SQL. This is a different approach as compared to the Tie::DBI.
34             This module is not what high end or midrange database programmers
35             would like or care to use. It works great for really simple stuff,
36             like SADU (search, add, delete, update) on existing tables. It
37             follows a basic Keep It Simple(tm) philosophy, in that the
38             programmer ought to be able to use a database table with very
39             little effort. Other modules attempt to make SQL access simple, but
40             in the end they rely on the user emitting SQL at some point. This
41             module hides the SQL from the end user by automatically generating it
42             in flight. The idea being that Perl programmers who need very simple
43             database access do not necessarily need to write SQL.
44              
45             =head1 SYNOPSIS
46              
47             # Brackets [] represent optional items, not array indices.
48             # Elipses ... mean more of the same inputs/options
49            
50             use DBIx::SimplePerl;
51             my $sice = DBIx::SimplePerl->new;
52            
53             ...
54             # all methods return a hash with two possible keys.
55             # On success, the return is
56             # { success => true }
57             # On failure, the return is
58             # { failed => {
59             # error => "error_message_from_call",
60             # code => "error_return_code_from_call"
61             # }
62             # }
63            
64             # sets internal $sice->{_dbh} to open database handle
65             $sice->db_open(
66             dsn => $dsn,
67             dbuser => $dbuser,
68             dbpass => $dbpass,
69             [AutoCommit => 0|1,]
70             [RaiseError => 0|1 ]
71             ...
72             );
73            
74             $sice->db_add(
75             table => $table_name,
76             columns => {
77             field1 => $data1,
78             [field2 => $data2,]
79             [...]
80             }
81             );
82            
83             $sice->db_search(
84             table => $table_name,
85             [search => {
86             field1=>$data1,
87             [field2=>@array2]
88             ...
89             }],
90             [ search_operator => 'AND' | 'OR' ]
91             [ count => field ],
92             [ max => field ],
93             [ min => field ],
94             [ distinct => { field1,
95             [field2], ... ]
96             } ],
97            
98             [ columns => { field1,
99             [field2], ... ]
100             } ],
101             [ order => fieldN]
102             );
103            
104             $sice->db_update(
105             table => $table_name,
106             search => {
107             field => $data1,
108             [field2 => $data2,]
109             ...
110             },
111             columns=> {
112             field1 => $data1,
113             ...
114             }
115             );
116            
117             $sice->db_commit;
118            
119             $sice->db_delete(
120             table => $table_name,
121             search => {
122             field => $data1,
123             ...
124             }
125             );
126            
127             # db_next returns the next row as a hash ref
128             my $x;
129             while ($x=$sice->db_next )
130             {
131             map { printf "key = %s, value =\'%s\'\n",$_,$x{$_} } keys %{$x};
132             }
133            
134             # db_array returns all the rows as an array of hash refs
135             my $x;
136             foreach $x (@{$sice->db_array })
137             {
138             map { printf "key = %s, value =\'%s\'\n",$_,$x{$_} } keys %{$x};
139             }
140            
141            
142            
143             $sice->db_trace(level => $number); # turn on DBI tracing
144             $sice->db_rows; # return rows affected by session handle
145             # note that DBI documentation indicates
146             # that the rows method upon which this is
147             # based is effectively useless.
148             $rc=$sice->db_ping; # perform a db_ping call
149             $sice->{debug} = 1 ; # turn on debugging
150             $sice->{debug} = 0 ; # turn off debugging
151             $sice->db_rollback; # roll back a transaction
152            
153            
154             # quoting for table, field, and value is set by default
155             # you can override it during or after creating the object.
156             $sice->{quote}->{table} = '"';
157             $sice->{quote}->{field} = '"';
158             $sice->{quote}->{value} = '"';
159            
160             # SQLite, Postgres, and MySQL are supported, with default
161             # quoting assumed for others. You can change this as needed.
162            
163             $sice->db_close;
164              
165             The session handle is available under the object as $sice->{_sth}
166              
167             =head2 Methods
168              
169             =over 4
170            
171             =item db_open(dsn => $dsn, dbuser => $dbuser, dbpass => $dbpass )
172              
173             The C method returns a database handle attached to
174             $self->{_dbh}. RaiseError defaults to 0 and AutoCommit defaults
175             to 1. This function attaches the object to a database.
176             As long as the DBD/DBI supports it, you may have multiple
177             independent objects connected to the same database.
178              
179             =item db_add(table => $table_name,columns => {field1=>$data1,...})
180              
181             The C method will take a record (the hash pointed to by
182             the columns field, generate the necessary SQL, and do an insert into
183             the table indicated. That is, if we have a table named "users", and
184             we want to add a record with a username, password, home directory,
185             and shell, we can do something like this:
186              
187             use DBIx::SimplePerl;
188             my $sice = DBIx::SimplePerl->new;
189             $sice->db_open(
190             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
191             'dbuser' => "",
192             'dbpass' => ""
193             );
194            
195             $sice->db_add(
196             table =>"users",
197             columns => {
198             username => $username,
199             password => $password,
200             homedir => $homedir,
201             shell => $shell
202             }
203             );
204              
205             and the method will generate the appropriate SQL to insert this
206             record:
207              
208             insert into "users" ("username","password","homedir","shell") \
209             values ("$username","$password","$homedir","$shell");
210              
211             If the insert operation failed or generated errors or warnings, you
212             will be able to check for the existence of and inspect $sice->{failed}.
213             As each DBD is different, no two different DBDs will generate the same
214             error messages or error codes.
215              
216             If you would like to see the SQL the method generates, then set
217             the debug attribute to a non-zero value
218              
219             $sice->{debug} = 1;
220              
221             and it will emit the SQL it generates on the STDERR.
222              
223             =item db_search(table => $table_name,search => {field1=>$data1,...})
224              
225             The C method will perform a select with an
226             appropriate where clause, generated by the hash pointed to by
227             the search field. That is, if we have a table named "users", and
228             we want to find a set of one or more records with a particular
229             username, we can do something like this:
230              
231             use DBIx::SimplePerl;
232             my $sice = DBIx::SimplePerl->new;
233             $sice->db_open(
234             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
235             'dbuser' => "",
236             'dbpass' => ""
237             );
238            
239             $sice->db_search(
240             table =>"users",
241             search => { username => $username }
242             );
243              
244             and the method will generate the appropriate SQL to perform this
245             select:
246              
247             select from "users" where "username"="$username";
248              
249             If you provide an array to the search field (username in this example)
250             the module will do the right thing and generate
251              
252             select from "users" where "username" in ( "@{$username}[0]" ,
253             "@{$username}[1]" , ... , "@{$username}[N]");
254            
255             So if you performed this call like this:
256              
257             $sice->db_search(
258             table =>"users",
259             search => {
260             username => [
261             "Tom",
262             "Dick",
263             "Harry"
264             ]
265             }
266             );
267              
268             the module will generate the query as
269              
270             select from "users" where "username" in ("Tom", "Dick", "Harry");
271            
272             This functionality is not yet in other methods than the search module.
273             This may change in future releases.
274              
275             Also, if you want to return only some of the columns in the database,
276             you could use the columns => "comma,separated,list,of,columns,to,return"
277             option
278              
279             $sice->db_search(
280             table =>"users",
281             search => {
282             username => [
283             "Tom",
284             "Dick",
285             "Harry"
286             ]
287             },
288             columns => "name,date,uid,homedir"
289             );
290              
291             And if you wanted to pre-order the output records, use the order=>field
292             option
293              
294             $sice->db_search(
295             table =>"users",
296             search => {
297             username => [
298             "Tom",
299             "Dick",
300             "Harry"
301             ]
302             },
303             columns => "name,date,uid,homedir",
304             order => "uid"
305             );
306              
307             or
308              
309             $sice->db_search(
310             table =>"users",
311             search => {
312             username => [
313             "Tom",
314             "Dick",
315             "Harry"
316             ]
317             },
318             order => "uid"
319             );
320              
321              
322              
323             If the select operation failed or generated errors or warnings, you
324             will be able to check for the existence of and inspect
325             $sice->{failed}->{error} and if the DBD developer provided an error
326             code, it would be in $sice->{failed}->{code}. As each DBD is
327             different, no two different DBDs will generate the same error
328             messages or error codes.
329              
330             As many fields as are relevant in the particular table may be used. The
331             search=> may be completely omitted to give a "SELECT * from table"
332             effect. The results are returned as a DBI session handle within the
333             object instance. To extract the data, use the db_next method.
334              
335             while ($sice->db_next)
336             {
337             # do something with the $_ hashref to the query results
338             }
339              
340             or if you prefer dealing with arrays, you can use a foreach with
341             db_array
342              
343             foreach (@$sice->db_array)
344             {
345             # do something with the $_ hashref to the query results
346             }
347            
348             If the select succeeds, then the $sice->db_search... will
349             return an anonymous hash with a key named "success". Testing
350             for the existence of this key is sufficent for determining if the
351             method call succeeded. Error messages (if generated) would be
352             stored in the anonymous hash's "failed" key. Lack of existence of
353             this key is another indicator of success. There is more than one
354             way to do it, and these should always be consistent.
355              
356             Of course though, they are not (yet) consistent. DBI returns
357              
358             function(column) => 'value'
359            
360             for the min, max, and count functions. So if you do a search for the
361             maximum of a set of columns
362              
363             $sice->db_search(
364             table => "users",
365             max => "uid"
366             );
367              
368             then when you query the returned results, be aware that they will
369             show up as
370              
371             'max(uid)' => value
372            
373             using the hashrefs. Since you don't care about the key, you can
374             extract the first value.
375              
376             $max = (values %{$sice->db_next} )[0];
377            
378             This is somewhat convoluted, so assume that this interface will change.
379              
380              
381             =item db_update( table => $table_name,
382             search => {field1=>$data1,...},
383             columns=> {field1=>$data1,...});
384              
385              
386             The C method will perform an update with an
387             appropriate where clause, generated by the hash pointed to by
388             the search field, using the column hash to insert the updated
389             values. Fields not specified in the column hash will not be
390             changed. That is, if we have a table named "users", and
391             we want to update a set of one or more records with a particular
392             username, we can do something like this:
393              
394             use DBIx::SimplePerl;
395             my $sice = DBIx::SimplePerl->new;
396             $sice->db_open(
397             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
398             'dbuser' => "",
399             'dbpass' => ""
400             );
401            
402             $sice->db_update(
403             table =>"users",
404             search => { username => $username },
405             columns => { homedir => $new_homedir }
406             );
407              
408             and the method will generate the appropriate SQL to perform this
409             update.:
410              
411             update "users" set "homedir"="$new_homedir" \
412             where "username"="$username";
413              
414             If the update operation failed or generated errors or warnings, you
415             will be able to check for the existence of and inspect $sice->{error}.
416             As many fields as are relevant in the particular table may be used
417             in the search hash or the column hash. The results are returned as
418             a DBI session handle, and any of the DBI methods may be used to
419             extract the data at this point.
420            
421             If the update succeeds, then the $sice->db_update... will
422             return an anonymous hash with a key named "success". Testing
423             for the existence of this key is sufficent for determining if the
424             method call succeeded. Error messages (if generated) would be
425             stored in the anonymous hash's "failed" key. Lack of existence of
426             this key is another indicator of success.
427              
428              
429             =item db_commit
430              
431             The C method will perform an explicit commit on the
432             db handle. This is useful when AutoCommit is set to 0. Note that
433             this means that if you disconnect on an AutoCommit => 0 db before
434             doing a db_close, that your state changes will likely be lost.
435              
436             B
437              
438             You would need to perform the db_commit after some group of operations
439             on an AutoCommit => 0 to insure that they are in fact committed to
440             disk. If AutoCommit => 0, this is entirely your responsibility.
441             Turning off AutoCommit can speed things up tremendously, though
442             it will do it at the expense of granularity. Your changes will be
443             much larger grained. This is why we default to AutoCommit => 1, so
444             you do not need to think about this for most cases.
445              
446             If the commit operation failed or generated errors or warnings, you
447             will be able to check for the existence of and inspect $sice->{error}.
448              
449             =item db_delete(table => $table_name, search => {field1=>$data1,...})
450              
451              
452             The C method will perform a record delete with an
453             appropriate where clause, generated by the hash pointed to by
454             the search field. This will not delete the table itself, just the
455             record. That is, if we have a table named "users", and
456             we want to delete a set of one or more records with a particular
457             username, we can do something like this:
458              
459             use DBIx::SimplePerl;
460             my $sice = DBIx::SimplePerl->new;
461             $sice->db_open(
462             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
463             'dbuser' => "",
464             'dbpass' => ""
465             );
466            
467             $sice->db_delete(
468             table =>"users",
469             search => {
470             username => $username
471             }
472             );
473              
474             and the method will generate the appropriate SQL to perform this
475             update.:
476              
477             delete from "users" where "username"="$username";
478              
479             Note that if more than one field is used in the search, the fields
480             will use as the conditional, in order,
481              
482             1) $sice->{search_conditional} (with values of "AND", "OR", or any other
483             SQL accepted operator for delete statements.
484              
485             2) "AND" which is the default unless overridden in this object by point 1.
486              
487             This allows you to have
488              
489             $sice->db_delete(
490             table =>"users",
491             search => {
492             username => $username,
493             dir => $dir
494             }
495             );
496              
497             become (by default)
498              
499             delete from "users" where "username"="$username" AND "dir"=$dir;
500              
501              
502              
503             If the delete operation failed or generated errors or warnings, you
504             will be able to check for the existence of and inspect $sice->{error}.
505             As many fields as are relevant in the particular table may be used
506             in the search hash. The results are returned as
507             a DBI session handle, and any of the DBI methods may be used to
508             extract the data at this point.
509            
510             If the delete succeeds, then the $sice->db_update... will
511             return an anonymous hash with a key named "success". Testing
512             for the existence of this key is sufficent for determining if the
513             method call succeeded. Error messages (if generated) would be
514             stored in the anonymous hash's "failed" key. Lack of existence of
515             this key is another indicator of success.
516              
517             =item db_create_table(table => $table_name,columns => {field1=>"type1",...})
518              
519             The C method will take a record (the hash pointed to by
520             the columns field, generate the necessary SQL, and do an create table into
521             the attached database handle. That is, if we want to create a table
522             named "users", with columns of username, password, home directory, uid,
523             shell, and date we can do something like this:
524              
525             use DBIx::SimplePerl;
526             my $sice = DBIx::SimplePerl->new;
527             $sice->db_open(
528             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
529             'dbuser' => "",
530             'dbpass' => ""
531             );
532            
533             $sice->db_create_table(
534             table =>"users",
535             columns => {
536             username => "varchar(30)",
537             password => "varchar(30)",
538             homedir => "varchar(255)",
539             shell => "varchar(30)",
540             uid => "integer",
541             date => "datetime"
542             }
543             );
544              
545             and the method will generate the appropriate SQL to create this
546             table:
547              
548             create table "users"
549             (
550             "username" varchar(30),
551             "password" varchar(30),
552             "homedir" varchar(255) ,
553             "shell" varchar(30),
554             "uid" integer,
555             "date" datetime
556             );
557              
558             If the create operation failed or generated errors or warnings, you
559             will be able to check for the existence of and inspect $sice->{failed}.
560             As each DBD is different, no two different DBDs will generate the same
561             error messages or error codes.
562              
563             If you would like to see the SQL the method generates, then set
564             the debug attribute to a non-zero value
565              
566             $sice->{debug} = 1;
567              
568             and it will emit the SQL it generates on the STDERR.
569              
570              
571             =cut
572             sub db_open
573             {
574 0     0 1   my ($self,%args) = @_;
575 0           my ($dsn,$dbuser,$dbpass,$options,%rc,$dbh,$tmp,$name,$autocommit);
576 0           my ($remaining,$raiseerror,@opts,%attr);
577            
578 0 0         printf STDERR "D[%s] db_open: args -> \'%s\'\n",$$,join(":",keys(%args)) if ($self->{debug});
579            
580             # quick error check
581 0           foreach (qw(dsn dbuser dbpass))
582             {
583 0 0         if (exists($args{$_}))
584             {
585 0 0         $dsn = $args{$_} if ($_ eq 'dsn');
586 0 0         $dbuser = $args{$_} if ($_ eq 'dbuser');
587 0 0         $dbpass = $args{$_} if ($_ eq 'dbpass');
588 0           delete $args{$_};
589             }
590             else
591             {
592 0           %rc= ( 'failed' => {'error' => "no $_ specified" } );
593 0           return \%rc;
594             }
595             }
596 0           foreach (keys %args)
597             {
598 0 0 0       $attr{$_}=$args{$_} if (
      0        
599             ($_ ne "dsn") &&
600             ($_ ne "dbuser") &&
601             ($_ ne "dbpass")
602             ) ;
603             }
604             # construct remaining arg string
605 0           $remaining = "";
606 0 0         $attr{'AutoCommit'} = 1 if (!defined($attr{AutoCommit}));
607 0 0         $attr{'RaiseError'} = 0 if (!defined($attr{RaiseError}));
608 0           map { push @opts,(sprintf "%s => %s",$_,$attr{$_}) } (keys %attr) ;
  0            
609              
610 0           $remaining = join(", ",@opts);
611 0 0         printf STDERR "D[%s] db_open: open optional args -> \'%s\'\n",$$,$remaining if ($self->{debug});
612            
613             # connect to DB
614 0           $self->{_dbh} = false;
615             #$self->{_sth} = false;
616            
617 0           $self->{_dbh}= DBI->connect(
618             $dsn,
619             $dbuser,
620             $dbpass,
621             \%attr
622             );
623            
624 0           %rc=%{$self->_check_and_return_if_error};
  0            
625 0 0         return \%rc if ($rc{failed});
626            
627 0 0         printf STDERR "D[%s]: DBIx::SimplePerl database connection succeeded\n",$$ if ($self->{debug});
628 0           %rc= ( 'success' => true );
629 0 0         printf STDERR "D[%s]: DBIx::SimplePerl database connection dump = %s\n",$$,Dumper($self) if ($self->{debug});
630             # handle field quoting
631 0 0         if (!defined($self->{quote}))
632             {
633 0 0         if ($dsn =~ /dbi:Pg/i)
    0          
    0          
634             { # postgresql
635 0           $self->{quote}->{table}='"';
636 0           $self->{quote}->{field}='"';
637 0           $self->{quote}->{value}="\'";
638             }
639             elsif ($dsn =~ /dbi:SQLite/i)
640             { # sqlite
641 0           $self->{quote}->{table}='"';
642 0           $self->{quote}->{field}="";
643 0           $self->{quote}->{value}='"';
644             }
645             elsif ($dsn =~ /DBI:mysql/i)
646             { # mysql
647 0           $self->{quote}->{table}="";
648 0           $self->{quote}->{field}="";
649 0           $self->{quote}->{value}='"';
650             }
651             else
652             { # default
653 0           $self->{quote}->{table}='"';
654 0           $self->{quote}->{field}="\'";
655 0           $self->{quote}->{value}='"';
656             }
657             }
658 0           return \%rc;
659             }
660              
661            
662             sub db_add
663             {
664 0     0 1   my ($self,%args)=@_;
665 0           my ($table,$q_table,$columns,$prep,%rc,@fields,@q_fields,@values);
666            
667             # quick error check
668 0           foreach (qw(table columns))
669             {
670 0 0         if (exists($args{$_}))
671             {
672 0 0         $table = $self->_quote_table($args{$_}) if ($_ eq 'table');
673 0 0         $columns = $args{$_} if ($_ eq 'columns');
674             }
675             else
676             {
677 0           %rc= ( 'failed' => {'error' => "no $_ specified" } );
678 0           return \%rc;
679             }
680             }
681            
682 0 0         if ( !defined( $self->{_dbh} ) )
683             {
684 0           %rc= ( 'failed' => { 'error' => "Database handle does not exist" } );
685 0           return \%rc;
686             }
687              
688             # extract fields and values from the columns
689 0           @fields=(keys %{$columns});
  0            
690 0           map { push @values,$self->_quote_value($columns->{$_}) } @fields;
  0            
691 0           map { push @q_fields,$self->_quote_field($_) } @fields;
  0            
692            
693             # create the SQL for the insert
694 0           $prep = sprintf 'INSERT INTO %s (',$table;
695 0           $prep .= join(",",@q_fields). ') VALUES (';
696 0           foreach (0 .. $#values)
697             {
698 0           $prep .= sprintf "%s",$values[$_];
699 0 0         $prep .= "," if ($_ < $#values);
700             }
701 0           $prep .= ')';
702              
703 0 0         printf STDERR "D[%s] db_add: prepare = \'%s\' \n",
704             $$,$prep if ($self->{debug});
705             # compile it
706 0           $self->{_sth} = $self->{_dbh}->prepare($prep) ;
707 0           %rc=%{$self->_check_and_return_if_error};
  0            
708 0 0         return \%rc if ($rc{failed});
709            
710 0 0         printf STDERR "D[%s] db_add: prepare succeeded\n",$$ if ($self->{debug});
711            
712             # execute it ...
713 0           $self->{_sth}->execute();
714 0           %rc=%{$self->_check_and_return_if_error};
  0            
715 0 0         return \%rc if ($rc{failed});
716            
717 0 0         printf STDERR "D[%s] db_add: execute succeeded\n",$$ if ($self->{debug});
718 0           %rc= ( 'success' => true );
719 0           return \%rc;
720             }
721            
722             sub db_search
723             {
724 0     0 1   my ($self,%args)=@_;
725 0           my ($table,$search,$prep,%rc,@fields,@values,@q_fields,$order);
726 0           my ($count, $max, $min, $boolean, $in_variant,$v_values,$cols);
727 0           my ($complex_cols,$specials,$distinct,$operator);
728            
729 0           $cols = "*";
730 0           $operator = "AND";
731            
732             # quick error check
733            
734 0           foreach (qw(table search order count max min boolean columns distinct search_operator))
735             {
736 0 0         if (exists($args{$_}))
737             {
738 0 0         $table = $self->_quote_table($args{$_}) if ($_ eq 'table');
739 0 0         $search = $args{$_} if ($_ eq 'search');
740 0 0         $order = $args{$_} if ($_ eq 'order');
741 0 0         $cols = $args{$_} if ($_ eq 'columns');
742 0 0         $distinct = $args{$_} if ($_ eq 'distinct');
743 0 0         $operator = $args{$_} if ($_ eq 'search_operator');
744 0 0         $count = $args{$_} if ($_ eq 'count');
745 0 0         $max = $args{$_} if ($_ eq 'max');
746 0 0         $min = $args{$_} if ($_ eq 'min');
747             }
748             }
749 0 0         if (!defined($table))
750             {
751 0           %rc= ( 'failed' => {'error' => "no table specified" } );
752 0           return \%rc;
753             }
754            
755 0 0         if ( !defined( $self->{_dbh} ) )
756             {
757 0           %rc= ( 'failed' => { 'error' => "Database handle does not exist" });
758 0           return \%rc;
759             }
760              
761             # only one of max, min, count.
762 0           $specials=0;
763 0 0         $specials++ if (defined($count));
764 0 0         $specials++ if (defined($min));
765 0 0         $specials++ if (defined($max));
766 0 0         if ( $specials > 1 )
767             {
768 0           %rc= ( 'failed' => { 'error' => "only one of MAX, MIN, COUNT can be used at a time in a query" } );
769 0           return \%rc;
770             }
771             # if search is not defined, then use simpler form of
772             # search (e.g. select * from table; )
773 0 0 0       if (!defined($search))
    0 0        
    0 0        
      0        
774             {
775 0 0 0       if ( (!defined($count)) && (!defined($min)) && (!defined($max)) && (!defined($distinct)) )
    0          
    0          
    0          
    0          
776             {
777 0           $prep = sprintf 'SELECT %s FROM %s',$cols,$table;
778             }
779             elsif (defined($count))
780             {
781 0           $prep = sprintf 'SELECT count(%s) FROM %s',$count,$table;
782             }
783             elsif (defined($max))
784             {
785 0           $prep = sprintf 'SELECT max(%s) FROM %s',$max,$table;
786             }
787             elsif (defined($min))
788             {
789 0           $prep = sprintf 'SELECT min(%s) FROM %s',$min,$table;
790             }
791             elsif (defined($distinct))
792             {
793 0           $prep .= sprintf 'SELECT DISTINCT %s FROM %s',$distinct,$table;
794             }
795             }
796             elsif (
797             (defined($search)) &&
798             (
799             (!defined($count)) &&
800             (!defined($min)) &&
801             (!defined($max))
802             )
803             )
804             {
805 0           $prep = sprintf 'SELECT %s FROM %s WHERE ',$cols,$table;
806             # extract fields and values from the columns
807 0           @fields=(keys %{$search});
  0            
808 0           map { push @q_fields,$self->_quote_field($_) } @fields;
  0            
809 0           $in_variant = (1==0); #force it to false
810            
811             # see if we are dealing with a field => [array of values]
812             # if this is the case, the we need to construct the search
813             # using the where field in ('value1', 'value2', ... , 'valueN')
814 0 0         map {
815 0           $in_variant = (1==1) if (ref($search->{$_}) eq "ARRAY");
816             } @fields;
817            
818 0 0         if (!$in_variant)
819             {
820             # normal method, using simple scalar values for fields
821 0           map { push @values,$self->_quote_value($search->{$_}) } @fields;
  0            
822              
823             # create the SQL for the insert
824 0           foreach (0 .. $#q_fields)
825             {
826 0 0         $prep .= (defined($self->{search_condition}) ? $self->{search_condition} : " AND ") if ($_ > 0);
    0          
827 0           $prep .= sprintf "%s=%s",$q_fields[$_],$values[$_];
828             }
829             }
830             else
831             {
832             # more complex method. First scan through the non-array bits
833             # and add them. Then
834            
835 0           my $_count=1;
836 0           foreach (@fields)
837             {
838 0 0         $prep .= " AND " if ($_count > 1);
839 0 0         if (ref($search->{$_}) ne "ARRAY")
840             {
841 0           $prep .= sprintf "%s=%s",$self->_quote_field($_),
842             $self->_quote_value($search->{$_});
843             }
844             else
845             {
846 0           my $_in_="(";
847 0           my $_field_=$_;
848 0           foreach (@{$search->{$_}})
  0            
849             {
850 0           $_in_ .= (sprintf "%s, ",$self->_quote_value($_));
851             }
852 0           $_in_ .= ")";
853 0           $_in_ =~ s/\,\s+\)$/\)/; # clean up the last comma
854 0           $prep .= sprintf "%s in %s",$self->_quote_field($_field_),$_in_;
855             }
856 0           $_count++;
857             }
858             }
859             }
860             elsif (
861             (defined($search)) &&
862             (
863             (defined($count)) ||
864             (defined($min)) ||
865             (defined($max))
866             )
867             )
868             {
869 0 0         $complex_cols = sprintf "MAX(%s)",$max if (defined($max));
870 0 0         $complex_cols = sprintf "MIN(%s)",$min if (defined($min));
871 0 0         $complex_cols = sprintf "COUNT(%s)",$count if (defined($count));
872            
873 0           $prep = sprintf 'SELECT %s FROM %s WHERE ',$complex_cols,$table;
874             # extract fields and values from the columns
875 0           @fields=(keys %{$search});
  0            
876 0           map { push @q_fields,$self->_quote_field($_) } @fields;
  0            
877 0           $in_variant = (1==0); #force it to false
878            
879             # see if we are dealing with a field => [array of values]
880             # if this is the case, the we need to construct the search
881             # using the where field in ('value1', 'value2', ... , 'valueN')
882 0 0         map {
883 0           $in_variant = (1==1) if (ref($search->{$_}) eq "ARRAY");
884             } @fields;
885            
886 0 0         if (!$in_variant)
887             {
888             # normal method, using simple scalar values for fields
889 0           map { push @values,$self->_quote_value($search->{$_}) } @fields;
  0            
890              
891             # create the SQL for the insert
892 0           foreach (0 .. $#q_fields)
893             {
894 0 0         $prep .= (sprintf " %s ",$operator) if ($_ > 0);
895 0           $prep .= sprintf "%s=%s",$q_fields[$_],$values[$_];
896             }
897             }
898             else
899             {
900             # more complex method. First scan through the non-array bits
901             # and add them. Then
902            
903 0           my $_count=1;
904 0           foreach (@fields)
905             {
906 0 0         $prep .= (sprintf " %s ",$operator) if ($_count > 1);
907 0 0         if (ref($search->{$_}) ne "ARRAY")
908             {
909 0           $prep .= sprintf "%s=%s",$self->_quote_field($_),
910             $self->_quote_value($search->{$_});
911             }
912             else
913             {
914 0           my $_in_="(";
915 0           my $_field_=$_;
916 0           foreach (@{$search->{$_}})
  0            
917             {
918 0           $_in_ .= (sprintf "%s, ",$self->_quote_value($_));
919             }
920 0           $_in_ .= ")";
921 0           $_in_ =~ s/\,\s+\)$/\)/; # clean up the last comma
922 0           $prep .= sprintf "%s in %s",$self->_quote_field($_field_),$_in_;
923             }
924 0           $_count++;
925             }
926             }
927             #############
928             }
929 0 0         if (defined($order)) { $prep .= (sprintf " ORDER BY %s ",$order)}
  0            
930 0 0         printf STDERR "D[%s] db_search: prepare = \'%s\' \n",
931             $$,$prep if ($self->{debug});
932              
933             # compile it
934 0           $self->{_sth} = $self->{_dbh}->prepare($prep);
935 0           %rc=%{$self->_check_and_return_if_error};
  0            
936 0 0         return \%rc if ($rc{failed});
937              
938 0 0         printf STDERR "D[%s] db_search: prepare succeeded\nprepare: %s\n",$$,$prep if ($self->{debug});
939            
940            
941             # execute it ...
942 0 0         printf STDERR "D[%s] db_search: executing search\n",$$ if ($self->{debug});
943 0           $self->{_sth}->execute();
944 0           %rc=%{$self->_check_and_return_if_error};
  0            
945 0 0         return \%rc if ($rc{failed});
946 0 0         printf STDERR "D[%s] db_search: execute succeeded\n",$$ if ($self->{debug});
947            
948 0           %rc= ( 'success' => true );
949 0           return \%rc;
950             }
951            
952             sub db_update
953             {
954 0     0 1   my ($self,%args)=@_;
955 0           my ($table,$search,$columns,$prep,%rc,@sfields,@svalues,@cfields,@cvalues);
956 0           my (@q_sfields,@q_cfields);
957            
958             # quick error check
959 0           foreach (qw(table search columns))
960             {
961 0 0         if (exists($args{$_}))
962             {
963 0 0         $table = $self->_quote_table($args{$_}) if ($_ eq 'table');
964 0 0         $search = $args{$_} if ($_ eq 'search');
965 0 0         $columns = $args{$_} if ($_ eq 'columns');
966             }
967             else
968             {
969 0           %rc= ( 'failed' => {'error' => "no $_ specified" } );
970 0           return \%rc;
971             }
972             }
973            
974 0 0         if ( !defined( $self->{_dbh} ) )
975             {
976 0           %rc= ( 'failed' => { 'error' => "Database handle does not exist" } );
977 0           return \%rc;
978             }
979              
980             # extract fields and values from the columns
981 0           @sfields=(keys %{$search});
  0            
982 0           map { push @svalues,$self->_quote_value($search->{$_}) } @sfields;
  0            
983 0           map { push @q_sfields,$self->_quote_field($_) } @sfields;
  0            
984 0           @cfields=(keys %{$columns});
  0            
985 0           map { push @cvalues,$self->_quote_value($columns->{$_}) } @cfields;
  0            
986 0           map { push @q_cfields,$self->_quote_field($_) } @cfields;
  0            
987            
988             # create the SQL for the insert
989 0           $prep = sprintf 'UPDATE %s SET ',$table;
990 0           foreach (0 .. $#cfields)
991             {
992 0 0         $prep .= "," if ($_ > 0);
993 0           $prep .= sprintf "%s=%s",$q_cfields[$_],$cvalues[$_];
994             }
995 0           $prep .= ' WHERE ';
996 0           foreach (0 .. $#sfields)
997             {
998 0 0         $prep .= "," if ($_ > 0);
999 0           $prep .= sprintf "%s=%s",$q_sfields[$_],$svalues[$_];
1000             }
1001 0 0         printf STDERR "D[%s] db_update: prepare = \'%s\' \n",
1002             $$,$prep if ($self->{debug});
1003            
1004              
1005             # compile it
1006 0           $self->{_sth} = $self->{_dbh}->prepare($prep) ;
1007 0           %rc=%{$self->_check_and_return_if_error};
  0            
1008 0 0         return \%rc if ($rc{failed});
1009 0 0         printf STDERR "D[%s] db_update: prepare succeeded\n",$$ if ($self->{debug});
1010            
1011            
1012             # execute it ...
1013 0           $self->{_sth}->execute();
1014 0           %rc=%{$self->_check_and_return_if_error};
  0            
1015 0 0         return \%rc if ($rc{failed});
1016 0 0         printf STDERR "D[%s] db_update: execute succeeded\n",$$ if ($self->{debug});
1017            
1018 0           %rc= ( 'success' => true );
1019 0           return \%rc;
1020             }
1021              
1022             sub db_delete
1023             {
1024 0     0 1   my ($self,%args)=@_;
1025 0           my ($table,$search,$prep,%rc,@fields,@values,@q_fields);
1026            
1027             # quick error check
1028 0           foreach (qw(table search))
1029             {
1030 0 0         if (exists($args{$_}))
1031             {
1032 0 0         $table = $self->_quote_table($args{$_}) if ($_ eq 'table');
1033 0 0         $search = $args{$_} if ($_ eq 'search');
1034             }
1035             else
1036             {
1037 0           %rc= ( 'failed' => {'error' => "no $_ specified" } );
1038 0           return \%rc;
1039             }
1040             }
1041            
1042 0 0         if ( !defined( $self->{_dbh} ) )
1043             {
1044 0           %rc= ( 'failed' => { 'error' => "Database handle does not exist" } );
1045 0           return \%rc;
1046             }
1047              
1048             # extract fields and values from the columns
1049 0           @fields=(keys %{$search});
  0            
1050 0           map { push @values,$self->_quote_value($search->{$_}) } @fields;
  0            
1051 0           map { push @q_fields,$self->_quote_field($_) } @fields;
  0            
1052            
1053            
1054             # create the SQL for the delete
1055 0           $prep = sprintf 'DELETE FROM %s WHERE ',$table;
1056 0           foreach (0 .. $#fields)
1057             {
1058 0 0         $prep .= " AND " if ($_ > 0);
1059 0           $prep .= sprintf "%s=%s",$q_fields[$_],$values[$_];
1060             }
1061 0 0         printf STDERR "D[%s] db_delete: SQL=\'%s\'\n",$$,$prep if ($self->{debug});
1062            
1063              
1064             # compile it
1065 0           $self->{_sth} = $self->{_dbh}->prepare($prep);
1066 0           %rc=%{$self->_check_and_return_if_error};
  0            
1067 0 0         return \%rc if ($rc{failed});
1068 0 0         printf STDERR "D[%s] db_delete: prepare succeeded\n",$$ if ($self->{debug});
1069            
1070             # execute it ...
1071 0           $self->{_sth}->execute();
1072 0           %rc=%{$self->_check_and_return_if_error};
  0            
1073 0 0         return \%rc if ($rc{failed});
1074 0 0         printf STDERR "D[%s] db_delete: execute succeeded\n",$$ if ($self->{debug});
1075            
1076 0           %rc= ( 'success' => true );
1077 0           return \%rc;
1078             }
1079              
1080             sub db_next
1081             {
1082 0     0 0   my ($self,%args)=@_;
1083 0           my $rc;
1084             # quick sanity check: return undef if no session handle to query from
1085 0 0         return undef if (!($self->{_sth}));
1086 0 0         printf STDERR "D[%s] db_next: returning hashref\n",$$ if ($self->{debug});
1087 0           $rc= $self->{_sth}->fetchrow_hashref;
1088 0           return $rc;
1089             }
1090              
1091             sub db_array
1092             {
1093 0     0 0   my ($self,%args)=@_;
1094 0           my $rc;
1095             # quick sanity check: return undef if no session handle to query from
1096 0 0         return undef if (!($self->{_sth}));
1097 0 0         printf STDERR "D[%s] db_array: returning array of hashes\n",$$ if ($self->{debug});
1098 0           $rc= $self->{_sth}->fetchall_arrayref({});
1099 0           return $rc;
1100             }
1101            
1102             sub db_rows
1103             {
1104 0     0 0   my ($self,%args)=@_;
1105 0           my $rc;
1106             # quick sanity check: return undef if no session handle to query from
1107 0 0         return undef if (!($self->{_sth}));
1108 0           $rc=$self->{_sth}->rows;
1109 0 0         printf STDERR "D[%s] db_rows: returning %s\n",$$,$rc if ($self->{debug});
1110 0           return $rc;
1111             }
1112              
1113             sub db_ping
1114             {
1115 0     0 0   my ($self,%args)=@_;
1116             # quick sanity check: return undef if no db handle set up
1117 0 0         return undef if (!($self->{_dbh}));
1118 0           return $self->{_dbh}->ping;
1119             }
1120              
1121             sub db_rollback
1122             {
1123 0     0 0   my ($self,%args)=@_;
1124             # quick sanity check: return undef if no db handle set up
1125 0 0         return undef if (!($self->{_dbh}));
1126 0           eval { $self->{_dbh}->rollback; };
  0            
1127 0           return $@;
1128             }
1129            
1130             sub db_trace
1131             {
1132 0     0 0   my ($self,%args)=@_;
1133 0           my ($level,$file);
1134 0 0         if (!($self->{_dbh}))
1135             {
1136 0           my %rc= ( 'failed' => {'error' => "no database connection to trace" } );
1137 0           return \%rc;
1138             }
1139 0           foreach (qw(level file))
1140             {
1141 0 0         if (exists($args{$_}))
1142             {
1143 0 0         $level = $args{$_} if ($_ eq 'level');
1144 0 0         $file = $args{$_} if ($_ eq 'file');
1145             }
1146             else
1147             {
1148 0           my %rc= ( 'failed' => {'error' => "no $_ specified" } );
1149 0           return \%rc;
1150             }
1151             }
1152 0 0         if (!$file)
1153             {
1154 0           $self->{_dbh}->trace($level);
1155             }
1156             else
1157             {
1158 0           $self->{_dbh}->trace($level,$file);
1159            
1160             }
1161             # quick sanity check: return undef if no session handle to query from
1162 0           return $self->{_sth}->fetchrow_hashref;
1163             }
1164             sub db_close
1165             {
1166 0     0 0   my ($self )=shift;
1167 0           my %rc;
1168 0 0         if (defined($self->{_sth})) { undef $self->{_sth} ; }
  0            
1169 0           $self->{_dbh}->disconnect();
1170 0 0         printf STDERR "D[%s] db_close\n",$$ if ($self->{debug});
1171 0           %rc=%{$self->_check_and_return_if_error};
  0            
1172 0 0         return \%rc if ($rc{failed});
1173            
1174 0           %rc= ( 'success' => true );
1175 0           return \%rc;
1176             }
1177              
1178             sub db_commit
1179             {
1180 0     0 1   my ($self )=shift;
1181 0           my %rc;
1182 0 0         $self->{_dbh}->commit() if (defined($self->{_dbh}));
1183 0 0         printf STDERR "D[%s] db_commit\n",$$ if ($self->{debug});
1184 0           %rc=%{$self->_check_and_return_if_error};
  0            
1185 0 0         return \%rc if ($rc{failed});
1186              
1187 0           %rc= ( 'success' => true );
1188 0           return \%rc;
1189             }
1190            
1191             sub db_create_table
1192             {
1193 0     0 1   my ($self,%args)=@_;
1194 0           my ($table,$columns,$prep,%rc,@fields,%types,@q_fields);
1195            
1196             # quick error check
1197 0           foreach (qw(table columns))
1198             {
1199 0 0         if (exists($args{$_}))
1200             {
1201 0 0         $table = $self->_quote_table($args{$_}) if ($_ eq 'table');
1202 0 0         $columns = $args{$_} if ($_ eq 'columns');
1203             }
1204             else
1205             {
1206 0           %rc= ( 'failed' => {'error' => "no $_ specified" } );
1207 0           return \%rc;
1208             }
1209             }
1210            
1211 0 0         if ( !defined( $self->{_dbh} ) )
1212             {
1213 0           %rc= ( 'failed' => { 'error' => "Database handle does not exist" } );
1214 0           return \%rc;
1215             }
1216              
1217             # extract fields and values from the columns
1218 0           @fields=(keys %{$columns});
  0            
1219 0           map { $types{$_}=$columns->{$_} } @fields;
  0            
1220 0           map { push @q_fields,$self->_quote_field($_) } @fields;
  0            
1221            
1222             # create the SQL for the insert
1223 0           $prep = sprintf 'CREATE TABLE %s (',$table;
1224 0           $prep .= "\n";
1225            
1226 0           foreach (0 .. $#fields)
1227             {
1228 0           $prep .= sprintf "\t%s %s",$q_fields[$_],$types{$fields[$_]};
1229 0 0         $prep .= ",\n" if ($_ < $#fields);
1230             }
1231 0           $prep .= ')';
1232 0 0         printf STDERR "D[%s] db_create_table: SQL=\'%s\'\n",$$,$prep if ($self->{debug});
1233              
1234             # compile it
1235 0           $self->{_sth} = $self->{_dbh}->prepare($prep);
1236 0           %rc=%{$self->_check_and_return_if_error};
  0            
1237 0 0         return \%rc if ($rc{failed});
1238 0 0         printf STDERR "D[%s] db_create_table: prepare succeeded\n",$$ if ($self->{debug});
1239            
1240             # execute it ...
1241 0           $self->{_sth}->execute();
1242 0           %rc=%{$self->_check_and_return_if_error};
  0            
1243 0 0         return \%rc if ($rc{failed});
1244 0 0         printf STDERR "D[%s] db_create_table: execute succeeded\n",$$ if ($self->{debug});
1245            
1246 0           %rc= ( 'success' => true );
1247 0           return \%rc;
1248             }
1249              
1250             sub _quote_table
1251             {
1252 0     0     my ($self,$value) = @_;
1253 0           my $_x = sprintf "%s%s%s",
1254             $self->{quote}->{table},
1255             $value,
1256             $self->{quote}->{table};
1257 0           return $_x;
1258             }
1259             sub _quote_field
1260             {
1261 0     0     my ($self,$value) = @_;
1262 0           my $_x = sprintf "%s%s%s",
1263             $self->{quote}->{field},
1264             $value,
1265             $self->{quote}->{field};
1266 0           return $_x;
1267             }
1268             sub _quote_value
1269             {
1270 0     0     my ($self,$value) = @_;
1271 0           my $_x = sprintf "%s%s%s",
1272             $self->{quote}->{value},
1273             $value,
1274             $self->{quote}->{value};
1275 0           return $_x;
1276             }
1277              
1278             sub _check_and_return_if_error
1279             {
1280 0     0     my ($self) = @_;
1281 0           my %rc;
1282 0 0 0       if (
1283             (defined($self->{_dbh}->err)) &&
1284             ($self->{_dbh}->err)
1285             )
1286             {
1287 0 0         printf STDERR "D[%s]: DBIx::SimplePerl database error \'%s\'\n",$$,$self->{_dbh}->err if ($self->{debug});
1288 0           %rc= (
1289             'failed' => {
1290             'error' => $self->{_dbh}->errstr ,
1291             'code' => $self->{_dbh}->err
1292             }
1293             );
1294 0           return \%rc;
1295             }
1296            
1297 0 0 0       if (
      0        
1298             (defined($self->{_sth} )) &&
1299             (defined($self->{_sth}->err)) &&
1300             ($self->{_sth}->err)
1301             )
1302             {
1303 0 0         printf STDERR "D[%s]: DBIx::SimplePerl session handle error \'%s\'\n",$$,$self->{_sth}->err if ($self->{debug});
1304 0           %rc= (
1305             'failed' => {
1306             'error' => $self->{_sth}->errstr ,
1307             'code' => $self->{_sth}->err
1308             }
1309             );
1310 0           return \%rc;
1311             }
1312             }
1313             =cut
1314             =pod
1315             =back
1316              
1317             =head1 EXAMPLE
1318              
1319             Suppose you have a nice database, a SQLite in this case, though it
1320             will work perfectly well with Mysql, Postgres, and anything else
1321             DBI supports. This database has a list of host names and MAC
1322             addresses, and you want to list them from the database.
1323              
1324             The table has been created using:
1325              
1326              
1327             CREATE TABLE hosts (
1328             mac_address text,
1329             ip_address text,
1330             dhcp_ipaddress text,
1331             host_name text,
1332             host_domain text,
1333             net_device text,
1334             gateway text,
1335             netmask text,
1336             mtu text,
1337             options text
1338             );
1339              
1340              
1341             and the script looks like this
1342              
1343              
1344             #!/usr/bin/perl
1345              
1346             use strict;
1347             use DBIx::SimplePerl;
1348             my ($dbh,$err,$sice);
1349             my ($rc,$debug,$q);
1350              
1351             $debug = 1;
1352             $sice = SICE->new( { debug=>$debug } );
1353             $sice->db_open(
1354             'dsn' => "dbi:SQLite:dbname=/etc/cluster/cluster.db",
1355             'dbuser' => "",
1356             'dbpass' => ""
1357             );
1358              
1359             printf "Machines in cluster.db\n" ;
1360             $rc = $sice->db_search('table' => 'hosts');
1361             if (defined($rc->{success}))
1362             {
1363             printf "mac\t\t\tip\t\thostname\n" ;
1364             $q=($sice->{_sth}->fetchall_hashref('mac_address'));
1365             foreach (sort keys %{$q})
1366             {
1367             printf "%s\t%s\t%s\n", $_,
1368             $q->{$_}->{ip_address},
1369             $q->{$_}->{host_name} ;
1370             }
1371             }
1372             else
1373             {
1374             printf "WARNING: the search did not succeed.\n
1375             DB returned the following error:\n\n%s\n\n",
1376             $rc->{failed};
1377             }
1378             $sice->db_close;
1379              
1380             The db_search does the query, and stores the result in a session
1381             handle stored as $object_name->{_sth}. You can then use your
1382             favorite DBI method to pull out the records. What DBI Simple
1383             saves you is writing SQL. It will do that portion for you. If you
1384             turn debugging by creating the object with debug=>1, then you can
1385             watch the SQL that is generated.
1386              
1387             =head1 WHY
1388              
1389             Why hide SQL? That question should answer itself, especially in
1390             programs not requiring the full firepower of a Class::DBI,
1391             DBIx::Class or most of the DBI methods. It is fairly easy to
1392             make a mistake in the SQL you generate, and debugging it can be
1393             annoying. This was the driving force behind this particular
1394             module. The SQL that is generated is fairly simple minded. It
1395             is executed, and results returned. If it fails, this is also
1396             caught and what DBI thinks is the reason it failed is returned as
1397             the $object->{failed} message.
1398              
1399             This module is not for the folks who need the full firepower of
1400             most of the rest of DBI. This module is for simple programs. If
1401             you exceed the capabilities of this module, then please look to
1402             one of the other modules that do DBs.
1403              
1404             The approach to this module is simplicity. It is intended to be
1405             robust for basic applications, and it is used in a few commercial
1406             products.
1407              
1408             =head1 AUTHOR
1409              
1410             Joe Landman (landman@scalableinformatics.com)
1411              
1412              
1413             =head1 COPYRIGHT
1414              
1415             Copyright (c) 2003-2007 Scalable Informatics LLC. All rights
1416             reserved.
1417              
1418             This library is free software; you can redistribute it and/or
1419             modify it under the same terms as Perl itself, either Perl version
1420             5.8.6 or, at your option, any later version of Perl 5 you may have
1421             available.
1422              
1423             =head1 SEE ALSO
1424              
1425             perl(1), DBI, Class::Accessor
1426              
1427             =head1 BUGS
1428              
1429             Well, quite likely. SQL is a standard, and standards are open to
1430             interpretation. This means that some things may not work as
1431             expected. We have run into issues in quoting fields and values,
1432             where DBD::Mysql happily accepted input that DBD::Pg croaked on.
1433             This module is known to work without noticable issues on DBD::SQLite,
1434             DBD::Mysql, DBD::Pg. Others may or may not work, depending upon
1435             how compatible they are with the specs in DBI for DBD module writers.
1436              
1437             Note: as of 1.50, RaiseError is set to 0. If you want the code to
1438             throw a signal upon an error, set this to 1 when you create the object.
1439             Also, the handles now are all outside of evals. This is to make error
1440             handling saner.
1441             =cut
1442              
1443             1;
1444             __END__