blob: 877a62be5832bbb171b9bf40b16b7d6679ecbef2 [file] [log] [blame]
#!/usr/bin/env perl
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# $Header$
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
use Pod::Usage;
use Getopt::Long;
use Data::Dumper;
use strict;
use warnings;
=head1 NAME
B<upg2_wizard.pl> - wizard to fix upg2 test
=head1 SYNOPSIS
B<upg2_wizard.pl> [options]
Options:
-help brief help message
-man full documentation
-connect psql connect parameters
-tablename LIKE expression describing new tables
-indexname LIKE expression describing new indexes
-preview show data file updates, but don't modify the files
=head1 OPTIONS
=over 8
=item B<-help>
Print a brief help message and exits.
=item B<-man>
Prints the manual page and exits.
=item B<-connect>
psql connect string, e.g:
-connect '-p 11000 template1'
=item B<-tablename>
LIKE expression describing new catalog table, eg:
-tablename foo
or
-tablename foo%bar
To specify multiple tables, use multiple tablename arguments, eg:
-tablename foo -tablename bar -tablename baz
=item B<-indexname>
LIKE expression describing new catalog indices, eg:
-indexname foo
or
-indexname foo%bar
To specify multiple indices, use multiple indexname arguments, eg:
-indexname foo -indexname bar -indexname baz
=item B<-preview>
Show data file updates, but don't modify the files.
=back
=head1 DESCRIPTION
The upg2_wizard is used to modify the data files for the upg2
regression test in accordance with the UPG2_README guidelines.
=head1 AUTHORS
Apache HAWQ
Address bug reports and comments to: dev@hawq.apache.org
=cut
my $glob_id = "";
my $glob_connect;
my $glob_tname;
my $glob_iname;
my $glob_preview;
BEGIN {
my $man = 0;
my $help = 0;
my $conn;
my @tname;
my @iname;
my $preview = 0;
GetOptions(
'help|?' => \$help, man => \$man,
"connect=s" => \$conn,
"tablename:s" => \@tname,
"indexname:s" => \@iname,
"preview|pretend" => \$preview
)
or pod2usage(2);
pod2usage(-msg => $glob_id, -exitstatus => 1) if $help;
pod2usage(-msg => $glob_id, -exitstatus => 0, -verbose => 2) if $man;
$glob_preview = $preview;
$glob_connect = $conn;
$glob_connect = '-p 11000 template1'
unless (defined($glob_connect));
$glob_tname = [];
push @{$glob_tname}, @tname if (scalar(@tname));
$glob_iname = [];
push @{$glob_iname}, @iname if (scalar(@iname));
}
# convert a postgresql psql formatted table into an array of hashes
sub tablelizer
{
my $ini = shift;
# first, split into separate lines, the find all the column headings
my @lines = split(/\n/, $ini);
return undef
unless (scalar(@lines));
my $line1 = shift @lines;
# look for <space>|<space>
my @colheads = split(/\s+\|\s+/, $line1);
# fixup first, last column head (remove leading,trailing spaces)
$colheads[0] =~ s/^\s+//;
$colheads[0] =~ s/\s+$//;
$colheads[-1] =~ s/^\s+//;
$colheads[-1] =~ s/\s+$//;
return undef
unless (scalar(@lines));
shift @lines; # skip dashed separator
my @rows;
for my $lin (@lines)
{
my @cols = split(/\|/, $lin, scalar(@colheads));
last
unless (scalar(@cols) == scalar(@colheads));
my $rowh = {};
for my $colhd (@colheads)
{
my $rawcol = shift @cols;
$rawcol =~ s/^\s+//;
$rawcol =~ s/\s+$//;
$rowh->{$colhd} = $rawcol;
}
push @rows, $rowh;
}
return \@rows;
}
# file fixer: general routine to merge new catalog objects into the
# existing data files
#
# args: hash of new relids
# sql query to find rows associated with new catalog objects
# formatted string of relids (for substitution into sql query)
# name of the column which is a relid foreign key
# data file name
# position of the relid key col in the row (0-based)
# formatted string of column names (vertical bar separator, in order)
sub file_fixer
{
my ($all_relid, $sql_str, $relid_list, $relid_colname,
$file_name, $relid_pos, $col_list_str) = @_;
my $psql_str = "psql ";
$psql_str .= $glob_connect
if (defined($glob_connect));
$sql_str =~ s/\*RELID_LIST\*/$relid_list/g;
$psql_str .= ' -c " ' . $sql_str . '"';
print $psql_str, "\n";
my $tabdef = `$psql_str`;
print $tabdef;
my $rowarr = tablelizer($tabdef);
my @all_newrows;
# find all the new rows (matching the relids of the new catalog objects)
for my $rr (@{$rowarr})
{
# print Data::Dumper->Dump([$rr]);
for my $kk (keys %{$rr})
{
# fix NULLs
$rr->{$kk} = '\N'
unless (length($rr->{$kk}));
}
push @all_newrows, $rr;
# if (exists($all_relid->{$rr->{$relid_colname}}));
}
goto L_previewo if $glob_preview;
# must be read and writeable
die ("bad file: $file_name")
unless (-r $file_name && -w $file_name);
my $cp2 = "cp $file_name $file_name" . ".old";
`$cp2`;
my @all_oldrows;
open my $file_in, "< $file_name" or die "cannot open $file_name: $!";
# get the dataset for existing catalog updates and filter out rows
# which might match the "new" rows...
for my $ini (<$file_in>)
{
next if ($ini =~ m/^\\\./);
my @foo = split(/\|/, $ini);
# print Data::Dumper->Dump(\@foo);
next
if (exists($all_relid->{$foo[$relid_pos]}));
push @all_oldrows, $ini;
}
close $file_in;
L_previewo:
my $file_out;
if ($glob_preview)
{
open $file_out, ">&STDOUT" or die "Can't dup STDOUT: $!";
print "\n\n";
}
else
{
open $file_out, "> $file_name"
or die "cannot open $file_name: $!";
}
# save the rows again
for my $outi (@all_oldrows)
{
print $file_out $outi;
}
my @col_list = split(/\|/, $col_list_str);
my $col1 = shift @col_list;
# add any new rows
for my $a1 (@all_newrows)
{
print $file_out $a1->{$col1};
for my $cname (@col_list)
{
print $file_out "|", $a1->{$cname};
}
print $file_out "\n";
}
print $file_out "\\.\n";
print "\n\n" if ($glob_preview);
close $file_out;
} # end file fixer
if (1)
{
my $exe = $0;
# assume current file is in src/test/resgress...
my $xdir = $exe;
$xdir =~ s/\/upg2\_wizard\.pl$//;
my $class_file = "$xdir/data/upgrade34/upg2_pg_class_toadd33.data.in";
my $attr_file = "$xdir/data/upgrade34/upg2_pg_attribute_toadd33.data.in";
my $depend_file = "$xdir/data/upgrade34/upg2_pg_depend_toadd33.data";
my $index_file = "$xdir/data/upgrade34/upg2_pg_index_toadd33.data.in";
my $type_file = "$xdir/data/upgrade34/upg2_pg_type_toadd33.data.in";
my $psql_str = "psql ";
$psql_str .= $glob_connect
if (defined($glob_connect));
my $sql_str = "select oid, * from pg_class where ";
my @all_name;
push @all_name, @{$glob_tname};
push @all_name, @{$glob_iname};
my @all_like;
for my $nam (@all_name)
{
push @all_like, " relname like \'". $nam . "\' ";
}
unless (scalar(@all_like))
{
die("no table or index names");
exit(1);
}
$sql_str .= join(" or ", @all_like) . " ;" ;
$psql_str .= ' -c " ' . $sql_str . '"';
print $psql_str, "\n";
my $tabdef = `$psql_str`;
print $tabdef;
my $rowarr = tablelizer($tabdef);
my %reg_tabs;
my $who_me = `whoami`;
chomp $who_me;
my %all_relid;
my %all_tab;
for my $rr (@{$rowarr})
{
$rr->{relacl} =~ s/$who_me/\@gpcurusername\@/g;
$rr->{relacl} = '\N'
unless (length($rr->{relacl}));
$rr->{reloptions} = '\N'
unless (length($rr->{reloptions}));
# print Data::Dumper->Dump([$rr]);
$all_tab{$rr->{relname}} = $rr;
$all_relid{$rr->{oid}} = $rr->{relname};
}
# print Data::Dumper->Dump([%all_relid]);
# print $class_file, "\n";
goto L_previewoo if $glob_preview;
die ("bad file")
unless (-r $class_file && -w $class_file);
my $cp1 = "cp $class_file $class_file" . ".old";
`$cp1`;
my @all_class;
open my $class_in, "< $class_file" or die "cannot open $class_file: $!";
for my $ini (<$class_in>)
{
next if ($ini =~ m/^\\\./);
my @foo = split(/\|/, $ini, 2);
# print Data::Dumper->Dump(\@foo);
next
if (exists($all_relid{$foo[0]}));
push @all_class, $ini;
}
close $class_in;
L_previewoo:
my $file_out;
if ($glob_preview)
{
open $file_out, ">&STDOUT" or die "Can't dup STDOUT: $!";
print "\n\n";
}
else
{
open my $file_out, "> $class_file"
or die "cannot open $class_file: $!";
}
for my $outi (@all_class)
{
print $file_out $outi;
}
my @class_col_list = split(/\|/,
"relname|relnamespace|reltype|relowner|relam|relfilenode|reltablespace|relpages|reltuples|reltoastrelid|reltoastidxid|relaosegrelid|relaosegidxid|relhasindex|relisshared|relkind|relstorage|relnatts|relchecks|reltriggers|relukeys|relfkeys|relrefs|relhasoids|relhaspkey|relhasrules|relhassubclass|relfrozenxid|relacl|reloptions"
) ;
for my $oid (sort {$a <=> $b} keys (%all_relid))
{
print $file_out $oid;
for my $cname (@class_col_list)
{
print $file_out "|", $all_tab{$all_relid{$oid}}->{$cname};
}
print $file_out "\n";
}
print $file_out "\\.\n";
print "\n\n" if ($glob_preview);
close $file_out;
my $relid_list_str = join(",", (sort {$a <=> $b} keys (%all_relid)));
file_fixer(\%all_relid,
"select * from pg_attribute where attrelid in " .
"( *RELID_LIST* ) order by attrelid, attnum;",
$relid_list_str,
"attrelid",
$attr_file, 0,
"attrelid|attname|atttypid|attstattarget|attlen|attnum|attndims|attcacheoff|atttypmod|attbyval|attstorage|attalign|attnotnull|atthasdef|attisdropped|attislocal|attinhcount"
);
# depend
file_fixer(\%all_relid,
"select * from pg_depend where refobjid in " .
"( *RELID_LIST* ) " .
" or refobjid in (select oid from pg_type where typrelid in " .
"( *RELID_LIST* ) ) " .
"order by classid, objid, refobjid;",
$relid_list_str,
"refobjid",
$depend_file, 4,
"classid|objid|objsubid|refclassid|refobjid|refobjsubid|deptype"
);
# index
file_fixer(\%all_relid,
"select * from pg_index where indexrelid in " .
"( *RELID_LIST* ) order by indexrelid, indrelid;",
$relid_list_str,
"indexrelid",
$index_file, 0,
"indexrelid|indrelid|indnatts|indisunique|indisprimary|indisclustered|indisvalid|indkey|indclass|indexprs|indpred"
);
# type
file_fixer(\%all_relid,
"select oid,* from pg_type where typrelid in " .
"( *RELID_LIST* ) order by oid, typname, typrelid;",
$relid_list_str,
"typrelid",
$type_file, 9,
"oid|typname|typnamespace|typowner|typlen|typbyval|typtype|typisdefined|typdelim|typrelid|typelem|typinput|typoutput|typreceive|typsend|typanalyze|typalign|typstorage|typnotnull|typbasetype|typtypmod|typndims|typdefaultbin|typdefault"
);
}
exit();