Files
percona-toolkit/lib/Schema.pm
Viktor Szépe c57441be8c War on typos Act 1 (#655)
* Fix typos in lib/ directory

* Update generated bin/ files

* PR 655 -  War on typos Act 1 #655

- Updated modules in tools that were not updated
- Fixed tests to reflect proposed changes

---------

Co-authored-by: Sveta Smirnova <sveta.smirnova@percona.com>
2023-08-22 16:18:38 +03:00

270 lines
7.8 KiB
Perl

# This program is copyright 2011 Percona Ireland Ltd.
# Feedback and improvements are welcome.
#
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
# licenses.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA.
# ###########################################################################
# Schema package
# ###########################################################################
{
# Package: Schema
# Schema encapsulates a data structure representing databases and tables.
# Although in MySQL "schema" is technically equivalent to "database", we
# use "schema" loosely to mean a collection of schema objects: databases,
# tables, and columns. These objects are organized in a hash keyed on
# database and table names. The hash is called schema and looks like,
# (start code)
# db1 => {
# tbl1 => {
# db => 'db1',
# tbl => 'tbl1',
# tbl_struct => <TableParser::parse()>
# ddl => "CREATE TABLE `tbl` ( ...",
# }
# }
# (stop code)
# Each table has at least a db and tbl key and probably a tbl_struct.
#
# The important thing about a Schema object is that it should be the only
# data structure with this data, and other modules should reference and add
# data to it rather than creating other similar copies. <ColumnMap> does
# this for example.
#
# The other important thing about a Schema object is that the data structure
# is the standard. Other modules should take db or tbl hashrefs pointing
# into the data structure. Tbl hashrefs should always have at least at db
# and tbl key (which is redundant but necessary so that each tbl hashref
# includes its own database and table name).
#
# Schema objects are usually added by a <SchemaIterator>, but you can add
# them manually if needed; see <add_schema_object()>.
package Schema;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
# Sub: new
#
# Parameters:
# %args - Arguments
#
# Returns:
# Schema object
sub new {
my ( $class, %args ) = @_;
my @required_args = qw();
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
schema => {}, # keyed on db->tbl
# columns => {}, # No tools use is_duplicate_table() or
# tables => {}, # is_duplicate_column() yet...
};
return bless $self, $class;
}
sub get_schema {
my ( $self ) = @_;
return $self->{schema};
}
sub get_table {
my ( $self, $db_name, $tbl_name ) = @_;
if ( exists $self->{schema}->{$db_name}
&& exists $self->{schema}->{$db_name}->{$tbl_name} ) {
return $self->{schema}->{$db_name}->{$tbl_name};
}
return;
}
#sub is_duplicate_column {
# my ( $self, $col ) = @_;
# return unless $col;
# return ($self->{columns}->{$col} || 0) > 1 ? 1 : 0;
#}
#sub is_duplicate_table {
# my ( $self, $tbl ) = @_;
# return unless $tbl;
# return ($self->{tables}->{$tbl} || 0) > 1 ? 1 : 0;
#}
# Sub: add_schema_object
# Add a schema object. This sub is called by
# <SchemaIterator::next_schema_object()>.
#
# Parameters:
# $schema_object - Schema object hashref.
sub add_schema_object {
my ( $self, $schema_object ) = @_;
die "I need a schema_object argument" unless $schema_object;
my ($db, $tbl) = @{$schema_object}{qw(db tbl)};
if ( !$db || !$tbl ) {
warn "No database or table for schema object";
return;
}
my $tbl_struct = $schema_object->{tbl_struct};
if ( !$tbl_struct ) {
warn "No table structure for $db.$tbl";
return;
}
# Add/save this schema object.
$self->{schema}->{lc $db}->{lc $tbl} = $schema_object;
# Get duplicate column and table names.
# map { $self->{columns}->{lc $_}++ } @{$tbl_struct->{cols}};
# $self->{tables}->{lc $tbl_struct->{name}}++;
return;
}
sub find_column {
my ( $self, %args ) = @_;
my $ignore = $args{ignore};
my $schema = $self->{schema};
my ($col, $tbl, $db);
if ( my $col_name = $args{col_name} ) {
($col, $tbl, $db) = reverse map { s/`//g; $_ } split /[.]/, $col_name;
PTDEBUG && _d('Column', $col_name, 'has db', $db, 'tbl', $tbl,
'col', $col);
}
else {
($col, $tbl, $db) = @args{qw(col tbl db)};
}
$db = lc($db || '');
$tbl = lc($tbl || '');
$col = lc($col || '');
if ( !$col ) {
PTDEBUG && _d('No column specified or parsed');
return;
}
PTDEBUG && _d('Finding column', $col, 'in', $db, $tbl);
if ( $db && !$schema->{$db} ) {
PTDEBUG && _d('Database', $db, 'does not exist');
return;
}
if ( $db && $tbl && !$schema->{$db}->{$tbl} ) {
PTDEBUG && _d('Table', $tbl, 'does not exist in database', $db);
return;
}
my @tbls;
my @search_dbs = $db ? ($db) : keys %$schema;
DATABASE:
foreach my $search_db ( @search_dbs ) {
my @search_tbls = $tbl ? ($tbl) : keys %{$schema->{$search_db}};
TABLE:
foreach my $search_tbl ( @search_tbls ) {
next DATABASE unless exists $schema->{$search_db}->{$search_tbl};
if ( $ignore
&& grep { $_->{db} eq $search_db && $_->{tbl} eq $search_tbl }
@$ignore ) {
PTDEBUG && _d('Ignoring', $search_db, $search_tbl, $col);
next TABLE;
}
my $tbl = $schema->{$search_db}->{$search_tbl};
if ( $tbl->{tbl_struct}->{is_col}->{$col} ) {
PTDEBUG && _d('Column', $col, 'exists in', $tbl->{db}, $tbl->{tbl});
push @tbls, $tbl;
}
}
}
@tbls = sort {$b->{name} cmp $a->{name}} @tbls;
return \@tbls;
}
sub find_table {
my ( $self, %args ) = @_;
my $ignore = $args{ignore};
my $schema = $self->{schema};
my ($tbl, $db);
if ( my $tbl_name = $args{tbl_name} ) {
($tbl, $db) = reverse map { s/`//g; $_ } split /[.]/, $tbl_name;
PTDEBUG && _d('Table', $tbl_name, 'has db', $db, 'tbl', $tbl);
}
else {
($tbl, $db) = @args{qw(tbl db)};
}
$db = lc($db || '');
$tbl = lc($tbl || '');
if ( !$tbl ) {
PTDEBUG && _d('No table specified or parsed');
return;
}
PTDEBUG && _d('Finding table', $tbl, 'in', $db);
if ( $db && !$schema->{$db} ) {
PTDEBUG && _d('Database', $db, 'does not exist');
return;
}
if ( $db && $tbl && !$schema->{$db}->{$tbl} ) {
PTDEBUG && _d('Table', $tbl, 'does not exist in database', $db);
return;
}
my @dbs;
my @search_dbs = $db ? ($db) : keys %$schema;
DATABASE:
foreach my $search_db ( @search_dbs ) {
if ( $ignore && grep { $_->{db} eq $search_db } @$ignore ) {
PTDEBUG && _d('Ignoring', $search_db);
next DATABASE;
}
if ( exists $schema->{$search_db}->{$tbl} ) {
PTDEBUG && _d('Table', $tbl, 'exists in', $search_db);
push @dbs, $search_db;
}
}
@dbs = sort @dbs;
return \@dbs;
}
sub _d {
my ($package, undef, $line) = caller 0;
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
map { defined $_ ? $_ : 'undef' }
@_;
print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
}
1;
}
# ###########################################################################
# End Schema package
# ###########################################################################