#!/usr/bin/perl

#################################################################
# adjust_upgrade.pl -- CLI interface to AdjustUpgrade module
#
# Copyright (c) 2023-2026, PostgreSQL Global Development Group
#
# src/test/perl/adjust_upgrade.pl
#################################################################

=pod

=head1 NAME

adjust_upgrade.pl - CLI interface to PostgreSQL::Test::AdjustUpgrade

=head1 SYNOPSIS

  # Adjust database contents before upgrade
  adjust_upgrade.pl --mode=adjust_database VERSION DBNAME [DBNAME ...]

  # Adjust old version dump file for comparison
  adjust_upgrade.pl --mode=adjust_old_dumpfile VERSION OLDFILE NEWFILE

  # Adjust new version dump file for comparison
  adjust_upgrade.pl --mode=adjust_new_dumpfile VERSION OLDFILE NEWFILE

=head1 DESCRIPTION

This script provides a command-line interface to the
L<PostgreSQL::Test::AdjustUpgrade> module, which encapsulates various
adjustments needed for cross-version upgrade testing.

The script supports three modes of operation:

=over

=item B<adjust_database>

Generates SQL statements to adjust the contents of databases in an
old-version installation before performing pg_upgrade.  The statements
are printed to stdout, one per line.

=item B<adjust_old_dumpfile>

Reads a pg_dumpall output file from an old version, applies necessary
transformations to make it comparable to a new-version dump, and writes
the result to a new file.

=item B<adjust_new_dumpfile>

Reads a pg_dumpall output file from the new (current) version, applies
necessary transformations to make it comparable to an old-version dump,
and writes the result to a new file.

=back

=head1 OPTIONS

=over

=item B<--mode>=I<MODE>

Required.  Specifies the operation mode: C<adjust_database>,
C<adjust_old_dumpfile>, or C<adjust_new_dumpfile>.

=back

=head1 ARGUMENTS

=over

=item I<VERSION>

The old PostgreSQL version being upgraded from (e.g., "14", "15.2").

=item I<DBNAME>

(adjust_database mode only) One or more database names to generate
adjustment statements for.

=item I<OLDFILE>

(dumpfile modes only) Path to the input dump file to be transformed.

=item I<NEWFILE>

(dumpfile modes only) Path where the transformed dump file will be written.

=back

=cut

use strict;
use warnings FATAL => 'all';

use FindBin;
use lib $FindBin::RealBin;
use PostgreSQL::Test::AdjustUpgrade;
use PostgreSQL::Version;

use Getopt::Long;

# Parse command-line options
my $mode;

my %options = ('mode=s' => \$mode,);

GetOptions(%options)
  || die "bad command line";

# Validate the mode argument
die "bad mode: $mode"
  if $mode !~ /^adjust_(database|(old|new)_dumpfile)$/;

# First positional argument is the old PostgreSQL version
my $version = PostgreSQL::Version->new(shift);

if ($mode =~ /database/)
{
	# Database adjustment mode: generate SQL statements to stdout
	# Build a hash of database names from remaining arguments
	my %dbs = map { $_ => 1 } @ARGV;
	my $stmts = adjust_database_contents($version, %dbs);
	print join("\n", @$stmts), "\n";
}
else
{
	# Dumpfile adjustment mode: transform input file to output file
	my ($oldfile, $newfile) = @ARGV;

	# Slurp the entire input file
	local $/ = undef;
	open(my $input, "<", $oldfile) || die "opening $oldfile: $!";
	my $dump = <$input>;
	close($input);

	# Apply the appropriate transformation
	if ($mode =~ /old/)
	{
		$dump = adjust_old_dumpfile($version, $dump);
	}
	else
	{
		$dump = adjust_new_dumpfile($version, $dump);
	}

	# Write the transformed dump to the output file
	open(my $output, ">", $newfile) || die "opening $newfile: $!";
	print $output $dump;
	close($output);
}

exit 0;
