Skip navigation.
Downloads | Product Documentation | Support

WebLogic jDriver for Oracle (Deprecated)

# WebLogic jDriver Advanced Features

Note: The WebLogic jDriver for Oracle is deprecated and will be removed in a future release. BEA recommends that you use the BEA WebLogic Type 4 JDBC Oracle driver. For more information, see BEA WebLogic Type 4 JDBC Drivers.

This section presents advanced features in WebLogic jDriver for Oracle:

- Allowing Mixed Case Metadata
- Recommended Data Type Mapping
- WebLogic Server and Oracle's NUMBER Column
- Using Oracle Long Raw Data Types
- Waiting on Oracle Resources
- Autocommit
- Transaction Isolation Levels
- Codeset Support
- Support for Oracle Array Fetches
- Using Stored Procedures
- DatabaseMetaData Methods
- Support for JDBC Extended SQL
- Overview of JDBC 2.0 for Oracle
- Configuration Required to Support JDBC 2.0
- BLOBs and CLOBs
- Character and ASCII Streams
- Batch Updates
- New Date Methods

Note: WebLogic Server also supports Oracle extension methods for prepared statements, callable statements, ARRAYs, STRUCTs, and REFs. However, to use these extensions, you must use the Oracle Thin Driver to connect to your database.

# Allowing Mixed Case Metadata

WebLogic Server supports the setting of the `allowMixedCaseMetaData` property. When set to the boolean `true`, this property sets up the Connection such that mixed case is used in calls to DatabaseMetaData methods. If this property is set to `false`, Oracle defaults to `UPPERCASE` for database metadata.

The following sample code shows how to set up the properties to include this feature:

>     Properties props = new Properties();
>     props.put("user",                   "scott");
>     props.put("password",               "tiger");
>     props.put("server",                 "DEMO");
>     props.put("allowMixedCaseMetaData", "true");

>     Driver myDriver = (Driver)
>       Class.for.Name(weblogic.jdbc.oci.Driver).newInstance();

>     Connection conn =
>        myDriver.connect("jdbc:weblogic:oracle", props);

If you do not set this property, WebLogic Server defaults to the Oracle default, and `UPPERCASE` is used for database metadata.

# Recommended Data Type Mapping

The following table shows the recommended mapping between Oracle data types and JDBC types. There are additional possibilities for representing Oracle data types in Java. If the `getObject()` method is called when result sets are being processed, it returns the default Java data type for the Oracle column being queried.

Note: In Oracle 9i, Oracle introduced the Timestamp datatype. The WebLogic jDriver for Oracle does not support this datatype.

Table 5-1 Oracle Types Mapped to WebLogic Server

Oracle | Java
`Varchar` | `String`
`Number` | `Tinyint`
`Number` | `Smallint`
`Number` | `Integer`
`Number` | `Long`
`Number` | `Float`
`Number` | `Numeric`
`Number` | `Double`
`Long` | `Longvarchar`
`RowID` | `String`
`Date` | `Timestamp`
`Raw` | `(var)Binary`
`Long raw` | `Longvarbinary`
`Char` | `(var)Char`
`Boolean*` | `Number OR Varchar`
`MLS label` | `String`
`Blob` | `Blob`
`Clob` | `Clob`

* Note that when `PreparedStatement.setBoolean()` is called, it converts a `VARCHAR` type to `1` or `0` (string), and it converts a `NUMBER` type to `1` or `0` (number).

# WebLogic Server and Oracle's NUMBER Column

Oracle provides a column type called `NUMBER`, which can be optionally specified with a precision and a scale, in the forms `NUMBER(P)` and `NUMBER(P,S)`. Even in the simple unqualified `NUMBER` form, this column can hold all number types from small integer values to very large floating point numbers, with high precision.

WebLogic Server reliably converts the values in a column to the Java type requested when a WebLogic Server application asks for a value from such a column. Of course, if a value of 123.456 is asked for with `getInt()`, the value will be rounded.

The method `getObject()`, however, poses a little more complexity. WebLogic Server guarantees to return a Java object which will represent any value in a `NUMBER` column with no loss in precision. This means that a value of 1 can be returned in an `Integer`, but a value like 123434567890.123456789 can only be returned in a `BigDecimal`.

There is no metadata from Oracle to report the maximum precision of the values in the column, so WebLogic Server must decide what sort of object to return based on each value. This means that one ResultSet may return multiple Java types from `getObject()` for a given NUMBER column. A table full of integer values may all be returned as `Integer` from `getObject()`, whereas a table of floating point measurements may be returned primarily as `Double`, with some `Integer` if any value happens to be something like "123.00". Oracle does not provide any information to distinguish between a `NUMBER` value of "1" and a `NUMBER` of "1.0000000000".

There is some more reliable behavior with qualified `NUMBER` columns, that is, those defined with a specific precision. Oracle's metadata provides these parameters to the driver so WebLogic Server will always return a Java object appropriate for the given precision and scale, regardless of the values in the table.

Table 5-2 Conversion Types for Oracle's Number Column Definitions

