8

This question is related to my original issue How to return an array from Java to PL/SQL ?, but is a more specific.

I have been reading Oracle Database JDBC Developer's Guide and

but I still fail to write a minimum code where I can create ARRAY using

ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);

as instructed in Creating ARRAY objects.

I'm using Oracle Database JVM.

I have tried following:

Example 1

create or replace type widgets_t is table of varchar2(32767);
/

create or replace and compile java source named "so20j1" as
public class so20j1 {
    public void f1() {
        String[] elements = new String[]{"foo", "bar", "zoo"};
        oracle.sql.ARRAY widgets =
            oracle.jdbc.OracleConnection.createARRAY("widgets_t", elements);
    }
};
/
show errors java source "so20j1"

Fails with:

Errors for JAVA SOURCE "so20j1":

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0  so20j1:4: non-static method
     createARRAY(java.lang.String,java.lang.Object) cannot be
     referenced from a static context

0/0  1 error
0/0  ^
0/0  oracle.sql.ARRAY widgets =
     oracle.jdbc.OracleConnection.createARRAY("widgets_t", elements);

Example 2

create or replace type widgets_t is table of varchar2(32767);
/

create or replace and compile java source named "so20j2" as

public class so20j2 {
    public void f1() {
        String[] elements = new String[]{"foo", "bar", "zoo"};
        oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
        java.sql.Connection conn = ora.defaultConnection();
        oracle.sql.ARRAY widgets = conn.createARRAY("widgets_t", elements);
    }
};
/
show errors java source "so20j2"

Fails with:

Errors for JAVA SOURCE "so20j2":

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0  so20j2:6: cannot find symbol
0/0  symbol  : method createARRAY(java.lang.String,java.lang.String[])
0/0  1 error
0/0  oracle.sql.ARRAY widgets = conn.createARRAY("widgets_t",
     elements);

0/0  ^
0/0  location: interface java.sql.Connection

Disclaimer: I'm not a Java programmer (yet).

Community
  • 1
  • 1
user272735
  • 10,473
  • 9
  • 65
  • 96
  • Firstly, you have to "CREATE TYPE elements AS varray(22) OF NUMBER(5,2);" and then use this type in oracle.jdbc.OracleConnection.createARRAY() – Zaki Oct 24 '11 at 16:40
  • @Zaki: If you read the question carefully, I'm sure you see that is exactly what I'm doing. The type name is `widgets_t`. – user272735 Oct 25 '11 at 05:42

7 Answers7

9

You're on the right track with #2, but you can't create an oracle Array from a connection of type java.sql.Connection. It has to be an OracleConnection to be able to use those methods.

oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
java.sql.Connection conn = ora.defaultConnection();
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
oracle.sql.ARRAY widgets = oraConn.createARRAY("widgets_t", elements);
Affe
  • 47,174
  • 11
  • 83
  • 83
  • Hmm ... with your example I unfortunately get a compilation error: `cannot find symbol: method unwrap(java.lang.Class)` – user272735 Oct 25 '11 at 04:44
  • 1
    But my example compiles if I cast `Connection` to `OracleConnection` this way: `oracle.jdbc.OracleConnection oraConn = (oracle.jdbc.OracleConnection)ora.defaultConnection();` +1 for that. – user272735 Oct 25 '11 at 04:49
  • unwrap is Java 6. If you are using an older java you will need to cast. – Affe Oct 25 '11 at 16:27
  • 2
    For anyone checking this out years later, `createARRAY` is deprecated now, you should use `createOracleArray` [apparently](https://stackoverflow.com/a/33347598/2137269) – Evan Knowles Jun 09 '21 at 10:49
  • 1
    `createOracleArray` is documented: https://docs.oracle.com/en/database/oracle/oracle-database/19/jajdb/oracle/jdbc/OracleConnection.html#createOracleArray_java_lang_String_java_lang_Object_ – gouessej Jun 28 '23 at 07:26
3

Here is a working example tested with Oracle 19:

final BigDecimal[] plainJavaArray = new BigDecimal[]{BigDecimal.valueOf(1L), BigDecimal.valueOf(2L)};
final oracle.jdbc.OracleConnection oracleConnection = (oracle.jdbc.OracleConnection) jdbcConnection;
final java.sql.Array array = oracleConnection.createOracleArray("SYS.ODCINUMBERLIST", plainJavaArray);

Keep in mind some very important aspects:

  • oracle.jdbc.OracleConnection.createOracleArray() expects the array type name, not the element type name unlike java.sql.Connection.createArrayOf().
  • java.sql.Connection.createArrayOf() throws a java.sql.SQLFeatureNotSupportedException.
  • The first parameter is case-sensitive; if you pass the correct array type name with the wrong case, you'll get an SQLException complaining about a wrong model name.
  • You can use SYS.ODCIVARCHAR2LIST or SYS.FI_CATEGORICALS for VARCHAR2, SYS.ODCIDATELIST for DATE, etc. SYS.ODCIGRANULELIST is twice bigger than SYS.ODCINUMBERLIST and if it's not enough, use SYS.FI_NUMERICALS. I haven't tested with user-defined types but CREATE TYPE ARRAY_OF_THING IS TABLE OF THING should work.
  • Don't use deprecated methods, they'll stop working or be removed sooner or later.
gouessej
  • 3,640
  • 3
  • 33
  • 67
3

Based on answers of Affe and Chris Mazzola I have succeeded to build two examples that compile in Oracle 11g R2 database.

Example based on Affe's answer

create or replace type widgets_t is table of varchar2(32767);
/

create or replace and compile java source named "so20ja1" as
public class so20ja1 {
    public void f1() throws java.sql.SQLException {
        String[] elements = new String[]{"foo", "bar", "zoo"};
        oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
        java.sql.Connection conn = ora.defaultConnection();
        oracle.jdbc.OracleConnection oraConn = (oracle.jdbc.OracleConnection)conn;
        java.sql.Array widgets = oraConn.createARRAY("widgets_t", elements);
    }
};
/
show errors java source "so20ja1"

Example based on Chris Mazzola's answer

create or replace type widgets_t is table of varchar2(32767);
/

create or replace and compile java source named "so20ja2" as
public class so20ja2 {
    public void f1() throws java.sql.SQLException {
        String[] elements = new String[]{"foo", "bar", "zoo"};
        oracle.jdbc.OracleDriver ora = new oracle.jdbc.OracleDriver();
        java.sql.Connection conn = ora.defaultConnection();
        oracle.sql.ArrayDescriptor desc = 
            oracle.sql.ArrayDescriptor.createDescriptor("widgets_t", conn);
        java.sql.Array widgets = new oracle.sql.ARRAY(desc, conn, elements);
    }
};
/
show errors java source "so20ja2"
user272735
  • 10,473
  • 9
  • 65
  • 96
1
// array sample (using a stored procedure to sum two or more numbers)
Connection connection = dataSource.getConnection(username,password);
ArrayDescriptor desc = 
    ArrayDescriptor.createDescriptor(schemaName + "." + arrayType, connection);

// first ? is the array, second ? is the result via out parameter
String sql = "call sum_numbers(?,?)";
CallableStatement cs = connection.prepareCall(sql);

String[] args = {"5","15","25","35"}; // what to sum
Array array = new oracle.sql.ARRAY(desc, connection, args);

cs.setArray(1, array);
cs.registerOutParameter(2, Types.INTEGER);
cs.execute();
int result = cs.getInt(2);
cs.close();
Chris Mazzola
  • 5,807
  • 5
  • 22
  • 15
  • I could compose a compiling example based on this answer. However this way is no more documented in Oracle 11g, but seems to be the way for 10g and earlier releases. – user272735 Oct 25 '11 at 06:33
0
Map<String, Object> params = new HashMap<>();

        params.put("input_to_sp", new ExampleArrayMapper (new String[] { "ABC" }));

        Map<String, Object> results = spObject.execute(params);

        final List<Object> output = (List<Object>) results.get("po_out_cur");


    public class ExampleArrayMapper extends AbstractSqlTypeValue {
        private String[] customObject;

        public ExampleArrayMapper (String[] customObject) {
            this.customObject= customObject;
        }

        public String getSQlTypeName() throws SQLException {
            return "NAME_OF_TYPE_IN_SQL";
        }

        @Override
        protected Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException {
            try {
                con = dataSource.getConnection().unwrap(OracleConnection.class);
                Array reportsArray = ((OracleConnection) con).createOracleArray(SQL_TYPE_NAME, customObject);
                return reportsArray;
            } finally {
                con.close();
            }
        }
    }
gouessej
  • 3,640
  • 3
  • 33
  • 67
0

Oracle 12.2 version:

oracle.jdbc.OracleArray  v_arr ;
String[] v_list ;


v_arr = ((oracle.jdbc.OracleConnection)DriverManager.getConnection("jdbc:default:connection:")).createARRAY ( "T_STRING_ARRAY" , v_list ) ;
Shabnam Siddiqui
  • 579
  • 4
  • 13
vasu2005s
  • 21
  • 1
0

Just to mention that in Java 1.6 you have connection.createArrayOf(..), which is standard.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    Sounds elegant and straightforward, but unfortunately all my efforts ends to: `cannot find symbol: createArrayOf(java.lang.String,java.lang.String[]) location: interface java.sql.Connection`. Thanks anyway ! – user272735 Oct 25 '11 at 05:48
  • Ah ! From [Oracle documentation](http://download.oracle.com/docs/cd/E11882_01/java.112/e16548/ssid.htm#CIHIEBGC): _the server-side embedded JVM uses Java Development Kit (JDK) 1.5_. – user272735 Oct 25 '11 at 06:24
  • 10
    Ah ! From [Oracle documentation](http://download.oracle.com/docs/cd/E11882_01/java.112/e16548/oraarr.htm#i1059642): _Oracle JDBC does not support the JDBC 4.0 method createArrayOf method of java.sql.Connection interface. This method only allows anonymous array types, while all Oracle array types are named. Use the Oracle specific method oracle.jdbc.OracleConnection.createARRAY instead._ – user272735 Oct 25 '11 at 06:28
  • 1
    `Connection.createArrayOf()` is still unsupported by Oracle 19, it throws a java.sql.SQLFeatureNotSupportedException. Rather use `OracleConnection.createOracleArray()` instead. – gouessej Jun 28 '23 at 07:15