PERL -- DBI unter Linux/UNIX

Vor dem Skriptstart...

...steht das Setzen der Umgebungsvariablen. S.o.

Verbindungsaufbau

use strict;
use DBI qw(:sql_types);
our $dbh;
unless ( $dbh = DBI->connect("dbi:Oracle:desy.desy.de", "USERNAME", 'PASSWORD', {AutoCommit => 0,RaiseError=>1}) ) {
die "Oracle Login Failed for USERNAME", "", "$DBI::errstr" ;
# -- oder $log->logdie ... bei Einsatz von Log4perl, s.u.
exit;
}

use strict -- keine unliebsamen Überraschungen, weil man Tippfehler in den Variablennamen hat
use DBI... -- das PERL Datenbank Interface nutzen, hier unter Nutzung von SQL-Typen, die man im Code explizit angeben kann
our $dbh -- eine globale Variable; d.h. $dbh kann im gesamten Programm genutzt werden und ist in unserem Fall für den Zugriff auf die Oracle-Datenbank (database handle).

Wenn der Verbindungsaufbau zum Oracle nicht funktioniert, hält das Skript an.

Datenabruf

Ein Beispiel:

my $sth = $dbh->prepare(
qq{select ID,SPALTE1,SPALTE2,SPALTE3
from USERNAME.TABELLENNAME
where SPALTE1 IS NOT NULL
and SPALTE2 <> 'bedingung'
});

$sth->execute;

my $hashref = $sth->fetchall_hashref('ID');

foreach my $id (sort keys %{$hash_ref}) {
my $spalte1=$hash_ref->{$id}->{SPALTE1};
my $spalte2=$hash_ref->{$id}->{SPALTE2};
print "$spalte1\n";
}

Hier werden im klassischen Dreisprung prepare/execute/fetch Daten abgerufen. Dabei landet das Ergebnis in einem PERL-Hash, der durch den Spaltennamen ID bestimmt ist. So könnte man Abrufen:

Oder prepare/execute/fetch in einem Stück:

my $array_ref=$dbh->selectall_arrayref(qq{select table_name from user_tables});
foreach my $t (@$array_ref) {print "$t\n";}

Man beachte den Unterschied: einmal wird ein Statement-Handle "prepared" ($sth) und einmal auf das Database-Handle zugegriffen ($dbh).

Daten schreiben

Ebenfalls nützlich sind (auch beim Abruf) Bind-Variablen. Die kommen im Schreibbeispiel vor:

my $sth = $dbh->prepare( qq{
INSERT INTO USERNAME.TABELLENNAME
(SPALTE1,SPALTE2,DATUMSANGABE)
VALUES
( ?, ?, to_date(?,'YYYY-MM-DD HH24:MI:SS') }
);


for (SCHÖNE SCHLEIFE) {
$sth->bind_param( 1, $variable1, SQL_VARCHAR );
$sth->bind_param( 2, substr($variable2,0,7), SQL_VARCHAR );
$sth->bind_param( 3, $DATE , SQL_VARCHAR ); # -- DATUM $sth->execute();
} # -- SCHLEIFE;
$dbh->commit();

Wenn ein Statement erst einmal "prepared" ist, kann durch binden von Variablen (deren aktuellen Werten) und "execute" das Kommando ausgeführt werden. Oracle muss dann nicht intern jedesmal den Parser anwerfen, um als String zusammengebastelte SQL-Kommandos zu übersetzen.

Das "commit" kann natürlich auch in der Schleife nützlich sein. Bei viiiieeeelen Datensätzen (>100.000) sollte zwischendurch ein "commit" kommen, sonst wird der UNDO-Tablespace evtl. zu sehr belastet. Ja, es gibt auch ein

$dbh->rollback;

womit alle INSERT/UPDATE/DELETE Kommandos seit dem letzten "commit" rückgängig gemacht werden. Dazu muss (s.o.) AutoCommit=>0 gesetzt worden sein.

was sonst noch nützlich ist

Falls man sein Skript auch mal definiert abbrechen können möchte, bietet es sich an, ein bisschen Signal-Handling einzubauen:

$SIG{TERM}=\&terminate;
$SIG{INT}=\&terminate;

...code...
sub terminate {
my $signame = shift;
$dbh->rollback;
$log->logdie("Received SIG$signame. Rollback issued.");
}

Ein Ctrl-C oder ein "kill PROZESS-ID" erzeugen dann ein Rollback. Hier sieht man auch die Verwendung von Log::Log4perl. Mit diesem Modul lassen sich Log-Dateien differenziert erstellen. Minimal-Konfiguration könnte folgendes sein:

use Log::Log4perl ;
...
Log::Log4perl->init('/abc/def/.../myscript.l4p.conf');
my $log = Log::Log4perl->get_logger();
$log->info("Invokation of $0");
$log->debug("Be phony...");
$log->warn("Huch! Das ist strange, ich mach trotzdem weiter: $!");
$log->logwarn("Das kommt zusaetzlich auf den Schirm.");
$log->logdie("Full stop. Auch am Schirm");
$log->logconfess("Full stop with full stack trace");

Und einer Konfiguration ähnlich:

log4perl.rootLogger=DEBUG, LOGFILE
log4perl.appender.LOGFILE=Log::Log4perl::Appender::File
log4perl.appender.LOGFILE.filename=/scratch/log/my.log
log4perl.appender.LOGFILE.mode=clobber
log4perl.appender.LOGFILE.layout=PatternLayout
log4perl.appender.LOGFILE.layout.ConversionPattern=[%r] %d %p %L %c - %m%n