Column Definition | Returned by getObject()
`NUMBER(P <= 9)` | `Integer`
`NUMBER(P <= 18)` | `Long`
`NUMBER(P = 19)` | `BigDecimal`
`NUMBER(P <=16, S 0)` | `Double`
`NUMBER(P = 17, S 0)` | `BigDecimal`

# Using Oracle Long Raw Data Types

There are two properties available for use with WebLogic Server in support of Oracle's chunking of BLOBs, CLOBs, Long, and Long raw data types. Although BLOB and CLOB data types are only supported with Oracle Version 8 and JDBC 2.0, these properties also apply to Oracle's Long raw data type, which is available in Oracle Version 7.

# Waiting on Oracle Resources

Note: The `waitOnResources()` method is not supported for use with the Oracle 8 API.

The WebLogic Server driver supports Oracle's `oopt()` C functionality, which allows a client to wait until resources become available. The Oracle C function sets options in cases in which requested resources are not available, such as whether to wait for locks.

A developer can specify whether a client will wait for DBMS resources, or will receive an immediate exception. The following code is an excerpt from a sample code file (`examples/jdbc/oracle/waiton.java`):

>     java.util.Properties props = new java.util.Properties();
>     props.put("user",     "scott");
>     props.put("password", "tiger");
>     props.put("server",   "myserver");

>     Driver myDriver = (Driver)
>       Class.forName("weblogic.jdbc.oci.Driver").newInstance();

>     // You must cast the Connection as a weblogic.jdbc.oci.Connection
>     // to take advantage of this extension

>     Connection conn =(weblogic.jdbc.oci.Connection)
>       myDriver.connect("jdbc:weblogic:oracle", props);

>     // After constructing the Connection object, immediately call
>     // the waitOnResources method

>     conn.waitOnResources(true);

Use of this method can cause several error return codes to be generated while the software waits for internal resources that are locked for short durations.

To take advantage of this feature, you must do the following:

1. Cast your Connection object as a `weblogic.jdbc.oci.Connection`.
2. Call the `waitOnResources()` method.

This functionality is described in section 4-97 of The OCI Functions for C.

# Autocommit

The default transaction mode for JDBC WebLogic Server assumes autocommit to be true. You can improve the performance of your programs by setting autocommit to false, after creating a Connection object, with the following statement:

>        Connection.setAutoCommit(false);

# Transaction Isolation Levels

WebLogic Server supports the following transaction isolation levels:

- `SET TRANSACTION ISOLATION LEVEL READ COMMITTED`
- `SET TRANSACTION ISOLATION LEVEL SERIALIZABLE`

The Oracle DBMS supports only these two isolation levels. Unlike other JDBC drivers, the WebLogic jDriver for Oracle throws an exception if you try to use an isolation level that is unsupported. Some drivers silently ignore attempts to set an unsupported isolation level.

The `READ_UNCOMMITTED` transaction isolation level is not supported.

# Codeset Support

JDBC and the WebLogic Server driver handle character strings in Java as Unicode strings. Because the Oracle DBMS uses a different codeset, the driver must convert character strings from Unicode to the codeset used by Oracle. The WebLogic Server examines the value stored in the Oracle environment variable `NLS_LANG` and select a codeset for the JDK to use for the conversion, using the mapping shown in Table 5-3. If the `NLS_LANG` variable is not set, or if it is set to a codeset not recognized by the JDK, the driver cannot determine the correct codeset. (For information about the correct syntax for setting `NLS_LANG`, see your Oracle documentation.)

If you are converting codesets, you should pass the following property to the WebLogic Server with the `Driver.connect()` method when you establish the connection in your code:

>     props.put("weblogic.oci.min_bind_size", 660);

This property defines the minimum size of buffers to be bound. The default is 2000 bytes, which is also the maximum value. If you are converting codesets, you should use this property to reduce the bind size to a maximum of 660, one-third of the maximum 2000 bytes, since Oracle codeset conversion triples the buffer to allow for expansion.

WebLogic Server provides the `weblogic.codeset` property to set the codeset from within your Java code. For example, to use the `cp863` codeset, create a Properties object and set the `weblogic.codeset` property before calling `Driver.connect()`, as shown in the following example:

>     java.util.Properties props = new java.util.Properties();
>     props.put("weblogic.codeset", "cp863");
>     props.put("user", "scott");
>     props.put("password", "tiger");

>     String connectUrl = "jdbc:weblogic:oracle";

>     Driver myDriver = (Driver)
>      Class.forName("weblogic.jdbc.oci.Driver").newInstance();

>     Connection conn =
>          myDriver.connect(connectUrl, props);

Codeset support can vary with different JVMs. Check the documentation for the JDK you are using to determine whether a particular codeset is supported.

Note: You must also set the `NLS_LANG` environment variable in your Oracle client to the same or a corresponding codeset.

Table 5-3 NLS_LANG Settings Mapped to JDK Codesets

