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 )