Perl x Open Food Facts Hackathon: Paris, France - May 24-25 Learn more

# -----------------------------------------------------------------------------
=encoding utf8
=head1 NAME
Quiq::PostgreSql::Psql - Wrapper für psql
=head1 BASE CLASS
L<Quiq::Object>
=head1 SYNOPSIS
use Quiq::PostgreSql::Psql;
Quiq::PostgreSql::Psql->run($database,@opt);
=head1 DESCRIPTION
Die Klasse stellt einen Wrapper für den PostgreSQL-Client psql dar.
=cut
# -----------------------------------------------------------------------------
use v5.10;
use strict;
our $VERSION = '1.225';
use Expect ();
# -----------------------------------------------------------------------------
=head1 METHODS
=head2 Klassenmethoden
=head3 run() - Starte psql-Sitzung ohne Passworteingabe
=head4 Synopsis
$exitCode = $class->run($database);
=head4 Arguments
=over 4
=item $database
Name der Datenbank oder der Universal Database Locator (UDL).
Der Name muss in der Datenbank-Konfigurationsdatei definiert sein.
=back
=head4 Options
=over 4
=item -command => $cmd
Führe Kommando $cmd aus und terminiere die Verbindung.
=item -echo => $bool (Default: I<wenn -script 1, sonst 0>)
Gib alle Kommandos, die an den Server geschickt werden, auf stdout aus.
=item -log => $file
Logge Sitzung nach Datei $file.
=item -script => $file
Führe SQL-Skript $file aus und terminiere die Verbindung.
=item -showInternal => $bool (Default: 0)
Gib die Queries aus, die psql im Zusammenhang mit Backslash-Kommandos
intern ausführt.
=item -stopOnError => $bool (Default: I<wenn -script 1, sonst 0>)
Terminiere beim ersten Fehler.
=item -debug => $bool (Default: 0)
Gib das ausgeführte psql-Kommando auf STDOUT aus.
=back
=head4 Returns
Bei interaktiver Sitzung 0. Bei Skript- oder Kommando-Ausführung
wie bei psql(1).
=head4 Description
Rufe psql auf und führe eine Anmeldung durch, auch bei
Passwort-Authentisierung. Die Datenbank kann per Name kontaktiert werden
kann, wenn der UDL in die Konfiguration (s. Quiq::Database::Config)
eingetragen wurde.
=head4 Example
$ perl -MQuiq::PostgreSql::Psql -E 'Quiq::PostgreSql::Psql->run("test")'
Password for user xv882js:
Pager usage is off.
Timing is on.
psql (8.2.15)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
dsstest=>
=cut
# -----------------------------------------------------------------------------
sub run {
my ($class,$database) = splice @_,0,2;
# Options
my $command = undef;
my $debug = 0;
my $echo = 0;
my $log = undef;
my $script = undef;
my $showInternal = 0;
my $stopOnError = 0;
$class->parameters(\@_,
-command => \$command,
-debug => \$debug,
-echo => \$echo,
-log => \$log,
-script => \$script,
-showInternal => \$showInternal,
-stopOnError => \$stopOnError,
);
# Führe Operation aus
my $udl = Quiq::Udl->new($database);
if ($udl->dbms ne 'postgresql') {
$class->throw(
'PSQL-00001: Not a PostgeSQL UDL',
Udl => $udl->asString,
);
}
my $c = Quiq::CommandLine->new('psql');
for my $opt (qw/user host port/) {
if (my $val = $udl->$opt) {
$c->addLongOption(
"--$opt" => $val,
);
}
}
$c->addBoolOption('--echo-hidden'=>$showInternal);
if ($command) {
$c->addOption(-P=>'pager=off');
$c->addLongOption('--command'=>$command);
}
if ($script) {
$c->addLongOption('--file'=>$script);
$stopOnError = 1;
$echo = 1;
}
if ($stopOnError) {
$c->addLongOption('--set'=>'ON_ERROR_STOP=1');
}
$c->addBoolOption('--echo-all'=>$echo);
$c->addLongOption('--log-file'=>$log);
if (my $database = $udl->db) {
$c->addArgument($database);
}
my $cmd = $c->command;
# if ($debug) {
say $cmd;
# }
my $exp = Expect->new;
if ($debug) {
$exp->exp_internal(1);
}
$exp->spawn($cmd) || do {
$class->throw(
'EXPECT-00099: Cannot spawn command',
Command => $cmd,
);
};
# Anmeldung. Wir unterscheiden drei Fälle.
my $interact = $command || $script? 0: 1;
$exp->expect(3,[
# mit Passwort
-re => 'Password.*?:',sub {
my $exp = shift;
$exp->send($udl->password."\n");
},
],[
# ohne Passwort
-re => '^psql ',sub {
},
],[
# Verbindung kommt nicht zustande
-re => '^psql:',sub {
# Ende der Kommunikation
$interact = 0;
},
]);
if ($interact) {
# Benutzer-Interaktion
$exp->interact;
return 0;
}
$exp->expect(undef);
return $exp->exitstatus/256;
}
# -----------------------------------------------------------------------------
=head1 VERSION
1.225
=head1 AUTHOR
Frank Seitz, L<http://fseitz.de/>
=head1 COPYRIGHT
Copyright (C) 2025 Frank Seitz
=head1 LICENSE
This code is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
# -----------------------------------------------------------------------------
1;
# eof