NLS_LANG | JDK codeset
`al24utffss` | `UTF8`
al32utf8 | UTF8
`ar8iso8859p6` | `ISO8859_6`
`cdn8pc863` | `Cp863`
`cl8iso8859p5` | `ISO8859_5`
`cl8maccyrillic` | `MacCyrillic`
`cl8mswin1251` | `Cp1251`
`ee8iso8859p2` | `ISO8859_2`
`ee8macce` | `MacCentralEurope`
`ee8maccroatian` | `MacCroatian`
`ee8mswin1250` | `Cp1250`
`ee8pc852` | `Cp852`
`el8iso8859p7` | `ISO8859_7`
`el8macgreek` | `MacGreek`
`el8mswin1253` | `Cp1253`
`el8pc737` | `Cp737`
`is8macicelandic` | `MacIceland`
`is8pc861` | `Cp861`
`iw8iso8859p8` | `ISO8859_8`
`ja16euc` | `EUC_JP`
`ja16sjis` | `SJIS`
`ko16ksc5601` | `EUC_KR`
`lt8pc772` | `Cp772`
`lt8pc774` | `Cp774`
`n8pc865` | `Cp865`
`ne8iso8859p10` | `ISO8859_10`
`nee8iso8859p4` | `ISO8859_4`
`ru8pc855` | `Cp855`
`ru8pc866` | `Cp866`
`se8iso8859p3` | `ISO8859_3`
`th8macthai` | `MacThai`
`tr8macturkish` | `MacTurkish`
`tr8pc857` | `Cp857`
`us7ascii` | `ASCII`
`us8pc437` | `Cp437`
`utf8` | `UTF8`
`we8ebcdic37` | `Cp1046`
`we8ebcdic500` | `Cp500`
`we8iso8859p1` | `ISO8859_1`
we8iso8859p15 | ISO8859_15_FDIS
`we8iso8859p9` | `ISO8859_9`
`we8macroman8` | `MacRoman`
`we8pc850` | `Cp850`
`we8pc860` | `Cp860`
`zht16big5` | `Big5`

# Support for Oracle Array Fetches

WebLogic Server supports Oracle array fetches. When called for the first time, `ResultSet.next()` retrieves an array of rows (rather than a single row) and stores it in memory. Each time that `next()` is called subsequently, it reads a row from the rows in memory until they are exhausted, and only then will `next()` go back to the database.

You set a property (`java.util.Property`) to control the size of the array fetch. The property is `weblogic.oci.cacheRows`; it is set by default to 100. Here's an example of setting this property to 300, which means that calls to `next()` only hit the database once for each 300 rows retrieved by the client.

>     Properties props = new Properties();
>     props.put("user",      "scott");
>     props.put("password",  "tiger");
>     props.put("server",    "DEMO");
>     props.put("weblogic.oci.cacheRows", "300");

>     Driver myDriver = (Driver)
>       Class.forName("weblogic.jdbc.oci.Driver").newInstance();

>     Connection conn = myDriver.connect("jdbc:weblogic:oracle", props);

You can improve client performance and lower the load on the database server by taking advantage of this JDBC extension. Caching rows in the client, however, requires client resources. You should tune your application for the best balance between performance and client resources, depending on your network configuration and your application.

If any columns in a SELECT are of type LONG, BLOB, or CLOB, WebLogic Server temporarily resets the cache size to 1 for the ResultSet associated with that select statement.

# Using Stored Procedures

This section describes variations in the implementation of stored procedures that are specific to Oracle.

- Binding a Parameter to an Oracle Cursor
- Notes on Using CallableStatement

## Binding a Parameter to an Oracle Cursor

WebLogic has created an extension to JDBC (`weblogic.jdbc.oci.CallableStatement`) that allows you to bind a parameter for a stored procedure to an Oracle cursor. You can create a JDBC ResultSet object with the results of the stored procedure. This allows you to return multiple ResultSets in an organized way. The ResultSets are determined at run time in the stored procedure.

Here is an example. First define the stored procedures as follows:

>     create or replace package
>     curs_types as
>     type EmpCurType is REF CURSOR RETURN emp%ROWTYPE;
>     end curs_types;
>     /

>     create or replace procedure
>     single_cursor(curs1 IN OUT curs_types.EmpCurType,
>     ctype in number) AS BEGIN
>       if ctype = 1 then
>         OPEN curs1 FOR SELECT * FROM emp;
>       elsif ctype = 2 then
>         OPEN curs1 FOR SELECT * FROM emp where sal  2000;
>       elsif ctype = 3 then
>         OPEN curs1 FOR SELECT * FROM emp where deptno = 20;
>       end if;
>     END single_cursor;
>     /
>     create or replace procedure
>     multi_cursor(curs1 IN OUT curs_types.EmpCurType,
>                  curs2 IN OUT curs_types.EmpCurType,
>                  curs3 IN OUT curs_types.EmpCurType) AS
>     BEGIN
>         OPEN curs1 FOR SELECT * FROM emp;
>         OPEN curs2 FOR SELECT * FROM emp where sal  2000;
>         OPEN curs3 FOR SELECT * FROM emp where deptno = 20;
>     END multi_cursor;
>     /

