File Coverage

blib/lib/DBIx/Admin/TableInfo.pm
Criterion Covered Total %
statement 9 85 10.5
branch 0 26 0.0
condition 0 14 0.0
subroutine 3 9 33.3
pod 4 5 80.0
total 16 139 11.5


line stmt bran cond sub pod time code
1             package DBIx::Admin::TableInfo;
2              
3 1     1   65320 use strict;
  1         2  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         20  
5              
6 1     1   445 use Moo;
  1         7961  
  1         4  
7              
8             has catalog =>
9             (
10             is => 'rw',
11             default => sub{return undef},
12             required => 0,
13             );
14              
15             has dbh =>
16             (
17             is => 'rw',
18             isa => sub{die "The 'dbh' parameter to new() is mandatory\n" if (! $_[0])},
19             default => sub{return ''},
20             required => 1,
21             );
22              
23             has info =>
24             (
25             is => 'rw',
26             default => sub{return {} },
27             required => 0,
28             );
29              
30             has schema =>
31             (
32             is => 'rw',
33             default => sub{return undef}, # See BUILD().
34             required => 0,
35             );
36              
37             has table =>
38             (
39             is => 'rw',
40             default => sub{return '%'},
41             required => 0,
42             );
43              
44             has type =>
45             (
46             is => 'rw',
47             default => sub{return 'TABLE'},
48             required => 0,
49             );
50              
51             our $VERSION = '3.03';
52              
53             # -----------------------------------------------
54              
55             sub BUILD
56             {
57 0     0 0   my($self) = @_;
58              
59 0 0         $self -> schema(dbh2schema($self -> dbh) ) if (! defined $self -> schema);
60 0           $self -> _info;
61              
62             } # End of BUILD.
63              
64             # -----------------------------------------------
65              
66             sub columns
67             {
68 0     0 1   my($self, $table, $by_position) = @_;
69 0           my($info) = $self -> info;
70              
71 0 0         if ($by_position)
72             {
73 0           return [sort{$$info{$table}{columns}{$a}{ORDINAL_POSITION} <=> $$info{$table}{columns}{$b}{ORDINAL_POSITION} } keys %{$$info{$table}{columns} }];
  0            
  0            
74             }
75             else
76             {
77 0           return [sort{$a cmp $b} keys %{$$info{$table}{columns} }];
  0            
  0            
78             }
79              
80             } # End of columns.
81              
82             # -----------------------------------------------
83             # Warning: This is a function, not a method.
84              
85             sub dbh2schema
86             {
87 0     0 1   my($dbh) = @_;
88 0           my($vendor) = uc $dbh -> get_info(17); # SQL_DBMS_NAME.
89             my(%schema) =
90             (
91             MYSQL => undef,
92             ORACLE => uc $$dbh{Username},
93 0           POSTGRESQL => 'public',
94             SQLITE => 'main',
95             );
96              
97 0           return $schema{$vendor};
98              
99             } # End of dbh2schema.
100              
101             # -----------------------------------------------
102              
103             sub _info
104             {
105 0     0     my($self) = @_;
106 0           my($info) = {};
107 0           my($vendor) = uc $self -> dbh -> get_info(17); # SQL_DBMS_NAME.
108 0           my($table_sth) = $self -> dbh -> table_info($self -> catalog, $self -> schema, $self -> table, $self -> type);
109              
110 0           my($column_data, $column_name, $column_sth, $count);
111 0           my($foreign_table);
112 0           my($primary_key_info);
113 0           my($table_data, $table_name, @table_name);
114              
115 0           while ($table_data = $table_sth -> fetchrow_hashref() )
116             {
117 0           $table_name = $$table_data{TABLE_NAME};
118              
119 0 0 0       next if ( ($vendor eq 'ORACLE') && ($table_name =~ /^BIN\$.+\$./) );
120 0 0 0       next if ( ($vendor eq 'POSTGRESQL') && ($table_name =~ /^(?:pg_|sql_)/) );
121 0 0 0       next if ( ($vendor eq 'SQLITE') && ($table_name eq 'sqlite_sequence') );
122              
123 0           $$info{$table_name} =
124             {
125             attributes => {%$table_data},
126             columns => {},
127             foreign_keys => {},
128             primary_keys => {},
129             };
130 0           $column_sth = $self -> dbh -> column_info($self -> catalog, $self -> schema, $table_name, '%');
131 0           $primary_key_info = [];
132              
133 0           push @table_name, $table_name;
134              
135 0           while ($column_data = $column_sth -> fetchrow_hashref() )
136             {
137 0           $column_name = $$column_data{COLUMN_NAME};
138 0           $$info{$table_name}{columns}{$column_name} = {%$column_data};
139              
140 0 0 0       push @$primary_key_info, $column_name if ( ($vendor eq 'MYSQL') && $$column_data{mysql_is_pri_key});
141             }
142              
143 0 0         if ($vendor eq 'MYSQL')
144             {
145 0           $count = 0;
146              
147 0           for (@$primary_key_info)
148             {
149 0           $count++;
150              
151 0 0         $$info{$table_name}{primary_keys}{$_} = {} if (! $$info{$table_name}{primary_keys}{$_});
152 0           $$info{$table_name}{primary_keys}{$_}{COLUMN_NAME} = $_;
153 0           $$info{$table_name}{primary_keys}{$_}{KEY_SEQ} = $count;
154             }
155             }
156             else
157             {
158 0           $column_sth = $self -> dbh -> primary_key_info($self -> catalog, $self -> schema, $table_name);
159              
160 0 0         if (defined $column_sth)
161             {
162 0           for $column_data (@{$column_sth -> fetchall_arrayref({})})
  0            
163             {
164 0           $$info{$table_name}{primary_keys}{$$column_data{COLUMN_NAME} } = {%$column_data};
165             }
166             }
167             }
168             }
169              
170 0           my(%referential_action) =
171             (
172             'CASCADE' => 0,
173             'RESTRICT' => 1,
174             'SET NULL' => 2,
175             'NO ACTION' => 3,
176             'SET DEFAULT' => 4,
177             );
178              
179 0           for $table_name (@table_name)
180             {
181 0           $$info{$table_name}{foreign_keys} = [];
182              
183 0           for $foreign_table (grep{! /^$table_name$/} @table_name)
  0            
184             {
185 0 0         if ($vendor eq 'SQLITE')
186             {
187 0           for my $row (@{$self -> dbh -> selectall_arrayref("pragma foreign_key_list($foreign_table)")})
  0            
188             {
189 0 0         next if ($$row[2] ne $table_name);
190              
191 0           push @{$$info{$table_name}{foreign_keys} },
192             {
193             DEFERABILITY => undef,
194             DELETE_RULE => $referential_action{$$row[6]},
195             FK_COLUMN_NAME => $$row[3],
196             FK_DATA_TYPE => undef,
197             FK_NAME => undef,
198             FK_TABLE_CAT => undef,
199             FK_TABLE_NAME => $foreign_table,
200             FK_TABLE_SCHEM => undef,
201             ORDINAL_POSITION => $$row[1],
202             UK_COLUMN_NAME => $$row[4],
203             UK_DATA_TYPE => undef,
204             UK_NAME => undef,
205             UK_TABLE_CAT => undef,
206             UK_TABLE_NAME => $$row[2],
207             UK_TABLE_SCHEM => undef,
208             UNIQUE_OR_PRIMARY => undef,
209 0           UPDATE_RULE => $referential_action{$$row[5]},
210             };
211             }
212             }
213             else
214             {
215 0   0       $table_sth = $self -> dbh -> foreign_key_info($self -> catalog, $self -> schema, $table_name, $self -> catalog, $self -> schema, $foreign_table) || next;
216              
217 0 0         if ($vendor eq 'MYSQL')
218             {
219 0           my($hashref) = $table_sth->fetchall_hashref(['PKTABLE_NAME']);
220              
221 0 0         push @{$$info{$table_name}{foreign_keys} }, $$hashref{$table_name} if ($$hashref{$table_name});
  0            
222             }
223             else
224             {
225 0           for $column_data (@{$table_sth -> fetchall_arrayref({})})
  0            
226             {
227 0           push @{$$info{$table_name}{foreign_keys} }, {%$column_data};
  0            
228             }
229             }
230             }
231             }
232             }
233              
234 0           $self -> info($info);
235              
236             } # End of _info.
237              
238             # -----------------------------------------------
239              
240             sub refresh
241             {
242 0     0 1   my($self) = @_;
243              
244 0           $self -> _info();
245              
246 0           return $self -> info;
247              
248             } # End of refresh.
249              
250             # -----------------------------------------------
251              
252             sub tables
253             {
254 0     0 1   my($self) = @_;
255              
256 0           return [sort keys %{$self -> info}];
  0            
257              
258             } # End of tables.
259              
260             # -----------------------------------------------
261              
262             1;
263              
264             =head1 NAME
265              
266             DBIx::Admin::TableInfo - A wrapper for all of table_info(), column_info(), *_key_info()
267              
268             =head1 Synopsis
269              
270             This is scripts/synopsis.pl:
271              
272             #!/usr/bin/env perl
273              
274             use strict;
275             use warnings;
276              
277             use DBI;
278             use DBIx::Admin::TableInfo 3.02;
279              
280             use Lingua::EN::PluralToSingular 'to_singular';
281              
282             use Text::Table::Manifold ':constants';
283              
284             # ---------------------
285              
286             my($attr) = {};
287             $$attr{sqlite_unicode} = 1 if ($ENV{DBI_DSN} =~ /SQLite/i);
288             my($dbh) = DBI -> connect($ENV{DBI_DSN}, $ENV{DBI_USER}, $ENV{DBI_PASS}, $attr);
289             my($vendor_name) = uc $dbh -> get_info(17);
290             my($info) = DBIx::Admin::TableInfo -> new(dbh => $dbh) -> info;
291              
292             $dbh -> do('pragma foreign_keys = on') if ($ENV{DBI_DSN} =~ /SQLite/i);
293              
294             my($temp_1, $temp_2, $temp_3);
295              
296             if ($vendor_name eq 'MYSQL')
297             {
298             $temp_1 = 'PKTABLE_NAME';
299             $temp_2 = 'FKTABLE_NAME';
300             $temp_3 = 'FKCOLUMN_NAME';
301             }
302             else # ORACLE && POSTGRESQL && SQLITE (at least).
303             {
304             $temp_1 = 'UK_TABLE_NAME';
305             $temp_2 = 'FK_TABLE_NAME';
306             $temp_3 = 'FK_COLUMN_NAME';
307             }
308              
309             my(%special_fk_column) =
310             (
311             spouse_id => 'person_id',
312             );
313              
314             my($destination_port);
315             my($fk_column_name, $fk_table_name, %foreign_key);
316             my($pk_table_name, $primary_key_name);
317             my($singular_name, $source_port);
318              
319             for my $table_name (sort keys %$info)
320             {
321             for my $item (@{$$info{$table_name}{foreign_keys} })
322             {
323             $pk_table_name = $$item{$temp_1};
324             $fk_table_name = $$item{$temp_2};
325             $fk_column_name = $$item{$temp_3};
326              
327             if ($pk_table_name)
328             {
329             $singular_name = to_singular($pk_table_name);
330              
331             if ($special_fk_column{$fk_column_name})
332             {
333             $primary_key_name = $special_fk_column{$fk_column_name};
334             }
335             elsif (defined($$info{$table_name}{columns}{$fk_column_name}) )
336             {
337             $primary_key_name = $fk_column_name;
338             }
339             elsif (defined($$info{$table_name}{columns}{id}) )
340             {
341             $primary_key_name = 'id';
342             }
343             else
344             {
345             die "Primary table '$pk_table_name'. Foreign table '$fk_table_name'. Unable to find primary key name for foreign key '$fk_column_name'\n"
346             }
347              
348             $foreign_key{$fk_table_name} = {} if (! $foreign_key{$fk_table_name});
349             $foreign_key{$fk_table_name}{$fk_column_name} = {} if (! $foreign_key{$fk_table_name}{$fk_column_name});
350             $primary_key_name =~ s/${singular_name}_//;
351             $foreign_key{$fk_table_name}{$fk_column_name}{$table_name} = $primary_key_name;
352             }
353             }
354             }
355              
356             my(@header) =
357             (
358             'Name',
359             'Type',
360             'Null',
361             'Key',
362             'Auto-increment',
363             );
364              
365             my($table) = Text::Table::Manifold -> new
366             (
367             alignment =>
368             [
369             align_left,
370             align_left,
371             align_left,
372             align_left,
373             align_left,
374             ],
375             format => format_text_unicodebox_table,
376             headers => \@header,
377             join => "\n",
378             );
379             my(%type) =
380             (
381             'character varying' => 'varchar',
382             'int(11)' => 'integer',
383             '"timestamp"' => 'timestamp',
384             );
385              
386             my($auto_increment);
387             my(@data);
388             my($index);
389             my($nullable);
390             my($primary_key);
391             my($type);
392              
393             for my $table_name (sort keys %$info)
394             {
395             print "Table: $table_name.\n\n";
396              
397             @data = ();
398             $index = undef;
399              
400             for my $column_name (keys %{$$info{$table_name}{columns} })
401             {
402             $type = $$info{$table_name}{columns}{$column_name}{TYPE_NAME};
403             $type = $type{$type} ? $type{$type} : $type;
404             $nullable = $$info{$table_name}{columns}{$column_name}{IS_NULLABLE} eq 'NO';
405             $primary_key = $$info{$table_name}{primary_keys}{$column_name};
406             $auto_increment = $primary_key; # Database server-independent kludge :-(.
407              
408             push @data,
409             [
410             $column_name,
411             $type,
412             $nullable ? 'not null' : '',
413             $primary_key ? 'primary key' : '',
414             $auto_increment ? 'auto_increment' : '',
415             ];
416              
417             $index = pop @data if ($column_name eq 'id');
418             }
419              
420             @data = sort{$$a[0] cmp $$b[0]} @data;
421              
422             unshift @data, $index if ($index);
423              
424             $table -> data(\@data);
425              
426             print $table -> render_as_string, "\n\n";
427             }
428              
429             If the environment vaiables DBI_DSN, DBI_USER and DBI_PASS are set (the latter 2 are optional [e.g.
430             for SQLite), then this demonstrates extracting a lot of information from a database schema.
431              
432             Also, for Postgres, you can set DBI_SCHEMA to a list of schemas, e.g. when processing the
433             MusicBrainz database.
434              
435             For details, see L.
436              
437             See also xt/author/fk.t, xt/author/mysql.fk.pl and xt/author/person.spouse.t.
438              
439             =head1 Description
440              
441             C is a pure Perl module.
442              
443             It is a convenient wrapper around all of these DBI methods:
444              
445             =over 4
446              
447             =item o table_info()
448              
449             =item o column_info()
450              
451             =item o primary_key_info()
452              
453             =item o foreign_key_info()
454              
455             =back
456              
457             =over 4
458              
459             =item o MySQL
460              
461             Warning:
462              
463             To get foreign key information in the output, the create table statement has to:
464              
465             =over 4
466              
467             =item o Include an index clause
468              
469             =item o Include a foreign key clause
470              
471             =item o Include an engine clause
472              
473             As an example, a column definition for Postgres and SQLite, which looks like:
474              
475             site_id integer not null references sites(id),
476              
477             has to, for MySql, look like:
478              
479             site_id integer not null, index (site_id), foreign key (site_id) references sites(id),
480              
481             Further, the create table statement, which for Postgres and SQLite looks like:
482              
483             create table designs (...)
484              
485             has to, for MySql, look like:
486              
487             create table designs (...) engine=innodb
488              
489             =back
490              
491             =item o Oracle
492              
493             See the L for which tables are ignored under Oracle.
494              
495             =item o Postgres
496              
497             The latter now takes '%' as the value of the 'table' parameter to new(), whereas
498             older versions of DBD::Pg required 'table' to be set to 'table'.
499              
500             See the L for which tables are ignored under Postgres.
501              
502             =item o SQLite
503              
504             See the L for which tables are ignored under SQLite.
505              
506             =back
507              
508             =head1 Distributions
509              
510             This module is available both as a Unix-style distro (*.tgz) and an
511             ActiveState-style distro (*.ppd). The latter is shipped in a *.zip file.
512              
513             See http://savage.net.au/Perl-modules.html for details.
514              
515             See http://savage.net.au/Perl-modules/html/installing-a-module.html for
516             help on unpacking and installing each type of distro.
517              
518             =head1 Constructor and initialization
519              
520             new(...) returns a C object.
521              
522             This is the class contructor.
523              
524             Usage: DBIx::Admin::TableInfo -> new().
525              
526             This method takes a set of parameters. Only the dbh parameter is mandatory.
527              
528             For each parameter you wish to use, call new as new(param_1 => value_1, ...).
529              
530             =over 4
531              
532             =item o catalog
533              
534             This is the value passed in as the catalog parameter to table_info() and column_info().
535              
536             The default value is undef.
537              
538             undef was chosen because it given the best results with MySQL.
539              
540             Note: The MySQL driver DBD::mysql V 2.9002 has a bug in it, in that it aborts if an empty string is
541             used here, even though the DBI docs say an empty string can be used for the catalog parameter to
542             C.
543              
544             This parameter is optional.
545              
546             =item o dbh
547              
548             This is a database handle.
549              
550             This parameter is mandatory.
551              
552             =item o schema
553              
554             This is the value passed in as the schema parameter to table_info() and column_info().
555              
556             The default value is undef.
557              
558             Note: If you are using Oracle, call C with schema set to uc $user_name.
559              
560             Note: If you are using Postgres, call C with schema set to 'public'.
561              
562             Note: If you are using SQLite, call C with schema set to 'main'.
563              
564             This parameter is optional.
565              
566             =item o table
567              
568             This is the value passed in as the table parameter to table_info().
569              
570             The default value is '%'.
571              
572             Note: If you are using an 'old' version of DBD::Pg, call C with table set to 'table'.
573              
574             Sorry - I cannot tell you exactly what 'old' means. As stated above, the default value (%)
575             works fine with DBD::Pg V 2.17.1.
576              
577             This parameter is optional.
578              
579             =item o type
580              
581             This is the value passed in as the type parameter to table_info().
582              
583             The default value is 'TABLE'.
584              
585             This parameter is optional.
586              
587             =back
588              
589             =head1 Methods
590              
591             =head2 columns($table_name, $by_position)
592              
593             Returns an array ref of column names.
594              
595             By default they are sorted by name.
596              
597             However, if you pass in a true value for $by_position, they are sorted by the column attribute
598             ORDINAL_POSITION. This is Postgres-specific.
599              
600             =head2 dbh2schema($dbh)
601              
602             Warning: This is a function, not a method. It is called like this:
603              
604             my($schema) = DBIx::Admin::TableInfo::dbh2schema($dbh);
605              
606             The code is just:
607              
608             my($dbh) = @_;
609             my($vendor) = uc $dbh -> get_info(17); # SQL_DBMS_NAME.
610             my(%schema) =
611             (
612             MYSQL => undef,
613             ORACLE => uc $$dbh{Username},
614             POSTGRESQL => 'public',
615             SQLITE => 'main',
616             );
617              
618             return $schema{$vendor};
619              
620             =head2 info()
621              
622             Returns a hash ref of all available data.
623              
624             The structure of this hash is described next:
625              
626             =over 4
627              
628             =item o First level: The keys are the names of the tables
629              
630             my($info) = $obj -> info();
631             my(@table_name) = sort keys %$info;
632              
633             I use singular names for my arrays, hence @table_name rather than @table_names.
634              
635             =item o Second level: The keys are 'attributes', 'columns', 'foreign_keys' and 'primary_keys'
636              
637             my($table_attributes) = $$info{$table_name}{attributes};
638              
639             This is a hash ref of the attributes of the table.
640             The keys of this hash ref are determined by the database server.
641              
642             my($columns) = $$info{$table_name}{columns};
643              
644             This is a hash ref of the columns of the table. The keys of this hash ref are the names of the
645             columns.
646              
647             my($foreign_keys) = $$info{$table_name}{foreign_keys};
648              
649             This is a hash ref of the foreign keys of the table. The keys of this hash ref are the names of the
650             tables which contain foreign keys pointing to $table_name.
651              
652             For MySQL, $foreign_keys will be the empty hash ref {}, as explained above.
653              
654             my($primary_keys) = $$info{$table_name}{primary_keys};
655              
656             This is a hash ref of the primary keys of the table. The keys of this hash ref are the names of the
657             columns which make up the primary key of $table_name.
658              
659             For any database server, if there is more than 1 column in the primary key, they will be numbered
660             (ordered) according to the hash key 'KEY_SEQ'.
661              
662             For MySQL, if there is more than 1 column in the primary key, they will be artificially numbered
663             according to the order in which they are returned by C, as explained above.
664              
665             =item o Third level, after 'attributes': Table attributes
666              
667             my($table_attributes) = $$info{$table_name}{attributes};
668              
669             while ( ($name, $value) = each(%$table_attributes) )
670             {
671             Use...
672             }
673              
674             For the attributes of the tables, there are no more levels in the hash ref.
675              
676             =item o Third level, after 'columns': The keys are the names of the columns.
677              
678             my($columns) = $$info{$table_name}{columns};
679              
680             my(@column_name) = sort keys %$columns;
681              
682             =over 4
683              
684             =item o Fourth level: Column attributes
685              
686             for $column_name (@column_name)
687             {
688             while ( ($name, $value) = each(%{$columns{$column_name} }) )
689             {
690             Use...
691             }
692             }
693              
694             =back
695              
696             =item o Third level, after 'foreign_keys': An arrayref contains the details (if any)
697              
698             But beware slightly differing spellings depending on the database server. This is documented in
699             L. Look closely at the usage of the '_' character.
700              
701             my($vendor) = uc $dbh -> get_info(17); # SQL_DBMS_NAME.
702              
703             for $item (@{$$info{$table_name}{foreign_keys} })
704             {
705             # Get the name of the table pointed to.
706              
707             $primary_table = ($vendor eq 'MYSQL') ? $$item{PKTABLE_NAME} : $$item{UK_TABLE_NAME};
708             }
709              
710             =item o Third level, after 'primary_keys': The keys are the names of columns
711              
712             These columns make up the primary key of the current table.
713              
714             my($primary_keys) = $$info{$table_name}{primary_keys};
715              
716             for $primary_key (sort{$$a{KEY_SEQ} <=> $$b{KEY_SEQ} } keys %$primary_keys)
717             {
718             $primary = $$primary_keys{$primary_key};
719              
720             for $attribute (sort keys %$primary)
721             {
722             Use...
723             }
724             }
725              
726             =back
727              
728             =head2 refresh()
729              
730             Returns the same hash ref as info().
731              
732             Use this after changing the database schema, when you want this module to re-interrogate
733             the database server.
734              
735             =head2 tables()
736              
737             Returns an array ref of table names.
738              
739             They are sorted by name.
740              
741             See the L for which tables are ignored under which databases.
742              
743             =head1 Example code
744              
745             Here are tested parameter values for various database vendors:
746              
747             =over 4
748              
749             =item o MS Access
750              
751             my($admin) = DBIx::Admin::TableInfo -> new(dbh => $dbh);
752              
753             In other words, the default values for catalog, schema, table and type will Just Work.
754              
755             =item o MySQL
756              
757             my($admin) = DBIx::Admin::TableInfo -> new(dbh => $dbh);
758              
759             In other words, the default values for catalog, schema, table and type will Just Work.
760              
761             =item o Oracle
762              
763             my($dbh) = DBI -> connect($dsn, $username, $password);
764             my($admin) = DBIx::Admin::TableInfo -> new
765             (
766             dbh => $dbh,
767             schema => uc $username, # Yep, upper case.
768             );
769              
770             See the FAQ for which tables are ignored under Oracle.
771              
772             =item o PostgreSQL
773              
774             my($admin) = DBIx::Admin::TableInfo -> new
775             (
776             dbh => $dbh,
777             schema => 'public',
778             );
779              
780             For PostgreSQL, you probably want to ignore table names matching /^(pg_|sql_)/.
781              
782             As stated above, for 'old' versions of DBD::Pg, use:
783              
784             my($admin) = DBIx::Admin::TableInfo -> new
785             (
786             dbh => $dbh,
787             schema => 'public',
788             table => 'table', # Yep, lower case.
789             );
790              
791             See the FAQ for which tables are ignored under Postgres.
792              
793             =item o SQLite
794              
795             my($admin) = DBIx::Admin::TableInfo -> new
796             (
797             dbh => $dbh,
798             schema => 'main',
799             );
800              
801             In other words, the default values for catalog, table and type will Just Work.
802              
803             See the FAQ for which tables are ignored under SQLite.
804              
805             =back
806              
807             See the examples/ directory in the distro.
808              
809             =head1 FAQ
810              
811             =head2 Which versions of the servers did you test?
812              
813             Versions as at 2014-08-06:
814             +----------|-------------+
815             | Vendor | V |
816             +----------|-------------+
817             | MariaDB | 5.5.38 |
818             +----------|-------------+
819             | Oracle | 10.2.0.1.0 | (Not tested for years)
820             +----------|-------------+
821             | Postgres | 9.1.3 |
822             +----------|-------------+
823             | SQLite | 3.8.4.1 |
824             +----------|-------------+
825              
826             But see these L when using
827             MySQL/MariaDB.
828              
829             =head2 Which tables are ignored for which databases?
830              
831             Here is the code which skips some tables:
832              
833             next if ( ($vendor eq 'ORACLE') && ($table_name =~ /^BIN\$.+\$./) );
834             next if ( ($vendor eq 'POSTGRESQL') && ($table_name =~ /^(?:pg_|sql_)/) );
835             next if ( ($vendor eq 'SQLITE') && ($table_name eq 'sqlite_sequence') );
836              
837             =head2 How do I identify foreign keys?
838              
839             Note: The table names here come from xt/author/person.spouse.t.
840              
841             See L for database server-specific create statements to activate
842             foreign keys.
843              
844             Then try:
845              
846             my($info) = DBIx::Admin::TableInfo -> new(dbh => $dbh) -> info;
847              
848             print Data::Dumper::Concise::Dumper($$info{people}{foreign_keys}), "\n";
849              
850             Output follows.
851              
852             But beware slightly differing spellings depending on the database server. This is documented in
853             L. Look closely at the usage of the '_' character.
854              
855             =over 4
856              
857             =item o MySQL
858              
859             [
860             {
861             DEFERABILITY => undef,
862             DELETE_RULE => undef,
863             FKCOLUMN_NAME => "spouse_id",
864             FKTABLE_CAT => "def",
865             FKTABLE_NAME => "spouses",
866             FKTABLE_SCHEM => "testdb",
867             FK_NAME => "spouses_ibfk_2",
868             KEY_SEQ => 1,
869             PKCOLUMN_NAME => "id",
870             PKTABLE_CAT => undef,
871             PKTABLE_NAME => "people",
872             PKTABLE_SCHEM => "testdb",
873             PK_NAME => undef,
874             UNIQUE_OR_PRIMARY => undef,
875             UPDATE_RULE => undef
876             }
877             ]
878              
879             Yes, there is just 1 element in this arrayref. MySQL can sliently drop an index if another index
880             can be used.
881              
882             =item o Postgres
883              
884             [
885             {
886             DEFERABILITY => 7,
887             DELETE_RULE => 3,
888             FK_COLUMN_NAME => "person_id",
889             FK_DATA_TYPE => "int4",
890             FK_NAME => "spouses_person_id_fkey",
891             FK_TABLE_CAT => undef,
892             FK_TABLE_NAME => "spouses",
893             FK_TABLE_SCHEM => "public",
894             ORDINAL_POSITION => 1,
895             UK_COLUMN_NAME => "id",
896             UK_DATA_TYPE => "int4",
897             UK_NAME => "people_pkey",
898             UK_TABLE_CAT => undef,
899             UK_TABLE_NAME => "people",
900             UK_TABLE_SCHEM => "public",
901             UNIQUE_OR_PRIMARY => "PRIMARY",
902             UPDATE_RULE => 3
903             },
904             {
905             DEFERABILITY => 7,
906             DELETE_RULE => 3,
907             FK_COLUMN_NAME => "spouse_id",
908             FK_DATA_TYPE => "int4",
909             FK_NAME => "spouses_spouse_id_fkey",
910             FK_TABLE_CAT => undef,
911             FK_TABLE_NAME => "spouses",
912             FK_TABLE_SCHEM => "public",
913             ORDINAL_POSITION => 1,
914             UK_COLUMN_NAME => "id",
915             UK_DATA_TYPE => "int4",
916             UK_NAME => "people_pkey",
917             UK_TABLE_CAT => undef,
918             UK_TABLE_NAME => "people",
919             UK_TABLE_SCHEM => "public",
920             UNIQUE_OR_PRIMARY => "PRIMARY",
921             UPDATE_RULE => 3
922             }
923             ]
924              
925             =item o SQLite
926              
927             [
928             {
929             DEFERABILITY => undef,
930             DELETE_RULE => 3,
931             FK_COLUMN_NAME => "spouse_id",
932             FK_DATA_TYPE => undef,
933             FK_NAME => undef,
934             FK_TABLE_CAT => undef,
935             FK_TABLE_NAME => "spouses",
936             FK_TABLE_SCHEM => undef,
937             ORDINAL_POSITION => 0,
938             UK_COLUMN_NAME => "id",
939             UK_DATA_TYPE => undef,
940             UK_NAME => undef,
941             UK_TABLE_CAT => undef,
942             UK_TABLE_NAME => "people",
943             UK_TABLE_SCHEM => undef,
944             UNIQUE_OR_PRIMARY => undef,
945             UPDATE_RULE => 3
946             },
947             {
948             DEFERABILITY => undef,
949             DELETE_RULE => 3,
950             FK_COLUMN_NAME => "person_id",
951             FK_DATA_TYPE => undef,
952             FK_NAME => undef,
953             FK_TABLE_CAT => undef,
954             FK_TABLE_NAME => "spouses",
955             FK_TABLE_SCHEM => undef,
956             ORDINAL_POSITION => 0,
957             UK_COLUMN_NAME => "id",
958             UK_DATA_TYPE => undef,
959             UK_NAME => undef,
960             UK_TABLE_CAT => undef,
961             UK_TABLE_NAME => "people",
962             UK_TABLE_SCHEM => undef,
963             UNIQUE_OR_PRIMARY => undef,
964             UPDATE_RULE => 3
965             }
966             ]
967              
968             =back
969              
970             You can also play with xt/author/fk.t and xt/author/dsn.ini (especially the 'active' option).
971              
972             fk.t does not delete the tables as it exits. This is so xt/author/mysql.fk.pl has something to play
973             with.
974              
975             See also xt/author/person.spouse.t.
976              
977             =head2 Does DBIx::Admin::TableInfo work with SQLite databases?
978              
979             Yes. As of V 2.08, this module uses the SQLite code "pragma foreign_key_list($table_name)" to
980             emulate the L call to foreign_key_info(...).
981              
982             =head2 What is returned by the SQLite "pragma foreign_key_list($table_name)" call?
983              
984             An arrayref is returned. Indexes and their interpretations:
985              
986             0: COUNT (0, 1, ...)
987             1: KEY_SEQ (0, or column # (1, 2, ...) within multi-column key)
988             2: PK_TABLE_NAME
989             3: FK_COLUMN_NAME
990             4: PK_COLUMN_NAME
991             5: UPDATE_RULE
992             6: DELETE_RULE
993             7: 'NONE' (Constant string)
994              
995             As these are stored in an arrayref, I use $$row[$i] just below to refer to the elements of the
996             array.
997              
998             =head2 How are these values mapped into the output?
999              
1000             See also the next point.
1001              
1002             my(%referential_action) =
1003             (
1004             'CASCADE' => 0,
1005             'RESTRICT' => 1,
1006             'SET NULL' => 2,
1007             'NO ACTION' => 3,
1008             'SET DEFAULT' => 4,
1009             );
1010              
1011             The hashref returned for foreign keys contains these key-value pairs:
1012              
1013             {
1014             DEFERABILITY => undef,
1015             DELETE_RULE => $referential_action{$$row[6]},
1016             FK_COLUMN_NAME => $$row[3],
1017             FK_DATA_TYPE => undef,
1018             FK_NAME => undef,
1019             FK_TABLE_CAT => undef,
1020             FK_TABLE_NAME => $table_name,
1021             FK_TABLE_SCHEM => undef,
1022             ORDINAL_POSITION => $$row[1],
1023             UK_COLUMN_NAME => $$row[4],
1024             UK_DATA_TYPE => undef,
1025             UK_NAME => undef,
1026             UK_TABLE_CAT => undef,
1027             UK_TABLE_NAME => $$row[2],
1028             UK_TABLE_SCHEM => undef,
1029             UNIQUE_OR_PRIMARY => undef,
1030             UPDATE_RULE => $referential_action{$$row[5]},
1031             }
1032              
1033             This list of keys matches what is returned when processing a Postgres database.
1034              
1035             =head2 Have you got FK and PK backwards?
1036              
1037             I certainly hope not. To me the FK_TABLE_NAME points to the UK_TABLE_NAME.
1038              
1039             The "pragma foreign_key_list($table_name)" call for SQLite returns data from the create statement,
1040             and thus it reports what the given table points to. The DBI call to foreign_key_info(...) returns
1041             data about foreign keys referencing (pointing to) the given table. This can be confusing.
1042              
1043             Here is a method from the module L, part of
1044             L.
1045              
1046             sub create_organizations_table
1047             {
1048             my($self) = @_;
1049             my($table_name) = 'organizations';
1050             my($primary_key) = $self -> creator -> generate_primary_key_sql($table_name);
1051             my($engine) = $self -> engine;
1052             my($result) = $self -> creator -> create_table(<
1053             create table $table_name
1054             (
1055             id $primary_key,
1056             visibility_id integer not null references visibilities(id),
1057             communication_type_id integer not null references communication_types(id),
1058             creator_id integer not null,
1059             role_id integer not null references roles(id),
1060             deleted integer not null,
1061             facebook_tag varchar(255) not null,
1062             homepage varchar(255) not null,
1063             name varchar(255) not null,
1064             timestamp timestamp not null default localtimestamp,
1065             twitter_tag varchar(255) not null,
1066             upper_name varchar(255) not null
1067             ) $engine
1068             SQL
1069              
1070             $self -> dbh -> do("create index ${table_name}_upper_name on $table_name (upper_name)");
1071              
1072             $self -> report($table_name, 'created', $result);
1073              
1074             } # End of create_organizations_table.
1075              
1076             Consider this line:
1077              
1078             visibility_id integer not null references visibilities(id),
1079              
1080             That means, for the 'visibilities' table, the info() method in the current module will return a
1081             hashref like:
1082              
1083             {
1084             visibilities =>
1085             {
1086             ...
1087             foreign_keys =>
1088             {
1089             ...
1090             organizations =>
1091             {
1092             UK_COLUMN_NAME => 'id',
1093             DEFERABILITY => undef,
1094             ORDINAL_POSITION => 0,
1095             FK_TABLE_CAT => undef,
1096             UK_NAME => undef,
1097             UK_DATA_TYPE => undef,
1098             UNIQUE_OR_PRIMARY => undef,
1099             UK_TABLE_SCHEM => undef,
1100             UK_TABLE_CAT => undef,
1101             FK_COLUMN_NAME => 'visibility_id',
1102             FK_TABLE_NAME => 'organizations',
1103             FK_TABLE_SCHEM => undef,
1104             FK_DATA_TYPE => undef,
1105             UK_TABLE_NAME => 'visibilities',
1106             DELETE_RULE => 3,
1107             FK_NAME => undef,
1108             UPDATE_RULE => 3
1109             },
1110             },
1111             }
1112              
1113             This is saying that for the table 'visibilities', there is a foreign key in the 'organizations'
1114             table. That foreign key is called 'visibility_id', and it points to the key called 'id' in the
1115             'visibilities' table.
1116              
1117             =head2 How do I use schemas in Postgres?
1118              
1119             You may need to do something like this:
1120              
1121             $dbh -> do("set search_path to $ENV{DBI_SCHEMA}") if ($ENV{DBI_SCHEMA});
1122              
1123             $ENV{DBI_SCHEMA} can be a comma-separated list, as in:
1124              
1125             $dbh -> do("set search_path to my_schema, public");
1126              
1127             See L for details.
1128              
1129             =head2 See Also
1130              
1131             L.
1132              
1133             L.
1134              
1135             =head1 Version Numbers
1136              
1137             Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
1138              
1139             =head1 Repository
1140              
1141             L
1142              
1143             =head1 Support
1144              
1145             Log a bug on RT: L.
1146              
1147             =head1 Author
1148              
1149             C was written by Ron Savage Iron@savage.net.auE> in 2004.
1150              
1151             Home page: http://savage.net.au/index.html
1152              
1153             =head1 Copyright
1154              
1155             Australian copyright (c) 2004, Ron Savage.
1156              
1157             All Programs of mine are 'OSI Certified Open Source Software';
1158             you can redistribute them and/or modify them under the terms of
1159             The Perl License, a copy of which is available at:
1160             http://www.opensource.org/licenses/index.html
1161              
1162             =cut