File Coverage

blib/lib/DBIx/Compat.pm
Criterion Covered Total %
statement 6 80 7.5
branch 1 28 3.5
condition 0 11 0.0
subroutine 2 18 11.1
pod 2 17 11.7
total 11 154 7.1


line stmt bran cond sub pod time code
1              
2             ###################################################################################
3             #
4             # DBIx::Compat - Copyright (c) 1997-1998 Gerald Richter / ECOS
5             #
6             # You may distribute under the terms of either the GNU General Public
7             # License or the Artistic License, as specified in the Perl README file.
8             # For use with Apache httpd and mod_perl, see also Apache copyright.
9             #
10             # THIS IS BETA SOFTWARE!
11             #
12             # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
13             # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14             # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15             #
16             # $Id: Compat.pm,v 1.27 2001/07/10 05:06:51 richter Exp $
17             #
18             ###################################################################################
19              
20             package DBIx::Compat ;
21              
22 1     1   2484 use DBI ;
  1         43917  
  1         1558  
23              
24             sub SelectFields
25              
26             {
27 0     0 0 0 my $hdl = shift ;
28 0         0 my $table = shift ;
29            
30 0         0 my $sth = $hdl -> prepare ("select * from $table where 1=0") ;
31 0 0       0 if (!$sth -> execute ())
32             {
33 0         0 warn "select * from $table where 1=0 failed $DBI::errstr" ;
34 0         0 return undef ;
35             }
36            
37 0         0 return $sth ;
38             }
39              
40             sub SelectFieldsQuoted
41              
42             {
43 0     0 0 0 my $hdl = shift ;
44 0         0 my $table = shift ;
45            
46 0         0 my $sth = $hdl -> prepare ("select * from \"$table\" where 1=0") ;
47 0 0       0 if (!$sth -> execute ())
48             {
49 0         0 warn "select * from \"$table\" where 1=0 failed $DBI::errstr" ;
50 0         0 return undef ;
51             }
52            
53 0         0 return $sth ;
54             }
55              
56             sub SelectAllFields
57              
58             {
59 0     0 0 0 my $hdl = shift ;
60 0         0 my $table = shift ;
61            
62 0         0 my $sth = $hdl -> prepare ("select * from $table") ;
63 0 0       0 if (!$sth -> execute ())
64             {
65 0         0 warn "select * from $table failed $DBI::errstr" ;
66 0         0 return undef ;
67             }
68            
69 0         0 return $sth ;
70             }
71              
72              
73              
74             sub ListFields
75              
76             {
77 0     0 1 0 my $hdl = shift ;
78 0         0 my $table = shift ;
79            
80 0         0 my $sth = $hdl -> prepare ("LISTFIELDS $table") ;
81 0 0       0 $sth -> execute () or return undef ;
82              
83             # Meaning of TYPE has changed from 1.19_18 -> 1.19_19
84 0 0       0 $Compat{mSQL}{QuoteTypes} = { 1=>1, 12=>1, -1=>1 } if (exists ($sth -> {msql_type})) ;
85              
86 0         0 return $sth ;
87             }
88              
89             sub ListFieldsFunc
90              
91             {
92 0     0 0 0 my $hdl = shift ;
93 0         0 my $table = shift ;
94            
95 0 0       0 my $sth = $hdl -> func($table, 'listfields' ) or return undef ;
96            
97 0         0 return $sth ;
98             }
99              
100              
101             sub ListTables
102              
103             {
104 0     0 1 0 my $hdl = shift ;
105              
106 0         0 return $hdl -> tables ;
107             }
108              
109             sub ListTablesODBC
110              
111             {
112 0     0 0 0 my $hdl = shift ;
113              
114 0         0 return grep (!/^MSys/, $hdl -> tables) ;
115             }
116              
117             sub ListTablesFunc
118              
119             {
120 0     0 0 0 my $hdl = shift ;
121              
122 0         0 my @tabs ;
123              
124 0         0 eval { @tabs = $hdl -> tables } ;
  0         0  
125            
126             # try the _ListTables function for DBD::mysql before 1.21..
127 0 0 0     0 @tabs = $hdl -> func('_ListTables' ) if ($#tabs < 0 || $@) ;
128              
129 0         0 return @tabs ;
130             }
131              
132             sub ListTablesPg
133              
134             {
135 0     0 0 0 my $hdl = shift ;
136 0         0 my @tabs ;
137 0         0 my $st = $hdl -> tables ;
138              
139 0         0 while ($dat = $st -> fetch)
140             {
141 0         0 push @tabs, $dat -> [0] ;
142             }
143              
144 0         0 return @tabs ;
145             }
146              
147              
148             sub ListTablesIfmx
149              
150             {
151 0     0 0 0 my $hdl = shift ;
152              
153 0         0 my @tabs = $hdl -> func('_tables' );
154              
155 0         0 return @tabs ;
156             }
157              
158              
159             sub LimitOffsetStrPg
160              
161             {
162 0     0 0 0 my ($start,$max) = @_;
163            
164 0 0       0 return ($max > 0?"LIMIT $max":'') . ($start > 0?" OFFSET $start":'') ;
    0          
165             }
166              
167              
168             sub LimitOffsetStrMySQL
169              
170             {
171 0     0 0 0 my ($start,$max) = @_;
172              
173 0   0     0 $start ||= 0 ;
174            
175 0 0       0 return ($max > 0)?"LIMIT $start,$max":'' ;
176             }
177              
178             sub MysqlGetSerial
179              
180             {
181 0     0 0 0 my ($dbh, $table) = @_ ;
182            
183 0         0 return $dbh -> {'mysql_insertid'} ;
184             }
185            
186             sub SeqGetSerial
187              
188             {
189 0     0 0 0 my ($dbh, $table, $seq) = @_ ;
190            
191 0   0     0 $seq ||= ($table . '_seq') ;
192 0         0 my $sth = $dbh -> prepare ("select $seq.nextval from dual") ;
193 0 0       0 $sth -> execute () or die "Cannot get serial from $seq ($DBI::errstr)" ;
194 0         0 my $row = $sth -> fetchrow_arrayref ;
195            
196 0         0 return $row->[0] ;
197             }
198            
199             sub PgGetSerial
200              
201             {
202 0     0 0 0 my ($dbh, $table, $seq) = @_ ;
203            
204 0   0     0 $seq ||= ($table . '_seq') ;
205 0         0 my $sth = $dbh -> prepare ("select nextval ('$seq')") ;
206 0 0       0 $sth -> execute () or die "Cannot get serial from $seq ($DBI::errstr)" ;
207 0         0 my $row = $sth -> fetchrow_arrayref ;
208            
209 0         0 return $row->[0] ;
210             }
211            
212              
213             sub InformixGetSerial
214              
215             {
216 0     0 0 0 my ($dbh, $table) = @_ ;
217            
218 0         0 my $sth = $dbh -> prepare ("select distinct dbinfo('sqlca.sqlerrd1') from $table") ;
219 0 0       0 $sth -> execute () or die "Cannot get serial from $seq ($DBI::errstr)" ;
220 0         0 my $row = $sth -> fetchrow_arrayref ;
221            
222 0         0 return $row->[0] ;
223             }
224              
225            
226             ####################################################################################
227              
228              
229             %Compat =
230             (
231             '*' =>
232             {
233             'Placeholders' => 10, # Default: Placeholder are supported
234             'ListFields' => \&SelectFields, # Default: Use Select to get field names
235             'ListTables' => \&ListTables, # Default: Use DBI $dbh -> tables
236             # QuoteTypes isn't used anymore !!
237             'QuoteTypes' => { 1=>1, 12=>1, -1=>1, 9 => 1, 10 => 1, 11 => 1}, # Default: ODBC Types, quote char, varchar and longvarchar
238             'NumericTypes' => { 2 => 1, 3 => 1, 4 => 1, 5 => 1, 6 => 1, 7 => 1, 8 => 1, -5 => 1, -6 => 1}, # Default numeric ODBC Types
239             'SupportJoin' => 1, # Default: Driver supports joins (select with multiple tables)
240             'SupportSQLJoin' => 1, # Default: Driver supports INNER/LEFT/RIGHT JOIN Syntax in SQL select
241             'SQLJoinOnly2Tabs' => 0, # Default: Driver supports LEFT/RIGHT JOIN with more then two tables
242             'HaveTypes' => 1, # Default: Driver supports $sth -> {TYPE}
243             'NullOperator' => 'IS', # Default: Operator to compare with NULL is IS
244             'HasInOperator' => 1, # Default: DBMS support x IN (y)
245             'NeedNullInCreate' => '', # Default: NULL allowed without explicit declare in CREATE
246             'EmptyIsNull' => 0, # Default: Empty strings ('') and NULL are different
247             'LimitOffset' => undef, # Default: Don't use LIMIT/OFFSET in SELECTs
248             'GetSerialPreInsert' => undef, # Default: Driver does not support serials
249             'GetSerialPostInsert' => undef, # Default: Driver does not support serials
250             'CreateTypes' => {}, # conversion for CreateTables
251             'CreateSeq' => 0, # Create sequence for counter
252             'CreatePublic' => 0, # Create public synonym for table
253             'CanDropColumn' => 1, # DBMS can drop a column
254             'QuoteIdentifier' => undef, # DBMS can handle idntifiers with spaces by quoteing them. Default: no
255             },
256             'SQLite' =>
257             {
258             'Placeholders' => 10, # Default: Placeholder are supported
259             'ListFields' => \&SelectFields, # Default: Use Select to get field names
260             'ListTables' => \&ListTables, # Default: Use DBI $dbh -> tables
261             # QuoteTypes isn't used anymore !!
262             'QuoteTypes' => { 1=>1, 12=>1, -1=>1, 9 => 1, 10 => 1, 11 => 1}, # Default: ODBC Types, quote char, varchar and longvarchar
263             'NumericTypes' => { 2 => 1, 3 => 1, 4 => 1, 5 => 1, 6 => 1, 7 => 1, 8 => 1, -5 => 1, -6 => 1}, # Default numeric ODBC Types
264             'SupportJoin' => 1, # Default: Driver supports joins (select with multiple tables)
265             'SupportSQLJoin' => 4, # Default: Driver supports INNER/LEFT/RIGHT JOIN Syntax in SQL select
266             'SQLJoinOnly2Tabs' => 0, # Default: Driver supports LEFT/RIGHT JOIN with more then two tables
267             'HaveTypes' => 0, # Default: Driver supports $sth -> {TYPE}
268             'NullOperator' => 'IS', # Default: Operator to compare with NULL is IS
269             'HasInOperator' => 1, # Default: DBMS support x IN (y)
270             'NeedNullInCreate' => '', # Default: NULL allowed without explicit declare in CREATE
271             'EmptyIsNull' => 0, # Default: Empty strings ('') and NULL are different
272             'LimitOffset' => \&LimitOffsetStrPg, # Default: Don't use LIMIT/OFFSET in SELECTs
273             'GetSerialPreInsert' => undef, # Default: Driver does not support serials
274             'GetSerialPostInsert' => undef, # Default: Driver does not support serials
275             'CreateTypes' => # conversion for CreateTables
276             {
277             'counter' => 'INTEGER PRIMARY KEY',
278             },
279             'CreateSeq' => 0, # Create sequence for counter
280             'CreatePublic' => 0, # Create public synonym for table
281             'CanDropColumn' => 0, # DBMS can drop a column
282             'QuoteIdentifier' => undef, # DBMS can handle idntifiers with spaces by quoteing them. Default: no
283             },
284              
285             'ConfFile' =>
286             {
287             'Placeholders' => 2, # Placeholders supported, but the perl
288             # type must be the same as the db type
289             'ListFields' => \&SelectFields,
290             'SupportJoin' => 0,
291             'HaveTypes' => 0 # Driver does not support $sth -> {TYPE}
292             },
293              
294             'CSV' =>
295             {
296             'Placeholders' => 2, # Placeholders supported, but the perl
297             # type must be the same as the db type
298             'ListFields' => \&SelectFields,
299             'SupportJoin' => 0,
300             'SupportSQLJoin' => 0, # Driver does not supports INNER/LEFT/RIGHt JOIN Syntax in SQL select
301             'HaveTypes' => 0, # Driver does not support $sth -> {TYPE}
302             'ListTables' => undef, # no tables
303             'EmptyIsNull' => 1, # DBD::CSV does not really knows about NULL
304             'HasInOperator' => 0, # DBD::CSV does not support x IN (y)
305             },
306              
307             'XBase' =>
308             {
309             # 'Placeholders' => 2, # Placeholders supported, but the perl
310             # type must be the same as the db type
311             'ListFields' => \&SelectAllFields,
312             'SupportJoin' => 0,
313             'HaveTypes' => 0 # Driver does not support $sth -> {TYPE}
314             },
315              
316             'Pg' =>
317             {
318             'Placeholders' => 2, # Placeholders supported, but the perl
319             # type must be the same as the db type
320              
321             'SupportSQLJoin' => 1, # Driver does not supports INNER/LEFT/RIGHt JOIN Syntax in SQL select
322             'NumericTypes' => {
323             20 => 1,
324             21 => 1,
325             22 => 1,
326             23 => 1,
327             700 => 1,
328             701 => 1,
329             1005 => 0,
330             1006 => 1,
331             1007 => 1,
332             },
333              
334            
335             'QuoteTypes' =>
336             { 16 => 1, 17=>1, 18=>1, 19=>1, 20=>1, 25=>1, 409=>1, 410=>1,
337             411=>1, 605=>1,
338             702 =>1, # abstime
339             703 =>1, # reltime
340             1002=>1, 1003=>1, 1004=>1, 1009=>1, 1026=>1,
341             1039=>1, 1040=>1, 1041=>1, 1042=>1, 1043=>1,
342             1082 =>1, # date
343             1083 =>1, # time
344             1184 =>1, # datetime
345             1186 =>1, # interval
346             1296 =>1
347             },
348             'LimitOffset' => \&LimitOffsetStrPg, # Only PostgreSQL 6.5+
349              
350             #### Use the following line for older DBD::Pg versions (< 0.89) which does
351             # not support the table_info function
352             # 'ListTables' => \&ListTablesPg, # DBD::Pg
353             'GetSerialPreInsert' => \&PgGetSerial,
354             'CreateTypes' => # conversion for CreateTables
355             {
356             'counter' => 'serial',
357             }
358             },
359              
360              
361            
362             'mSQL' => {
363             'Placeholders' => 2, # Placeholders supported, but the perl
364             # type must be the same as the db type
365             'SupportSQLJoin' => 0, # Driver does not supports INNER/LEFT/RIGHt JOIN Syntax in SQL select
366             'ListFields' => \&ListFields, # mSQL has it own ListFields function
367             'ListTables' => \&ListTablesFunc,# DBD::mysql $dbh -> func
368             'NullOperator' => '=', # Operator to compare with NULL is =
369             'QuoteTypes' => { 1=>1, 12=>1, -1=>1 }
370             # ### use the following line for older mSQL drivers
371             # 'QuoteTypes' => { 2=>1, 6=>1 }
372             },
373              
374             'mysql' => {
375             'ListFields' => \&ListFields, # mysql has it own ListFields function
376             'QuoteTypes' => { 1=>1, 12=>1, -1=>1 , 9=>1},
377             'Placeholders' => 10, # Placeholders supported, but the perl
378             # type must be the same as the db type
379             'SQLJoinOnly2Tabs' => 0, # mysql supports LEFT/RIGHT JOIN with more than two tables
380             'ListTables' => \&ListTablesFunc, # DBD::mysql $dbh -> func
381             'LimitOffset' => \&LimitOffsetStrMySQL,
382             'GetSerialPostInsert' => \&MysqlGetSerial,
383             'CreateTypes' => # conversion for CreateTables
384             {
385             'counter' => 'integer not null auto_increment',
386             }
387             },
388              
389             'Solid' => {
390             'Placeholders' => 3, # Placeholders supported, but cannot use a
391             # string where a number expected
392             'QuoteTypes' => { 1=>1, 12=>1, -1=>1, 9=> 1 }
393             },
394              
395             'ODBC' => {
396             'Placeholders' => 10, # Placeholders supported, but seems not
397             # to works all the time ?
398             'QuoteTypes' => { 1=>1, 12=>1, -1=>1},
399             'NeedNullInCreate' => 'NULL',
400             'ListTables' => \&ListTablesODBC, # Use DBI $dbh -> tables, exclude /^MSys/
401             'SQLJoinOnly2Tabs' => 0, # Driver supports LEFT/RIGHT JOIN only with two tables
402             'CreateTypes' => # conversion for CreateTables
403             {
404             'tinytext' => 'text',
405             'text' => 'longtext',
406             },
407             },
408             'Oracle' => {
409             'Placeholders' => 3, # Placeholders supported, but cannot use a
410             # string where a number expected
411             'QuoteTypes' => {
412             -4=>1,
413             -3=>1,
414             -1=>1,
415             1=>1, 9=>1, 11=>1, 12=>1, },
416             'SupportSQLJoin' => 3, # Oracle need a = b (+) instead of INNER/LEFT/RIGHt JOIN Syntax in SQL select
417             'EmptyIsNull' => 1, # Oracle converts empty strings ('') to NULL
418             # older DBD::Orcales only need the following one entry, but some test may fail
419             # 'HaveTypes' => 0 # Driver does not supports $sth -> {TYPE}
420             'GetSerialPreInsert' => \&SeqGetSerial,
421             'CreateTypes' => # conversion for CreateTables
422             {
423             'counter' => 'integer',
424             'tinytext' => 'varchar2(256)',
425             'text' => 'varchar2(2000)',
426             'datetime' => 'date',
427             'bool' => 'number(1)',
428             'bit' => 'number(1)',
429             },
430             'CreateSeq' => 1, # Create sequence for counter
431             'CreatePublic' => 1, # Create public synonym for table
432             'CanDropColumn' => 0, # DBMS can drop a column
433             'QuoteIdentifier' => '""', # DBMS can handle idntifiers with spaces by quoteing them.
434             ## 'ListFields' => \&SelectFieldsQuoted, # Use Select to get field names
435             },
436              
437             'Sybase' =>
438             {
439             'Placeholders' => 10,
440             'ListFields' => \&SelectFields,
441             'QuoteTypes' => {
442             -6=>0, -4=>0, -2=>0, -1=>1, 1=>1, 2=>0, 3=>1,
443             4=>0, 6=>0, 7=>0, 9=>0
444              
445             },
446             'SupportSQLJoin' => 2, # Driver need *= instead of INNER/LEFT/RIGHt JOIN Syntax in SQL select
447             'HaveTypes' => 1,
448             'NullOperator' => 'IS',
449             'NeedNullInCreate' => 'NULL'
450             },
451              
452             'Informix' => {
453             'Placeholders' => 2,
454             'SupportSQLJoin' => 4,
455             'SQLJoinOnly2Tabs' => 0,
456             'ListTables' => \&ListTablesIfmx,
457             'GetSerialPostInsert' => \&InformixGetSerial,
458             'QuoteIdentifier' => $ENV{DELIMIDENT}?'""':undef, # DBMS can handle idntifiers with spaces by quoteing them.
459             },
460              
461              
462             'Sprite' => {
463             'Placeholders' => 2, # Placeholders supported, but perl type must be the same as type in db
464             # string where a number expected
465             'QuoteTypes' => {
466             -4=>1,
467             -3=>1,
468             -1=>1,
469             1=>1, 9=>1, 11=>1, 12=>1, },
470             'SupportJoin' => 0, # NO JOINS (YET) IN SPRITE!
471             'SupportSQLJoin' => 0, # Oracle need a = b (+) instead of INNER/LEFT/RIGHt JOIN Syntax in SQL select
472             'EmptyIsNull' => 1, # Sprite converts empty strings ('') to NULL
473             'HaveTypes' => 1, # Driver does supports $sth -> {TYPE}
474             'GetSerialPreInsert' => \&SeqGetSerial,
475             'HasInOperator' => 0, # DBMS not support x IN (y)
476             },
477              
478              
479              
480             ) ;
481              
482              
483             ###########################################################################################################
484              
485             sub GetItem
486              
487             {
488 5     5 0 48 my ($driver, $name) = @_ ;
489              
490 5 50       16 return $Compat{$driver}{$name} if (exists ($Compat{$driver}{$name})) ;
491 5         20 return $Compat{'*'}{$name} ;
492             }
493              
494             1 ;
495              
496              
497             =head1 NAME
498              
499             DBIx::Compat - Perl extension for Compatibility Infos about DBD Drivers
500              
501             =head1 SYNOPSIS
502              
503             use DBIx::Compat;
504              
505             my $HaveTypes = DBIx::Compat::GetItem ($drv, 'HaveTypes') ;
506              
507             =head1 DESCRIPTION
508              
509             DBIx::Compat contains a hash which gives information about DBD drivers, to allow
510             to write driver independent programs.
511              
512             Currently there are the following attributes defined:
513              
514              
515             =head2 B
516              
517             A function which will return information about all fields of an table.
518             Needs an database handle and a tablename as argument.
519             Must at least return the fieldnames and the fieldtypes.
520              
521             Example:
522            
523             $ListFields = $DBIx::Compat::Compat{$Driver}{ListFields} ;
524             $sth = &{$ListFields}($DBHandle, $Table) or die "Cannot list fields" ;
525            
526             @{ $sth -> {NAME} } ; # array of fieldnames
527             @{ $sth -> {TYPE} } ; # array of filedtypes
528              
529             $sth -> finish ;
530              
531              
532              
533             =head2 B
534              
535             A function which will return an array of all tables of the datasource. Defaults to
536             C<$dbh> -> C.
537              
538             =head2 B
539              
540             Hash which contains one entry for all datatypes that are numeric.
541              
542             =head2 B
543              
544             Set to true if the DBMS supports joins (select with multiple tables)
545              
546             =head2 B
547              
548             Set to 1 if the DBMS supports INNER/LEFT/RIGHT JOIN Syntax in SQL select.
549             Set to 2 if DBMS needs a *= b syntax for inner join (MS-SQL, Sybase).
550             Set to 3 if DBMS needs a = b (+) syntax for inner join (Oracle syntax).
551              
552              
553             =head2 B
554              
555             Set to true if DBMS can only support two tables in inner joins.
556              
557             =head2 B
558              
559             Set to true if DBMS supports datatypes (most DBMS will do)
560              
561             =head2 B
562              
563             Set to C<'NULL'> if DBMS requires the NULL keyword when creating tables
564             where fields should contains nulls.
565              
566             =head2 B
567              
568             Set to true if an empty string ('') and NULL is the same for the DBMS.
569              
570             =head2 B
571              
572             An function which will be used to create a SQL text for limiting the
573             number of fetched rows and selecting the starting row in selects.
574              
575              
576             =head1 B
577              
578              
579             =head2 B
580              
581             Gives information if and how placeholders are supported:
582              
583             =over 4
584              
585             =item B<0> = Not supported
586              
587             =item B<1> = Supported, but not fully, unknown how much
588              
589             =item B<2> = Supported, but perl type must be the same as type in db
590              
591             =item B<3> = Supported, but can not give a string when a numeric type is in the db
592              
593             =item B<10> = Supported under all circumstances
594              
595             =back
596              
597              
598             =head2 B
599              
600             Gives information which datatypes must be quoted when passed literal
601             (not via a placeholder). Contains a hash with all type number which
602             need to be quoted.
603              
604             $DBIx::Compat::Compat{$Driver}{QuoteTypes}{$Type}
605            
606             will be true when the type in $Type for the driver $Driver must be
607             quoted.
608              
609              
610             =head1 Supported Drivers
611              
612             Currently there are entry for
613              
614             =item B
615              
616             =item B
617              
618             =item B
619              
620             =item B
621              
622             =item B
623              
624             =item B
625              
626             =item B
627              
628             =item B
629              
630             =item B
631              
632             if you detect an error in the definition or add an definition for a new
633             DBD driver, please mail it to the author.
634              
635              
636             =head1 AUTHOR
637              
638             G.Richter
639              
640             =head1 SEE ALSO
641              
642             perl(1), DBI(3), DBIx::Recordset(3)
643              
644             =cut