In your Java code, you'll construct `CallableStatements` with the stored procedures and register the output parameter as data type `java.sql.Types.OTHER`. When you retrieve the data into a ResultSet, use the output parameter index as an argument for the `getResultSet()` method.

>       java.sql.CallableStatement cstmt = conn.prepareCall(
>                            "BEGIN OPEN ? " +
>                            "FOR select * from emp; END;");
>       cstmt.registerOutParameter(1, java.sql.Types.OTHER);

>       cstmt.execute();
>       ResultSet rs = cstmt.getResultSet(1);
>       printResultSet(rs);
>       rs.close();
>       cstmt.close();

>       java.sql.CallableStatement cstmt2 = conn.prepareCall(
>                            "BEGIN single_cursor(?, ?); END;");
>       cstmt2.registerOutParameter(1, java.sql.Types.OTHER);

>       cstmt2.setInt(2, 1);
>       cstmt2.execute();
>       rs = cstmt2.getResultSet(1);
>       printResultSet(rs);

>       cstmt2.setInt(2, 2);
>       cstmt2.execute();
>       rs = cstmt2.getResultSet(1);}
>       printResultSet(rs);

>       cstmt2.setInt(2, 3);
>       cstmt2.execute();
>       rs = cstmt2.getResultSet(1);
>       printResultSet(rs);
>       cstmt2.close();

>       java.sql.CallableStatement cstmt3 = conn.prepareCall(
>                              "BEGIN multi_cursor(?, ?, ?); END;");
>       cstmt3.registerOutParameter(1, java.sql.Types.OTHER);
>       cstmt3.registerOutParameter(2, java.sql.Types.OTHER);
>       cstmt3.registerOutParameter(3, java.sql.Types.OTHER);

>       cstmt3.execute();

>       ResultSet rs1 = cstmt3.getResultSet(1);
>       ResultSet rs2 = cstmt3.getResultSet(2);
>       ResultSet rs3 = cstmt3.getResultSet(3);

For the full code for this example, including the `printResultSet()` method, see the examples in the `samples/examples/jdbc/oracle/` directory.

Note that the default size of an Oracle stored procedure string is 256K.

## Notes on Using CallableStatement

The default length of a string bound to an OUTPUT parameter of a CallableStatement is 128 characters. If the value you assign to the bound parameter exceeds that length, you'll get the following error:

>     ORA-6502: value or numeric error

You can adjust the length of the value of the bound parameter by passing an explicit length with the scale argument to the `CallableStatement.registerOutputParameter()` method. Here is a code example that binds a `VARCHAR` that will never be larger than 256 characters:

>       CallableStatement cstmt =
>         conn.prepareCall("BEGIN testproc(?); END;");

>       cstmt.registerOutputParameter(1, Types.VARCHAR, 256);
>       cstmt.execute();
>       System.out.println(cstmt.getString());
>       cstmt.close();

# DatabaseMetaData Methods

This section describes some variations in the implementation of DatabaseMetaData methods that are specific to Oracle:

- As a general rule, the String catalog argument is ignored in all `DatabaseMetaData` methods.
- In the `DatabaseMetaData`.`getProcedureColumns()` method:

- The String catalog argument is ignored.
- The String schemaPattern argument accepts only exact matches (no pattern matching).
- The String procedureNamePattern argument accepts only exact matches (no pattern matching).
- The String columnNamePattern argument is ignored.

# Support for JDBC Extended SQL

The JavaSoft JDBC specification includes SQL Extensions, also called SQL Escape Syntax. All WebLogic jDrivers support Extended SQL. Extended SQL provides access to common SQL extensions in a way that is portable between DBMSs.

For example, the function to extract the day name from a date is not defined by the SQL standards. For Oracle, the SQL is:

>       select to_char(date_column, 'DAY') from table_with_dates

The equivalent function for Sybase and Microsoft SQL Server is:

>       select datename(dw, date_column) from table_with_dates

Using Extended SQL, you can retrieve the day name for both DBMSs as follows:

>       select {fn dayname(date_column)} from table_with_dates

Here's an example that demonstrates several features of Extended SQL:

>       String query =
>       "-- This SQL includes comments and " +
>           "JDBC extended SQL syntax.\n" +
>       "select into date_table values( \n" +
>       "      {fn now()},        -- current time \n" +
>       "      {d '1997-05-24'},  -- a date       \n" +
>       "      {t '10:30:29' },   -- a time       \n" +
>       "      {ts '1997-05-24 10:30:29.123'},  -- a timestamp\n" +
>       "     '{string data with { or } will not be altered}'\n" +
>       "-- Also note that you can safely include" +
>          " { and } in comments or\n" +
>       "-- string data.";
>       Statement stmt = conn.createStatement();
>       stmt.executeUpdate(query);

Extended SQL is delimited with curly braces ("`{}`") to differentiate it from common SQL. Comments are preceded by two hyphens, and are ended by a new line ("`\n`"). The entire Extended SQL sequence, including comments, SQL, and Extended SQL, is placed within double quotes and passed to the `execute()` method of a `Statement` object. Here is Extended SQL used as part of a `CallableStatement`:

