DBIx-BulkUtil
view release on metacpan or search on metacpan
lib/DBIx/BulkUtil.pm view on Meta::CPAN
#-J => "utf8",
-S => $server,
-t => $delimiter,
-r => $row_delimiter,
-e => $error_file->filename(),
@header_opt,
@id_opt,
@commit_opt,
@max_err_opt,
@packet_size,
@passthru,
@fmt_file_opt,
);
print "Executing: @cmd\n";
push @cmd, -P => $self->{PASSWORD};
open(my $fh, "-|", @cmd) or confess "Can't exec bcp: $!";
my ($rows, $failed, $partially_failed);
local ($_, $.);
my $err_cnt = my $c_lib_err_cnt = my $srvr_err_cnt = 0;
while (<$fh>) {
print;
if ( /^(Server|C[TS]LIB) Message/ ) {
my $msg_type = $1;
if ( $msg_type eq 'CSLIB' ) {
if ( m|/N(\d+)| ) {
# Sybase says truncation is not an error, so we will too
# Or else we might get > 1 error on the same row
unless ( $1 == 36 ) {
$err_cnt++;
$c_lib_err_cnt++;
}
}
} elsif ( $msg_type eq 'CTLIB' ) {
$err_cnt++;
$c_lib_err_cnt++;
} else {
# On server errors the whole batch is an error
if ( /\s(\d+)/ ) {
# Ignore 'slow bcp' warning
unless ( $1 == 4852 ) {
$err_cnt += $commit_size;
$srvr_err_cnt += $commit_size;
}
} else {
$err_cnt += $commit_size;
$srvr_err_cnt += $commit_size;
}
}
}
$rows = $1 if /^(\d+) rows copied/;
# failed or partially failed
if ( /^bcp copy in ((?:partially )?)failed/ ) {
$partially_failed++ if $1;
$failed++;
}
}
# "NaN" (literally "NaN") to numeric errors
# do not show up on STDOUT.
# So we may as well search the err file to count
# all CSLIB and CTLIB errors.
# Truncation errors do not show up in file, so we
# don't have to filter them out as we would if we
# were parsing STDOUT.
my $err_file_cnt = 0;
open(my $err_h, "<", $error_file->filename()) or die "Failed to open $error_file: $!";
while (<$err_h>) {
$err_file_cnt++ if /^#@ Row \d+: Not transferred/;
}
close $err_h;
if ( $err_file_cnt > $c_lib_err_cnt ) {
$err_cnt += $err_file_cnt - $c_lib_err_cnt;
}
# BCP 11.x,12.x returns meaningful exit status
# 10.x does not (returns 0 even on errors)
my $close_success = close $fh;
unless ($close_success) {
my $exit_stat = $? >> 8;
my $exit_sig = $? & 127;
my $exit_core = $? & 128;
# bcp will exit with non-zero status on any 'Server' error,
# but not on 'CSLIB' errors unless 'CSLIB' error count exceeds max.
if ( $exit_stat != 0 ) {
if ( $dir eq 'in' ) {
# Some of this may seem unneccessary, but Sybase bcp is
# horribly inconsistent.
# Exceeded the error count
confess "BCP error - max error count ($max_err_cnt) exceeded - bcp returned status $exit_stat: $!"
if $err_cnt > $max_err_cnt;
# The load was aborted before bcp indicated that it finished
confess "BCP error - bcp aborted [$exit_stat]: $!"
if !defined($rows) and !$failed;
# BCP failed - even if we allow some errors on a small file, if zero rows are copied
# then call it a total failure.
confess "BCP error - bcp failed [$exit_stat]: $!"
if $failed and !$partially_failed;
} else {
confess "BCP error - bcp returned status $exit_stat: $!";
}
}
confess "BCP error - bcp recieved signal $exit_sig" if $exit_sig > 0;
confess "BCP error - bcp coredumped" if $exit_core;
}
# Will miss error count exceeded error on 10.x
# But will catch other errors if load is aborted
# Or no rows are loaded.
confess "BCP error - no rows copied" if !defined($rows);
( run in 0.686 second using v1.01-cache-2.11-cpan-98e64b0badf )