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 2     2   104447 use strict;
  2         15  
  2         59  
4 2     2   10 use warnings;
  2         5  
  2         50  
5              
6 2     2   1151 use Moo;
  2         25417  
  2         11  
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.04';
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             =over 4
840              
841             =item o See scripts/foreign.keys.pl
842              
843             First set the environment variables DBI_DSN, DBI_USER and DBI_PASS.
844              
845             Then, it writes in CSV format to STDOUT, which you can redirect to, say, foreign.keys.csv.
846              
847             =item o Take a very simplistic and brute-force approach
848              
849             Note: The table names here come from xt/author/person.spouse.t.
850              
851             See L for database server-specific create statements to activate
852             foreign keys.
853              
854             First set the environment variables DBI_DSN, DBI_USER and DBI_PASS.
855              
856             Then try:
857              
858             my($info) = DBIx::Admin::TableInfo -> new(dbh => $dbh) -> info;
859              
860             print Data::Dumper::Concise::Dumper($$info{people}{foreign_keys}), "\n";
861              
862             Sample output follows below.
863              
864             =back
865              
866             Beware: Slightly differing spellings depending on the database server. This is documented in
867             L. Look closely at the presence or absence of the
868             '_' character.
869              
870             =over 4
871              
872             =item o MySQL
873              
874             [
875             {
876             DEFERABILITY => undef,
877             DELETE_RULE => undef,
878             FKCOLUMN_NAME => "spouse_id",
879             FKTABLE_CAT => "def",
880             FKTABLE_NAME => "spouses",
881             FKTABLE_SCHEM => "testdb",
882             FK_NAME => "spouses_ibfk_2",
883             KEY_SEQ => 1,
884             PKCOLUMN_NAME => "id",
885             PKTABLE_CAT => undef,
886             PKTABLE_NAME => "people",
887             PKTABLE_SCHEM => "testdb",
888             PK_NAME => undef,
889             UNIQUE_OR_PRIMARY => undef,
890             UPDATE_RULE => undef
891             }
892             ]
893              
894             Yes, there is just 1 element in this arrayref. MySQL can sliently drop an index if another index
895             can be used.
896              
897             =item o Postgres
898              
899             [
900             {
901             DEFERABILITY => 7,
902             DELETE_RULE => 3,
903             FK_COLUMN_NAME => "person_id",
904             FK_DATA_TYPE => "int4",
905             FK_NAME => "spouses_person_id_fkey",
906             FK_TABLE_CAT => undef,
907             FK_TABLE_NAME => "spouses",
908             FK_TABLE_SCHEM => "public",
909             ORDINAL_POSITION => 1,
910             UK_COLUMN_NAME => "id",
911             UK_DATA_TYPE => "int4",
912             UK_NAME => "people_pkey",
913             UK_TABLE_CAT => undef,
914             UK_TABLE_NAME => "people",
915             UK_TABLE_SCHEM => "public",
916             UNIQUE_OR_PRIMARY => "PRIMARY",
917             UPDATE_RULE => 3
918             },
919             {
920             DEFERABILITY => 7,
921             DELETE_RULE => 3,
922             FK_COLUMN_NAME => "spouse_id",
923             FK_DATA_TYPE => "int4",
924             FK_NAME => "spouses_spouse_id_fkey",
925             FK_TABLE_CAT => undef,
926             FK_TABLE_NAME => "spouses",
927             FK_TABLE_SCHEM => "public",
928             ORDINAL_POSITION => 1,
929             UK_COLUMN_NAME => "id",
930             UK_DATA_TYPE => "int4",
931             UK_NAME => "people_pkey",
932             UK_TABLE_CAT => undef,
933             UK_TABLE_NAME => "people",
934             UK_TABLE_SCHEM => "public",
935             UNIQUE_OR_PRIMARY => "PRIMARY",
936             UPDATE_RULE => 3
937             }
938             ]
939              
940             =item o SQLite
941              
942             [
943             {
944             DEFERABILITY => undef,
945             DELETE_RULE => 3,
946             FK_COLUMN_NAME => "spouse_id",
947             FK_DATA_TYPE => undef,
948             FK_NAME => undef,
949             FK_TABLE_CAT => undef,
950             FK_TABLE_NAME => "spouses",
951             FK_TABLE_SCHEM => undef,
952             ORDINAL_POSITION => 0,
953             UK_COLUMN_NAME => "id",
954             UK_DATA_TYPE => undef,
955             UK_NAME => undef,
956             UK_TABLE_CAT => undef,
957             UK_TABLE_NAME => "people",
958             UK_TABLE_SCHEM => undef,
959             UNIQUE_OR_PRIMARY => undef,
960             UPDATE_RULE => 3
961             },
962             {
963             DEFERABILITY => undef,
964             DELETE_RULE => 3,
965             FK_COLUMN_NAME => "person_id",
966             FK_DATA_TYPE => undef,
967             FK_NAME => undef,
968             FK_TABLE_CAT => undef,
969             FK_TABLE_NAME => "spouses",
970             FK_TABLE_SCHEM => undef,
971             ORDINAL_POSITION => 0,
972             UK_COLUMN_NAME => "id",
973             UK_DATA_TYPE => undef,
974             UK_NAME => undef,
975             UK_TABLE_CAT => undef,
976             UK_TABLE_NAME => "people",
977             UK_TABLE_SCHEM => undef,
978             UNIQUE_OR_PRIMARY => undef,
979             UPDATE_RULE => 3
980             }
981             ]
982              
983             =back
984              
985             You can also play with xt/author/fk.t and xt/author/dsn.ini (especially the 'active' option).
986              
987             fk.t does not delete the tables as it exits. This is so xt/author/mysql.fk.pl has something to play
988             with.
989              
990             See also xt/author/person.spouse.t.
991              
992             =head2 Does DBIx::Admin::TableInfo work with SQLite databases?
993              
994             Yes. As of V 2.08, this module uses the SQLite code "pragma foreign_key_list($table_name)" to
995             emulate the L call to foreign_key_info(...).
996              
997             =head2 What is returned by the SQLite "pragma foreign_key_list($table_name)" call?
998              
999             An arrayref is returned. Indexes and their interpretations:
1000              
1001             0: COUNT (0, 1, ...)
1002             1: KEY_SEQ (0, or column # (1, 2, ...) within multi-column key)
1003             2: PK_TABLE_NAME
1004             3: FK_COLUMN_NAME
1005             4: PK_COLUMN_NAME
1006             5: UPDATE_RULE
1007             6: DELETE_RULE
1008             7: 'NONE' (Constant string)
1009              
1010             As these are stored in an arrayref, I use $$row[$i] just below to refer to the elements of the
1011             array.
1012              
1013             =head2 How are these values mapped into the output?
1014              
1015             See also the next point.
1016              
1017             my(%referential_action) =
1018             (
1019             'CASCADE' => 0,
1020             'RESTRICT' => 1,
1021             'SET NULL' => 2,
1022             'NO ACTION' => 3,
1023             'SET DEFAULT' => 4,
1024             );
1025              
1026             The hashref returned for foreign keys contains these key-value pairs:
1027              
1028             {
1029             DEFERABILITY => undef,
1030             DELETE_RULE => $referential_action{$$row[6]},
1031             FK_COLUMN_NAME => $$row[3],
1032             FK_DATA_TYPE => undef,
1033             FK_NAME => undef,
1034             FK_TABLE_CAT => undef,
1035             FK_TABLE_NAME => $table_name,
1036             FK_TABLE_SCHEM => undef,
1037             ORDINAL_POSITION => $$row[1],
1038             UK_COLUMN_NAME => $$row[4],
1039             UK_DATA_TYPE => undef,
1040             UK_NAME => undef,
1041             UK_TABLE_CAT => undef,
1042             UK_TABLE_NAME => $$row[2],
1043             UK_TABLE_SCHEM => undef,
1044             UNIQUE_OR_PRIMARY => undef,
1045             UPDATE_RULE => $referential_action{$$row[5]},
1046             }
1047              
1048             This list of keys matches what is returned when processing a Postgres database.
1049              
1050             =head2 Have you gotten FK and PK backwards?
1051              
1052             I certainly hope not. To me the FK_TABLE_NAME points to the UK_TABLE_NAME.
1053              
1054             The "pragma foreign_key_list($table_name)" call for SQLite returns data from the create statement,
1055             and thus it reports what the given table points to. The DBI call to foreign_key_info(...) returns
1056             data about foreign keys referencing (pointing to) the given table. This can be confusing.
1057              
1058             Here is a method from the module L, part of
1059             L.
1060              
1061             sub create_organizations_table
1062             {
1063             my($self) = @_;
1064             my($table_name) = 'organizations';
1065             my($primary_key) = $self -> creator -> generate_primary_key_sql($table_name);
1066             my($engine) = $self -> engine;
1067             my($result) = $self -> creator -> create_table(<
1068             create table $table_name
1069             (
1070             id $primary_key,
1071             visibility_id integer not null references visibilities(id),
1072             communication_type_id integer not null references communication_types(id),
1073             creator_id integer not null,
1074             role_id integer not null references roles(id),
1075             deleted integer not null,
1076             facebook_tag varchar(255) not null,
1077             homepage varchar(255) not null,
1078             name varchar(255) not null,
1079             timestamp timestamp not null default localtimestamp,
1080             twitter_tag varchar(255) not null,
1081             upper_name varchar(255) not null
1082             ) $engine
1083             SQL
1084              
1085             $self -> dbh -> do("create index ${table_name}_upper_name on $table_name (upper_name)");
1086              
1087             $self -> report($table_name, 'created', $result);
1088              
1089             } # End of create_organizations_table.
1090              
1091             Consider this line:
1092              
1093             visibility_id integer not null references visibilities(id),
1094              
1095             That means, for the 'visibilities' table, the info() method in the current module will return a
1096             hashref like:
1097              
1098             {
1099             visibilities =>
1100             {
1101             ...
1102             foreign_keys =>
1103             {
1104             ...
1105             organizations =>
1106             {
1107             UK_COLUMN_NAME => 'id',
1108             DEFERABILITY => undef,
1109             ORDINAL_POSITION => 0,
1110             FK_TABLE_CAT => undef,
1111             UK_NAME => undef,
1112             UK_DATA_TYPE => undef,
1113             UNIQUE_OR_PRIMARY => undef,
1114             UK_TABLE_SCHEM => undef,
1115             UK_TABLE_CAT => undef,
1116             FK_COLUMN_NAME => 'visibility_id',
1117             FK_TABLE_NAME => 'organizations',
1118             FK_TABLE_SCHEM => undef,
1119             FK_DATA_TYPE => undef,
1120             UK_TABLE_NAME => 'visibilities',
1121             DELETE_RULE => 3,
1122             FK_NAME => undef,
1123             UPDATE_RULE => 3
1124             },
1125             },
1126             }
1127              
1128             This is saying that for the table 'visibilities', there is a foreign key in the 'organizations'
1129             table. That foreign key is called 'visibility_id', and it points to the key called 'id' in the
1130             'visibilities' table.
1131              
1132             =head2 How do I use schemas in Postgres?
1133              
1134             You may need to do something like this:
1135              
1136             $dbh -> do("set search_path to $ENV{DBI_SCHEMA}") if ($ENV{DBI_SCHEMA});
1137              
1138             $ENV{DBI_SCHEMA} can be a comma-separated list, as in:
1139              
1140             $dbh -> do("set search_path to my_schema, public");
1141              
1142             See L for details.
1143              
1144             =head2 See Also
1145              
1146             L.
1147              
1148             L.
1149              
1150             =head1 Version Numbers
1151              
1152             Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
1153              
1154             =head1 Repository
1155              
1156             L
1157              
1158             =head1 Support
1159              
1160             Bugs should be reported via the CPAN bug tracker at
1161              
1162             L
1163              
1164             =head1 Author
1165              
1166             C was written by Ron Savage Iron@savage.net.auE> in 2004.
1167              
1168             Home page: http://savage.net.au/index.html
1169              
1170             =head1 Copyright
1171              
1172             Australian copyright (c) 2004, Ron Savage.
1173              
1174             All Programs of mine are 'OSI Certified Open Source Software';
1175             you can redistribute them and/or modify them under the terms of
1176             The Perl License, a copy of which is available at:
1177             http://www.opensource.org/licenses/index.html
1178              
1179             =cut