>        CallableStatement cstmt =
>         conn.prepareCall("{ ? = call func_squareInt(?)}");

This example shows that you can nest extended SQL expressions:

>        select {fn dayname({fn now()})}

You can retrieve lists of supported Extended SQL functions from a DatabaseMetaData object. This example shows how to list all the functions a JDBC driver supports:

>        DatabaseMetaData md = conn.getMetaData();
>        System.out.println("Numeric functions:     " +
>           md.getNumericFunctions());
>       System.out.println("\nString functions:    " +
>           md.getStringFunctions());
>       System.out.println("\nTime/date functions: " +
>           md.getTimeDateFunctions());
>       System.out.println("\nSystem functions:    " +
>           md.getSystemFunctions());
>       conn.close();

# Overview of JDBC 2.0 for Oracle

The following JDBC 2.0 features are implemented in WebLogic jDriver for Oracle:

- BLOBs (Binary Large Objects)—WebLogic Server can now handle this Oracle data type.
- CLOBs (Character Large Objects)—WebLogic Server can now handle this Oracle data type.
- Character Streams for both ASCII and Unicode characters—A better way to handle characters streams, as streams of characters instead of as byte arrays.
- Batch Updates—You can now send multiple statements to the database as a single unit.

These features have been added to the existing JDBC functionality previously available in the WebLogic Server. All of your existing code for previous drivers will work with the new WebLogic jDriver for Oracle.

Note: WebLogic Server also supports Oracle extension methods for prepared statements, callable statements, arrays, STRUCTs, and REFs. However, to use these extensions, you must use the Oracle Thin Driver to connect to your database.

# Configuration Required to Support JDBC 2.0

WebLogic Server Version runs on an SDK that provides the Java 2 environment required by JDBC 2.0. For a complete list of supported configurations, see the WebLogic Server Supported Configurations page.

# BLOBs and CLOBs

The BLOB (Binary Large Object) and CLOB (Character Large Object) data types were made available with the release of Oracle version 8. The JDBC 2.0 specification and WebLogic Server also support these data types. This section contains information about using these data types.

## Transaction Boundaries

BLOBs and CLOBs in Oracle behave differently than other data types in regards to transactional boundaries (statements issued before an SQL commit or rollback statement). in that a BLOB or CLOB will be come inactive as soon as a transaction is committed. If AutoCommit is set to TRUE, the transaction will be automatically committed after each command issued on the connection, including SELECT statements. For this reason you will need to set AutoCommit to false if you need to have a BLOB or CLOB available across multiple SQL statements. You will then need to manually commit (or rollback) the transactions at the appropriate time. To set AutoCommit to false, enter the following command:

>     conn.setAutoCommit(false); // where conn is your connection object

## BLOBs

The BLOB data type, available with Oracle version 8, allows you to store and retrieve large binary objects in an Oracle table. Although BLOBs are defined as part of the JDBC 2.0 specification, the specification does not provide methods to update BLOB columns in a table. The BEA WebLogic implementation of BLOBs, however, does provide this functionality by means of an extension to JDBC 2.0.

### Connection Properties

  `weblogic.oci.selectBlobChunkSize`

  This property sets the size of an internal buffer used for sending bytes or characters to an I/O stream. When the Chunk size is reached, the driver will perform an implicit `flush()` operation, which will cause the data to be sent to the DBMS.

  Explicitly setting this value can be useful in controlling memory usage on the client.

  If the value of this property is not explicitly set, a default value of `65534` will be used.

  Set this property by passing it to the Connection object as a property. For example, this code fragment sets `weblogic.oci.selectBlobChunkSize` to 1200:

  `Properties props = new Properties();
  props.put("user", "scott");
  props.put("password", "tiger");
  props.put("server", "DEMO");`

  `props.put ("weblogic.oci.selectBlobChunkSize","1200");`

  `Driver myDriver = (Driver)
  Class.forName("weblogic.jdbc.oci.Driver").newInstance();`

  `Connection conn =
  driver.connect("jdbc:weblogic:oracle:myServer", props);`

  `weblogic.oci.insertBlobChunkSize`

  This property specifies the buffer size (in bytes) of input streams used internally by the driver.

  Set this property to a positive integer to insert BLOBs into an Oracle DBMS with the BLOB chunking feature. By default, this property is set to zero (0), which means that BLOB chunking is turned off.

### Import Statements

To use the BLOB functionality described in this section, import the following classes in your client code:

>     import java.sql.*;
>     import java.util.*;
>     import java.io.*;
>     import weblogic.jdbc.common.*;

### Initializing a BLOB Field

When you first insert a row containing a BLOB data type, you must insert the row with an "empty" BLOB before the field can be updated with real data. You can insert an empty BLOB with the Oracle `EMPTY_BLOB()` function.

To initialize a BLOB field:

1. Create a table with one or more columns defined as a BLOB data type.
2. Insert a new row with an empty BLOB column, using the Oracle `EMPTY_BLOB()` function:

>     stmt.execute("INSERT into myTable values (1,EMPTY_BLOB()");

