1

I have a java application which is using Oracle SQLLDR utility to upload the CSV file data to the oracle database.

Occasionally, the SQLLDR utility doesn't provide the return/response code and whereas we could see the Index are disabled in the table (This ensures the SQLLDR utility is invoked) and also I have used TOP command in the server to find whether any SQLLDR process is running, but there are no such process.

In addition the DBA confirms, there is no active session on the database related to SQLLDR operation.

Is there anything which needs to be checked in the oracle table level ? Please let me know the way forward.

Karthick88it
  • 601
  • 2
  • 12
  • 28
  • How is Sqlldr related to Java? – mentallurg Jun 25 '20 at 01:45
  • @mentallurg It is related through process builder. Here is the piece of code, which is used in the application and the process doesn't return for the response code. `code` ProcessBuilder pb = new ProcessBuilder(new String[] {"sh", "-c", cmd }); p = pb.start(); p.waitFor(); `code` – Karthick88it Jun 25 '20 at 04:34
  • Any process executed in Linux will return an `exit code` to `shell` (`0`: success; `any other`: failure). You can check `exit code` value to determine if execution has failed. Also suggest to run `SQLLDR` manually and see the output. IMO better to log failed executions to keep Support/Devops engineer's hairs in place :-) – Tom Lime Oct 16 '20 at 13:47
  • @TomLime When we execute them manually it works through SQLLDR utility. If I execute through java using process builder occasionally the exit code is not returned and no active sessions are running on database side. Is there anyway to check whether the process builder invoked session/process is Active ? – Karthick88it Oct 19 '20 at 06:43
  • @KarthickSambanghi, just for debugging purposes you can add a `&& touch /tmp/was_executed` to your `cmd`. Like: `sqlldr ... && touch /tmp/was_executed`. This will create a `/tmp/was_executed` file upon successful execution (exit code **0**). So you will know that `sqlldr` **was executed correctly** and the issue is somewhere else. If the file wasn't created, this means that `sqlldr` execution failed (exit code **other than 0**). Don't forget to remove the file creation part after you finish debugging. Once process finished execution - you will not see it with `top` command. – Tom Lime Oct 19 '20 at 08:25

1 Answers1

4

SQL

 connect scott/tiger;
 create table employee
(
  id integer,
  name varchar2(10),
  dept varchar2(15),
  salary integer,
  hiredon date
)

Control file

load data
 infile '/home/db1212/x.txt'
 into table employee
 fields terminated by ","
 ( id, name, dept, salary )

x.txt

200,Jason,Technology,5500
300,Mayla,Technology,7000
400,Nisha,Marketing,9500
500,Randy,Technology,6000
501,Ritu,Accounting,5400

Execute

$ sqlldr scott/tiger control=/home/db1212/x.ctl

returns

SQL*Loader: Release 12.1.0.2.0 - Production on Sat Oct 17 21:23:47 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

Path used:      Conventional
Commit point reached - logical record count 5

Table EMPLOYEE:
  5 Rows successfully loaded.

Check the log file:
  x.log
for more information about the load.

Execute second time to generate error

$ sqlldr scott/tiger control=/home/db1212/x.ctl

returns

SQL*Loader: Release 12.1.0.2.0 - Production on Sat Oct 17 21:25:39 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

Path used:      Conventional
SQL*Loader-601: For INSERT option, table must be empty.  Error on table EMPLOYEE

Truncate table in SQL*Plus by

truncate table employee;

Using following Java class from inside

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class t1 {

    public static void main(String[] args) {

        t1 obj = new t1();

        String output = obj.executeCommand();

        System.out.println(output);

    }

    private String executeCommand() {

        StringBuffer output = new StringBuffer();

        try {

            Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "sqlldr scott/tiger control=/home/db1212/x.ctl"});
            p.waitFor();
            BufferedReader reader
                    = new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = "";
            System.out.println("Return code:"+p.exitValue()+"\n"); 
            while ((line = reader.readLine()) != null) {
                output.append(line + "\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return output.toString();

    }

}

Build and run t1.java

$ javac t1.java 
$ java t1

returns

Return code:0


SQL*Loader: Release 12.1.0.2.0 - Production on Sat Oct 17 21:30:31 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

Path used:      Conventional
Commit point reached - logical record count 5

Table EMPLOYEE:
5 Rows successfully loaded.

Check the log file:
x.log
for more information about the load.

Executing second time to mimic error

$ java t1

returns

Return code:1


SQL*Loader: Release 12.1.0.2.0 - Production on Sat Oct 17 21:30:39 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

Path used:      Conventional

truncating table again

truncate table employee;

and changing the input file x.txt

200,Jason,Technology,5500
300,Mayla,Technology,7000
400,Nisha,MarketingAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9500
500,Randy,Technology,6000
A501,Ritu,Accounting,5400 

gives for execution

$ java t1

following output

Return code:2


SQL*Loader: Release 12.1.0.2.0 - Production on Sat Oct 17 21:47:05 2020

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

Path used:      Conventional
Commit point reached - logical record count 5

Table EMPLOYEE:
  3 Rows successfully loaded.

Check the log file:
  x.log
for more information about the load.

This means:

So in case of

  • succesful execution EX_SUCC = 0
  • general SQLLoader error like "SQLLoader-601: For INSERT option, table must be empty. Error on table EMPLOYEE" i.e.unsuccesful execution or parameter gives EX_FAIL = 1 (Unix, Windows returns 3)
  • succesful execution / loading but with SQL Errors like "ORA-12899: value too large for column "SCOTT"."EMPLOYEE"."DEPT" (actual: 44, maximum: 15)" returns EX_WARN = 2

Unfortunately documentation states

SQLLoader returns any exit code other than zero, you should consult your system log files and SQLLoader log files for more detailed diagnostic information.

which means nothing else then that there is no way to get the errors directly as stderr, pipes etc. and you have to verify the written log file if EX_FAIL or EX_WARN.

Dharman
  • 30,962
  • 25
  • 85
  • 135
devnull
  • 570
  • 2
  • 7
  • In my case, I'm trying to load the data on everyday basis on the already available table(delta load). occasionally there is no return code received from p.exitValue() and whereas the indexes are disabled on the table. This ensures the data loading have been started, But DBA confirms that there are no active sessions on DB and top process also not showing active session. But java process keeps on running. How we can troubleshoot further on this ? – Karthick88it Oct 19 '20 at 05:32
  • In addition is there a way to check whether the process builder session is active or not. – Karthick88it Oct 19 '20 at 06:44
  • I have now tried Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "sqlldr scott/tiger control=/home/db1212/x.ctl direct=true"}); which even returns for direct path loading a return value - Output is : Return code:1 SQL*Loader: Release 12.1.0.2.0 - Production on Mon Oct 19 15:17:47 2020 Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved. Path used: Direct. That there are no active sessions maybe result of using direct path since this uses Direct Path API and this may not in result creating a server process attached to client. – devnull Oct 19 '20 at 13:21
  • So - Please try for test to use conventional path. Doing that you need to disable index manually if you use direct path load in combination with SKIP_INDEX_MAINTENANCE=TRUE. Using manual disabled indexes and conventional path shoud give you to see sessions in DB and on TOP. Anyway - that there is no return code is - lets say - odd. Please have a look here: https://stackoverflow.com/questions/56982666/java-process-waitfor-returns-with-inconsistent-value I'm using java-1.8.0-openjdk-1.8.0.265.b01-1.el7_9.x86_64 on Scientific Linux 7.8 (3.10.0-1062.9.1.el7.x86_64) i.e. RHEL 7.8 clone – devnull Oct 19 '20 at 13:32