1
# This program is copyright 2011 Percona Inc.
2
# Feedback and improvements are welcome.
4
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
5
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
6
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
8
# This program is free software; you can redistribute it and/or modify it under
9
# the terms of the GNU General Public License as published by the Free Software
10
# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
11
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16
# Place, Suite 330, Boston, MA 02111-1307 USA.
17
# ###########################################################################
18
# Schema package $Revision: 7565 $
19
# ###########################################################################
22
# Schema encapsulates a data structure representing databases and tables.
23
# Although in MySQL "schema" is technically equivalent to "databae", we
24
# use "schema" loosely to mean a collection of schema objects: databases,
25
# tables, and columns. These objects are organized in a hash keyed on
26
# database and table names. The hash is called schema and looks like,
32
# tbl_struct => <TableParser::parse()>
33
# ddl => "CREATE TABLE `tbl` ( ...",
37
# Each table has at least a db and tbl key and probably a tbl_struct.
39
# The important thing about a Schema object is that it should be the only
40
# data structure with this data, and other modules should reference and add
41
# data to it rather than creating other similar copies. <ColumnMap> does
44
# The other important thing about a Schema object is that the data structure
45
# is the standard. Other modules should take db or tbl hashrefs pointing
46
# into the data structure. Tbl hashrefs should always have at least at db
47
# and tbl key (which is redundant but necessary so that each tbl hashref
48
# includes its own database and table name).
50
# Schema objects are usually added by a <SchemaIterator>, but you can add
51
# them manually if needed; see <add_schema_object()>.
56
use warnings FATAL => 'all';
57
use English qw(-no_match_vars);
58
use constant MKDEBUG => $ENV{MKDEBUG} || 0;
68
my ( $class, %args ) = @_;
69
my @required_args = qw();
70
foreach my $arg ( @required_args ) {
71
die "I need a $arg argument" unless $args{$arg};
76
schema => {}, # keyed on db->tbl
77
# columns => {}, # No tools use is_duplicate_table() or
78
# tables => {}, # is_duplicate_column() yet...
80
return bless $self, $class;
85
return $self->{schema};
89
my ( $self, $db_name, $tbl_name ) = @_;
90
if ( exists $self->{schema}->{$db_name}
91
&& exists $self->{schema}->{$db_name}->{$tbl_name} ) {
92
return $self->{schema}->{$db_name}->{$tbl_name};
97
#sub is_duplicate_column {
98
# my ( $self, $col ) = @_;
100
# return ($self->{columns}->{$col} || 0) > 1 ? 1 : 0;
103
#sub is_duplicate_table {
104
# my ( $self, $tbl ) = @_;
105
# return unless $tbl;
106
# return ($self->{tables}->{$tbl} || 0) > 1 ? 1 : 0;
109
# Sub: add_schema_object
110
# Add a schema object. This sub is called by
111
# <SchemaIterator::next_schema_object()>.
114
# $schema_object - Schema object hashref.
115
sub add_schema_object {
116
my ( $self, $schema_object ) = @_;
117
die "I need a schema_object argument" unless $schema_object;
119
my ($db, $tbl) = @{$schema_object}{qw(db tbl)};
120
if ( !$db || !$tbl ) {
121
warn "No database or table for schema object";
125
my $tbl_struct = $schema_object->{tbl_struct};
126
if ( !$tbl_struct ) {
127
warn "No table structure for $db.$tbl";
131
# Add/save this schema object.
132
$self->{schema}->{lc $db}->{lc $tbl} = $schema_object;
134
# Get duplicate column and table names.
135
# map { $self->{columns}->{lc $_}++ } @{$tbl_struct->{cols}};
136
# $self->{tables}->{lc $tbl_struct->{name}}++;
142
my ( $self, %args ) = @_;
143
my $ignore = $args{ignore};
144
my $schema = $self->{schema};
146
my ($col, $tbl, $db);
147
if ( my $col_name = $args{col_name} ) {
148
($col, $tbl, $db) = reverse map { s/`//g; $_ } split /[.]/, $col_name;
149
MKDEBUG && _d('Column', $col_name, 'has db', $db, 'tbl', $tbl,
153
($col, $tbl, $db) = @args{qw(col tbl db)};
161
MKDEBUG && _d('No column specified or parsed');
164
MKDEBUG && _d('Finding column', $col, 'in', $db, $tbl);
166
if ( $db && !$schema->{$db} ) {
167
MKDEBUG && _d('Database', $db, 'does not exist');
171
if ( $db && $tbl && !$schema->{$db}->{$tbl} ) {
172
MKDEBUG && _d('Table', $tbl, 'does not exist in database', $db);
177
my @search_dbs = $db ? ($db) : keys %$schema;
179
foreach my $search_db ( @search_dbs ) {
180
my @search_tbls = $tbl ? ($tbl) : keys %{$schema->{$search_db}};
183
foreach my $search_tbl ( @search_tbls ) {
184
next DATABASE unless exists $schema->{$search_db}->{$search_tbl};
187
&& grep { $_->{db} eq $search_db && $_->{tbl} eq $search_tbl }
189
MKDEBUG && _d('Ignoring', $search_db, $search_tbl, $col);
193
my $tbl = $schema->{$search_db}->{$search_tbl};
194
if ( $tbl->{tbl_struct}->{is_col}->{$col} ) {
195
MKDEBUG && _d('Column', $col, 'exists in', $tbl->{db}, $tbl->{tbl});
205
my ( $self, %args ) = @_;
206
my $ignore = $args{ignore};
207
my $schema = $self->{schema};
210
if ( my $tbl_name = $args{tbl_name} ) {
211
($tbl, $db) = reverse map { s/`//g; $_ } split /[.]/, $tbl_name;
212
MKDEBUG && _d('Table', $tbl_name, 'has db', $db, 'tbl', $tbl);
215
($tbl, $db) = @args{qw(tbl db)};
222
MKDEBUG && _d('No table specified or parsed');
225
MKDEBUG && _d('Finding table', $tbl, 'in', $db);
227
if ( $db && !$schema->{$db} ) {
228
MKDEBUG && _d('Database', $db, 'does not exist');
232
if ( $db && $tbl && !$schema->{$db}->{$tbl} ) {
233
MKDEBUG && _d('Table', $tbl, 'does not exist in database', $db);
238
my @search_dbs = $db ? ($db) : keys %$schema;
240
foreach my $search_db ( @search_dbs ) {
241
if ( $ignore && grep { $_->{db} eq $search_db } @$ignore ) {
242
MKDEBUG && _d('Ignoring', $search_db);
246
if ( exists $schema->{$search_db}->{$tbl} ) {
247
MKDEBUG && _d('Table', $tbl, 'exists in', $search_db);
248
push @dbs, $search_db;
256
my ($package, undef, $line) = caller 0;
257
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
258
map { defined $_ ? $_ : 'undef' }
260
print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
265
# ###########################################################################
267
# ###########################################################################