3. Obtain a "handle" to the BLOB column:

>     java.sql.Blob myBlob = null;
>     Statement stmt2 = conn.createStatement();
>     stmt2.execute("SELECT myBlobColumn from myTable
>       where pk = 1 for update");
>     ResultSet rs = stmt2.getResultSet();
>     rs.next() {
>       myBlob = rs.getBlob("myBlobColumn");
>       // do something with the BLOB
>     }

4. You can now write data to the BLOB. Continue with the next section, Writing Binary Data to a BLOB.

### Writing Binary Data to a BLOB

To write binary data to a `BLOB` column:

1. Obtain a handle to the BLOB field as described above, in Initializing a BLOB Field, step 3.
2. Create an InputStream object containing the binary data.

>     java.io.InputStream is = // create your input stream

3. Create an output stream to which you write your BLOB data. Note that you must cast your BLOB object to `weblogic.jdbc.common.OracleBlob`.

>     java.io.OutputStream os =
>     ((weblogic.jdbc.common.OracleBlob) myBlob).getBinaryOutputStream();

4. Write the input stream containing your binary data to the output stream. The write operation is finalized when you call the `flush()` method on the `OutputStream` object.

>     byte[] inBytes = new byte[65534]; // see note below
>     		int numBytes = is.read(inBytes);
>     while (numBytes > 0) {
>       os.write(inBytes, 0, numBytes);
>       numBytes = is.read(inBytes);
>     }
>     os.flush();

Note: The value `[65534]` in the above code presumes that you have not set the `weblogic.oci.select.BlobChunkSize` property whose default is `65534`. If you have set this property, setting the byte[] value to match the value set in the `weblogic.oci.select.BlobChunkSize property` will provide the most efficient handling of the data. For more information about this property, see Connection Properties.

5. Clean up:

>     os.close();
>     pstmt.close();
>     conn.close();

### Writing a BLOB Object

Writing a BLOB object to a table is performed with Prepared Statements. For example, to write the `myBlob` object to the table `myOtherTable`:

>     PreparedStatement pstmt = conn.preparedStatement(
>         "UPDATE myOtherTable SET myOtherBlobColumn = ? WHERE id = 12");

>     pstmt.setBlob(1, myBlob);

### Reading BLOB Data

When you retrieve a BLOB column with the `getBlob()` method and then use a `ResultSet` from a SQL SELECT statement, only a pointer to the BLOB data is returned; the binary data is not actually transferred to the client until the `getBinaryStream()` method is called and the data is read into the stream object.

To read BLOB data from an Oracle table:

1. Execute a SELECT statement:

>     stmt2.execute("SELECT myBlobColumn from myTable");

2. Use the results from the SELECT statement.

>     int STREAM_SIZE = 10;
>     byte[] r = new byte[STREAM_SIZE];

>     ResultSet rs = stmt2.getResultSet();
>     java.sql.Blob myBlob = null;
>     while (rs.next) {
>       myBlob = rs.getBlob("myBlobColumn");

>      java.io.InputStream readis = myBlob.getBinaryStream();

>      for (int i=0 ; i < STREAM_SIZE ; i++) {
>           r[i] = (byte) readis.read();
>          System.out.println("output [" + i + "] = " + r[i]);
>      }

3. Clean up:

>     rs.close();
>     stmt2.close();

Note: You can also use a `CallableStatement` to generate a `ResultSet`. This `ResultSet` can then be used as shown above. See your JDK documentation under `java.sql.CallableStatment` for details.

### Other Methods

The following methods of the `java.sql.Blob` interface are also implemented in the WebLogic Server JDBC 2.0 driver. For details, see your JDK documentation:

- `getBinaryStream()`
- `getBytes()`
- `length()`

The `position()` method is not implemented.

## CLOBs

The CLOB data type, available with Oracle version 8, enables storage of large character strings in an Oracle table. Since the JDBC 2.0 specification does not include functionality to directly update CLOB columns, BEA has implemented the methods `getAsciiOutputStream()` (for ASCII data) and `getCharacterOutputStream()` (for Unicode data) to insert or update a CLOB.

### Codeset Support

Depending on which version of the Oracle Server and client you are using you may need to set one of the following properties by passing them to the Connection object when you establish your connection the DBMS in your Java client code.

  `weblogic.codeset`

  This property allows you to set a codeset from within your Java code. You must also set the `NLS_LANG` environment variable for the Oracle client.

  `weblogic.oci.ncodeset`

  This property sets the National codeset used by the Oracle server. You must also set the `NLS_NCHAR` environment variable for the Oracle client.

  `weblogic.oci.codeset_width`

  This property tells the WebLogic Server which type you are using. Note the following restrictions on codeset use:

  Possible Values:

  `0` for variable-width codesets

  `1` for fixed-width codesets (`1` is the default value)

  `2` or `3` for the width, in bytes, of the codeset

  `weblogic.oci.ncodeset_width`

  If you are using one of Oracle's National codesets, specify the width of that codeset with this property. Note the following restrictions on codeset use:

  Possible Values:

  `0` for variable-width codesets

  `1` for fixed-width codesets (1 is the default value)

  `2` or `3` for the width, in bytes, of the codeset

### Initializing a CLOB Field

When you first insert a row containing a CLOB data type, you must insert the row with an "empty" CLOB before the field can be updated with real data. You can insert an empty CLOB with the Oracle `EMPTY_CLOB()` function.

To initialize a CLOB column:

1. Create a table with one or more columns defined as a CLOB data type.
2. Insert a new row with an empty CLOB column, using the Oracle `EMPTY_CLOB()` function:

>     stmt.execute("INSERT into myTable VALUES (1,EMPTY_CLOB()");

3. Obtain an object for the CLOB column:

>     java.sql.Clob myClob = null;
>     Statement stmt2 = conn.createStatement();
>     stmt2.execute("SELECT myClobColumn from myTable
>       where pk = 1 for update");
>     ResultSet rs = stmt2.getResultSet();
>     while (rs.next) {
>       myClob = rs.getClob("myClobColumn");
>     }

4. You can now write character data to the CLOB. If your data is in the ASCII format, Continue with the next section, Writing ASCII Data to a CLOB. If your character data is in Unicode format, see Writing Unicode Data to a CLOB

### Writing ASCII Data to a CLOB

To write ASCII character data to a `CLOB` column:

1. Obtain a "handle" to the CLOB as described above, in Initializing a CLOB Field, step 3.
2. Create an object containing the character data:

>     String s = // some ASCII data

3. Create an ASCII output stream to which you write your CLOB characters. Note that you must cast your CLOB object to weblogic.jdbc.common.OracleClob.

>     java.io.OutputStream os =
>     ((weblogic.jdbc.common.OracleClob) myclob).getAsciiOutputStream();

4. Write the input stream containing your ASCII data to the output stream. The write operation is finalized when you call the `flush()` method on the `OutputStream` object.

>     byte[] b = s.getBytes("ASCII");

>     os.write(b);
>     os.flush();

5. Clean up:

>     os.close();
>     pstmt.close();
>     conn.close();

### Writing Unicode Data to a CLOB

To write Unicode character data to a `CLOB` column:

1. Obtain a "handle" to the CLOB as described earlier, in step 3 of "Initializing a CLOB Field."
2. Create an object containing the character data:

>     String s = // some Unicode character data

3. Create a character output stream to which you write your CLOB characters. Note that you must cast your CLOB object to weblogic.jdbc.common.OracleClob.

>     java.io.Writer wr =
>     ((weblogic.jdbc.common.OracleClob) myclob).getCharacterOutputStream();

4. Write the input stream containing your ASCII data to the output stream. The write operation is finalized when you call the `flush()` method on the `OutputStream` object.

>     char[] b = s.toCharArray(); // converts 's' to a character array

>     wr.write(b);
>     wr.flush();

5. Clean up:

>     wr.close();
>     pstmt.close();
>     conn.close();

### Writing CLOB Objects

Writing a CLOB object to a table is performed with Prepared Statements. For example, to write the `myClob` object to the table `myOtherTable`:

>     PreparedStatement pstmt = conn.preparedStatement(
>         "UPDATE myOtherTable SET myOtherClobColumn = ? WHERE id = 12");

>     pstmt.setClob(1, myClob);

### Updating a CLOB Value Using a Prepared Statement

If you use a prepared statement to update a CLOB and the new value is shorter than the previous value, the CLOB will retain the characters that were not specifically replaced during the update. For example, if the current value of a CLOB is `abcdefghij` and you update the CLOB using a prepared statement with `zxyw`, the value in the CLOB is updated to `zxywefghij`. To correct values updated with a prepared statement, you should use the `dbms_lob.trim` procedure to remove the excess characters left after the update. See the Oracle documentation for more information about the `dbms_lob.trim` procedure.

### Reading CLOB Data

When a CLOB column is retrieved using a result set from a SQL SELECT statement, only a pointer to the CLOB data is returned; the actual data is not transferred to the client with the result set until the `getAsciiStream()` method is called and the characters are read in to the stream.

To read CLOB data from an Oracle table:

1. Execute a SELECT statement:

>     java.sql.Clob myClob = null;
>     Statement stmt2 = conn.createStatement();
>     stmt2.execute("SELECT myClobColumn from myTable");

2. Use the results from the SELECT statement:

>     ResultSet rs = stmt2.getResultSet();

>     while (rs.next) {
>       myClob = rs.getClob("myClobColumn");
>       java.io.InputStream readClobis =
>           myReadClob.getAsciiStream();
>       char[] c = new char[26];
>       for (int i=0 ; i < 26  ; i++) {
>           c[i] = (char) readClobis.read();
>           System.out.println("output [" + i + "] = " + c[i]);
>       }
>     }

3. Clean up:

>     rs.close();
>     stmt2.close();

Note: You can also use a `CallableStatement` to generate a `ResultSet`. This `ResultSet` can then be used as shown above. See your JDK documentation under `java.sql.CallableStatment` for details.

### Other Methods

The following methods of the `java.sql.Clob` interface are also implemented in the WebLogic Server (a JDBC 2.0 driver):

- `getSubString()`
- `length()`

For details about these methods, see the JDK documentation.

Note: The `position()` method is not implemented.

# Character and ASCII Streams

Some new methods in the JDBC 2.0 specification allow character and ASCII streams to be manipulated as characters rather than as bytes, as in earlier versions. The following methods for handling character and ASCII streams are implemented in WebLogic Server.

## Unicode Character Streams

  `getCharacterStream()`

  The `java.sql.ResultSet` interface uses this method for reading Unicode streams as the Java type `java.io.Reader`. This method replaces the deprecated `getUnicodeStream()` method.

  `setCharacterStream()`

  The `java.sql.PreparedStatement` interface uses this method for writing a `java.io.Reader` object. This method replaces the deprecated `setUnicodeStream()` method.

## ASCII Character Streams

  `getAsciiStream()`

  The `java.sql.ResultSet` interface uses this method for reading ASCII streams as the Java type `java.io.InputStream`.

  `setAsciiStream()`

  The `java.sql.PreparedStatement` interface uses this method for writing a `java.io.InputStream` object.

For details about using these methods, see your JDK documentation.

# Batch Updates

Batch updates are a feature of JDBC 2.0 that allows you to send multiple SQL update statements to the DBMS as a single unit. Depending on the application, this can provide improved performance over sending multiple update statements individually. The Batch update feature is available in the `Statement` interface and requires the use of SQL statements that do not return a result set.

The following SQL statements can be used with Batch updates:

- `INSERT INTO`
- `UPDATE`
- `DELETE`
- `CREATE TABLE`
- `DROP TABLE`
- `ALTER TABLE`

## Using Batch Updates

This is the basic procedure for using Batch updates:

1. Get a connection from a connection pool that uses the WebLogic jDriver for Oracle as described in Using the Connection Pool in an Application.
2. Create a statement object using the `createStatement()` method. For example:

>     Statement stmt = conn.createStatement();

3. Use the `addBatch()` method to add SQL statements to the batch. These statements are not sent to the DBMS until the `executeBatch()` method is called. For example:

>     stmt.addBatch("INSERT INTO batchTest VALUES ('JOE', 20,35)");
>     stmt.addBatch("INSERT INTO batchTest VALUES ('Bob', 30,44)");
>     stmt.addBatch("INSERT INTO batchTest VALUES ('Ed',  34,22)");

4. Use the `executeBatch()` method to send the batch to the DBMS for processing. For example:

>     stmt.executeBatch();

If any of the statements fail an exception is thrown, and none of the statements is executed.

To use batch updates with for `PreparedStatements` and `CallableStatements`, create the statement normally, set the input parameters, and then call the `addBatch()` method with no arguments. Repeat for each additional set of input parameter values (each update), and then call `executeBatch()`. For example:

1. Get a connection from a connection pool that uses the WebLogic jDriver for Oracle as described in Using the Connection Pool in an Application.
2. Create a PreparedStatement object using the `prepareStatement()` method. For example:

>     PreparedStatement pstmt = conn.prepareStatement("INSERT INTO batchTest VALUES (?,?,?)");

3. Set the input parameters and then call `addBatch()` to add an update to the batch. These statements are not sent to the DBMS until the `executeBatch()` method is called. For example:

>     pstmt.setString(1,"Joe");
>     pstmt.setInt(2,20);
>     pstmt.setInt(3,35);
>     pstmt.addBatch();

4. Repeat for each additional set of input parameter values:

>     pstmt.setString(1,"Bob");
>     pstmt.setInt(2,30);
>     pstmt.setInt(3,44);
>     pstmt.addBatch();

>     pstmt.setString(1,"Ed");
>     pstmt.setInt(2,34);
>     pstmt.setInt(3,22);
>     pstmt.addBatch();

5. Use the `executeBatch()` method to send the batch to the DBMS for processing. For example:

>     pstmt.executeBatch();

If any of the prepared statements fail, an exception is thrown and none of the statements is executed.

Batch updates also work with `CallableStatement` objects for stored procedures. Each stored procedure must return an update count. The stored procedure cannot take any OUT or INOUT parameters.

## Clearing the Batch

You may clear a batch of statements that was created with the `addBatch()` method, by using the `clearBatch()` method. For example:

>     stmt.clearBatch();

## Update Counts

According to the JDBC 2.0 specification, the `executeBatch()` method should return an array of Integers containing the number of rows updated for each Statement. The Oracle DBMS, however, does not supply this information to the driver. Instead, the Oracle DBMS returns `-2` for all updates.

# New Date Methods

The following methods have a signature which takes a `java.util.Calendar` object as a parameter. `java.util.Calendar` allows you to specify time zone and location information that is used to translate dates. Consult your JDK API guide for details about using the `java.util.Calendar` class.

>     java.sql.ResultSet.getDate(int columnIndex, Calendar cal)

  (returns a `java.sql.Date` object)

>     java.sql.PreparedStatement.setDate
>       (int parameterIndex, Date x, Calendar cal)