38 - JDBC Developer's Guide and Reference
38 - JDBC Developer's Guide and Reference
38 - JDBC Developer's Guide and Reference
Release 2 (9.2)
March 2002
Part No. A96654-01
Oracle9i JDBC Developer’s Guide and Reference, Release 2 (9.2)
Primary Author: Elizabeth Hanes Perry, Mike Sanko, Brian Wright, Thomas Pfaeffle
Contributors: Magdi Morsi, Ron Peterson, Ekkehard Rohwedder, Ashok Shivarudraiah, Catherine
Wong, Ed Shirk, Sunil Kunisetty, Joyce Yang, Mehul Bastawala, Luxi Chidambaran, Srinath
Krishnaswamy, Rajkumar Irudayaraj, Scott Urman, Jerry Schwarz, Steve Ding, Soulaiman Htite, Douglas
Surber, Anthony Lai, Paul Lo, Prabha Krishna, Ellen Barnes, Susan Kraft, Sheryl Maring, Angie Long
The Programs (which include both the software and documentation) contain proprietary information of
Oracle Corporation; they are provided under a license agreement containing restrictions on use and
disclosure and are also protected by copyright, patent and other intellectual and industrial property
laws. Reverse engineering, disassembly or decompilation of the Programs, except to the extent required
to obtain interoperability with other independently created software or as specified by law, is prohibited.
The information contained in this document is subject to change without notice. If you find any problems
in the documentation, please report them to us in writing. Oracle Corporation does not warrant that this
document is error-free. Except as may be expressly permitted in your license agreement for these
Programs, no part of these Programs may be reproduced or transmitted in any form or by any means,
electronic or mechanical, for any purpose, without the express written permission of Oracle Corporation.
If the Programs are delivered to the U.S. Government or anyone licensing or using the programs on
behalf of the U.S. Government, the following notice is applicable:
Restricted Rights Notice Programs delivered subject to the DOD FAR Supplement are "commercial
computer software" and use, duplication, and disclosure of the Programs, including documentation,
shall be subject to the licensing restrictions set forth in the applicable Oracle license agreement.
Otherwise, Programs delivered subject to the Federal Acquisition Regulations are "restricted computer
software" and use, duplication, and disclosure of the Programs shall be subject to the restrictions in FAR
52.227-19, Commercial Computer Software - Restricted Rights (June, 1987). Oracle Corporation, 500
Oracle Parkway, Redwood City, CA 94065.
The Programs are not intended for use in any nuclear, aviation, mass transit, medical, or other inherently
dangerous applications. It shall be the licensee's responsibility to take all appropriate fail-safe, backup,
redundancy, and other measures to ensure the safe use of such applications if the Programs are used for
such purposes, and Oracle Corporation disclaims liability for any damages caused by such use of the
Programs.
Oracle is a registered trademark, and Oracle9i, Oracle8i, Oracle8, Oracle7, PL/SQL, SQL*Plus, and
Oracle Store are trademarks or registered trademarks of Oracle Corporation. Other names may be
trademarks of their respective owners.
Contents
Preface.......................................................................................................................................................... xix
Intended Audience ............................................................................................................................... xx
Documentation Accessibility .............................................................................................................. xx
Organization ......................................................................................................................................... xxi
Related Documentation ..................................................................................................................... xxii
Conventions........................................................................................................................................ xxvi
1 Overview
Introduction ......................................................................................................................................... 1-2
What is JDBC? ............................................................................................................................... 1-2
JDBC versus SQLJ......................................................................................................................... 1-2
Overview of the Oracle JDBC Drivers............................................................................................ 1-4
Common Features of Oracle JDBC Drivers .............................................................................. 1-4
JDBC Thin Driver.......................................................................................................................... 1-5
JDBC OCI Driver .......................................................................................................................... 1-6
JDBC Server-Side Thin Driver .................................................................................................... 1-7
JDBC Server-Side Internal Driver .............................................................................................. 1-8
Choosing the Appropriate Driver .............................................................................................. 1-8
Overview of Application and Applet Functionality.................................................................. 1-10
Application Basics ...................................................................................................................... 1-10
Applet Basics ............................................................................................................................... 1-10
Oracle Extensions ....................................................................................................................... 1-11
iii
Package oracle.jdbc..................................................................................................................... 1-11
Server-Side Basics ............................................................................................................................. 1-13
Session and Transaction Context.............................................................................................. 1-13
Connecting to the Database....................................................................................................... 1-13
Environments and Support............................................................................................................. 1-14
Supported JDK and JDBC Versions ......................................................................................... 1-14
JNI and Java Environments....................................................................................................... 1-14
JDBC and IDEs ............................................................................................................................ 1-15
Changes At This Release ................................................................................................................. 1-16
2 Getting Started
Requirements and Compatibilities for Oracle JDBC Drivers.................................................... 2-2
Verifying a JDBC Client Installation .............................................................................................. 2-5
Check Installed Directories and Files......................................................................................... 2-5
Check the Environment Variables.............................................................................................. 2-6
Make Sure You Can Compile and Run Java............................................................................. 2-8
Determine the Version of the JDBC Driver ............................................................................... 2-8
Testing JDBC and the Database Connection: JdbcCheckup ................................................... 2-9
3 Basic Features
First Steps in JDBC ............................................................................................................................. 3-2
Import Packages............................................................................................................................ 3-2
Register the JDBC Drivers ........................................................................................................... 3-3
Open a Connection to a Database .............................................................................................. 3-3
Create a Statement Object.......................................................................................................... 3-11
Execute a Query and Return a Result Set Object ................................................................... 3-11
Process the Result Set ................................................................................................................. 3-11
Close the Result Set and Statement Objects ............................................................................ 3-12
Make Changes to the Database................................................................................................. 3-12
Commit Changes ........................................................................................................................ 3-13
Close the Connection.................................................................................................................. 3-14
Sample: Connecting, Querying, and Processing the Results ................................................... 3-15
Datatype Mappings .......................................................................................................................... 3-16
Table of Mappings ...................................................................................................................... 3-16
Notes Regarding Mappings ...................................................................................................... 3-18
iv
Java Streams in JDBC....................................................................................................................... 3-20
Streaming LONG or LONG RAW Columns .......................................................................... 3-20
Streaming CHAR, VARCHAR, or RAW Columns................................................................ 3-25
Data Streaming and Multiple Columns .................................................................................. 3-26
Streaming LOBs and External Files ......................................................................................... 3-27
Closing a Stream ......................................................................................................................... 3-29
Notes and Precautions on Streams .......................................................................................... 3-29
Stored Procedure Calls in JDBC Programs .................................................................................. 3-32
PL/SQL Stored Procedures....................................................................................................... 3-32
Java Stored Procedures .............................................................................................................. 3-33
Processing SQL Exceptions............................................................................................................. 3-34
Retrieving Error Information .................................................................................................... 3-34
Printing the Stack Trace............................................................................................................. 3-35
v
Pre-JDK1.4 Savepoint Support.................................................................................................... 5-8
vi
Limitations of the Oracle 8.0.x and 7.3.x JDBC Drivers ........................................................ 7-18
Using Result Set Meta Data Extensions ....................................................................................... 7-19
vii
Reading and Writing Data with a ORAData Implementation............................................. 9-23
Additional Uses for ORAData .................................................................................................. 9-26
The Deprecated CustomDatum Interface ............................................................................... 9-27
Object-Type Inheritance .................................................................................................................. 9-29
Creating Subtypes....................................................................................................................... 9-29
Implementing Customized Classes for Subtypes .................................................................. 9-30
Retrieving Subtype Objects ....................................................................................................... 9-37
Creating Subtype Objects .......................................................................................................... 9-40
Sending Subtype Objects ........................................................................................................... 9-41
Accessing Subtype Data Fields ................................................................................................. 9-41
Inheritance Meta Data Methods ............................................................................................... 9-43
Using JPublisher to Create Custom Object Classes ................................................................... 9-45
JPublisher Functionality ............................................................................................................ 9-45
JPublisher Type Mappings ........................................................................................................ 9-45
Describing an Object Type.............................................................................................................. 9-49
Functionality for Getting Object Meta Data............................................................................ 9-49
Steps for Retrieving Object Meta Data..................................................................................... 9-50
SQLJ Object Types............................................................................................................................ 9-52
Creating a SQLJ Object Type in SQL Representation............................................................ 9-53
Inserting an Instance of a SQLJ Object Type........................................................................... 9-59
Retrieving Instances of a SQLJ Object Type............................................................................ 9-60
Meta Data Methods for SQLJ Object Types ............................................................................ 9-61
SQLJ Object Types and Custom Object Types Compared.................................................... 9-62
viii
11 Working with Oracle Collections
Oracle Extensions for Collections (Arrays).................................................................................. 11-2
Choices in Materializing Collections ....................................................................................... 11-2
Creating Collections ................................................................................................................... 11-3
Creating Multi-Level Collection Types ................................................................................... 11-4
Overview of Collection (Array) Functionality ............................................................................ 11-5
Array Getter and Setter Methods ............................................................................................. 11-5
ARRAY Descriptors and ARRAY Class Functionality ......................................................... 11-6
ARRAY Performance Extension Methods.................................................................................... 11-8
Accessing oracle.sql.ARRAY Elements as Arrays of Java Primitive Types ....................... 11-8
ARRAY Automatic Element Buffering.................................................................................... 11-9
ARRAY Automatic Indexing .................................................................................................... 11-9
Creating and Using Arrays............................................................................................................ 11-11
Creating ARRAY Objects and Descriptors ........................................................................... 11-11
Retrieving an Array and Its Elements ................................................................................... 11-15
Passing Arrays to Statement Objects ..................................................................................... 11-22
Using a Type Map to Map Array Elements................................................................................ 11-25
Custom Collection Classes with JPublisher.............................................................................. 11-27
12 Performance Extensions
Update Batching................................................................................................................................ 12-2
Overview of Update Batching Models .................................................................................... 12-2
Oracle Update Batching............................................................................................................. 12-4
Standard Update Batching ...................................................................................................... 12-10
Premature Batch Flush............................................................................................................. 12-18
Additional Oracle Performance Extensions .............................................................................. 12-20
Oracle Row Prefetching ........................................................................................................... 12-20
Defining Column Types .......................................................................................................... 12-23
DatabaseMetaData TABLE_REMARKS Reporting ............................................................. 12-26
ix
Creating Scrollable or Updatable Result Sets ............................................................................. 13-8
Specifying Result Set Scrollability and Updatability............................................................. 13-8
Result Set Limitations and Downgrade Rules...................................................................... 13-10
Positioning and Processing in Scrollable Result Sets ............................................................. 13-13
Positioning in a Scrollable Result Set..................................................................................... 13-13
Processing a Scrollable Result Set........................................................................................... 13-15
Updating Result Sets...................................................................................................................... 13-18
Performing a DELETE Operation in a Result Set................................................................. 13-18
Performing an UPDATE Operation in a Result Set ............................................................. 13-19
Performing an INSERT Operation in a Result Set ............................................................... 13-21
Update Conflicts ....................................................................................................................... 13-23
Fetch Size .......................................................................................................................................... 13-24
Setting the Fetch Size................................................................................................................ 13-24
Use of Standard Fetch Size versus Oracle Row-Prefetch Setting....................................... 13-25
Refetching Rows ............................................................................................................................. 13-26
Seeing Database Changes Made Internally and Externally ................................................... 13-27
Seeing Internal Changes .......................................................................................................... 13-27
Seeing External Changes.......................................................................................................... 13-28
Visibility versus Detection of External Changes.................................................................. 13-29
Summary of Visibility of Internal and External Changes................................................... 13-30
Oracle Implementation of Scroll-Sensitive Result Sets ....................................................... 13-30
Summary of New Methods for Result Set Enhancements ..................................................... 13-32
Modified Connection Methods............................................................................................... 13-32
New Result Set Methods.......................................................................................................... 13-32
Statement Methods................................................................................................................... 13-35
Database Meta Data Methods ................................................................................................. 13-35
14 Statement Caching
About Statement Caching ............................................................................................................... 14-2
Basics of Statement Caching...................................................................................................... 14-2
Implicit Statement Caching ....................................................................................................... 14-2
Explicit Statement Caching ....................................................................................................... 14-3
Using Statement Caching ................................................................................................................ 14-5
Enabling and Disabling Statement Caching ........................................................................... 14-5
Checking for Statement Creation Status.................................................................................. 14-6
x
Physically Closing a Cached Statement .................................................................................. 14-7
Using Implicit Statement Caching ........................................................................................... 14-7
Using Explicit Statement Caching............................................................................................ 14-9
15 Distributed Transactions
Overview ............................................................................................................................................ 15-2
Distributed Transaction Components and Scenarios............................................................ 15-3
Distributed Transaction Concepts............................................................................................ 15-3
Switching Between Global and Local Transactions............................................................... 15-5
Oracle XA Packages ................................................................................................................... 15-7
XA Components ................................................................................................................................ 15-8
XA Data Source Interface and Oracle Implementation......................................................... 15-8
XA Connection Interface and Oracle Implementation.......................................................... 15-9
XA Resource Interface and Oracle Implementation ............................................................ 15-10
XA Resource Method Functionality and Input Parameters ............................................... 15-11
XA ID Interface and Oracle Implementation........................................................................ 15-16
Error Handling and Optimizations ............................................................................................. 15-18
XA Exception Classes and Methods ...................................................................................... 15-18
Mapping between Oracle Errors and XA Errors.................................................................. 15-19
XA Error Handling ................................................................................................................... 15-19
Oracle XA Optimizations ........................................................................................................ 15-20
Implementing a Distributed Transaction................................................................................... 15-21
Summary of Imports for Oracle XA....................................................................................... 15-21
Oracle XA Code Sample .......................................................................................................... 15-21
xi
Pooled Connection Interface and Oracle Implementation ................................................. 16-13
Creating a Connection Pool Data Source and Connecting ................................................. 16-14
Connection Caching ....................................................................................................................... 16-16
Overview of Connection Caching .......................................................................................... 16-16
Typical Steps in Using a Connection Cache ......................................................................... 16-20
Oracle Connection Cache Specification: OracleConnectionCache Interface.................... 16-23
Oracle Connection Cache Implementation: OracleConnectionCacheImpl Class ........... 16-24
Oracle Connection Event Listener: OracleConnectionEventListener Class..................... 16-28
18 Advanced Topics
JDBC and Globalization Support .................................................................................................. 18-2
How JDBC Drivers Perform Globalization Support Conversions ...................................... 18-3
xii
Globalization Support and Object Types ................................................................................ 18-4
SQL CHAR Data Size Restrictions with the Thin Driver...................................................... 18-6
JDBC Client-Side Security Features.............................................................................................. 18-8
JDBC Support for Oracle Advanced Security......................................................................... 18-8
JDBC Support for Login Authentication ................................................................................. 18-9
JDBC Support for Data Encryption and Integrity................................................................ 18-10
JDBC in Applets.............................................................................................................................. 18-15
Connecting to the Database through the Applet ................................................................. 18-15
Connecting to a Database on a Different Host Than the Web Server ............................... 18-17
Using Applets with Firewalls ................................................................................................. 18-20
Packaging Applets.................................................................................................................... 18-23
Specifying an Applet in an HTML Page ............................................................................... 18-24
JDBC in the Server: the Server-Side Internal Driver............................................................... 18-26
Connecting to the Database with the Server-Side Internal Driver.................................... 18-26
Exception-Handling Extensions for the Server-Side Internal Driver................................ 18-28
Session and Transaction Context for the Server-Side Internal Driver .............................. 18-30
Testing JDBC on the Server ..................................................................................................... 18-30
Loading an Application into the Server ................................................................................ 18-32
Server-Side Character Set Conversion of oracle.sql.CHAR Data ...................................... 18-33
xiii
20 Reference Information
Valid SQL-JDBC Datatype Mappings .......................................................................................... 20-2
Supported SQL and PL/SQL Datatypes ....................................................................................... 20-5
Embedded SQL92 Syntax .............................................................................................................. 20-10
Time and Date Literals............................................................................................................. 20-10
Scalar Functions ........................................................................................................................ 20-12
LIKE Escape Characters........................................................................................................... 20-13
Outer Joins ................................................................................................................................. 20-13
Function Call Syntax ................................................................................................................ 20-14
SQL92 to SQL Syntax Example............................................................................................... 20-14
Oracle JDBC Notes and Limitations ........................................................................................... 20-16
CursorName .............................................................................................................................. 20-16
SQL92 Outer Join Escapes ....................................................................................................... 20-16
PL/SQL TABLE, BOOLEAN, and RECORD Types ............................................................ 20-16
IEEE 754 Floating Point Compliance ..................................................................................... 20-17
Catalog Arguments to DatabaseMetaData Calls ................................................................. 20-17
SQLWarning Class.................................................................................................................... 20-17
Bind by Name............................................................................................................................ 20-17
Related Information ....................................................................................................................... 20-19
Oracle JDBC Drivers and SQLJ............................................................................................... 20-19
Java Technology ........................................................................................................................ 20-19
A Row Set
Introduction ......................................................................................................................................... A-2
Row Set Setup and Configuration................................................................................................... A-4
Runtime Properties for Row Set ...................................................................................................... A-5
Row Set Listener ................................................................................................................................. A-6
Traversing Through the Rows .......................................................................................................... A-8
Cached Row Set................................................................................................................................... A-9
CachedRowSet Constraints ....................................................................................................... A-13
JDBC Row Set.................................................................................................................................... A-15
xiv
General JDBC Messages.................................................................................................................... B-3
JDBC Messages Sorted by ORA Number.................................................................................. B-3
JDBC Messages Sorted Alphabetically ...................................................................................... B-9
HeteroRM XA Messages.................................................................................................................. B-15
HeteroRM XA Messages Sorted by ORA Number................................................................ B-15
HeteroRM XA Messages Sorted Alphabetically .................................................................... B-16
TTC Messages.................................................................................................................................... B-17
TTC Messages Sorted by ORA Number.................................................................................. B-17
TTC Messages Sorted Alphabetically ...................................................................................... B-19
Index
xv
xvi
Send Us Your Comments
Oracle9i JDBC Developer’s Guide and Reference, Release 2 (9.2)
Part No. A96654-01
Oracle Corporation welcomes your comments and suggestions on the quality and usefulness of this
document. Your input is an important part of the information used for revision.
■ Did you find any errors?
■ Is the information clearly presented?
■ Do you need more information? If so, where?
■ Are the examples correct? Do you need more examples?
■ What features did you like most?
If you find any errors or have any other suggestions for improvement, please indicate the document
title and part number, and the chapter, section, and page number (if available). You can send com-
ments to us in the following ways:
■ Electronic mail: [email protected]
■ FAX: (650) 506-7225 Attn: Java Platform Group, Information Development Manager
■ Postal service:
Oracle Corporation
Java Platform Group, Information Development Manager
500 Oracle Parkway, Mailstop 4op9
Redwood Shores, CA 94065
USA
If you would like a reply, please give your name, address, telephone number, and (optionally) elec-
tronic mail address.
If you have problems with the software, please contact your local Oracle Support Services.
xvii
xviii
Preface
This preface introduces you to the Oracle9i JDBC Developer’s Guide and Reference,
discussing the intended audience, structure, and conventions of this document. A
list of related Oracle documents is also provided.
This preface contains these topics:
■ Intended Audience
■ Documentation Accessibility
■ Organization
■ Related Documentation
■ Conventions
xix
Intended Audience
This manual is intended for anyone with an interest in JDBC programming but
assumes at least some prior knowledge of the following:
■ Java
■ SQL
■ Oracle PL/SQL
■ Oracle databases
Documentation Accessibility
Our goal is to make Oracle products, services, and supporting documentation
accessible, with good usability, to the disabled community. To that end, our
documentation includes features that make information available to users of
assistive technology. This documentation is available in HTML format, and contains
markup to facilitate access by the disabled community. Standards will continue to
evolve over time, and Oracle Corporation is actively engaged with other
market-leading technology vendors to address technical obstacles so that our
documentation can be accessible to all of our customers. For additional information,
visit the Oracle Accessibility Program Web site at
http://www.oracle.com/accessibility/
xx
Organization
This document contains the following chapters and appendices:
■ Chapter 1, "Overview"—Provides an overview of the Oracle implementation of
JDBC and the Oracle JDBC driver architecture.
■ Chapter 2, "Getting Started"—Introduces the Oracle JDBC drivers and some
scenarios of how you can use them. This chapter also guides you through the
basics of testing your installation and configuration.
■ Chapter 3, "Basic Features"—Covers the basic steps in creating any JDBC
application. It also discusses additional basic features of Java and JDBC
supported by the Oracle JDBC drivers.
■ Chapter 4, "Overview of JDBC 2.0 Support"—Presents an overview of JDBC 2.0
features and describes the differences in how these features are supported in the
JDK 1.2.x and JDK 1.1.x environments.
■ Chapter 6, "Overview of Oracle Extensions"—Provides an overview of the JDBC
extension classes supplied by Oracle.
■ Chapter 7, "Accessing and Manipulating Oracle Data"—Describes data access
using the Oracle datatype formats rather than Java formats.
■ Chapter 8, "Working with LOBs and BFILEs"—Covers the Oracle extensions to
the JDBC standard that let you access and manipulate LOBs and LOB data.
■ Chapter 9, "Working with Oracle Object Types"—Explains how to map Oracle
object types to Java classes by using either standard JDBC or Oracle extensions.
■ Chapter 10, "Working with Oracle Object References"—Describes the Oracle
extensions to standard JDBC that let you access and manipulate object
references.
■ Chapter 11, "Working with Oracle Collections"—Discusses the Oracle
extensions to standard JDBC that let you access and manipulate arrays and their
data.
■ Chapter 12, "Performance Extensions"—Describes Oracle extensions to the
JDBC standard that enhance the performance of your applications.
■ Chapter 13, "Result Set Enhancements"—This chapter discusses JDBC 2.0 result
set enhancements such as scrollable result sets and updatable result sets,
including support issues under JDK 1.1.x
■ Chapter 14, "Statement Caching"—Describes Oracle extension statements for
caching.
xxi
■ Chapter 15, "Distributed Transactions"—Covers distributed transactions,
otherwise known as global transactions, and standard XA functionality.
(Distributed transactions are sets of transactions, often to multiple databases,
that have to be committed in a coordinated manner.)
■ Chapter 16, "Connection Pooling and Caching"—Discusses JDBC 2.0 data
sources (and their usage of JNDI), connection pooling functionality (a
framework for connection caching implementations), and a sample connection
caching implementation provided by Oracle.
■ Chapter 17, "JDBC OCI Extensions"—Describes extensions specific to the OCI
driver.
■ Chapter 18, "Advanced Topics"—Describes advanced JDBC topics such as
globalization support, working with applets, the server-side driver, and
embedded SQL92 syntax.
■ Chapter 19, "Coding Tips and Troubleshooting"—Includes coding tips and
general guidelines for troubleshooting your JDBC applications.
■ Chapter 20, "Reference Information"—Contains detailed JDBC reference
information.
■ Appendix A, "Row Set"—Describes JDBC and cached row sets.
■ Appendix B, "JDBC Error Messages"—Lists JDBC error messages and the
corresponding ORA error numbers.
Related Documentation
Also available from the Oracle Java Platform group, for Oracle9i releases:
■ Oracle9i Java Developer’s Guide
This book introduces the basic concepts of Java in Oracle9i and provides
general information about server-side configuration and functionality.
Information that pertains to the Oracle Java platform as a whole, rather than to
a particular product (such as JDBC or SQLJ) is in this book.
■ Oracle9i Support for JavaServer Pages Reference
This book covers the use of JavaServer Pages technology to embed Java code
and JavaBean invocations inside HTML pages. Both standard JSP features and
Oracle-specific features are described. Discussion covers considerations for the
Oracle9i release 2 Oracle HTTP Server JServ environment, but also covers
xxii
features for servlet 2.2 environments and emulation of some of those features by
the Oracle JSP container for JServ.
■ Oracle9i SQLJ Developer’s Guide and Reference
This book covers the use of SQLJ to embed static SQL operations directly into
Java code, covering SQLJ language syntax and SQLJ translator options and
features. Both standard SQLJ features and Oracle-specific SQLJ features are
described.
■ Oracle9i JPublisher User’s Guide
This book describes how to use the Oracle JPublisher utility to translate object
types and other user-defined types to Java classes. If you are developing SQLJ
or JDBC applications that use object types, VARRAY types, nested table types,
or object reference types, then JPublisher can generate custom Java classes to
map to them.
■ Oracle9i Java Stored Procedures Developer’s Guide
This book discusses Java stored procedures—programs that run directly in the
Oracle9i database. With stored procedures (functions, procedures, triggers, and
SQL methods), Java developers can implement business logic at the server
level, thereby improving application performance, scalability, and security.
The following OC4J documents, for Oracle9i Application Server releases, are also
available from the Oracle Java Platform group:
■ Oracle9iAS Containers for J2EE User’s Guide
This book provides some overview and general information for OC4J; primer
chapters for servlets, JSP pages, and EJBs; and general configuration and
deployment instructions.
■ Oracle9iAS Containers for J2EE Support for JavaServer Pages Reference
This book provides information for JSP developers who want to run their pages
in OC4J. It includes a general overview of JSP standards and programming
considerations, as well as discussion of Oracle value-added features and steps
for getting started in the OC4J environment.
■ Oracle9iAS Containers for J2EE JSP Tag Libraries and Utilities Reference
This book provides conceptual information and detailed syntax and usage
information for tag libraries, JavaBeans, and other Java utilities provided with
OC4J.
■ Oracle9iAS Containers for J2EE Servlet Developer’s Guide
xxiii
This book provides information for servlet developers regarding use of servlets
and the servlet container in OC4J. It also documents relevant OC4J
configuration files.
■ Oracle9iAS Containers for J2EE Services Guide
This book provides information about basic Java services supplied with OC4J,
such as JTA, JNDI, and the Oracle9i Application Server Java Object Cache.
■ Oracle9iAS Containers for J2EE Enterprise JavaBeans Developer’s Guide and
Reference
This book provides information about the EJB implementation and EJB
container in OC4J.
The following documents are from the Oracle Server Technologies group:
■ Oracle9i XML Developer’s Kits Guide - XDK
■ Oracle9i Application Developer’s Guide - Fundamentals
■ Oracle9i Supplied Java Packages Reference
■ Oracle9i Supplied PL/SQL Packages and Types Reference
■ PL/SQL User’s Guide and Reference
■ Oracle9i SQL Reference
■ Oracle9i Net Services Administrator’s Guide
■ Oracle Advanced Security Administrator’s Guide
■ Oracle9i Database Reference
■ Oracle9i Database Error Messages
The following documents from the Oracle9i Application Server group may also be
of some interest:
■ Oracle9i Application Server Administrator’s Guide
■ Oracle Enterprise Manager Administrator’s Guide
■ Oracle HTTP Server Administration Guide
■ Oracle9i Application Server Performance Guide
■ Oracle9i Application Server Globalization Support Guide
■ Oracle9iAS Web Cache Administration and Deployment Guide
■ Oracle9i Application Server: Migrating from Oracle9i Application Server 1.x
xxiv
The following are available from the JDeveloper group:
■ Oracle JDeveloper online help
■ Oracle JDeveloper documentation on the Oracle Technology Network:
http://otn.oracle.com/products/jdev/content.html
In North America, printed documentation is available for sale in the Oracle Store at
http://oraclestore.oracle.com/
Customers in Europe, the Middle East, and Africa (EMEA) can purchase
documentation from
http://www.oraclebookshop.com/
If you already have a username and password for OTN, then you can go directly to
the documentation section of the OTN Web site at
http://otn.oracle.com/docs/index.htm
The following Oracle Technology Network (OTN) resources are available for further
information about JavaServer Pages:
■ OTN Web site for Java servlets and JavaServer Pages:
http://otn.oracle.com/tech/java/servlets/
xxv
http://java.sun.com/products/jsp/index.html
■ Web site for Java Servlet technology, including the latest specifications:
http://java.sun.com/products/servlet/index.html
It is recommended, however, that you request only the daily digest of the
posted e-mails. To do this add the following line to the message body as well:
set jsp-interest digest
Conventions
This section describes the conventions used in the text and code examples of this
documentation set. It describes:
■ Conventions in Text
■ Conventions in Code Examples
xxvi
Conventions in Text
We use various conventions in text to help you more quickly identify special terms.
The following table describes those conventions and provides examples of their use.
xxvii
SELECT username FROM dba_users WHERE username = ’MIGRATE’;
The following table describes typographic conventions used in code examples and
provides examples of their use.
xxviii
1
Overview
Overview 1-1
Introduction
Introduction
This section presents a brief introduction to Oracle JDBC, including a comparison to
SQLJ.
What is JDBC?
JDBC (Java Database Connectivity) is a standard Java interface for connecting from
Java to relational databases. The JDBC standard was defined by Sun Microsystems,
allowing individual providers to implement and extend the standard with their
own JDBC drivers.
JDBC is based on the X/Open SQL Call Level Interface and complies with the
SQL92 Entry Level standard.
In addition to supporting the standard JDBC API, Oracle drivers have extensions to
support Oracle-specific datatypes and to enhance performance.
in turn, can use JDBC calls. The generated Java code compiles and runs like any
other Java program.
Although SQLJ provides direct support for static SQL operations known at the time
the program is written, it can also interoperate with dynamic SQL through JDBC.
SQLJ allows you to create JDBC objects when they are needed for dynamic SQL
operations. In this way, SQLJ and JDBC can co-exist in the same program.
Convenient conversions are supported between JDBC connections and SQLJ
connection contexts, as well as between JDBC result sets and SQLJ iterators. For
more information on this, see the Oracle9i SQLJ Developer’s Guide and Reference.
The syntax and semantics of SQLJ and JDBC do not depend on the configuration
under which they are running, thus enabling implementation on the client or
database side or in the middle tier.
Note: You can intermix SQLJ code and JDBC code in the same
source. This is discussed in the Oracle9i SQLJ Developer’s Guide and
Reference.
Overview 1-3
Overview of the Oracle JDBC Drivers
Figure 1–1 illustrates the driver-database architecture for the JDBC Thin, OCI, and
server-side internal drivers.
The rest of this section describes common features of the Oracle drivers and then
discusses each one individually, concluding with a discussion of some of the
considerations in choosing the appropriate driver for your application.
Overview 1-5
Overview of the Oracle JDBC Drivers
The driver supports only TCP/IP protocol and requires a TNS listener on the
TCP/IP sockets from the database server.
Note: When the JDBC Thin driver is used with an applet, the
client browser must have the capability to support Java sockets.
Using the Thin driver inside an Oracle server or middle tier is considered
separately, under "JDBC Server-Side Thin Driver" below.
Note: In Oracle9i, the OCI driver is a single OCI driver for use
with all database versions. It replaces the distinct OCI8 and OCI7
drivers of previous releases. While the OCI8 and OCI7 drivers are
deprecated for Oracle9i, they are still supported for backward
compatibility.
The JDBC OCI driver provides OCI connection pooling functionality, which can
either be part of the JDBC client or a JDBC stored procedure. OCI driver connection
pooling requires fewer physical connections than standard connection pooling, it
also provides a uniform interface, and allows you to dynamically configure the
attributes of the connection pool. For a complete description of OCI driver
connection pooling, see "OCI Driver Connection Pooling" on page 17-2.
The OCI driver supports Oracle7, Oracle8/8i, and Oracle9i with the highest
compatibility. It also supports all installed Oracle Net adapters, including IPC,
named pipes, TCP/IP, and IPX/SPX.
The OCI driver, written in a combination of Java and C, converts JDBC invocations
to calls to the Oracle Call Interface (OCI), using native methods to call C-entry
points. These calls are then sent over Oracle Net to the Oracle database server. The
OCI driver communicate with the server using the Oracle-developed TTC protocol.
The OCI driver uses the OCI libraries, C-entry points, Oracle Net, CORE libraries,
and other necessary files on the client machine on which it is installed.
The Oracle Call Interface (OCI) is an application programming interface (API) that
allows you to create applications that use the native procedures or function calls of
a third-generation language to access an Oracle database server and control all
phases of SQL statement execution. The OCI driver is designed to build scalable,
multi-threaded applications that can support large numbers of users securely.
The Oracle9i JDBC OCI driver has the following functionality:
■ Uses OCI
■ Connection Pooling
■ OCI optimized fetch
■ Prefetching
■ Fastest LOB access
■ Client-side object cache
■ Transparent Application Failover (TAF)
■ Middle-tier authentication
■ Advanced security
Overview 1-7
Overview of the Oracle JDBC Drivers
About Permission for the Server-Side Thin Driver The thin driver opens a socket to use
for its connection. Because the Oracle server is enforcing the Java security model,
this means that a check is performed for a SocketPermission object.
To use the JDBC server-side Thin driver, the connecting user must be granted with
the appropriate permission. This is an example of how the permission can be
granted for user SCOTT:
create role jdbcthin;
call dbms_java.grant_permission('JDBCTHIN',
'java.net.SocketPermission',
'*', 'connect' );
grant jdbcthin to scott;
Note that JDBCTHIN in the grant_permission call must be in upper case. The '*'
is a pattern. It is possible to limit the permission to allow connecting to specific
machines or ports. See the Javadoc for complete details on the
java.net.SocketPermission class. Also, refer to the Oracle9i Java Developer’s
Guide for further discussion of Java security inside the Oracle server.
■ If you are writing an applet, you must use the JDBC Thin driver. JDBC
OCI-based driver classes will not work inside a Web browser, because they call
native (C language) methods.
■ If you want maximum portability and performance, use the JDBC Thin driver.
You can connect to an Oracle server from either an application or an applet
using the JDBC Thin driver.
■ If you are writing a client application for an Oracle client environment and need
maximum performance, then choose the JDBC OCI driver.
■ For code that runs in an Oracle server acting as a middle tier, use the server-side
Thin driver.
■ If your code will run inside the target Oracle server, then use the JDBC
server-side internal driver to access that server. (You can also access remote
servers using the server-side Thin driver.)
■ If performance is critical to your application, you want maximum scalability of
the Oracle server, or you need the enhanced availability features like TAF or the
enhanced proxy features like middle-tier authentication
Overview 1-9
Overview of Application and Applet Functionality
Application Basics
You can use either the Oracle JDBC Thin or OCI driver for a client application.
Because the JDBC OCI driver uses native methods, there can be significant
performance advantages in using this driver for your applications.
An application that can run on a client can also run in the Oracle server, using the
JDBC server-side internal driver.
If you are using a JDBC OCI driver in an application, then the application will
require an Oracle installation on its clients. For example, the application will require
the installation of Oracle Net and client libraries.
The JDBC Thin and OCI drivers offer support for data encryption and integrity
checksum features of the Oracle Advanced Security option (formerly known as
ANO or ASO). See "JDBC Client-Side Security Features" on page 18-8. Such security
is not necessary for the server-side internal driver.
Applet Basics
This section describes the issues you should take into consideration if you are
writing an applet that uses the JDBC Thin driver.
For more about applets and a discussion of relevant firewall, browser, and security
issues, see "JDBC in Applets" on page 18-15.
Both of these topics are described in greater detail in "Connecting to the Database
through the Applet" on page 18-15.
The Thin driver offers support for data encryption and integrity checksum features
of the Oracle Advanced Security option. See "JDBC Client-Side Security Features"
on page 18-8.
Oracle Extensions
A number of Oracle extensions are available to Oracle JDBC application and applet
programmers, in the following categories:
■ type extensions (such as ROWIDs and REF CURSOR types)
■ wrapper classes for SQL types (the oracle.sql package)
■ support for custom Java classes to map to user-defined types
■ extended LOB support
■ extended connection, statement, and result set functionality
■ performance enhancements
See Chapter 6, "Overview of Oracle Extensions" for an overview of type extensions
and extended functionality, and succeeding chapters for further detail. See
Chapter 12, "Performance Extensions" regarding Oracle performance enhancements.
Package oracle.jdbc
Beginning in Oracle9i, the Oracle extensions to JDBC are captured in the package
oracle.jdbc. This package contains classes and interfaces that specify the Oracle
extensions in a manner similar to the way the classes and interfaces in java.sql
specify the public JDBC API.
Overview 1-11
Overview of Application and Applet Functionality
Your code should use the package oracle.jdbc instead of the package
oracle.jdbc.driver used in earlier versions of Oracle. Use of the package
oracle.jdbc.driver is now deprecated, but will continue to be supported for
backwards compatibility.
All that is required to convert your code is to replace "oracle.jdbc.driver"
with "oracle.jdbc" in the source and recompile. This cannot be done piece-wise.
You must convert all classes and interfaces that are referenced by an application.
Conversion is not required, but is highly recommended. Future releases of Oracle
may have features that are incompatible with use of the package
oracle.jdbc.driver.
The purpose of this change is to enable the Oracle JDBC drivers to have multiple
implementations. In all releases up to and including Oracle9i, all of the Oracle JDBC
drivers have used the same top level implementation classes, the classes in the
package oracle.jdbc.driver. By converting your code to use oracle.jdbc,
you will be able to take advantage of future enhancements that use different
implementation classes. There are no such enhancements in Oracle9i, but there are
plans for such enhancements in the future.
Additionally, these interfaces permit the use of some code patterns that are difficult
to use when your code uses the package oracle.jdbc.driver. For example, you
can more easily develop wrapper classes for the Oracle JDBC classes. If you wished
to wrap the OracleStatement class in order to log all SQL statements, you could
easily do so by creating a class that wraps OracleStatment . That class would
implement the interface oracle.jdbc.OracleStatement and hold an
oracle.jdbc.OracleStatement as an instance variable. This wrapping pattern
is much more difficult when your code uses the package oracle.jdbc.driver as
you cannot extend the class oracle.jdbc.driver.OracleStatement.
Once again, your code should use the new package oracle.jdbc instead of the
package oracle.jdbc.driver. Conversion is not required as
oracle.jdbc.driver will continue to be supported for backwards compatibility.
Conversion is highly recommended as there may in later releases be features that
are not supported if your code uses oracle.jdbc.driver.
Server-Side Basics
By using the Oracle JDBC server-side internal driver, code that runs in an Oracle
database, such as in Java stored procedures or Enterprise JavaBeans, can access the
database in which it runs.
For a complete discussion of the server-side driver, see "JDBC in the Server: the
Server-Side Internal Driver" on page 18-26.
Overview 1-13
Environments and Support
Notes:
■ The server-side internal driver supports only JDK 1.2.x.
■ Each driver implementation uses its own JDBC classes ZIP
file—classes12.zip for JDK 1.4, 1.3.x, and1.2.x versions, and
classes111.zip for JDK 1.1.x versions.
Because JNI is now supported by Oracle JDBC, you can use the OCI driver with
Java virtual machines other than that of Sun Microsystems—in particular, with
Microsoft and IBM JVMs. These JVMs support only JNI for native C calls.
Overview 1-15
Changes At This Release
Note: Notice that starting with Oracle8i release 8.1.6, the Oracle
JDBC drivers no longer support JDK 1.0.x versions.
Notes:
■ Different JDKs require different class files—classes in
classes12.zip, classes111.zip, respectively.
■ The JDBC drivers do not support structured objects when run
against an 8.0.x database. This is because JDBC depends on
PL/SQL functions that did not exist in those releases.
■ Any client-side driver might work with 7.x databases, but this
has not been tested and is not supported.
– classes12.zip contains the classes for use with 1.2.x, 1.3.x, and 1.4—all
the JDBC driver classes except the classes necessary for globalization
support.
– nls_charset12.zip contains the classes necessary for globalization
support with JDK 1.2.x, 1.3.x, and 1.4.
– jta.zip and jndi.zip contain classes for the Java Transaction API and
the Java Naming and Directory Interface for JDK 1.2.x, 1.3.x, and 1.4. These
are only required if you will be using JTA features for distributed
transaction management or JNDI features for naming services. (These files
can also be obtained from the Sun Microsystems Web site, but it is advisable
to use the versions from Oracle, because those have been tested with the
Oracle drivers.)
– classes111.zip contains the classes for use with JDK 1.1.x—all the
JDBC driver classes except the classes necessary for globalization support.
classes111.zip also contains Oracle extensions that allow you to use
JDBC 2.0 functionality for objects, arrays, and LOBs under JDK 1.1.x.
– nls_charset11.zip contains the classes necessary for globalization
support with the JDK 1.1.x.
The nls_charset12.zip and nls_charset11.zip files provide support
for specific character sets. They have been separated out from the
classes*.zip files to give you the option of excluding character sets in
situations where complete globalization support is not needed. For more
information on nls_charset12.zip and nls_charset11.zip, see
"Globalization Support and Object Types" on page 18-4.
■ ojdbc14.jar contains classes for use with JDK 1.4. It contains the JDBC
driver classes except classes necessary for globalization support in Object
and Collection types.
■ readme.txt: The readme.txt file contains late-breaking and release-specific
information about the drivers that might not be in this manual.
Check that all these directories have been created and populated.
You must set the CLASSPATH for your installed JDBC OCI or Thin driver.
Depending on which JDK version you use, you must set one of these values for the
CLASSPATH:
Ensure that there is only one classes*.zip file version and one
nls_charset*.zip file version in your CLASSPATH.
JDBC OCI Driver: If you are installing the JDBC OCI driver, you must also set the
following value for the library path environment variable
■ On Solaris, set LD_LIBRARY_PATH as follows:
[Oracle Home]/lib
JDBC Thin Drivers: If you are installing the JDBC Thin driver, you do not have to set
any other environment variables.
class JDBCVersion
{
public static void main (String args[])
throws SQLException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver
(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@host:port:sid","scott","tiger");
class JdbcCheckup
{
public static void main(String args[])
throws SQLException, IOException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
System.out.println("Connecting...");
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@" + database, user, password);
System.out.println("connected.");
// Create a statement
Statement stmt = conn.createStatement();
while (rset.next())
System.out.println(rset.getString(1));
// close the result set, the statement and connect
rset.close();
stmt.close();
conn.close();
System.out.println("Your JDBC installation is correct.");
}
try
{
StringBuffer buffer = new StringBuffer();
System.out.print(prompt);
System.out.flush();
int c = System.in.read();
while (c != '\n' && c != -1)
{
buffer.append((char)c);
c = System.in.read();
}
return buffer.toString().trim();
}
catch(IOException e)
{
return "";
}
}
}
This chapter covers the most basic steps taken in any JDBC application. It also
describes additional basic features of Java and JDBC supported by the Oracle JDBC
drivers.
The following topics are discussed:
■ First Steps in JDBC
■ Sample: Connecting, Querying, and Processing the Results
■ Datatype Mappings
■ Java Streams in JDBC
■ Stored Procedure Calls in JDBC Programs
■ Processing SQL Exceptions
Import Packages
Regardless of which Oracle JDBC driver you use, include the following import
statements at the beginning of your program (java.math only if needed):
Import the following Oracle packages when you want to access the extended
functionality provided by the Oracle drivers. However, they are not required for the
example presented in this section:
For an overview of the Oracle extensions to the JDBC standard, see Chapter 6,
"Overview of Oracle Extensions".
Because you are using one of Oracle’s JDBC drivers, you declare a specific driver
name string to registerDriver(). You register the driver only once in your Java
application.
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
If you are already familiar with the getConnection() method, you can skip
ahead to either of these sections, depending on the driver you installed:
■ "Opening a Connection for the JDBC OCI Driver" on page 3-9
■ "Opening a Connection for the JDBC Thin Driver" on page 3-10
Notes:
■ With JDK 1.2, using JNDI (Java Naming and Directory
Interface) is becoming the recommended way to make
connections. See "A Brief Overview of Oracle Data Source
Support for JNDI" on page 16-2 and "Creating a Data Source
Instance, Registering with JNDI, and Connecting" on page 16-8.
■ If you are using the Thin driver, be aware that it does not
support OS authentication in making the connection. As a
result, special logins are not supported.
■ This discussion in this section does not apply to the server-side
internal driver, which uses an implicit connection. See
"Connecting to the Database with the Server-Side Internal
Driver" on page 18-26.
The following example connects user scott with password tiger to a database
with INSTANCE_NAME orcl through port 1521 of host myhost, using the Thin
driver.
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:orcl", "scott", "tiger");
If you want to use the default connection for an OCI driver, specify either:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:scott/tiger@");
or:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@", "scott", "tiger");
For all JDBC drivers, you can also specify the database with a Oracle Net
keyword-value pair. The Oracle Net keyword-value pair substitutes for the
TNSNAMES entry. The following example uses the same parameters as the
preceding example, but in the keyword-value format:
Connection conn = DriverManager.getConnection
(jdbc:oracle:oci:@MyHostString","scott","tiger");
or:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@(description=(address=(host= myhost)
(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))",
"scott", "tiger");
The following example connects user scott with password tiger to a database on
host myhost using the OCI driver. In this case, however, the URL includes the
userid and password, and is the only input parameter.
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:scott/tiger@myhost);
If you want to connect with the Thin driver, you must specify the port number and
SID. For example, if you want to connect to the database on host myhost that has a
TCP/IP listener up on port 1521, and the SID (system identifier) is orcl:
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:scott/tiger@myhost:1521:orcl);
In addition to the URL, use an object of the standard Java Properties class as
input. For example:
java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);
Table 3–1 lists the connection properties that Oracle JDBC drivers support.
See Table 18–4, "OCI Driver Client Parameters for Encryption and Integrity" and
Table 18–5, "Thin Driver Client Parameters for Encryption and Integrity" for
descriptions of encryption and integrity drivers.
Note: The ability to specify a role is supported only for sys user
name.
Example The following example illustrates how to use the internal_logon and
sysdba arguments to specify sys logon.
//import packages and register the driver
import java.sql.*;
import java.math.*;
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
Properties for Oracle Performance Extensions Some of these properties are for use with
Oracle performance extensions. Setting these properties is equivalent to using
corresponding methods on the OracleConnection object, as follows:
■ Setting the defaultRowPrefetch property is equivalent to calling
setDefaultRowPrefetch() .
See "Oracle Row Prefetching" on page 12-20.
■ Setting the remarksReporting property is equivalent to calling
setRemarksReporting().
See "DatabaseMetaData TABLE_REMARKS Reporting" on page 12-26.
Example The following example shows how to use the put() method of the java.
util.Properties class, in this case to set Oracle performance extension
parameters.
//import packages and register the driver
import java.sql.*;
import java.math.*;
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
Note that both the ":" and "@" characters are necessary.
For the JDBC OCI and Thin drivers, you can also specify the database with a Oracle
Net keyword-value pair. This is less readable than a TNSNAMES entry but does not
depend on the accuracy of the TNSNAMES.ORA file. The Oracle Net keyword-value
pair also works with other JDBC drivers.
For example, if you want to connect to the database on host myhost that has a
TCP/IP listener up on port 1521, and the SID (system identifier) is orcl, use a
statement such as:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@(description=(address=(host= myhost)
(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))",
"scott", "tiger");
Note: Oracle JDBC does not support login timeouts. Calling the
static DriverManager.setLoginTimeout() method will have
no effect.
Note: The JDBC Thin driver supports only the TCP/IP protocol.
For example, use this string if you want to connect to the database on host myhost
that has a TCP/IP listener on port 1521 for the database SID (system identifier)
orcl. You can logon as user scott, with password tiger:
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:orcl", "scott", "tiger");
You can also specify the database with a Oracle Net keyword-value pair. This is less
readable than the first version, but also works with the other JDBC drivers.
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@(description=(address=(host=myhost)
(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))", "scott",
"tiger");
Notes: Oracle JDBC does not support login timeouts. Calling the
static DriverManager.setLoginTimeout() method will have
no effect.
Note that there is nothing Oracle-specific about this statement; it follows standard
JDBC syntax.
For example, the following code will iterate through the ResultSet object rset
from the previous section and will retrieve and print each employee name:
while (rset.next())
System.out.println (rset.getString(1));
Once again, this is standard JDBC syntax. The next() method returns false when it
reaches the end of the result set. The employee names are materialized as Java
strings.
When you close a Statement object that a given Connection object creates, the
connection itself remains open.
Use setXXX() methods on the PreparedStatement object to bind data into the
prepared statement to be sent to the database. The various setXXX() methods are
described in "Standard setObject() and Oracle setOracleObject() Methods" on
page 7-11 and "Other setXXX() Methods" on page 7-12.
Note that there is nothing Oracle-specific about the functionality described here; it
follows standard JDBC syntax.
The following example shows how to use a prepared statement to execute INSERT
operations that add two rows to the EMP table.
// Prepare to insert new names in the EMP table
PreparedStatement pstmt =
conn.prepareStatement ("insert into EMP (EMPNO, ENAME) values (?, ?)");
Commit Changes
By default, DML operations (INSERT, UPDATE, DELETE) are committed
automatically as soon as they are executed. This is known as auto-commit mode. You
can, however, disable auto-commit mode with the following method call on the
Connection object:
conn.setAutoCommit(false);
(For further discussion of auto-commit mode and an example of disabling it, see
"Disabling Auto-Commit Mode" on page 19-6.)
If you disable auto-commit mode, then you must manually commit or roll back
changes with the appropriate method call on the Connection object:
conn.commit();
or:
conn.rollback();
A COMMIT or ROLLBACK operation affects all DML statements executed since the
last COMMIT or ROLLBACK.
Important:
■ If auto-commit mode is disabled and you close the connection
without explicitly committing or rolling back your last changes,
then an implicit COMMIT operation is executed.
■ Any DDL operation, such as CREATE or ALTER , always
includes an implicit COMMIT. If auto-commit mode is disabled,
this implicit COMMIT will not only commit the DDL statement,
but also any pending DML operations that had not yet been
explicitly committed or rolled back.
class JdbcTest {
public static void main (String args []) throws SQLException {
// Load Oracle driver
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
// Connect to the local database
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:ORCL","scott", "tiger");
If you want to adapt the code for the OCI driver, replace the Connection
statement with the following:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@MyHostString", "scott", "tiger");
Datatype Mappings
The Oracle JDBC drivers support standard JDBC 1.0 and 2.0 types as well as
Oracle-specific BFILE and ROWID datatypes and types of the REF CURSOR
category.
This section documents standard and Oracle-specific SQL-Java default type
mappings.
Table of Mappings
For reference, Table 3–2 shows the default mappings between SQL datatypes, JDBC
typecodes, standard Java types, and Oracle extended types.
The SQL Datatypes column lists the SQL types that exist in the database.
The JDBC Typecodes column lists data typecodes supported by the JDBC standard
and defined in the java.sql.Types class, or by Oracle in the oracle.jdbc.
OracleTypes class. For standard typecodes, the codes are identical in these two
classes.
The Standard Java Types column lists standard types defined in the Java language.
The Oracle Extension Java Types column lists the oracle.sql.* Java types that
correspond to each SQL datatype in the database. These are Oracle extensions that
let you retrieve all SQL data in the form of a oracle.sql.* Java type. Mapping
SQL datatypes into the oracle.sql datatypes lets you store and retrieve data
without losing information. Refer to "Package oracle.sql" on page 6-7 for more
information on the oracle.sql.* package.
Table 3–2 Default Mappings Between SQL Types and Java Types
Oracle Extension Java
SQL Datatypes JDBC Typecodes Standard Java Types Types
STANDARD JDBC 1.0 TYPES:
CHAR java.sql.Types.CHAR java.lang.String oracle.sql.CHAR
VARCHAR2 java.sql.Types.VARCHAR java.lang.String oracle.sql.CHAR
LONG java.sql.Types.LONGVARCHAR java.lang.String oracle.sql.CHAR
NUMBER java.sql.Types.NUMERIC java.math.BigDecimal oracle.sql.NUMBER
NUMBER java.sql.Types.DECIMAL java.math.BigDecimal oracle.sql.NUMBER
NUMBER java.sql.Types.BIT boolean oracle.sql.NUMBER
Table 3–2 Default Mappings Between SQL Types and Java Types (Cont.)
Oracle Extension Java
SQL Datatypes JDBC Typecodes Standard Java Types Types
NUMBER java.sql.Types.TINYINT byte oracle.sql.NUMBER
NUMBER java.sql.Types.SMALLINT short oracle.sql.NUMBER
NUMBER java.sql.Types.INTEGER int oracle.sql.NUMBER
NUMBER java.sql.Types.BIGINT long oracle.sql.NUMBER
NUMBER java.sql.Types.REAL float oracle.sql.NUMBER
NUMBER java.sql.Types.FLOAT double oracle.sql.NUMBER
NUMBER java.sql.Types.DOUBLE double oracle.sql.NUMBER
RAW java.sql.Types.BINARY byte[] oracle.sql.RAW
RAW java.sql.Types.VARBINARY byte[] oracle.sql.RAW
LONGRAW java.sql.Types.LONGVARBINARY byte[] oracle.sql.RAW
DATE java.sql.Types.DATE java.sql.Date oracle.sql.DATE
DATE java.sql.Types.TIME java.sql.Time oracle.sql.DATE
DATE java.sql.Types.TIMESTAMP javal.sql.Timestamp oracle.sql.DATE
STANDARD JDBC 2.0 TYPES:
BLOB java.sql.Types.BLOB java.sql.Blob oracle.sql.BLOB
CLOB java.sql.Types.CLOB java.sql.Clob oracle.sql.CLOB
user-defined java.sql.Types.STRUCT java.sql.Struct oracle.sql.STRUCT
object
user-defined java.sql.Types.REF java.sql.Ref oracle.sql.REF
reference
user-defined java.sql.Types.ARRAY java.sql.Array oracle.sql.ARRAY
collection
ORACLE EXTENSIONS:
BFILE oracle.jdbc.OracleTypes.BFILE n/a oracle.sql.BFILE
ROWID oracle.jdbc.OracleTypes.ROWID n/a oracle.sql.ROWID
REF CURSOR oracle.jdbc.OracleTypes.CURSOR java.sql.ResultSet oracle.jdbc.OracleResultSet
type
Table 3–2 Default Mappings Between SQL Types and Java Types (Cont.)
Oracle Extension Java
SQL Datatypes JDBC Typecodes Standard Java Types Types
TS oracle.jdbc.OracleTypes. n/a oracle.sql.TIMESTAMP
TIMESTAMP
TSTZ oracle.jdbc.OracleTypes. n/a oracle.sql.TIMESTAMPTZ
TIMESTAMPTZ
TSLTZ oracle.jdbc.OracleTypes. n/a oracle.sql.TIMESTAMPLTZ
TIMESTAMPLTZ
For a list of all the Java datatypes to which you can validly map a SQL datatype, see
"Valid SQL-JDBC Datatype Mappings" on page 20-2.
See Chapter 6, "Overview of Oracle Extensions", for more information on type
mappings. In Chapter 6 you can also find more information on the following:
■ packages oracle.sql, oracle.jdbc, and oracle.jdbc2
■ type extensions for the Oracle BFILE and ROWID datatypes and user-defined
types of the REF CURSOR category
You can get LONG and LONG RAW data with any of the three stream types. The driver
performs conversions for you, depending on the character set of your database and
the driver. For more information about globalization support, see "JDBC and
Globalization Support" on page 18-2.
For example, the LONG RAW value 20 is represented in hexadecimal as 14 or "1" "4".
In ASCII, 1 is represented by "49" and "4" is represented by "52". In Unicode, a
padding of zeros is used to separate individual values. So, the hexadecimal value 14
is represented as 0 "1" 0 "4". The Unicode representation is 0 "49" 0 "52".
Table 3–3 summarizes LONG and LONG RAW data conversions for each stream type.
Getting a LONG RAW Data Column with getBinaryStream() This Java example writes the
contents of a LONG RAW column to a file on the local file system. In this case, the
driver fetches the data incrementally.
The following code creates the table that stores a column of LONG RAW data
associated with the name LESLIE:
-- SQL code:
create table streamexample (NAME varchar2 (256), GIFDATA long raw);
insert into streamexample values ('LESLIE', '00010203040506070809');
The following Java code snippet writes the data from the LESLIE LONG RAW column
into a file called leslie.gif:
ResultSet rset = stmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");
In this example the contents of the GIFDATA column are transferred incrementally
in chunk -sized pieces between the database and the client. The InputStream
object returned by the call to getBinaryStream() reads the data directly from the
database connection.
Getting a LONG RAW Data Column with getBytes() This version of the example gets the
content of the GIFDATA column with getBytes() instead of
getBinaryStream(). In this case, the driver fetches all the data in one call and
stores it in a byte array. The previous code snippet can be rewritten as:
ResultSet rset2 = stmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");
Because a LONG RAW column can contain up to 2 gigabytes of data, the getBytes()
example will probably use much more memory than the getBinaryStream()
example. Use streams if you do not know the maximum size of the data in your
LONG or LONG RAW columns.
example, if you have a very small LONG column, you might want to avoid returning
the data incrementally and instead, return the data in one call.
To avoid streaming, use the defineColumnType() method to redefine the type of
the LONG column. For example, if you redefine the LONG or LONG RAW column as
type VARCHAR or VARBINARY, then the driver will not automatically stream the
data.
If you redefine column types with defineColumnType(), you must declare the
types of all columns in the query. If you do not, executeQuery() will fail. In
addition, you must cast the Statement object to an oracle.jdbc.
OracleStatement object.
As an added benefit, using defineColumnType() saves the driver two round
trips to the database when executing the query. Without defineColumnType(),
the JDBC driver has to request the datatypes of the column types.
Using the example from the previous section, the Statement object stmt is cast to
the OracleStatement and the column containing LONG RAW data is redefined to
be of the type VARBINARAY. The data is not streamed—instead, it is returned in a
byte array.
//cast the statement stmt to an OracleStatement
oracle.jdbc.OracleStatement ostmt =
(oracle.jdbc.OracleStatement)stmt;
If you try to get a CHAR, VARCHAR, or RAW column as a data stream without
redefining the column type, the JDBC driver will return a Java InputStream, but
no real streaming occurs. In the case of these datatypes, the JDBC driver fully
fetches the data into an in-memory buffer during a call to the executeQuery()
method or next() method. The getXXXStream() entry points return a stream
that reads data from this buffer.
The incoming data for each row has the following shape:
<a date><the characters of the long column><a number>
As you process each row of the iterator, you must complete any processing of the
stream column before reading the number column.
An exception to this behavior is LOB data, which is also transferred between server
and client as a Java stream. For more information on how the driver treats LOB
data, see "Streaming LOBs and External Files" on page 3-27.
while rset.next()
{
//get the date
java.sql.Date date = rset.getDate(1);
the location of the actual data. External files (binary files, or BFILEs) are managed
similarly. The JDBC drivers can support these types through the use of streams:
■ BLOBs (unstructured binary data)
■ CLOBs (character data)
■ BFILEs (external files)
LOBs and BFILEs behave differently from the other types of streaming data
described in this chapter. The driver transfers data between server and client as a
Java stream. However, unlike most Java streams, a locator representing the data is
stored in the table. Thus, you can access the data at any time during the life of the
connection.
Streaming BFILEs
An external file, or BFILE, is used to store a locator to a file outside the database,
stored somewhere on the filesystem of the data server. The locator points to the
actual location of the file.
When a query selects one or more BFILE columns, the JDBC driver transfers to the
client the file pointed to by the locator. The transfer is performed in a Java stream.
To manipulate BFILE data from JDBC, use methods in the Oracle extension class
oracle.sql.BFILE. This class provides functionality such as reading from the
BFILE into an input stream, writing from an output stream into a BFILE,
determining the length of a BFILE, and closing a BFILE.
For a complete discussion of how to use streaming BFILE data, see "Reading BFILE
Data" on page 8-22.
Closing a Stream
You can discard the data from a stream at any time by calling the stream’s close()
method. You can also close and discard the stream by closing its result set or
connection object. You can find more information about the close() method for
data streams in "Bypassing Streaming Data Columns" on page 3-27. For information
on how to avoid closing a stream and discarding its data by accident, see
"Streaming Data Precautions" on page 3-29.
To recover the data from a column containing a data stream, it is not enough to
get the column; you must immediately process its contents. Otherwise, the
contents will be discarded when you get the next column.
■ Call the stream column in SELECT-list order.
If your query selects multiple columns, the database sends each row as a set of
bytes representing the columns in the SELECT order. If one of the columns
contains stream data, the database sends the entire data stream before
proceeding to the next column.
If you do not use the SELECT-list order to access data, then you can lose the
stream data. That is, if you bypass the stream data column and access data in a
column that follows it, the stream data will be lost. For example, if you try to
access the data for the NUMBER column before reading the data from the stream
data column, the JDBC driver first reads then discards the streaming data
automatically. This can be very inefficient if the LONG column contains a large
amount of data.
If you try to access the LONG column later in the program, the data will not be
available and the driver will return a "Stream Closed " error.
The second point is illustrated in the following example:
ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
int n = rset.getInt(3); // This discards the streaming data
InputStream is = rset.getAsciiStream(2);
// Raises an error: stream closed.
}
If you get the stream but do not use it before you get the NUMBER column, the stream
still closes automatically:
ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
InputStream is = rset.getAsciiStream(2); // Get the stream
int n = rset.getInt(3);
// Discards streaming data and closes the stream
}
int c = is.read(); // c is -1: no more characters to read-stream closed
The 8.1.6 Oracle JDBC drivers may not raise an error if you exceed the limit when
using setBytes() or setString(), but you may receive the following error:
ORA-17070: Data size bigger than max size for this type
Future versions of the Oracle drivers will raise an error if the length exceeds these
limits.
As an example of using Oracle syntax, here is a PL/SQL code snippet that creates a
stored function. The PL/SQL function gets a character sequence and concatenates a
suffix to it:
create or replace function foo (val1 char)
return char as
begin
return val1 || ’suffix’;
end;
This would print output such as the following for an error originating in the JDBC
driver:
exception: Invalid column type
(There is no ORA number message prefix for errors originating in the JDBC driver,
although you can get the ORA number with a getErrorCode() call.)
To illustrate how the JDBC drivers handle errors, assume the following code uses an
incorrect column index:
// Iterate through the result and print the employee names
// of the code
try {
while (rset.next ())
System.out.println (rset.getString (5)); // incorrect column index
}
catch(SQLException e) { e.printStackTrace (); }
Assuming the column index is incorrect, executing the program would produce the
following error text:
java.sql.SQLException: Invalid column index
at oracle.jdbc.dbaccess.DBError.check_error(DBError.java:235)
at oracle.jdbc.OracleStatement.prepare_for_new_get(OracleStatemen
t.java:1560)
at oracle.jdbc.OracleStatement.getStringValue(OracleStatement.jav
a:1653)
at oracle.jdbc.OracleResultSet.getString(OracleResultSet.java:175
)
at Employee.main(Employee.java:41)
Oracle JDBC supports JDBC 2.0 functionality and standardizes functionality that
was previously supported through Oracle extensions.
This chapter provides an overview of JDBC 2.0 support in the Oracle JDBC drivers,
focusing in particular on any differences in support between the JDK 1.2.x and JDK
1.1.x environments. The following topics are discussed:
■ Introduction
■ JDBC 2.0 Support: JDK 1.2.x versus JDK 1.1.x
■ Overview of JDBC 2.0 Features
Introduction
The Oracle JDBC drivers are compliant with the JDBC 2.0 specification. JDBC 2.0
functionality previously implemented through Oracle extensions in the
oracle.jdbc2 package—such as structured objects, object references, arrays, and
LOBs—is now implemented through the standard java.sql package in JDK 1.2.
In a JDK 1.1.x environment, you can continue to use the oracle.jdbc2 package.
You can also use JDBC 2.0 features in connection objects, statement objects, result
set objects, and database meta data objects under JDK 1.1.x by casting your objects
to the Oracle types.
Furthermore, you can use features of the JDBC 2.0 Optional Package (also known as
the JDBC 2.0 Standard Extension API) under either JDK 1.2.x or JDK 1.1.x. These
features, including connection pooling and distributed transactions, are supported
through the standard javax.sql package. This package and the classes that
implement its interfaces are now included with the JDBC classes ZIP file for either
JDK 1.2.x or JDK 1.1.x.
Datatype Support
Oracle JDBC fully supports JDK 1.2.x, which includes standard JDBC 2.0
functionality through implementation of interfaces in the standard java.sql
package. These interfaces are implemented as appropriate by classes in the
oracle.sql and oracle.jdbc packages.
For JDBC 2.0 functionality under JDK 1.2.x, where you are using classes12.zip,
no special imports are required. The following imports, both of which you will
likely need even if you are not using JDBC 2.0 features, will suffice:
import java.sql.*;
import oracle.sql.*;
JDBC 2.0 features are not supported by JDK 1.1.x; however, Oracle provides
extensions that allow you to use a significant subset of JDBC 2.0 datatypes under
JDK 1.1.x, where you are using classes111.zip. These extensions support
database objects, object references, arrays, and LOBs.
The package oracle.jdbc2 is included in classes111.zip. This package
provides interfaces that mimic JDBC 2.0-related interfaces that became standard
with JDK 1.2.x for SQL3 and advanced datatypes. The interfaces in oracle.jdbc2
are implemented as appropriate by classes in the oracle.sql package for a JDK
1.1.x environment.
The following imports are required for JDBC 2.0 datatypes under JDK 1.1.x:
import java.sql.*;
import oracle.jdbc2.*;
import oracle.sql.*;
implement the java.util.Map interface under JDK 1.2.x. Note, however, that
the class java.util.Hashtable satisfies either requirement. If you used
Hashtable objects for your type maps under JDK 1.1.x, then no change is
necessary. For more information, see "Creating a Type Map Object and Defining
Mappings for a SQLData Implementation" on page 9-12.
If these points do not apply to your code, then you do not need to make any code
changes or recompile to run under JDK 1.2.x.
This chapter provides an overview of the JDBC 3.0 features supported in the Oracle
JDBC drivers, focusing in particular on any differences in support between the JDK
1.4 environment and previous JDK environments. The following topics are
discussed:
■ Introduction
■ JDBC 3.0 Support: JDK 1.4 and Previous Releases
■ Overview of Supported JDBC 3.0 Features
■ Transaction Savepoints
Introduction
The Oracle JDBC drivers support the following JDBC 3.0 features:
■ Using global and distributed transactions on the same connection (see "Oracle
XA Packages" on page 15-5)
■ Transaction savepoints (see "Transaction Savepoints" on page 5-5)
■ Re-use of prepared statements by connection pools (also known as statement
caching; see Chapter 14, "Statement Caching")
■ Full support for JDK1.4 (see "JDBC 3.0 Support: JDK 1.4 and Previous Releases"
in this chapter)
All of these features are provided in the package oracle.jdbc. This package
supports all JDK releases from 1.1.x through 1.4; JDBC 3.0 features that depend on
JDK1.4 are made available to earlier JDK versions through Oracle extensions.
Transaction Savepoints
The JDBC 3.0 specification supports savepoints, which offer finer demarcation
within transactions. Applications can set a savepoint within a transaction and then
roll back (but not commit) all work done after the savepoint. Savepoints relax the
atomicity property of transactions. A transaction with a savepoint is atomic in the
sense that it appears to be a single unit outside the context of the transaction, but
code operating within the transaction can preserve partial states.
JDK1.4 specifies a standard savepoint API. Oracle JDBC provides two different
savepoint interfaces: one (java.sql.Savepoint) for JDK1.4 and one
(oracle.jdbc.OracleSavepoint) that works across all supported JDK
versions. JDK1.4 adds savepoint-related APIs to java.sql.Connection; the
Oracle JDK version-independent interface oracle.jdbc.OracleConnection
provides equivalent functionality.
Creating a Savepoint
You create a savepoint using either Connection.setSavepoint(), which
returns a java.sql.Savepoint instance, or
OracleConnection.oracleSetSavepoint(), which returns an
oracle.jdbc.OracleSavepoint instance.
A savepoint is either named or unnamed. You specify a savepoint’s name by
supplying a string to the setSavepoint() method; if you do not specify a name,
the savepoint is assigned an integer ID. You retrieve a name using
getSavepointName(); you retrieve an ID using getSavepointId().
Releasing a Savepoint
You remove a savepoint using Connection.releaseSavepoint(Savepoint
svpt) or
OracleConnection.oracleReleaseSavepoint(OracleSavepoint svpt).
Savepoint Notes
■ After a savepoint has been released, attempting to reference it in a rollback
operation will cause an SQLException to be thrown.
■ When a transaction is committed or rolled back, all savepoints created in that
transaction are automatically released and become invalid.
■ Rolling a transaction back to a savepoint automatically releases and makes
invalid any savepoints created after the savepoint in question.
Savepoint Interfaces
The following methods are used to get information from savepoints. These methods
are defined within both the java.sql.Connection and
oracle.jdbc.OracleSavepoint interfaces:
public int getSavepointId() throws SQLException;
Return the savepoint ID for an unnamed savepoint.
Exceptions:
■ SQLException: Thrown if self is a named savepoint.
public String getSavepointName() throws SQLException;
Return the name of a named savepoint.
Exceptions:
■ SQLException: Thrown if self is an unnamed savepoint.
These methods are defined within the java.sql.Connection interface:
public Savepoint setSavepoint() throws SQLException;
Create an unnamed savepoint.
Exceptions:
■ SQLException: Thrown on database error, or if Connection is in
auto-commit mode or participating in a global transaction.
publicSavepoint setSavepoint(String name) throws SQLException;
Create a named savepoint. If a Savepoint by this name already exists, this
instance replaces it.
Exceptions:
■ SQLException: Thrown on database error or if Connection is in
auto-commit mode or participating in a global transaction.
public void rollback(Savepoint savepoint) throws SQLException;
Remove specified Savepoint from current transaction. Any references to the
savepoint after it is removed cause an SQLException to be thrown.
Exceptions:
■ SQLException: Thrown on database error or if Connection is in
auto-commit mode or participating in a global transaction.
Oracle’s extensions to the JDBC standard include Java packages and interfaces that
let you access and manipulate Oracle datatypes and use Oracle performance
extensions. Compared to standard JDBC, the extensions offer you greater flexibility
in how you can manipulate the data. This chapter presents an overview of the
packages and classes included in Oracle’s extensions to standard JDBC. It also
describes some of the key support features of the extensions.
This chapter includes these topics:
■ Introduction to Oracle Extensions
■ Support Features of the Oracle Extensions
■ Oracle JDBC Packages and Classes
■ Oracle Character Datatypes Support
■ Additional Oracle Type Extensions
Oracle JDBC uses these type maps to determine which Java class to instantiate and
populate when it retrieves Oracle object data from a result set.
Where schema_name is the name of the schema and sql_type_name is the SQL
type name of the object. Notice that schema_name and sql_type_name are
separated by a dot (".").
To specify an object type in JDBC, you use its fully qualified name (that is, a schema
name and SQL type name). It is not necessary to enter a schema name if the type
name is in current naming space (that is, the current schema). Schema naming
follows these rules:
■ Both the schema name and the type name may or may not be quoted. However,
if the SQL type name has a dot in it, such as CORPORATE.EMPLOYEE, the type
name must be quoted.
■ The JDBC driver looks for the first unquoted dot in the object’s name and uses
the string before the dot as the schema name and the string following the dot as
the type name. If no dot is found, the JDBC driver takes the current schema as
default. That is, you can specify only the type name (without indicating a
schema) instead of specifying the fully qualified name if the object type name
belongs to the current schema. This also explains why you must quote the type
name if the type name has a dot in it.
For example, assume that user Scott creates a type called person.address
and then wants to use it in his session. Scott might want to skip the schema
name and pass in person.address to the JDBC driver. In this case, if
person.address is not quoted, then the dot will be detected, and the JDBC
driver will mistakenly interpret person as the schema name and address as
the type name.
■ JDBC passes the object type name string to the database unchanged. That is, the
JDBC driver will not change the character case even if it is quoted.
For example, if ScOtT.PersonType is passed to the JDBC driver as an object
type name, the JDBC driver will pass the string to the database unchanged. As
another example, if there is white space between characters in the type name
string, then the JDBC driver will not remove the white space.
OCI Extensions
See Chapter 17, "JDBC OCI Extensions" for the following OCI driver-specific
information:
■ OCI Driver Connection Pooling
■ Middle-Tier Authentication Through Proxy Connections
■ OCI Driver Transparent Application Failover
■ OCI HeteroRM XA
■ Accessing PL/SQL Index-by Tables
Package oracle.sql
The oracle.sql package supports direct access to data in SQL format. This
package consists primarily of classes that provide Java mappings to SQL datatypes.
Essentially, the classes act as Java wrappers for the raw SQL data. Because data in
an oracle.sql.* object remains in SQL format, no information is lost. For SQL
primitive types, these classes simply wrap the SQL data. For SQL structured types
(objects and arrays), they provide additional information such as conversion
methods and details of structure.
Each of the oracle.sql.* datatype classes extends oracle.sql.Datum, a
superclass that encapsulates functionality common to all the datatypes. Some of the
classes are for JDBC 2.0-compliant datatypes. These classes, as Table 6–1 indicates,
implement standard JDBC 2.0 interfaces in the java.sql package (oracle.jdbc2
for JDK 1.1.x), as well as extending the oracle.sql.Datum class.
You can find more detailed information about each of these classes later in this
chapter. Additional details about use of the Oracle extended types (STRUCT, REF,
ARRAY, BLOB, CLOB, BFILE, and ROWID) are described in the following locations:
■ "Oracle Character Datatypes Support" on page 6-28
Notes:
■ For information about retrieving data from a result set or
callable statement object into oracle.sql.* types, as
opposed to Java types, see Chapter 7, "Accessing and
Manipulating Oracle Data".
■ The LONG and LONG RAW SQL types and REF CURSOR type
category have no oracle.sql.* classes. Use standard JDBC
functionality for these types. For example, retrieve LONG or
LONG RAW data as input streams using the standard JDBC result
set and callable statement methods getBinaryStream() and
getCharacterStream(). Use the getCursor() method for
REF CURSOR types.
The STRUCT class implements the standard JDBC 2.0 java.sql.Struct interface
(oracle.jdbc2.Struct under JDK 1.1.x) and extends the oracle.sql.Datum
class.
In the database, Oracle stores the raw bytes of object data in a linearized form. A
STRUCT object is a wrapper for the raw bytes of an Oracle object. It contains the
SQL type name of the Oracle object and a "values" array of oracle.sql.Datum
objects that hold the attribute values in SQL format.
You can materialize a STRUCT’s attributes as oracle.sql.Datum[] objects if you
use the getOracleAttributes() method, or as java.lang.Object[] objects
if you use the getAttributes() method. Materializing the attributes as
oracle.sql.* objects gives you all the advantages of the oracle.sql.* format:
■ Materializing oracle.sql.STRUCT data in oracle.sql.* format
completely preserves data by maintaining it in SQL format. No translation is
performed. This is useful if you want to access data but not necessarily display
it.
■ It allows complete flexibility in how your Java application unpacks data.
Notes:
■ Elements of the values array, although of the generic Datum
type, actually contain data associated with the relevant
oracle.sql.* type appropriate for the given attribute. You
can cast the element to the appropriate oracle.sql.* type as
desired. For example, a CHAR data attribute within the STRUCT
is materialized as oracle.sql.Datum. To use it as CHAR data,
you must cast it to the oracle.sql.CHAR type.
■ Nested objects in the values array of a STRUCT object are
materialized by the JDBC driver as instances of STRUCT.
In some cases, you might want to manually create a STRUCT object and pass it to a
prepared statement or callable statement. To do this, you must also create a
StructDescriptor object.
For more information about working with Oracle objects using the
oracle.sql.STRUCT and StructDescriptor classes, see "Using the Default
STRUCT Class for Oracle Objects" on page 9-3.
■ BLOBs point to large unstructured binary data items and are supported by the
oracle.sql.BLOB class.
■ CLOBs point to large fixed-width character data items (that is, characters that
require a fixed number of bytes per character) and are supported by the
oracle.sql.CLOB class.
■ BFILEs point to the content of external files (operating system files) and are
supported by the oracle.sql.BFILE class.
You can select a BLOB, CLOB, or BFILE locator from the database using a standard
SELECT statement, but bear in mind that you are receiving only the locator, not the
data itself. Additional steps are necessary to retrieve the data.
For information about how to access and manipulate locators and data for LOBs
and BFILEs, see Chapter 8, "Working with LOBs and BFILEs".
The following code shows how the TimeZone and Calendar objects are created
for US_PACIFIC, which is a time zone name not defined in the JDK:
TimeZone tz = TimeZone.getDefault();
tz.setID("US_PACIFIC");
GregorianCalendar gcal = new GregorianCalendar(tz);
■ updateTIMESTAMP(int paramIdx)
■ updateTIMESTAMPTZ(int paramIdx)
■ updateTIMESTAMPLTZ(int paramIdx)
Before accessing TIMESTAMPLTZ data, call the
OracleConnection.setSessionTime() method to set the session time zone.
When this method is called, the JDBC driver sets the session time zone of the
connection and saves the session time zone so that any TIMESTAMPLTZ data
accessed through JDBC can be adjusted using the session time zone.
Class oracle.sql.OPAQUE
The oracle.sql.OPAQUE class gives you the name and characteristics of the
OPAQUE type and any attributes. OPAQUE types provide access only to the
uninterrupted bytes of the instance.
Package oracle.jdbc
The interfaces of the oracle.jdbc package provide Oracle-specific extensions to
allow access to raw SQL format data by using oracle.sql.* objects.
For the oracle.jdbc package, Table 6–2 lists key interfaces and classes used for
connections, statements, and result sets.
Table 6–2 Key Interfaces and Classes of the oracle.jdbc Package (Cont.)
Interface
Name or Class Key Functionality
OracleDatabaseMetaData Class methods to get meta information about
the database, such as database product
name/version, table information, and
default transaction isolation level
(implements
java.sql.DatabaseMetaData )
OracleTypes Class defines integer constants used to identify
SQL types. For standard types, it uses the
same values as the standard
java.sql.Types class. In addition, it
adds constants for Oracle extended types.
The remainder of this section describes the interfaces and classes of the
oracle.jdbc package. For more information about using these interfaces and
classes to access Oracle type extensions, see Chapter 7, "Accessing and
Manipulating Oracle Data".
Class oracle.jdbc.OracleDriver
Use this class to register the Oracle JDBC drivers for use by your application. You
can input a new instance of this class to the static registerDriver() method of
the java.sql.DriverManager class so that your application can access and use
the Oracle drivers. The registerDriver() method takes as input a "driver" class,
that is, a class that implements the java.sql.Driver interface, as is the case with
OracleDriver.
Once you register the Oracle JDBC drivers, you can create your connection using
the DriverManager class. For more information on registering drivers and writing
a connection string, see "First Steps in JDBC" on page 3-2.
Interface oracle.jdbc.OracleConnection
This interface extends standard JDBC connection functionality to create and return
Oracle statement objects, set flags and options for Oracle performance extensions,
support type maps for Oracle objects, and support client identifiers.
"Additional Oracle Performance Extensions" on page 12-20 describes the
performance extensions, including row prefetching, update batching, and metadata
TABLE_REMARKS reporting.
Interface oracle.jdbc.OracleStatement
This interface extends standard JDBC statement functionality and is the
superinterface of the OraclePreparedStatement and
OracleCallableStatement classes. Extended functionality includes support for
setting flags and options for Oracle performance extensions on a
statement-by-statement basis, as opposed to the OracleConnection interface that
sets these on a connection-wide basis.
"Additional Oracle Performance Extensions" on page 12-20 describes the
performance extensions, including row prefetching and column type definitions.
Key methods include:
■ executeQuery(): Executes a database query and returns an
OracleResultSet object.
■ getResultSet(): Retrieves an OracleResultSet object.
■ close(): Closes the current statement.
These oracle.jdbc.OracleStatement methods are Oracle-defined extensions:
■ defineColumnType(): Defines the type you will use to retrieve data from a
particular database table column.
■ getRowPrefetch(): Retrieves the row-prefetch value for this statement.
■ setRowPrefetch(): Sets the row-prefetch value for this statement.
Interface oracle.jdbc.OraclePreparedStatement
This interface extends the OracleStatement interface and extends standard JDBC
prepared statement functionality. Also, the
oracle.jdbc.OraclePreparedStatement interface is extended by the
OracleCallableStatement interface. Extended functionality consists of
setXXX() methods for binding oracle.sql.* types and objects into prepared
statements, and methods to support Oracle performance extensions on a
statement-by-statement basis.
"Additional Oracle Performance Extensions" on page 12-20 describes the
performance extensions, including database update batching.
Interface oracle.jdbc.OracleCallableStatement
This interface extends the OraclePreparedStatement interface (which extends
the OracleStatement interface) and incorporates standard JDBC callable
statement functionality.
Key methods include:
■ getOracleObject(): This is a generic getXXX() method for retrieving data
into an oracle.sql.Datum object, which can be cast to the specific
oracle.sql.* type as necessary.
■ getXXX(): These methods, such as getCLOB(), are for retrieving data into
specific oracle.sql.* objects.
Interface oracle.jdbc.OracleResultSet
This interface extends standard JDBC result set functionality, implementing
getXXX() methods for retrieving data into oracle.sql.* objects.
Key methods include:
■ getOracleObject(): This is a generic getXXX() method for retrieving data
into an oracle.sql.Datum object. It can be cast to the specific
oracle.sql.* type as necessary.
■ getXXX(): These methods, such as getCLOB(), are for retrieving data into
oracle.sql.* objects.
Interface oracle.jdbc.OracleResultSetMetaData
This interface extends standard JDBC result set metadata functionality to retrieve
information about Oracle result set objects. See "Using Result Set Meta Data
Extensions" on page 7-19 for information on the functionality of the
OracleResultSetMetadata interface.
Class oracle.jdbc.OracleTypes
The OracleTypes class defines constants that JDBC uses to identify SQL types.
Each variable in this class has a constant integer value. The
oracle.jdbc.OracleTypes class duplicates the typecode definitions of the
standard Java java.sql.Types class and contains these additional typecodes for
Oracle extensions:
■ OracleTypes.BFILE
■ OracleTypes.ROWID
■ OracleTypes.CURSOR (for REF CURSOR types)
As in java.sql.Types, all the variable names are in all-caps.
JDBC uses the SQL types identified by the elements of the OracleTypes class in
two main areas: registering output parameters, and in the setNull() method of
the PreparedStatement class.
OracleTypes and the setNull() Method The typecodes in Types and OracleTypes
identify the SQL type of the data item, which the setNull() method sets to NULL.
The setNull() method can be found in the java.sql.PreparedStatement
interface and the oracle.jdbc.OraclePreparedStatement interface.
These are the forms that setNull() can take for PreparedStatement and
OraclePreparedStatement objects (assume a standard prepared statement
object ps):
ps.setNull(int index, int sqlType);
In this example, the prepared statement inserts a NULL STRUCT object of type
EMPLOYEE into the database.
PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO employee_table VALUES (?)");
((oracle.jdbc.OraclePreparedStatement) pstmt)
.setExecuteBatch(10); // Oracle-specific method
Method getJavaSqlConnection()
The getJavaSqlConnection() method of the oracle.sql.* classes returns
java.sql.Connection while the getConnection() method returns
oracle.jdbc.driver.OracleConnection . Because the methods that use the
oracle.jdbc.driver package are deprecated, the getConnection() method
is also deprecated in favor of the getJavaSqlConnection() method.
For the following Oracle datatype classes, the getJavaSqlConnection() method
was added:
■ oracle.sql.ARRAY
■ oracle.sql.BFILE
■ oracle.sql.BLOB
■ oracle.sql.CLOB
■ oracle.sql.OPAQUE
■ oracle.sql.REF
■ oracle.sql.STRUCT
The following shows the getJavaSqlConnection() and the getConnection()
methods in the Array class:
public class ARRAY
{
// New API
//
java.sql.Connection getJavaSqlConnection()
throws SQLException;
// Deprecated API.
//
oracle.jdbc.driver.OracleConnection
getConnection() throws SQLException;
...
}
The usage of SQL NCHAR datatypes is similar to that of the SQL CHAR (CHAR,
VARCHAR2, and CLOB) datatypes. JDBC uses the same classes and methods to access
SQL NCHAR datatypes that are used for the corresponding SQL CHAR datatypes.
Therefore, there are no separate, corresponding classes defined in the oracle.sql
package for SQL NCHAR datatypes. Likewise, there is no separate, corresponding
constant defined in the oracle.jdbc.OracleTypes class for SQL NCHAR
datatypes. The only difference in usage between the two datatypes occur in a data
bind situation: a JDBC program must call the setFormOfUse() method to specify
if the data is bound for a SQL NCHAR datatype.
//
// oracle.jdbc.OraclePreparedStatement.FORM_NCHAR should be used for all NCHAR,
// NVARCHAR2 and NCLOB data types.
//
pstmt.setFormOfUse(2, Const.NCHAR);
pstmt.setFormOfUse(3, Const.NCHAR);
Class oracle.sql.CHAR
The CHAR class is used by Oracle JDBC in handling and converting character data.
The JDBC driver constructs and populates oracle.sql.CHAR objects once
character data has been read from the database.
The CHAR objects constructed and returned by the JDBC driver can be in the
database character set, UTF-8, or ISO-Latin-1 (WE8ISO8859P1 ). The CHAR
objects that are Oracle object attributes are returned in the database character set.
JDBC application code rarely needs to construct CHAR objects directly, since the
JDBC driver automatically creates CHAR objects as character data are obtained
from the database. There may be circumstances, however, where constructing CHAR
objects directly in application code is useful—for example, to repeatedly pass the
same character data to one or more prepared statements without the overhead of
converting from Java strings each time.
Each character set that Oracle supports has a unique, predefined Oracle ID.
For more information on character sets and character set IDs, see the Oracle9i
Database Globalization Support Guide.
The CHAR class has multiple constructors—they can take a string, a byte array,
or an object as input along with the CharacterSet object. In the case of a
string, the string is converted to the character set indicated by the
CharacterSet object before being placed into the CHAR object.
See the oracle.sql.CHAR class Javadoc for more information.
Notes:
■ The CharacterSet object cannot be null.
■ The CharacterSet class is an abstract class, therefore it has
no constructor. The only way to create instances is to use the
make() method.
■ The server recognizes the special value
CharacterSet.DEFAULT_CHARSET as the database character
set. For the client, this value is not meaningful.
■ Oracle does not intend or recommend that users extend the
CharacterSet class.
Example: ROWID The following example shows how to access and manipulate ROWID
data.
Statement stmt = conn.createStatement();
// Query the employee names with "FOR UPDATE" to lock the rows.
// Select the ROWID to identify the rows to be updated.
ResultSet rset =
stmt.executeQuery ("SELECT ename, rowid FROM emp FOR UPDATE");
PreparedStatement pstmt =
conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
Example: Accessing REF CURSOR Data This example shows how to access REF
CURSOR data.
import oracle.jdbc.*;
...
CallableStatement cstmt;
ResultSet cursor;
cstmt = conn.prepareCall
("begin open ? for select ename from emp; end;");
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
cursor = ((OracleCallableStatement)cstmt).getCursor(1);
Table 6–3 Support for Oracle Type Extensions, 8.0.x and 7.3.x JDBC Drivers
Type Extension, Type Extension,
Oracle Datatype OracleTypes Definition Current Drivers 8.0.x/7.3.x drivers
NUMBER OracleTypes.NUMBER oracle.sql.NUMBER no type extension for wrapper class
CHAR OracleTypes.CHAR oracle.sql.CHAR no type extension for wrapper class
RAW OracleTypes.RAW oracle.sql.RAW no type extension for wrapper class
DATE OracleTypes.DATE oracle.sql.DATE no type extension for wrapper class
ROWID OracleTypes.ROWID oracle.sql.ROWID oracle.jdbc.driver.OracleRowid
BLOB OracleTypes.BLOB oracle.sql.BLOB oracle.jdbc.driver.OracleBlob in 8.0.x;
not supported in 7.3.x
CLOB OracleTypes.CLOB oracle.sql.CLOB oracle.jdbc.driver.OracleClob in 8.0.x;
not supported in 7.3.x
BFILE n/a oracle.sql.BFILE oracle.jdbc.driver.OracleBfile in 8.0.x;
not supported in 7.3.x
structured object OracleTypes.STRUCT oracle.sql.STRUCT or not supported
custom class
object reference OracleTypes.REF oracle.sql.REF or custom not supported
class
collection (array) OracleTypes.ARRAY oracle.sql.ARRAY or not supported
custom class
OPAQUE OracleTypes.OPAQUE oracle.sql.OPAQUE not supported
If you need the extended functionality provided by the Oracle extensions to JDBC,
you can select the results into a standard ResultSet object, as above, and then cast
that object into an OracleResultSet object later.
Similarly, when you want to execute a stored procedure using a callable statement,
the JDBC drivers will return an OracleCallableStatement object typed as a
java.sql.CallableStatement . If you want to apply only standard JDBC
methods to the object, then keep it as a CallableStatement type. However, if
you want to use the Oracle extensions on the object, you must cast it to an
OracleCallableStatement type. Although the type by which the Java compiler
will identify the object is changed, the object itself is unchanged.
You use the standard JDBC java.sql.Connection.prepareStatement()
method to create a PreparedStatement object. If you want to apply only
standard JDBC methods to the object, keep it as a PreparedStatement type.
However, if you want to use the Oracle extensions on the object, you must cast it to
an OraclePreparedStatement type. While the type by which the Java compiler
will identify the object is changed, the object itself is unchanged.
Key extensions to the result set and statement classes include
getOracleObject() and setOracleObject() methods that you can use to
access and manipulate data in oracle.sql.* formats, instead of standard Java
formats. For more information, see the next section: "Comparison of Oracle get and
set Methods to Standard JDBC".
When you have retrieved data into a Datum object, you can use the standard Java
instanceof operator to determine which oracle.sql.* type it really is.
For more information on getOracleObject() return types, see Table 7–1,
"Summary of getObject() and getOracleObject() Return Types" on page 7-6.
Example: Using getOracleObject() with a ResultSet The following example creates a table
that contains a column of character data (in this case, a row number) and a column
containing a BFILE locator. A SELECT statement retrieves the contents of the table
into a result set. The getOracleObject() then retrieves the CHAR data into the
char_datum variable and the BFILE locator into the bfile_datum variable. Note
that because getOracleObject() returns a Datum object, the results must be cast
to CHAR and BFILE, respectively.
stmt.execute ("CREATE TABLE bfile_table (x varchar2 (30), b bfile)");
stmt.execute
("INSERT INTO bfile_table VALUES (’one’, bfilename (’TEST_DIR’, ’file1’))");
cstmt.execute ();
For information on type compatibility between all SQL and Java types, see
Table 20–1, "Valid SQL Datatype-Java Class Mappings" on page 20-2.
getBigDecimal() Note
Example: Casting Return Values This example assumes that you have fetched data of
type CHAR into a result set (where it is in column 1). Because you want to
manipulate the CHAR data without losing precision, cast your result set to an
OracleResultSet, and use getOracleObject() to return the CHAR data in
oracle.sql.* format. If you do not cast your result set, you have to use
getObject(), which returns your character data into a Java String and loses
some of the precision of your SQL data.
The getOracleObject() method returns an oracle.sql.CHAR object into an
oracle.sql.Datum return variable unless you cast the output. Cast the
getOracleObject() output to oracle.sql.CHAR if you want to use a CHAR
return variable and any of the special functionality of that class (such as the
getCharacterSet() method that returns the character set used to represent the
characters).
CHAR char = (CHAR)ors.getOracleObject(1);
CharacterSet cs = char.getCharacterSet();
Alternatively, you can return the object into a generic oracle.sql.Datum return
variable and cast it later when you must use the CHAR getCharacterSet()
method.
Datum rawdatum = ors.getOracleObject(1);
...
CharacterSet cs = ((CHAR)rawdatum).getCharacterSet();
For a prepared statement object ps, the setOracleObject() method binds the
oracle.sql.CHAR data represented by the charVal variable to the prepared
statement. To bind the oracle.sql.* data, the prepared statement must be cast to
an OraclePreparedStatement. Similarly, the setObject() method binds the
Java String data represented by the variable strVal.
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
((OraclePreparedStatement)ps).setOracleObject(1,charVal);
ps.setObject(2,strVal);
Note: Under JDK 1.1.x, for compatibility with the JDBC 2.0
standard, OraclePreparedStatement and
OracleCallableStatement classes provide setXXX() methods
that take oracle.jdbc2 input parameters for BLOBs, CLOBs,
object references, and arrays. For example, a setBlob() method
takes an oracle.jdbc2.Blob input parameter, where it would
take a java.sql.Blob input parameter under JDK 1.2.x.
For information on all supported type mappings between SQL and Java, see
Table 20–1, "Valid SQL Datatype-Java Class Mappings" on page 20-2.
binds.) For information about how to work around these limits using the stream
API, see "Using Streams to Avoid Limits on setBytes() and setString()" on page 3-31.
Note:
■ Remember to cast your prepared statement object to
OraclePreparedStatement to use the setFixedCHAR()
method.
■ There is no need to use setFixedCHAR() for an INSERT
statement. The database always automatically pads the data to
the column width as it inserts it.
((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC");
runQuery (pstmt); // This will print "No of rows are 1"
while (rs.next())
System.out.println("No of rows are " + rs.getInt(1));
rs.close();
rs = null;
}
while (rset.next())
{
OracleResultSetMetaData orsmd = ((OracleResultSet)rset).getMetaData();
int numColumns = orsmd.getColumnCount();
System.out.println("Num of columns = " + numColumns);
This chapter describes how you use JDBC and the oracle.sql.* classes to access
and manipulate LOB and BFILE locators and data, covering the following topics:
■ Oracle Extensions for LOBs and BFILEs
■ Working with BLOBs and CLOBs
■ Working with BFILEs
Example: Getting BLOB and CLOB Locators from a Result Set Assume the database has a
table called lob_table with a column for a BLOB locator, blob_col, and a
column for a CLOB locator, clob_col. This example assumes that you have
already created the Statement object, stmt.
First, select the LOB locators into a standard result set, then get the LOB data into
appropriate Java classes:
// Select LOB locator into standard result set.
ResultSet rs =
stmt.executeQuery ("SELECT blob_col, clob_col FROM lob_table");
while (rs.next())
{
// Get LOB locators into Java wrapper classes.
java.sql.Blob blob = (java.sql.Blob)rs.getObject(1);
java.sql.Clob clob = (java.sql.Clob)rs.getObject(2);
(...process...)
}
The output is cast to java.sql.Blob and Clob. As an alternative, you can cast the
output to oracle.sql.BLOB and CLOB to take advantage of extended
functionality offered by the oracle.sql.* classes. For example, you can rewrite
the above code to get the LOB locators as:
// Get LOB locators into Java wrapper classes.
oracle.sql.BLOB blob = (BLOB)rs.getObject(1);
oracle.sql.CLOB clob = (CLOB)rs.getObject(2);
(...process...)
Example: Getting a CLOB Locator from a Callable Statement The callable statement
methods for retrieving LOBs are identical to the result set methods.
For example, if you have an OracleCallableStatement ocs that calls a
function func that has a CLOB output parameter, then set up the callable statement
as in the following example.
This example registers OracleTypes.CLOB as the typecode of the output
parameter.
OracleCallableStatement ocs =
(OracleCallableStatement)conn.prepareCall("{? = call func()}");
ocs.registerOutParameter(1, OracleTypes.CLOB);
ocs.execute();
oracle.sql.CLOB clob = ocs.getCLOB(1);
OracleCallableStatement ocs =
(OracleCallableStatement)conn.prepareCall("{call proc(?))}");
ocs.setClob(1, my_clob);
ocs.execute();
Notes:
■ To write LOB data, the application must acquire a write lock on
the LOB object. One way to accomplish this is through a
SELECT FOR UPDATE. Also, disable auto-commit mode.
■ The implementation of the data access API uses direct native
calls in the JDBC OCI and server-side internal drivers, thereby
providing better performance. You can use the same API on the
LOB classes in all Oracle JDBC drivers.
■ In the case of the JDBC Thin driver only, the implementation of
the data access API uses the PL/SQL DBMS_LOB package
internally. You never have to use DBMS_LOB directly. This is in
contrast to the 8.0.x drivers. For more information on the
DBMS_LOB package, see the Oracle9i Supplied PL/SQL Packages
Reference.
To read and write LOB data, you can use these methods:
■ To read from a BLOB, use the getBinaryStream() method of an
oracle.sql.BLOB object to retrieve the entire BLOB as an input stream. This
returns a java.io.InputStream object.
As with any InputStream object, use one of the overloaded read() methods
to read the LOB data, and use the close() method when you finish.
Notes:
■ The stream "write" methods described in this section write
directly to the database when you write to the output stream.
You do not need to execute an UPDATE to write the data. CLOBs
and BLOBs are transaction controlled. After writing to either,
you must commit the transaction for the changes to be
permanent. BFILEs are not transaction controlled. Once you
write to them the changes are permanent, even if the
transaction is rolled back, unless the external file system does
something else.
■ When writing to or reading from a CLOB, the JDBC drivers
perform all character set conversions for you.
...
The following example reads a vector of data into a character array, then uses the
getCharacterOutputStream() method to write the array of character data to a
CLOB. The getCharacterOutputStream() method returns a
java.io.Writer instance in an oracle.sql.CLOB object, not a
java.sql.Clob object.
java.io.Writer writer;
The next example reads a vector of data into a byte array, then uses the
getAsciiOutputStream() method to write the array of ASCII data to a CLOB.
Because getAsciiOutputStream() returns an ASCII output stream, you must
cast the output to a oracle.sql.CLOB datatype.
java.io.OutputStream out;
Create a BLOB or CLOB column in a table with the SQL CREATE TABLE statement,
then populate the LOB. This includes creating the LOB entry in the table, obtaining
the LOB locator, creating a file handler for the data (if you are reading the data from
a file), and then copying the data into the LOB.
3. Declare a file handler for the john.gif file, then print the length of the file.
This value will be used later to ensure that the entire file is read into the BLOB.
Next, create a FileInputStream object to read the contents of the GIF file,
and an OutputStream object to retrieve the BLOB as a stream.
File binaryFile = new File("john.gif");
System.out.println("john.gif length = " + binaryFile.length());
FileInputStream instream = new FileInputStream(binaryFile);
OutputStream outstream = blob.getBinaryOutputStream();
5. Use the read() method to read the GIF file to the byte array buffer, then use
the write() method to write it to the BLOB. When you finish, close the input
and output streams.
while ((length = instream.read(buffer)) != -1)
outstream.write(buffer, 0, length);
instream.close();
outstream.close();
Once your data is in the BLOB or CLOB, you can manipulate the data. This is
described in the next section, "Accessing and Manipulating BLOB and CLOB Data".
into a result set. The result of the data manipulation is to print the length of the
BLOB in bytes.
// Select the blob - what we are really doing here
// is getting the blob locator into a result set
BLOB blob;
cmd = "SELECT * FROM my_blob_table";
ResultSet rset = stmt.executeQuery (cmd);
■ trim(long): Trims the value of the BLOB to the length specified by the
argument.
Notes:
■ In the OracleResultSet and OracleCallableStatement
classes, getBFILE() and getBfile() both return
oracle.sql.BFILE. There is no java.sql interface (or
oracle.jdbc2 interface) for BFILEs.
■ If using getObject() or getOracleObject(), remember to
cast the output, as necessary. For more information, see
"Casting Your get Method Return Values" on page 7-10.
Example: Getting a BFILE locator from a Result Set Assume that the database has a table
called bfile_table with a single column for the BFILE locator bfile_col. This
example assumes that you have already created your Statement object stmt.
Select the BFILE locator into a standard result set. If you cast the result set to an
OracleResultSet, you can use getBFILE() to get the BFILE locator:
// Select the BFILE locator into a result set
ResultSet rs = stmt.executeQuery("SELECT bfile_col FROM bfile_table");
while (rs.next())
{
oracle.sql.BFILE my_bfile = ((OracleResultSet)rs).getBFILE(1);
}
Note that as an alternative, you can use getObject() to return the BFILE locator.
In this case, because getObject() returns a java.lang.Object, cast the results
to BFILE. For example:
oracle.sql.BFILE my_bfile = (BFILE)rs.getObject(1);
Example: Getting a BFILE Locator from a Callable Statement Assume you have an
OracleCallableStatement object ocs that calls a function func that has a
BFILE output parameter. The following code example sets up the callable
statement, registers the output parameter as OracleTypes.BFILE, executes the
statement, and retrieves the BFILE locator:
OracleCallableStatement ocs =
(OracleCallableStatement)conn.prepareCall("{? = call func()}");
ocs.registerOutParameter(1, OracleTypes.BFILE);
ocs.execute();
oracle.sql.BFILE bfile = ocs.getBFILE(1);
Example: Passing a BFILE Locator to a Prepared Statement Assume you want to insert a
BFILE locator into a table, and you have an OraclePreparedStatement object
ops to insert data into a table. The first column is a string (to designate a row
number), the second column is a BFILE, and you have a valid oracle.sql.BFILE
object (bfile). Write the BFILE to the database as follows:
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement
("INSERT INTO my_bfile_table VALUES (?,?)");
ops.setString(1,"one");
ops.setBFILE(2, bfile);
ops.execute();
Notes:
■ BFILEs are read-only. You cannot insert data or otherwise write
to a BFILE.
■ You cannot use JDBC to create a new BFILE. They are created
only externally.
Example: Reading BFILE Data The following example uses the getBinaryStream()
method of an oracle.sql.BFILE object to read BFILE data into a byte stream and
then read the byte stream into a byte array. The example assumes that the BFILE has
already been opened.
// Read BFILE data from a BFILE locator
Inputstream in = bfile.getBinaryStream();
byte[] byte_array = new byte{10};
int byte_read = in.read(byte_array);
Use the SQL CREATE TABLE statement to create a table containing a BFILE column,
then execute the statement. In this example, the name of the table is my_bfile_
table.
// Create a table containing a BFILE field
cmd = "CREATE TABLE my_bfile_table (x varchar2 (30), b bfile)";
stmt.execute (cmd);
In this example, the VARCHAR2 column designates a row number, and the BFILE
column stores the locator of the BFILE data.
In this example, the name of the directory alias is test_dir. The locator of the
BFILE file1.data is loaded into the BFILE column on row one, and the locator
of the BFILE jdbcTest.data is loaded into the bfile column on row two.
As an alternative, you might want to create the row for the row number and BFILE
locator now, but wait until later to insert the locator. In this case, insert the row
number into the table, and null as a place holder for the BFILE locator.
cmd ="INSERT INTO my_bfile_table VALUES ('three', null)";
stmt.execute(cmd);
Here, three is inserted into the row number column, and null is inserted as the
place holder. Later in your program, insert the BFILE locator into the table by using
a prepared statement.
First get a valid BFILE locator into the bfile object:
rs = stmt.executeQuery("SELECT b FROM my_bfile_table WHERE x=’two’");
rs.next();
oracle.sql.BFILE bfile = ((OracleResultSet)rs).getBFILE(1);
Then, create your prepared statement. Note that because this example uses the
setBFILE() method to identify the BFILE, the prepared statement must be cast to
an OraclePreparedStatement:
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement
(UPDATE my_bfile_table SET b=? WHERE x = ’three’);
ops.setBFILE(1, bfile);
ops.execute();
Now row two and row three contain the same BFILE.
Once you have the BFILE locators available in a table, you can access and
manipulate the BFILE data. The next section, "Accessing and Manipulating BFILE
Data", describes this.
if (rset.next ())
BFILE bfile = ((OracleResultSet)rset).getBFILE (2);
bfile.openFile();
This chapter describes JDBC support for user-defined object types. It discusses
functionality of the generic, weakly typed oracle.sql.STRUCT class, as well as
how to map to custom Java classes that implement either the JDBC standard
SQLData interface or the Oracle ORAData interface. This chapter also describes
how JDBC drivers access SQLJ object types in SQL representation.
The following topics are covered:
■ Mapping Oracle Objects
■ Using the Default STRUCT Class for Oracle Objects
■ Creating and Using Custom Object Classes for Oracle Objects
■ Object-Type Inheritance
■ Using JPublisher to Create Custom Object Classes
■ Describing an Object Type
■ SQLJ Object Types
Note: When you use the SQLData interface, you must use a Java
type map to specify your SQL-Java mapping, unless weakly typed
java.sql.Struct objects will suffice. See "Understanding Type
Maps for SQLData Implementations" on page 9-11.
STRUCT Descriptors
Creating and using a STRUCT object requires a descriptor—an instance of the
oracle.sql.StructDescriptor class—to exist for the SQL type (such as
EMPLOYEE) that will correspond to the STRUCT object. You need only one
StructDescriptor object for any number of STRUCT objects that correspond to
the same SQL type.
STRUCT descriptors are further discussed in "Creating STRUCT Objects and
Descriptors" on page 9-4.
Where sql_type_name is a Java string containing the name of the Oracle object
type (such as EMPLOYEE ) and connection is your connection object.
Once you have your StructDescriptor object for the Oracle object type, you can
construct the STRUCT object. To do this, pass in the StructDescriptor, your
connection object, and an array of Java objects containing the attributes you want
the STRUCT to contain.
STRUCT struct = new STRUCT(structdesc, connection, attributes);
Note: The JDBC driver does not verify that the connection object
from the setConnection() method connects to the same
database from which the type descriptor was initially derived.
Another way to return the object as a STRUCT object is to cast the result set to an
OracleResultSet object and use the Oracle extension getSTRUCT() method:
oracle.sql.STRUCT oracleSTRUCT=((OracleResultSet)rs).getSTRUCT(1);
or:
oracle.sql.Datum[] attrs =
((oracle.sql.STRUCT)jdbcStruct).getOracleAttributes();
or:
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
((OraclePreparedStatement)ps).setOracleObject(1, mySTRUCT);
or:
rs.getObject(int columnIndex, Map map);
For a description of how to create these custom object classes with SQLData, see
"Creating and Using Custom Object Classes for Oracle Objects" on page 9-10.
When using a SQLData implementation, if you do not include a type map entry,
then the object will map to the oracle.sql.STRUCT class by default. (ORAData
implementations, by contrast, have their own mapping functionality so that a type
map entry is not required. When using a ORAData implementation, use the Oracle
getORAData() method instead of the standard getObject() method.)
The type map relates a Java class to the SQL type name of an Oracle object. This
one-to-one mapping is stored in a hash table as a keyword-value pair. When you
read data from an Oracle object, the JDBC driver considers the type map to
determine which Java class to use to materialize the data from the Oracle object type
(SQL object type). When you write data to an Oracle object, the JDBC driver gets the
SQL type name from the Java class by calling the getSQLTypeName() method of
the SQLData interface. The actual conversion between SQL and Java is performed
by the driver.
The attributes of the Java class that corresponds to an Oracle object can use either
Java native types or Oracle native types (instances of the oracle.sql.* classes) to
store attributes.
Creating a Type Map Object and Defining Mappings for a SQLData Implementation
When using a SQLData implementation, the JDBC applications programmer is
responsible for providing a type map, which must be an instance of a class as
follows:
■ under JDK 1.2.x, an instance of a class that implements the standard
java.util.Map interface
or:
■ under JDK 1.1.x, an instance of a class that extends the standard
java.util.Dictionary class (or an instance of the Dictionary class itself)
You have the option of creating your own class to accomplish this, but under either
JDK 1.2.x or JDK 1.1.x, the standard class java.util.Hashtable meets the
requirement.
Note: If you are migrating from JDK 1.1.x to JDK 1.2.x, you must
ensure that your code uses a class that implements the Map
interface. If you were using the java.util.Hashtable class
under 1.1.x, then no change is necessary.
Hashtable and other classes used for type maps implement a put() method that
takes keyword-value pairs as input, where each key is a fully qualified SQL type
name and the corresponding value is an instance of a specified Java class.
A type map is associated with a connection instance. The standard
java.sql.Connection interface and the Oracle-specific
oracle.jdbc.OracleConnection interface include a getTypeMap() method.
Under JDK 1.2.x, both return a Map object; under JDK 1.1.x, both return a
Dictionary object.
The remainder of this section covers the following topics:
■ Adding Entries to an Existing Type Map
■ Creating a New Type Map
2. Use the type map’s put() method to add map entries. The put() method
takes two arguments: a SQL type name string and an instance of a specified
Java class that you want to map to.
myMap.put(sqlTypeName, classObject);
The sqlTypeName is a string that represents the fully qualified name of the
SQL type in the database. The classObject is the Java class object to which
you want to map the SQL type. Get the class object with the
Class.forName() method, as follows:
myMap.put(sqlTypeName, Class.forName(className));
For example, if you have a PERSON SQL datatype defined in the CORPORATE
database schema, then map it to a Person Java class defined as Person with
this statement:
myMap.put("CORPORATE.PERSON", Class.forName("Person"));
The map has an entry that maps the PERSON SQL datatype in the CORPORATE
database to the Person Java class.
Note: SQL type names in the type map must be all uppercase,
because that is how the Oracle database stores SQL names.
2. Use the put() method of the type map object to add entries to the map. For
more information on the put() method, see Step 2 under "Adding Entries to an
Existing Type Map" on page 9-13. For example, if you have an EMPLOYEE SQL
type defined in the CORPORATE database, then you can map it to an Employee
class object defined by Employee.java, with this statement:
newMap.put("CORPORATE.EMPLOYEE", class.forName("Employee"));
3. When you finish adding entries to the map, use the OracleConnection
object’s setTypeMap() method to overwrite the connection’s existing type
map. For example:
oraconn.setTypeMap(newMap);
■ The readSQL() method takes as input a SQLInput stream and a string that
indicates the SQL type name of the data (in other words, the name of the Oracle
object type, such as EMPLOYEE).
When your Java application calls getObject(), the JDBC driver creates a
SQLInput stream object and populates it with data from the database. The
driver can also determine the SQL type name of the data when it reads it from
the database. When the driver calls readSQL() , it passes in these parameters.
■ For each Java datatype that maps to an attribute of the Oracle object,
readSQL() must call the appropriate readXXX() method of the SQLInput
stream that is passed in.
For example, if you are reading EMPLOYEE objects that have an employee name
as a CHAR variable and an employee number as a NUMBER variable, you must
have a readString() call and a readInt() call in your readSQL() method.
JDBC calls these methods according to the order in which the attributes appear
in the SQL definition of the Oracle object type.
■ The readSQL() method takes the data that the readXXX() methods read and
convert, and assigns them to the appropriate fields or elements of a custom
object class instance.
You must implement writeSQL() as follows:
public void writeSQL(SQLOutput stream) throws SQLException
1. Query the database to read the Oracle object into a JDBC result set.
ResultSet rs = stmt.executeQuery("SELECT emp_col FROM personnel");
The PERSONNEL table contains one column, EMP_COL, of SQL type EMP_
OBJECT. This SQL type is defined in the type map to map to the Java class
Employee.
2. Use the getObject() method of your result set to populate an instance of
your custom object class with data from one row of the result set. The
getObject() method returns the user-defined SQLData object because the
type map contains an entry for Employee.
if (rs.next())
Employee emp = (Employee)rs.getObject(1);
Note that if the type map did not have an entry for the object, then
getObject() would return an oracle.sql.STRUCT object. Cast the output
to type STRUCT, because the getObject() method signature returns the
generic java.lang.Object type.
if (rs.next())
STRUCT empstruct = (STRUCT)rs.getObject(1);
The getObject() call triggers readSQL() and readXXX() calls from the
SQLData interface, as described above.
Note: If you want to avoid using a type map, then use the
getSTRUCT() method. This method always returns a STRUCT
object, even if there is a mapping entry in the type map.
3. If you have get methods in your custom object class, then use them to read
data from your object attributes. For example, if EMPLOYEE has an EmpName
(employee name) of type CHAR, and an EmpNum (employee number) of type
NUMBER, then provide a getEmpName() method that returns a Java String
and a getEmpNum() method that returns an integer (int). Then invoke them
in your Java application, as follows:
String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();
3. Use the getObject() method to retrieve the employee object. The following
code assumes that there is a type map entry to map the Oracle object to Java
type Employee:
Employee emp = (Employee)ocs.getObject(1);
OracleCallableStatement ocs =
(OracleCallableStatement) conn.prepareCall("{ call addEmployee(?) }");
This statement uses the emp object and the empname and empnumber variables
assigned in "Reading SQLData Objects from a Result Set" on page 9-17.
2. Prepare a statement that updates an Oracle object in a row of a database table,
as appropriate, using the data provided in your Java datatype object.
PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO PERSONNEL VALUES (?)");
{
ORAData create (Datum d, int sql_Type_Code) throws SQLException;
}
This method takes as input the column index of the data in your result set, and
a ORADataFactory instance. For example, you can implement a
getORAFactory() method in your custom object class to produce the
ORADataFactory instance to input to getORAData(). The type map is not
required when using Java classes that implement ORAData .
or:
■ Use the standard getObject(index, map) method specified by the
ResultSet interface to retrieve data as instances of ORAData. In this case, you
must have an entry in the type map that identifies the factory class to be used
for the given object type, and its corresponding SQL type name.
To insert object data:
■ Use the Oracle-specific OraclePreparedStatement class setORAData()
method (assume an OraclePreparedStatement object ops):
ops.setORAData (int bind_index, ORAData custom_obj);
This method takes as input the parameter index of the bind variable and the
name of the object containing the variable.
or:
Notes:
■ ORAData and ORADataFactory are defined as separate
interfaces so that different Java classes can implement them if
you wish (such as an Employee class and an
EmployeeFactory class).
■ To use the ORAData interface, your custom object classes must
import oracle.sql.* (or at least ORAData,
ORADataFactory, and Datum).
1. Query the database to read the Oracle object into a result set, casting to an
Oracle result set.
OracleResultSet ors = (OracleResultSet)stmt.executeQuery
("SELECT Emp_col FROM PERSONNEL");
or:
if (ors.next())
ORAData datum = ors.getORAData(1, Employee.getORAFactory());
This example assumes that Employee is the name of your custom object class
and ors is the name of your OracleResultSet object.
In case you do not want to use getORAData(), the JDBC drivers let you use
the getObject() method of a standard JDBC ResultSet to retrieve
ORAData data. However, you must have an entry in the type map that
identifies the factory class to be used for the given object type, and its
corresponding SQL type name.
For example, if the SQL type name for your object is EMPLOYEE, then the
corresponding Java class is Employee, which will implement ORAData. The
corresponding Factory class is EmployeeFactory, which will implement
ORADataFactory.
Use this statement to declare the EmployeeFactory entry for your type map:
map.put ("EMPLOYEE", Class.forName ("EmployeeFactory"));
Then use the form of getObject() where you specify the map object:
Employee emp = (Employee) rs.getObject (1, map);
If the connection’s default type map already has an entry that identifies the
factory class to be used for the given object type, and its corresponding SQL
type name, then you can use this form of getObject():
3. If you have get methods in your custom object class, use them to read data
from your object attributes into Java variables in your application. For example,
if EMPLOYEE has EmpName of type CHAR and EmpNum (employee number) of
type NUMBER, provide a getEmpName() method that returns a Java string and
a getEmpNum() method that returns an integer. Then invoke them in your Java
application as follows:
String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();
Note: The type map is not used when you are performing
database INSERT and UPDATE operations.
1. If you have set methods in your custom object class, then use them to write
data from Java variables in your application to attributes of your Java datatype
object.
emp.setEmpName(empname);
emp.setEmpNum(empnumber);
This statement uses the emp object and the empname and empnumber variables
defined in "Reading Data from an Oracle Object Using a ORAData
Implementation" on page 9-23.
2. Write an Oracle prepared statement that updates an Oracle object in a row of a
database table, as appropriate, using the data provided in your Java datatype
object.
The setORAData() method calls the toDatum() method of the custom object
class instance to retrieve an oracle.sql.STRUCT object that can be written to
the database.
In this step you could also use the setObject() method to bind the Java
datatype. For example:
opstmt.setObject(1,emp);
Note: You can use your Java datatype objects as either IN or OUT
bind variables.
Object-Type Inheritance
Object-type inheritance is an Oracle9i feature which allows a new object type to be
created by extending another object type. (While Oracle9i does not yet support
JDBC 3.0, object-type inheritance is supported and documented.) The new object
type is then a subtype of the object type from which it extends. The subtype
automatically inherits all the attributes and methods defined in the supertype. The
subtype can add attributes and methods, and overload or override methods
inherited from the supertype.
Object-type inheritance introduces substitutability. Substitutability is the ability of a
slot declared to hold a value of type T to do so in addition to any subtype of type T.
Oracle9i JDBC drivers handle substitutability transparently.
A database object is returned with its most specific type without losing information.
For example, if the STUDENT_T object is stored in a PERSON_T slot, the Oracle JDBC
driver returns a Java object that represents the STUDENT_T object.
Creating Subtypes
Create custom object classes if you want to have Java classes that explicitly
correspond to the Oracle object types. (See "Creating and Using Custom Object
Classes for Oracle Objects" on page 9-10.) If you have a hierarchy of object types,
you may want a corresponding hierarchy of Java classes.
The most common way to create a database subtype in JDBC is to pass the extended
SQL CREATE TYPE command to the execute() method of the
java.sql.Statement interface. For example, to create a type inheritance
hierarchy for:
PERSON_T
|
STUDENT_T
|
PARTTIMESTUDENT_T
In the following code, the "foo" member procedure in type ST is overloaded and
the member procedure "print" overwrites the copy it inherits from type T.
CREATE TYPE T AS OBJECT (...,
MEMBER PROCEDURE foo(x NUMBER),
MEMBER PROCEDURE Print(),
...
NOT FINAL;
Once the subtypes have been created, they can be used as both columns of a base
table as well as attributes of a object type. For complete details on the syntax to
create subtypes, see the Oracle9i Application Developer’s Guide - Object-Relational
Features for details.
Person.java using ORAData Code for the Person.java class which implements the
ORAData and ORADataFactory interfaces:
class Person implements ORAData, ORADataFactory
{
static final Person _personFactory = new Person();
public Person () {}
Student.java extending Person.java Code for the Student.java class which extends
the Person.java class:
class Student extends Person
{
static final Student _studentFactory = new Student ();
public Student () {}
Customized classes that implement the ORAData interface do not have to mirror the
database object type hierarchy. For example, you could have declared the above
class, Student, without a superclass. In this case, Student would contain fields to
hold the inherited attributes from PERSON_T as well as the attributes declared by
STUDENT_T.
}
}
Person.java using SQLData Code for the Person.java class which implements the
SQLData interface:
import java.sql.*;
public Person () {}
Student.java extending Student.java Code for the Student.java class which extends
the Person.java class:
import java.sql.*;
Customized classes that implement the SQLData interface do not have to mirror the
database object type hierarchy. For example, you could have declared the above
class, Student, without a superclass. In this case, Student would contain fields to
hold the inherited attributes from PERSON_T as well as the attributes declared by
STUDENT_T.
Student.java using SQLData Code for the Student.java class which does not extend
the Person.java class, but implements the SQLData interface directly:
import java.sql.*;
public Student () {}
JPublisher Utility
Even though you can manually create customized classes that implement the
SQLData, ORAData , and ORADataFactory interfaces, it is recommended that you
use Oracle9i JPublisher to automatically generate these classes. The customized
classes generated by JPublisher that implement the SQLData, ORAData, and
ORADataFactory interfaces, can mirror the inheritance hierarchy.
To learn more about JPublisher, see "Using JPublisher to Create Custom Object
Classes" on page 9-45 and the Oracle9i JPublisher User’s Guide.
if (s != null)
{
if (s instanceof Person)
System.out.println ("This is a Person");
else if (s instanceof Student)
System.out.println ("This is a Student");
else if (s instanceof ParttimeStudent)
System.out.pritnln ("This is a PartimeStudent");
else
System.out.println ("Unknown type");
}
}
The JDBC drivers check the connection type map for each call to the following:
■ getObject() method of the java.sql.ResultSet and
java.sql.CallableStatement interfaces
■ getAttribute() method of the java.sql.Struct interface
■ getArray() method of the java.sql.Array interface
■ getValue() method of the oracle.sql.REF interface
s is initialized with data fields inherited from PERSON_T and STUDENT_T, and data
fields defined in PARTTIMESTUDENT_T.
if (sqlname.equals ("SCOTT.PERSON")
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
}
else if (sqlname.equals ("SCOTT.STUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
}
else if (sqlname.equals ("SCOTT.PARTTIMESTUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
System.out.println ("numHours="+((BigDecimal)attrs[5]).intValue());
}
else
throw new Exception ("Invalid type name: "+sqlname);
}
}
rset.close ();
stmt.close ();
conn.close ();
JPublisher Functionality
You can direct JPublisher to create custom object classes that implement either the
SQLData interface or the ORAData interface, according to how you set the
JPublisher type mappings.
If you use the ORAData interface, JPublisher will also create a custom reference
class to map to object references for the Oracle object type. If you use the SQLData
interface, JPublisher will not produce a custom reference class; you would use
standard java.sql.Ref instances instead.
If you want additional functionality, you can subclass the custom object class and
add features as desired. When you run JPublisher, there is a command-line option
for specifying both a generated class name and the name of the subclass you will
implement. For the SQL-Java mapping to work properly, JPublisher must know the
subclass name, which is incorporated into some of the functionality of the generated
class.
For more information about JPublisher features or options, see the Oracle9i
JPublisher User’s Guide.
Type-Mapping Modes
JPublisher defines the following type-mapping modes, two of which apply to
numeric types only:
■ JDBC mapping (setting jdbc)—Uses standard default mappings between SQL
types and Java native types. For a custom object class, uses a SQLData
implementation.
■ Oracle mapping (setting oracle)—Uses corresponding oracle.sql types to
map to SQL types. For a custom object, reference, or collection class, uses a
ORAData implementation.
■ object-JDBC mapping (for numeric types only) (setting objectjdbc)—This is
an extension of JDBC mapping. Where relevant, object-JDBC mapping uses
numeric object types from the standard java.lang package (such as
java.lang.Integer, Float, and Double), instead of primitive Java types
(such as int, float, and double). The java.lang types are nullable, while
the primitive types are not.
Table 9–1 JPublisher SQL Type Categories, Supported Settings, and Defaults
SQL Type JPublisher
Category Mapping Option Mapping Settings Default
UDT types -usertypes oracle, jdbc oracle
numeric types -numbertypes oracle, jdbc, objectjdbc, bigdecimal objectjdbc
LOB types -lobtypes oracle, jdbc oracle
built-in types -builtintypes oracle, jdbc jdbc
This returns a string that specifies the type of the specified attribute, such as
"BigDecimal".
■ int getColumnCount() throws SQLException
This returns the number of attributes in the object type.
As well as the following method, supported only by StructMetaData:
■ String getOracleColumnClassName(int column)
throws SQLException
This returns the fully-qualified name of the oracle.sql.Datum subclass
whose instances are manufactured if the OracleResultSet class
getOracleObject() method is called to retrieve the value of the specified
attribute. For example, "oracle.sql.NUMBER".
To use the getOracleColumnClassName() method, you must cast the
ResultSetMetaData object (that was returned by the getMetaData()
method) to a StructMetaData object.
Example The following method shows how to retrieve information about the
attributes of a structured object type. This includes the initial step of creating a
StructDescriptor instance.
//
// Print out the ADT's attribute names and types
//
void getAttributeInfo (Connection conn, String type_name) throws SQLException
{
// get the type descriptor
StructDescriptor desc = StructDescriptor.createDescriptor (type_name, conn);
// temporary buffers
String attr_name;
int attr_type;
String attr_typeName;
According to the Information Technology - SQLJ - Part 2 document, a SQLJ object type
is a database object type designed for Java. A SQLJ object type maps to a Java class.
Once the mapping is "registered" through the extended SQL CREATE TYPE
command (a DDL statement), the Java application can insert or select the Java
objects directly into or from the database through an Oracle9i JDBC driver. The
database SQL engine can access the data fields of these Java objects, stored as SQL
attributes in the database, as well as invoke the methods defined in these Java
objects.
The extended SQL CREATE TYPE command is further discussed in "Creating a Java
Class Definition for a SQLJ Object Type" on page 9-53.
SQLJ object type functionality has the following features:
■ Publishes pre-existing Java classes to SQL using the extended SQL CREATE
TYPE command, creating a mapping between the SQL type and the Java type;
no type map is necessary
■ Provides a standard way to access Java objects in the database
■ Provides a standard way to store Java objects persistently
■ Accesses static fields in a Java class using SQL static functions and defines SQL
member functions having side effects, which is useful in UPDATE statements
You can obtain additional information on SQLJ object types at the ANSI Web site:
http://www.ansi.org/
The Java class corresponding to a SQLJ object type implements the SQLData
interface or the ORAData and ORADataFactory interfaces, as is the case for
custom Java classes that correspond to user-defined Oracle object types in previous
Oracle JDBC implementations. The Java class provides methods for moving data
between SQL and Java—either using the readSQL() and writeSQL() methods
for classes implementing the SQLData interface, or the toDatum() method for
classes implementing the ORAData interface.
The following code shows how the Person class for the SQLJ object type, PERSON_
T, implements the SQLData interface:
import java.sql.*;
import java.io.*;
public Person () {}
{
stream.writeInt (ssn);
stream.writeString (name);
stream.writeObject (address);
}
// other methods
public int length () { ... }
}
Note: You can also invoke the loadjava tool by calling the
dbms_java.loadjava (’...’) procedure from SQL*Plus,
specifying the loadjava command line as the input string.
The following command shows the loadjava tool loading the Person class into
the database:
% loadjava -u SCOTT/TIGER -r -f -v Person.class
The extended SQL CREATE TYPE command performs the following functions:
■ It checks to see if a Java class exists that corresponds to the SQLJ object type and
whether this class is public and implements the required interface as specified
in the USING clause (see the catalog book Magdi told you about).
■ It populates the database catalog with the external names for attributes,
functions, and the Java class.
■ If external attribute names are used, then the extended SQL CREATE TYPE
command checks for the existence of the Java fields (as specified in the
EXTERNAL NAME clause) and whether these fields are compatible with
corresponding SQL attributes.
■ If external attribute names are used, then the extended SQL CREATE TYPE
command validates the SQL external function against the Java class methods.
■ It generates internal classes to support constructors, external static variable
names, and external functions that return self as a result. The classes are
stored in the same schema as the SQLJ object type.
See the Oracle9i SQL Reference for a complete description of the extended SQL
CREATE TYPE command.
Once a SQLJ object type is created, it can be used for the column type of a database
table as well as for attributes of other object types. The database SQL engine can
access the attributes of the SQLJ object type as well as invoke methods. For
example, in SQL*Plus you can do the following:
SQL> select col2.ss_no from tab2;
...
SQL> select col2.length() from tab2;
...
External Attribute Names The extended SQL CREATE TYPE command validates the
compatibility between SQLJ object type attributes and corresponding Java fields by
comparing the external attribute names (external name variables) to the
corresponding Java fields. An external attribute name specifies a field in the Java
class. For example, in the following code, the ssn external name specifies the ss_
no field in the Person Java class:
CREATE TYPE person_t AS OBJECT EXTERNAL NAME 'Person' LANGUAGE JAVA
USING SQLData
(ss_no number (9) external name 'ssn',
name VARCHAR2(200) external name 'name',
address Address_t external name 'address',
member function length return number external name 'length () return int');
/
Though optional, external attribute names are good to use when one-to-one
correspondences exists between the attributes of a SQLJ object type and the fields of
a corresponding Java class. If you choose to use this feature and a declared external
attribute name does not exist in the Java class or the SQL attribute is not compatible
with the external attribute type, then a SQL error occurs upon executing the
extended SQL CREATE TYPE command. Or if the provided SQLData or ORAData
interface implementation does not support compatible mapping between a SQL
attribute and its corresponding Java field, then an exception may occur.
External SQL Functions The extended SQL CREATE TYPE command validates the
compatibility between SQLJ object type functions and corresponding Java methods
by comparing the external SQL function (MEMBER FUNCTION or STATIC
FUNCTION) to the corresponding Java method. An external SQL function specifies a
method in the Java class.
When creating a SQLJ object type in the database, you can declare one or more
external SQL functions along with the attributes. Table 9–2 describes the possible
kinds of functions that you can use in the creation of a SQLJ object type:
Table 9–2 Kinds of External SQL Functions for a SQLJ Object Type
Function Kind Syntax
Static functions Oracle- STATIC FUNCTION foo (...) RETURN
specific NUMBER EXTERNAL NAME ’bar (...)
return double’
Member function SQLJ Part2 MEMBER FUNCTION foo (...) RETURN
Standard NUMBER EXTERNAL NAME ’todo (...)
return double’
Static function that returns Oracle- STATIC FUNCTION foo RETURN NUMBER
the value of a static Java specific EXTERNAL VARIABLE NAME ’max_length’
field, which can only be
public
Static function that calls a Oracle- STATIC FUNCTION foo (...) RETURN
constructor in Java specific person_t EXTERNAL NAME ’Person (...)
return Person’
Member function that has SQLJ Part2 MEMBER FUNCTION foo (...) RETURN
a side effect (changes the Standard SELF AS RESULT EXTERNAL NAME ’dump
state of an object) (...) return Person’
Code Examples The following code shows some typical external SQL functions being
declared for a SQLJ object type:
CREATE TYPE person_t AS OBJECT EXTERNAL NAME 'Person' LANGUAGE JAVA
USING SQLData
(
num number external name ’foo’,
The following code shows how to create the SQLJ object type PERSON_T to
represent the Java class Person:
CREATE TYPE person_t AS OBJECT EXTERNAL NAME 'Person' LANGUAGE JAVA
USING SQLData
(
ss_no NUMBER(9) EXTERNAL NAME 'ssn',
name VARCHAR2(100) EXTERNAL NAME 'name',
address address_t EXTERNAL NAME 'address',
MEMBER FUNCTION length RETURN integer EXTERNAL NAME 'length() return int'
);
Creating SQLJ Object Types Using JDBC As an alternative to creating a SQLJ object type
directly in SQL, using a tool such as SQL*Plus, you can create a SQLJ object type
using JDBC code. The following code shows this:
Connection conn = ....
Statement stmt = conn.createStatement();
String sql =
"CREATE TYPE person_t as object external name 'Person' language java
" using SQLData "+
"( "+
" ss_no number(9), "+
" name varchar2(100), "+
" address address_t "+
")";
stmt.execute(sql);
stmt.close(); // release the resource
conn.close(); // close the database connection
Before sending the Java object to the database, the Oracle JDBC driver converts it
into a format acceptable to the database SQL engine.
To create a SQLJ object type of person_t, as described in previous sections, the
JDBC application creates a Person object and then inserts it into the database. The
following code binds the person_t SQLJ object type instance in a SQL insert
statement:
Person person = new Person();
person.ssn = 1000;
person.name = "SCOTT";
person.address = new Address ("some street", "some city", "CA", 12345);
Assume that you have table tab1 containing column col1 of SQLJ object type
PERSON_T. If PERSON_T was created to map to the Java class Person, then
querying col1 through the Oracle JDBC driver will return the data as instances of
the Person class. The following code shows this:
ResultSet rset = stmt.executeQuery ("select col1 from tab1");
while (rset.next())
Person value = (Person) rset.getObject(1);
Notes:
■ If the Java class does not exist on the client when the SQLJ
object type is returned, a run-time exception occurs.
■ If the Java class exists on the client but has been modified, then
the SQLJ object type will only be read or written properly if the
readSQL() and writeSQL() methods for the SQLData
interface, or the create() and toDatum() methods for the
ORAData interface, remain compatible with the original set of
SQL attributes.
Where name is the SQLJ object type and conn is the connection to the database.
The oracle.sql.StructDescriptor class defines the following meta data
(instance) methods:
■ boolean isJavaObject() : indicates whether the type descriptor points to a
SQLJ object type
■ String getJavaClassName() : returns the name of the Java class
corresponding to the SQLJ object type
■ String getLanguage() : returns the string JAVA for a SQLJ object type and
returns null for an Oracle object type (SQL object type)
■ ResultSetMetaData getMetaData() : returns the meta data of the SQLJ
object type as a result set meta data type (see "Functionality for Getting Object
Meta Data" on page 9-49)
■ getLocalAttributeCount() : returns the number of local attributes being
used, which does not include those used through inheritance
The oracle.jdbc.StructMetaData interface provides the following method:
■ String getAttributeJavaName(int idx) : returns the field name given
the relative position of the SQL attribute; the relative position starts at zero and
inherited attributes are included
Table 9–3 SQLJ Object Type and Custom Object Type Features Compared
Feature SQLJ Object Type Behavior Custom Object Type Behavior
Typecodes Use the OracleTypes.JAVA_STRUCT Use the OracleTypes.STRUCT typecode
typecode to register a SQLJ object type as a to register a custom object type as a SQL OUT
SQL OUT parameter. The parameter. The OracleTypes.STRUCT
OracleTypes.JAVA_STRUCT typecode typecode is also used in the _SQL_
is also used in the _SQL_TYPECODE field TYPECODE field of a class implementing the
of a class implementing the ORAData or ORAData or SQLData interface.The
SQLData interface. This typecode is OracleTypes.STRUCT typecode is
reported in a ResultSetMetaData reported in a ResultSetMetaData
instance and meta data or stored procedure. instance and meta data or stored procedure.
Creation Create a Java class implementing the Issue the extended SQL CREATE TYPE
SQLData or ORAData and command for a custom object type and then
ORADataFactory interfaces first and create the SQLData or ORAData Java
then load the Java class into the database. wrapper class using JPublisher, or do this
Next, issue the extended SQL CREATE manually. See "Using JPublisher to Create
TYPE command to create the SQLJ object Custom Object Classes" on page 9-45 for
type. complete details.
Method Support Supports external names, constructor calls, There is no default class for implementing
and calls for member functions with side type methods as Java methods. Some methods
effects. See Table 9–2, "Kinds of External SQL may also be implemented in SQL.
Functions for a SQLJ Object Type" on
page 9-58 for a complete description.
Type Mapping Type mapping is automatically done by the Register the correspondence between SQL and
extended SQL CREATE TYPE command. Java in a type map. Otherwise, the type is
However, the SQLJ object type must have a materialized as oracle.sql.STRUCT.
defining Java class on the client.
Corresponding If the corresponding Java class is missing If the corresponding Java class is missing
Java Class is when a SQLJ object type is returned to the when a custom object type is returned to the
Missing client, you will receive an exception. client, then oracle.sql.STRUCT is used.
Inheritance There are rules for mapping SQL hierarchy There are no mapping rules.
to a Java class hierarchy. See the Oracle9i
SQL Reference for a complete description of
these rules.
This chapter describes Oracle extensions to standard JDBC that let you access and
manipulate object references. The following topics are discussed:
■ Oracle Extensions for Object References
■ Overview of Object Reference Functionality
■ Retrieving and Passing an Object Reference
■ Accessing and Updating Object Values through an Object Reference
■ Custom Reference Classes with JPublisher
Notes:
■ If you are using the oracle.sql.ORAData interface for
custom object classes, you will presumably use ORAData for
corresponding custom reference classes as well. If you are using
the standard java.sql.SQLData interface for custom object
classes, however, you can only use weak Java types for
references (java.sql.Ref or oracle.sql.REF). The
SQLData interface is for mapping SQL object types only.
■ You cannot create REF objects in your JDBC application; you
can only retrieve existing REF objects from the database.
■ You cannot have a reference to an array, even though arrays,
like objects, are structured types.
Result Set and Callable Statement Getter Methods The OracleResultSet and
OracleCallableStatement classes support getREF() and getRef() methods
to retrieve REF objects as output parameters—either as oracle.sql.REF instances
or java.sql.Ref instances (oracle.jdbc2.Ref under JDK 1.1.x). You can also
use the getObject() method. These methods take as input a String column
name or int column index.
■ getValue(): Retrieves the referenced object from the database, allowing you
to access its attribute values. It optionally takes a type map object, or else you
can use the default type map of the database connection object.
This method is an Oracle extension.
■ setValue(): Sets the referenced object in the database, allowing you to update
its attribute values. It takes an instance of the object type as input (either a
STRUCT instance or an instance of a custom object class).
This method is an Oracle extension.
The ADDRESS object type has two attributes: a street name and a house number. The
PEOPLE table has three columns: a column for character data, a column for numeric
data, and a column containing a reference to an ADDRESS object.
To retrieve an object reference, follow these general steps:
1. Use a standard SQL SELECT statement to retrieve the reference from a database
table REF column.
2. Use getREF() to get the address reference from the result set into a REF object.
3. Let Address be the Java custom class corresponding to the SQL object type
ADDRESS.
4. Add the correspondence between the Java class Address and the SQL type
ADDRESS to your type map.
5. Use the getValue() method to retrieve the contents of the Address reference.
Cast the output to a Java Address object.
Here is the code for these steps (other than adding Address to the type map),
where stmt is a previously defined statement object. The PEOPLE database table is
defined earlier in this section:
ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE");
while (rs.next())
{
As with other SQL types, you could retrieve the reference with the getObject()
method of your result set. Note that this would require you to cast the output. For
example:
REF ref = (REF)rs.getObject(1);
Then, you can create a Java Address object (this example omits the content for the
constructor of the Address class) that corresponds to the database ADDRESS object.
Use the setValue() method of the REF class to set the value of the database
object:
Address addr = new Address(...);
ref.setValue(addr);
Here, the setValue() method updates the database ADDRESS object immediately.
For more information about JPublisher, see "Using JPublisher to Create Custom
Object Classes" on page 9-45, or refer to the Oracle9i JPublisher User’s Guide.
This chapter describes Oracle extensions to standard JDBC that let you access and
manipulate Oracle collections, which map to Java arrays, and their data. The
following topics are discussed:
■ Oracle Extensions for Collections (Arrays)
■ Overview of Collection (Array) Functionality
■ Creating and Using Arrays
■ Using a Type Map to Map Array Elements
■ Custom Collection Classes with JPublisher
strongly typed, which can help you find coding errors during compilation that
might not otherwise be discovered until runtime.
Furthermore, custom collection classes produced by JPublisher offer the feature of
being writable, with individually accessible elements. (This is also something you
could implement in a custom collection class yourself.)
For more information about custom collection classes, see "Custom Collection
Classes with JPublisher" on page 11-27.
Creating Collections
This section presents background information about creating Oracle collections.
Because Oracle supports only named collections, you must declare a particular
VARRAY type name or nested table type name. "VARRAY" and "nested table" are not
types themselves, but categories of types.
A SQL type name is assigned to a collection when you create it, as in the following
SQL syntax:
CREATE TYPE <sql_type_name> AS <datatype>;
A VARRAY is an array of varying size. It has an ordered set of data elements, and
all the elements are of the same datatype. Each element has an index, which is a
number corresponding to the element's position in the VARRAY. The number of
elements in a VARRAY is the "size" of the VARRAY. You must specify a maximum
size when you declare the VARRAY type. For example:
CREATE TYPE myNumType AS VARRAY(10) OF NUMBER;
This statement defines myNumType as a SQL type name that describes a VARRAY of
NUMBER values that can contain no more than 10-elements.
A nested table is an unordered set of data elements, all of the same datatype. The
database stores a nested table in a separate table which has a single column, and the
type of that column is a built-in type or an object type. If the table is an object type,
it can also be viewed as a multi-column table, with a column for each attribute of
the object type. Create a nested table with this SQL syntax:
CREATE TYPE myNumList AS TABLE OF integer;
This statement identifies myNumList as a SQL type name that defines the table type
used for the nested tables of the type INTEGER.
Once the multi-level collection types have been created, they can be used as both
columns of a base table as well as attributes of a object type.
See the Oracle9i Application Developer’s Guide - Object-Relational Features for the SQL
syntax to create multi-level collections types and how to specify the storage tables
for inner collections.
Result Set and Callable Statement Getter Methods The OracleResultSet and
OracleCallableStatement classes support getARRAY() and getArray()
methods to retrieve ARRAY objects as output parameters—either as
oracle.sql.ARRAY instances or java.sql.Array instances
(oracle.jdbc2.Array under JDK 1.1.x). You can also use the getObject()
method. These methods take as input a String column name or int column
index.
ARRAY Descriptors
Creating and using an ARRAY object requires the existence of a descriptor—an
instance of the oracle.sql.ArrayDescriptor class—to exist for the SQL type
of the collection being materialized in the array. You need only one
ArrayDescriptor object for any number of ARRAY objects that correspond to the
same SQL type.
ARRAY descriptors are further discussed in "Creating ARRAY Objects and
Descriptors" on page 11-11.
Each method using the first signature returns collection elements as an XXX[],
where XXX is a Java primitive type. Each method using the second signature returns
a slice of the collection containing the number of elements specified by count,
starting at the index location.
Where NUM_VARRAY is the SQL type name for the collection type.
Note: The name of the collection type is not the same as the type
name of the elements. For example:
CREATE TYPE person AS object
(c1 NUMBER(5), c2 VARCHAR2(30));
CREATE TYPE array_of_persons AS varray(10)
OF person;
In the preceding statements, the SQL name of the collection type is
ARRAY_OF_PERSON. The SQL name of the collection elements is
PERSON.
Before you can construct an Array object, an ArrayDescriptor must first exist
for the given SQL type of the array. If an ArrayDescriptor does not exist, then
you must construct one by passing the SQL type name of the collection type and
your Connection object (which JDBC uses to go to the database to gather meta
data) to the constructor.
ArrayDescriptor arraydesc = ArrayDescriptor.createDescriptor
(sql_type_name, connection);
Where sql_type_name is the type name of the array and connection is your
Connection object.
Once you have your ArrayDescriptor object for the SQL type of the array, you
can construct the ARRAY object. To do this, pass in the array descriptor, your
connection object, and a Java object containing the individual elements you want
the array to contain.
ARRAY array = new ARRAY(arraydesc, connection, elements);
int[][][] elems = { {{1}, {1, 2}}, {{2}, {2, 3}}, {{3}, {3, 4}} };
// some operations
...
Note: The JDBC driver does not verify that the connection object
from the setConnection() method connects to the same
database from which the type descriptor was initially derived.
the index into the array for that element, and the second column stores the element
value. In the case of VARRAYs, the index represents the position of the element in
the array. In the case of nested tables, which are by definition unordered, the index
reflects only the return order of the elements in the particular query.
Oracle recommends using getResultSet() when getting data from nested tables.
Nested tables can have an unlimited number of elements. The ResultSet object
returned by the method initially points at the first row of data. You get the contents
of the nested table by using the next() method and the appropriate getXXX()
method. In contrast, getArray() returns the entire contents of the nested table at
one time.
The getResultSet() method uses the connection’s default type map to
determine the mapping between the SQL type of the Oracle object and its
corresponding Java datatype. If you do not want to use the connection’s default
type map, another version of the method, getResultSet(map), enables you to
specify an alternate type map.
Oracle also provides the getResultSet(index,count) and
getResultSet(index,count,map) methods to retrieve a subset of the array
elements.
getArray() The getArray() method is a standard JDBC method that returns the
array elements into a java.lang.Object instance that you can cast as
appropriate (see "Comparing the Data Retrieval Methods" on page 11-17). The
elements are converted to the Java types corresponding to the SQL type of the data
in the original array.
Oracle also provides a getArray(index,count) method to retrieve a subset of
the array elements.
In this case, the result set contains one row for each array element, with two
columns in each row. The first column stores the index into the array; the second
column stores the element value.
If you use getArray() to retrieve an array of primitive datatypes, then a
java.lang.Object that contains the element values is returned. The elements of
this array are of the Java type corresponding to the SQL type of the elements. For
example:
BigDecimal[] values = (BigDecimal[]) intArray.getArray();
Note that if you use getResultSet() to obtain the array, you would first get the
result set object, then use the next() method to iterate through it. Notice the use of
the parameter indexes in the getInt() method to retrieve the element index and
the element value.
ResultSet rset = my_array.getResultSet();
while (rset.next())
{
while (rset.next())
{
ARRAY varray3 = (ARRAY) rset.getObject (1);
Object varrayElems = varray3.getArray (1); // access array elements of
"varray3"
Datum[] varray3Elems = (Datum[]) varrayElems;
{
ARRAY varray2 = (ARRAY) varray3Elems[i];
Datum[] varray2Elems = varray2.getOracleArray(); // access array elements of
"varray2"
while (varray1Elems.next())
System.out.println ("idx="+varray1Elems.getInt(1)+"
value="+varray1Elems.getInt(2));
}
}
}
rset.close ();
stmt.close ();
conn.close ();
2. Define the array that you want to pass to the prepared statement as an
oracle.sql.ARRAY object.
ARRAY array = new ARRAY(descriptor, connection, elements);
If you want to retrieve all the employees belonging to the SALES department into
an array of instances of the custom object class EmployeeObj , then you must add
an entry to the type map to specify mapping between the EMPLOYEE SQL type and
the EmployeeObj custom object class.
To do this, first create your statement and result set objects, then select the
EMPLOYEE_LIST associated with the SALES department into the result set. Cast the
result set to OracleResultSet so you can use the getARRAY() method to
retrieve the EMPLOYEE_LIST into an ARRAY object (employeeArray in the
example below).
The EmployeeObj custom object class in this example implements the SQLData
interface.
Statement s = conn.createStatement();
OracleResultSet rs = (OracleResultSet)s.executeQuery
("SELECT Employees FROM employee_table WHERE DeptName = ’SALES’");
Now that you have the EMPLOYEE_LIST object, get the existing type map and add
an entry that maps the EMPLOYEE SQL type to the EmployeeObj Java type.
// add type map entry to map SQL type
// "EMPLOYEE" to Java type "EmployeeObj"
Map map = conn.getTypeMap();
map.put("EMPLOYEE", Class.forName("EmployeeObj"));
Next, retrieve the SQL EMPLOYEE objects from the EMPLOYEE_LIST. To do this,
invoke the getArray() method of the employeeArray array object. This method
returns an array of objects. The getArray() method returns the EMPLOYEE objects
into the employees object array.
// Retrieve array elements
Object[] employees = (Object[]) employeeArray.getArray();
Finally, create a loop to assign each of the EMPLOYEE SQL objects to the
EmployeeObj Java object emp.
// Each array element is mapped to EmployeeObj object.
for (int i=0; i<employees.length; i++)
{
EmployeeObj emp = (EmployeeObj) employees[i];
...
}
This chapter describes the Oracle performance extensions to the JDBC standard.
In the course of discussing update batching, it also includes a discussion of the
standard update-batching model provided with JDBC 2.0.
This chapter covers the following topics:
■ Update Batching
■ Additional Oracle Performance Extensions
Update Batching
You can reduce the number of round trips to the database, thereby improving
application performance, by grouping multiple UPDATE, DELETE, or INSERT
statements into a single "batch" and having the whole batch sent to the database and
processed in one trip. This is referred to in this manual as update batching and in the
Sun Microsystems JDBC 2.0 specification as batch updates.
This is especially useful with prepared statements, when you are repeating the same
statement with different bind variables.
With Oracle8i release 8.1.6 and higher, Oracle JDBC supports two distinct models
for update batching:
■ the standard model, supported since Oracle8i release 8.1.6 and implementing
the Sun Microsystems JDBC 2.0 Specification, which is referred to as standard
update batching
■ the Oracle-specific model, supported since release 8.1.5 and independent of the
Sun Microsystems JDBC 2.0 Specification, which is referred to as Oracle update
batching
■ You can choose to explicitly execute a batch at any time, overriding both the
connection batch value and the statement batch value.
Standard update batching is a manual, explicit model. There is no batch value. You
manually add operations to the batch and then explicitly choose when to execute
the batch.
Oracle update batching is a more efficient model because the driver knows ahead of
time how many operations will be batched. In this sense, the Oracle model is more
static and predictable. With the standard model, the driver has no way of knowing
in advance how many operations will be batched. In this sense, the standard model
is more dynamic in nature.
If you want to use update batching, here is how to choose between the two models:
■ Use Oracle update batching if portability is not critical. This will probably result
in the greatest performance improvement.
■ Use standard update batching if portability is a higher priority than
performance.
Note that with standard update batching, you can use either standard
PreparedStatement, CallableStatement, and Statement objects, or
Oracle-specific OraclePreparedStatement, OracleCallableStatement,
and OracleStatement objects.
Notes:
■ Do not mix standard update batching syntax with Oracle
update batching syntax in the same application. The JDBC
driver will throw an exception when you mix these syntaxes.
■ Disable auto-commit mode if you use either update batching
model. In case an error occurs while you are executing a batch,
this allows you the option of committing or rolling back the
operations that executed successfully prior to the error.
Even though this sets the default batch value for all the prepared statements of the
connection, you can override it by calling setDefaultBatch() on individual
Oracle prepared statements.
The connection batch value will apply to statement objects created after this batch
value was set.
3. If you send an execute-update call to the database at this point, then no data
will be sent to the database, and the call will return 0.
// No data is sent to the database by this call to executeUpdate
System.out.println ("Number of rows updated so far: "
+ ps.executeUpdate ());
4. If you enter a set of input values for a second row and an execute-update, then
the number of batch calls to executeUpdate() will be equal to the batch
value of 2. The data will be sent to the database, and both rows will be inserted
in a single round trip.
ps.setInt (1, 11);
ps.setString (2, "Applications");
ps.close ();
To check the particular statement batch value of an Oracle prepared statement, use
the OraclePreparedStatement class getExecuteBatch() method:
Integer batch_val = ((OraclePreparedStatement)ps).getExecuteBatch();
Calling commit() on the connection object in Oracle batching not only commits
operations in batches that have been executed, but also issues an implicit
sendBatch() call to execute all pending batches. So commit() effectively
commits changes for all operations that have been added to a batch.
conn.setAutoCommit(false);
PreparedStatement ps =
conn.prepareStatement("insert into dept values (?, ?, ?)");
ps.setInt(1, 23);
ps.setString(2, "Sales");
ps.setString(3, "USA");
ps.executeUpdate(); //JDBC queues this for later execution
ps.setInt(1, 24);
ps.setString(2, "Blue Sky");
ps.setString(3, "Montana");
ps.executeUpdate(); //JDBC queues this for later execution
ps.setInt(1, 25);
ps.setString(2, "Applications");
ps.setString(3, "India");
ps.executeUpdate(); //The queue size equals the batch value of 3
//JDBC sends the requests to the database
ps.setInt(1, 26);
ps.setString(2, "HR");
ps.setString(3, "Mongolia");
ps.executeUpdate(); //JDBC queues this for later execution
ps.close();
...
Notes:
■ Do not mix standard update batching syntax with Oracle
update batching syntax in the same application. The Oracle
JDBC driver will throw exceptions when these syntaxes are
mixed.
■ Disable auto-commit mode if you use either update batching
model. In case an error occurs while you are executing a batch,
this allows you the option of committing or rolling back the
operations that executed successfully prior to the error.
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
...
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
The executeBatch() method returns an int array, typically one element per
batched operation, indicating success or failure in executing the batch and
sometimes containing information about the number of rows affected. This is
discussed in "Update Counts in the Oracle Implementation of Standard Batching"
on page 12-15.
Notes:
■ After calling addBatch(), you must call either
executeBatch() or clearBatch() before a call to
executeUpdate(), otherwise there will be a SQL exception.
■ When a batch is executed, operations are performed in the
order in which they were batched.
■ The statement batch is reset to empty once executeBatch()
has returned.
■ An executeBatch() call closes the statement object’s current
result set, if one exists.
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
if (...condition...)
{
int[] updateCounts = pstmt.executeBatch();
...
}
else
{
pstmt.clearBatch();
...
}
Notes:
■ After calling addBatch(), you must call either
executeBatch() or clearBatch() before a call to
executeUpdate(), otherwise there will be a SQL exception.
■ A clearBatch() call resets the statement batch to empty.
■ Nothing is returned by the clearBatch() method.
■ disabling auto-commit mode (which you should always do when using either
update batching model)
■ creating a prepared statement object
■ adding operations to the batch associated with the prepared statement object
■ executing the batch
■ committing the operations from the batch
Assume a Connection instance conn:
conn.setAutoCommit(false);
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
conn.commit();
pstmt.close();
...
You can process the update counts array to determine if the batch executed
successfully. This is discussed in the next section ("Error Handling in the Oracle
Implementation of Standard Batching").
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch(); // Now start a batch
pstmt.setInt(1, 4000);
pstmt.setString(2, "Stan Leland");
pstmt.addBatch();
pstmt.setInt(1, 5000);
pstmt.setString(2, "Amy Feiner");
The old functionality lost all these batch flush values which can be obtained now. To
switch back to the old functionality, you can set the AccumulateBatchResult
property to false , as shown below:
HashTable info = new HashTable ();
info.put ("user", "SCOTT");
info.put ("passwd", "TIGER");
// other properties
...
Example:
((OraclePreparedStatement)pstmt).setExecuteBatch (2);
/*
* Premature batch flush happens here.
*/
pstmt.setInt (1, 22);
pstmt.setString (2, "test22");
int count = pstmt.executeUpdate (); // returns 0
Note: With JDBC 2.0, the ability to preset the fetch size has
become standard functionality. For information about the standard
implementation of this feature, see "Fetch Size" on page 13-24.
is the prefetch setting. Then, once your next() calls have run through those N
rows, JDBC will go back to fetch the next N rows that match the criteria.
You can set the number of rows to prefetch for a particular Oracle statement (any
type of statement). You can also reset the default number of rows that will be
prefetched for all statements in your connection. The default number of rows to
prefetch to the client is 10.
Set the number of rows to prefetch for a particular statement as follows:
1. Cast your statement object to an OracleStatement,
OraclePreparedStatement , or OracleCallableStatement object, as
applicable, if it is not already one of these.
2. Use the setRowPrefetch() method of the statement object to specify the
number of rows to prefetch, passing in the number as an integer. If you want to
check the current prefetch number, use the getRowPrefetch() method of the
Statement object, which returns an integer.
Set the default number of rows to prefetch for all statements in a connection, as
follows:
1. Cast your Connection object to an OracleConnection object.
2. Use the setDefaultRowPrefetch() method of your OracleConnection
object to set the default number of rows to prefetch, passing in an integer that
specifies the desired default. If you want to check the current setting of the
default, then use the getDefaultRowPrefetch() method of the
OracleConnection object. This method returns an integer.
Equivalently, instead of calling setDefaultRowPrefetch(), you can set the
defaultRowPrefetch Java property if you use a Java Properties object in
establishing the connection. See "Specifying a Database URL and Properties
Object" on page 3-6.
Notes:
■ Do not mix the JDBC 2.0 fetch size API and the Oracle
row-prefetching API in your application. You can use one or
the other, but not both.
■ Be aware that setting the Oracle row-prefetch value can affect
not only queries, but also: 1) explicitly refetching rows in a
result set through the result set refreshRow() method
available with JDBC 2.0 (relevant for scroll-sensitive/read-only,
scroll-sensitive/updatable, and scroll-insensitive/updatable
result sets); and 2) the "window" size of a scroll-sensitive result
set, affecting how often automatic refetches are performed. The
Oracle row-prefetch value will be overridden, however, by any
setting of the fetch size. See "Fetch Size" on page 13-24 for more
information.
while( rset.next () )
System.out.println( rset.getString (1) );
while( rset.next() )
System.out.println( rset.getString (1) );
stmt.close();
Set a maximum field size if you do not want to receive the full default length of
the data. Calling the setMaxFieldSize() method of the standard JDBC
Note: You must define the datatype for every column of the
expected result set. If the number of columns for which you specify
types does not match the number of columns in the result set, the
process fails with a SQL exception.
Example: Defining Column Types The following example illustrates the use of this
feature. It assumes you have imported the oracle.jdbc.* interfaces.
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:","scott","tiger");
while (rset.next() )
System.out.println(rset.getString(1));
stmt.close();
As this example shows, you must cast the statement (stmt) to type
OracleStatement in the invocation of the defineColumnType() method. The
connection’s createStatement() method returns an object of type
Standard JDBC 2.0 features in JDK 1.2.x include enhancements to result set
functionality—processing forward or backward, positioning relatively or absolutely,
seeing changes to the database made internally or externally, and updating result
set data and then copying the changes to the database.
This chapter discusses these features, including the following topics:
■ Overview
■ Creating Scrollable or Updatable Result Sets
■ Positioning and Processing in Scrollable Result Sets
■ Updating Result Sets
■ Fetch Size
■ Refetching Rows
■ Seeing Database Changes Made Internally and Externally
■ Summary of New Methods for Result Set Enhancements
The Oracle JDBC drivers also include extensions to support these features in a JDK
1.1.x environment.
For more general and conceptual information about JDBC 2.0 result set
enhancements, refer to the Sun Microsystems JDBC 2.0 API specification.
Overview
This section provides an overview of JDBC 2.0 result set functionality and
categories, and some discussion of implementation requirements for the Oracle
JDBC drivers.
Result Set Functionality and Result Set Categories Supported in JDBC 2.0
Result set functionality in JDBC 2.0 includes enhancements for scrollability and
positioning, sensitivity to changes by others, and updatability.
■ Scrollability, positioning, and sensitivity are determined by the result set type.
■ Updatability is determined by the concurrency type.
Specify the desired result set type and concurrency type when you create the
statement object that will produce the result set.
Together, the various result set types and concurrency types provide for six different
categories of result set.
This section provides an overview of these enhancements, types, and categories.
A sensitive result set can see changes made to the database while the result set is
open, providing a dynamic view of the underlying data. Changes made to the
underlying columns values of rows in the result set are visible.
An insensitive result set is not sensitive to changes made to the database while the
result set is open, providing a static view of the underlying data. You would need to
retrieve a new result set to see changes made to the database.
Sensitivity is not an option in a JDBC 1.0/non-scrollable result set.
Updatability
Updatability refers to the ability to update data in a result set and then (presumably)
copy the changes to the database. This includes inserting new rows into the result
set or deleting existing rows.
Updatability might also require database write locks to mediate access to the
underlying database. Because you cannot have multiple write locks concurrently,
updatability in a result set is associated with concurrency in database access.
Result sets can optionally be updatable under JDBC 2.0, but not under JDBC 1.0.
Important: Because all rows of any scrollable result set are stored
in the client-side cache, a situation where the result set contains
many rows, many columns, or very large columns might cause the
client-side Java virtual machine to fail. Do not specify scrollability for
a large result set.
Scrollable cursors in the Oracle server, and therefore a server-side cache, will be
supported in a future Oracle release.
/**
* Return the data stored in the i-th row and j-th column.
*/
public Object get (int i, int j) throws IOException;
/**
* Remove the i-th row.
*/
public void remove (int i) throws IOException;
/**
* Remove the data stored in i-th row and j-th column
*/
public void remove (int i, int j) throws IOException;
/**
* Remove all data from the cache.
*/
public void clear () throws IOException;
/**
* Close the cache.
*/
public void close () throws IOException;
}
If you implement this interface with your own class, your application code must
instantiate your class and then use the setResultSetCache() method of an
OracleStatement, OraclePreparedStatement, or
OracleCallableStatement object to set the caching mechanism to use your
implementation. Following is the method signature:
In using JDBC 2.0 result set enhancements, however, you may specify the result set
type (for scrollability and sensitivity) and the concurrency type (for updatability)
when you create a generic statement or prepare a prepared statement or callable
statement that will execute a query.
(Note, however, that callable statements are intended to execute stored procedures
and functions and rarely return a result set. Still, the callable statement class is a
subclass of the prepared statement class and so inherits this functionality.)
This section discusses the creation of result sets to use JDBC 2.0 enhancements.
And you can specify one of the following static constant values for concurrency
type:
■ ResultSet.CONCUR_READ_ONLY
■ ResultSet.CONCUR_UPDATABLE
Note: If you are using the Oracle JDBC drivers in a JDK 1.1.x
environment , the static constants discussed here are part of the
Oracle extensions, belonging only to the OracleResultSet class,
which you must specify. For example:
OracleResultSet.TYPE_SCROLL_SENSITIVE
instead of:
ResultSet.TYPE_SCROLL_SENSITIVE
pstmt.setString(1, "28959");
ResultSet rs = pstmt.executeQuery();
...
Workaround As a workaround for the "SELECT *" limitation, you can use table
aliases as in the following example:
SELECT t.* FROM TABLE t ...
Notes:
■ Criteria that would prevent the JDBC driver from fulfilling the
result set type specifications are listed in "Result Set
Limitations" on page 13-10.
■ Any manipulations of the result set type and concurrency type
by the JDBC driver are independent of each other.
beforeFirst() Method Positions to before the first row of the result set, or has no effect
if there are no rows in the result set.
This is where you would typically start iterating through a result set to process it
going forward, and is the default initial position for any kind of result set.
You are outside the result set bounds after a beforeFirst() call. There is no valid
current row, and you cannot position relatively from this point.
afterLast() Method Positions to after the last row of the result set, or has no effect if
there are no rows in the result set.
This is where you would typically start iterating through a result set to process it
going backward.
You are outside the result set bounds after an afterLast() call. There is no valid
current row, and you cannot position relatively from this point.
first() Method Positions to the first row of the result set, or returns false if there are
no rows in the result set.
last() Method Positions to the last row of the result set, or returns false if there are
no rows in the result set.
absolute() Method Positions to an absolute row from either the beginning or end of
the result set. If you input a positive number, it positions from the beginning; if you
input a negative number, it positions from the end. This method returns false if
there are no rows in the result set.
Attempting to move forward beyond the last row, such as an absolute(11) call if
there are 10 rows, will position to after the last row, having the same effect as an
afterLast() call.
Attempting to move backward beyond the first row, such as an absolute(-11)
call if there are 10 rows, will position to before the first row, having the same effect
as a beforeFirst() call.
relative() Method Moves to a position relative to the current row, either forward if you
input a positive number or backward if you input a negative number, or returns
false if there are no rows in the result set.
The result set must be at a valid current row for use of the relative() method.
Attempting to move forward beyond the last row will position to after the last row,
having the same effect as an afterLast() call.
Attempting to move backward beyond the first row will position to before the first
row, having the same effect as a beforeFirst() call.
A relative(0) call is valid but has no effect.
Important: You cannot position relatively from before the first row
(which is the default initial position) or after the last row.
Attempting relative positioning from either of these positions
would result in a SQL exception.
The previous() method works similarly to the next() method, in that it returns
true as long as the new current row is valid, and false as soon as it runs out of
rows (has passed the first row).
rs.afterLast();
while (rs.previous())
{
System.out.println(rs.getString("empno") + " " + rs.getFloat("sal"));
}
...
Unlike relative positioning, you can (and typically do) use next() from before the
first row and previous() from after the last row. You do not have to be at a valid
current row to use these methods.
Note: In a non-scrollable result set, you can process only with the
next() method. Attempting to use the previous() method will
cause a SQL exception.
Presuming the result set is also scrollable, you can position to a row using any of the
available positioning methods (except beforeFirst() and afterLast(), which
do not go to a valid current row), and then delete that row, as in the following
example (presuming a result set rs):
...
rs.absolute(5);
rs.deleteRow();
...
See "Positioning in a Scrollable Result Set" on page 13-13 for information about the
positioning methods.
Important: The deleted row remains in the result set object even
after it has been deleted from the database.
In a scrollable result set, by contrast, a DELETE operation is evident
in the local result set object—the row would no longer be in the
result set after the DELETE. The row preceding the deleted row
becomes the current row, and row numbers of subsequent rows are
changed accordingly.
Refer to "Seeing Internal Changes" on page 13-27 for more
information.
rs.updateFloat(2, 10000.0f);
2. Call the updateRow() method to copy the changes to the database (or the
cancelRowUpdates() method to cancel the changes).
Once you call updateRow(), the changes are executed and will be made
permanent with the next transaction COMMIT operation. Be aware that by
default, the auto-commit flag is set to true so that any executed operation is
committed immediately.
If you choose to cancel the changes before copying them to the database, call the
cancelRowUpdates() method instead. This will also revert to the original
values for that row in the local result set object. Note that once you call the
updateRow() method, the changes are written to the transaction and cannot
be canceled unless you roll back the transaction (auto-commit must be disabled
to allow a ROLLBACK operation).
Positioning to a different row before calling updateRow() also cancels the
changes and reverts to the original values in the result set.
Before calling updateRow(), you can call the usual getXXX() methods to
verify that the values have been updated correctly. These methods take an int
column index or string column name as input. For example:
float myfloat = rs.getFloat(2);
...process myfloat to see if it’s appropriate...
Note: Result set UPDATE operations are visible in the local result
set object for all result set types (forward-only, scroll-sensitive, and
scroll-insensitive).
Refer to "Seeing Internal Changes" on page 13-27 for more
information.
Note: The result set will remember the current position prior to
the moveToInsertRow() call. Afterward, you can go back to it
with a moveToCurrentRow() call.
(Note that you can specify a string for column name, instead of an integer for
column number.)
3. Copy the changes to the database by calling the result set insertRow()
method.
Once you call insertRow(), the insert is executed and will be made
permanent with the next transaction COMMIT operation.
Positioning to a different row before calling insertRow() cancels the insert
and clears the insert-row.
Before calling insertRow() you can call the usual getXXX() methods to
verify that the values have been set correctly in the insert-row. These methods
take an int column index or string column name as input. For example:
float myfloat = rs.getFloat(2);
...process myfloat to see if it’s appropriate...
Example The following example performs a result set INSERT operation, moving to
the insert-row, writing the data, copying the data into the database, and then
returning to what was the current row prior to going to the insert-row. (The column
number is used to specify column 1, and the column name—sal— is used to
specify column 2.)
...
Statement stmt = conn.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs.moveToInsertRow();
rs.updateString(1, "28959");
rs.updateFloat("sal", 100000.0f);
rs.insertRow();
// Changes will be made permanent with the next COMMIT operation.
rs.moveToCurrentRow(); // Go back to where we came from...
...
Update Conflicts
It is important to be aware of the following facts regarding updatable result sets
with the JDBC drivers:
■ The drivers do not enforce write locks for an updatable result set.
■ The drivers do not check for conflicts with a result set DELETE or UPDATE
operation.
A conflict will occur if you try to perform a DELETE or UPDATE operation on a row
updated by another committed transaction.
The Oracle JDBC drivers use the ROWID to uniquely identify a row in a database
table. As long as the ROWID is still valid when a driver tries to send an UPDATE or
DELETE operation to the database, the operation will be executed.
The driver will not report any changes made by another committed transaction.
Any conflicts are silently ignored and your changes will overwrite the previous
changes.
To avoid such conflicts, use the Oracle FOR UPDATE feature when executing the
query that produces the result set. This will avoid conflicts, but will also prevent
simultaneous access to the data. Only a single write lock can be held concurrently
on a data item.
Fetch Size
By default, when Oracle JDBC executes a query, it receives the result set 10 rows at a
time from the database cursor. This is the default Oracle row-prefetch value. You can
change the number of rows retrieved with each trip to the database cursor by
changing the row-prefetch value (see "Oracle Row Prefetching" on page 12-20 for
more information).
JDBC 2.0 also allows you to specify the number of rows fetched with each database
round trip for a query, and this number is referred to as the fetch size. In Oracle
JDBC, the row-prefetch value is used as the default fetch size in a statement object.
Setting the fetch size overrides the row-prefetch setting and affects subsequent
queries executed through that statement object.
Fetch size is also used in a result set. When the statement object executes a query,
the fetch size of the statement object is passed to the result set object produced by
the query. However, you can also set the fetch size in the result set object to override
the statement fetch size that was passed to it. (Also note that changes made to a
statement object’s fetch size after a result set is produced will have no affect on that
result set.)
The result set fetch size, either set explicitly, or by default equal to the statement
fetch size that was passed to it, determines the number of rows that are retrieved in
any subsequent trips to the database for that result set. This includes any trips that
are still required to complete the original query, as well as any refetching of data into
the result set. (Data can be refetched, either explicitly or implicitly, to update a
scroll-sensitive or scroll-insensitive/updatable result set. See "Refetching Rows" on
page 13-26.)
affect any subsequent trips to the database to get more rows for the original query,
as well as affecting any later refetching of rows. (See "Refetching Rows" on
page 13-26.)
Note: Do not mix the JDBC 2.0 fetch size API and the Oracle row
prefetching API in your application. You can use one or the other,
but not both.
Refetching Rows
The result set refreshRow() method is supported for some types of result sets for
refetching data. This consists of going back to the database to re-obtain the database
rows that correspond to N rows in the result set, starting with the current row,
where N is the fetch size (described above in "Fetch Size" on page 13-24). This lets
you see the latest updates to the database that were made outside of your result set,
subject to the isolation level of the enclosing transaction.
Because refetching re-obtains only rows that correspond to rows already in your
result set, it does nothing about rows that have been inserted or deleted in the
database since the original query. It ignores rows that have been inserted, and rows
will remain in your result set even after the corresponding rows have been deleted
from the database. When there is an attempt to refetch a row that has been deleted
in the database, the corresponding row in the result set will maintain its original
values.
Following is the refreshRow() method signature:
■ void refreshRow() throws SQLException
You must be at a valid current row when you call this method, not outside the row
bounds and not at the insert-row.
With the 8.1.6 release, the refreshRow() method is supported for the following
result set categories:
■ scroll-sensitive/read-only
■ scroll-sensitive/updatable
■ scroll-insensitive/updatable
Oracle JDBC might support additional result set categories in future releases.
For implementation details of scroll-sensitive result sets, including exactly how and
how soon external updates become visible, see "Oracle Implementation of
Scroll-Sensitive Result Sets" on page 13-30.
JDBC 2.0 DatabaseMetaData objects include the following methods to verify this.
Each takes a result set type as input (ResultSet.TYPE_FORWARD_ONLY,
ResultSet.TYPE_SCROLL_SENSITIVE , or ResultSet.TYPE_SCROLL_
INSENSITIVE).
■ boolean othersDeletesAreVisible(int) throws SQLException
■ boolean othersUpdatesAreVisible(int) throws SQLException
■ boolean othersInsertsAreVisible(int) throws SQLException
Table 13–1 Visibility of Internal and External Changes for Oracle JDBC
Can See Can See Can See Can See Can See Can See
Internal Internal Internal External External External
Result Set Type DELETE? UPDATE? INSERT? DELETE? UPDATE? INSERT?
forward-only no yes no no no no
scroll-sensitive yes yes no no yes no
scroll-insensitive yes yes no no no no
For implementation details of scroll-sensitive result sets, including exactly how and
how soon external updates become visible, see "Oracle Implementation of
Scroll-Sensitive Result Sets" on page 13-30.
Notes:
■ Remember that explicit use of the refreshRow() method,
described in "Refetching Rows" on page 13-26, is distinct from
the concept of "visibility" of external changes. This is discussed
in "Seeing External Changes" on page 13-28.
■ Remember that even when external changes are "visible", as
with UPDATE operations underlying a scroll-sensitive result set,
they are not "detected". The result set rowDeleted(),
rowUpdated(), and rowInserted() methods always return
false. This is further discussed in "Visibility versus Detection
of External Changes" on page 13-29.
rows in the result set starting with that row, where N is the fetch size being used by
the result set (see "Fetch Size" on page 13-24). Note that there is no current row, and
therefore no window, when a result set is first created. The default position is before
the first row, which is not a valid current row.
As you move from row to row, the window remains unchanged as long as the
current row stays within that window. However, once you move to a new current
row outside the window, you redefine the window to be the N rows starting with
the new current row.
Whenever the window is redefined, the N rows in the database corresponding to
the rows in the new window are automatically refetched through an implicit call to
the refreshRow() method (described in "Refetching Rows" on page 13-26),
thereby updating the data throughout the new window.
So external updates are not instantaneously visible in a scroll-sensitive result set;
they are only visible after the automatic refetches just described.
Statement Methods
Following is an alphabetical summary of statement methods for JDBC 2.0 result set
enhancements. These methods are available in generic statement, prepared
statement, and callable statement objects.
■ int getFetchSize() throws SQLException
Check the fetch size to determine how many rows are fetched in each database
round trip when executing a query (also available in result set objects).
■ void setFetchSize(int rows) throws SQLException
Set the fetch size to determine how many rows are fetched in each database
round trip when executing a query (also available in result set objects).
■ void setResultSetCache(OracleResultSetCache cache)
throws SQLException
Use your own client-side cache implementation for scrollable result sets. Create
your own class that implements the OracleResultSetCache interface, then
use the setResultSetCache() method to input an instance of this class to
the statement object that will create the result set.
■ int getResultSetType() throws SQLException
Check the result set type of result sets produced by this statement object (which
was specified when the statement object was created).
■ int getResultSetConcurrency() throws SQLException
Check the concurrency type of result sets produced by this statement object
(which was specified when the statement object was created).
This chapter describes the benefits and use of statement caching, an Oracle JDBC
extension.
This following topics are discussed:
■ About Statement Caching
■ Using Statement Caching
driver automatically searches the cache for a matching statement. The match criteria
are the following:
■ The SQL string in the statement must be identical (case-sensitive) to one in the
cache.
■ The statement type must be the same (prepared or callable).
■ The scrollable type of result sets produced by the statement must be the same
(forward-only or scrollable). You can determine the scrollability when you
create the statement. (See "Specifying Result Set Scrollability and Updatability"
on page 13-8 for complete details.)
If a match is found during the cache search, the cached statement is returned. If a
match is not found, then a new statement is created and returned. The new
statement, along with its cursor and state, are cached when you call the close()
method of the statement object.
When a cached OraclePreparedStatement or OracleCallableStatement
object is retrieved, the state and data information are automatically re-initialized
and reset to default values, while metadata is saved. The Least Recently Used (LRU)
scheme performs the statement cache operation.
You can prevent a particular statement from being implicitly cached; see "Disabling
Implicit Statement Caching for a Particular Statement" on page 14-8.
With implicit statement caching, you take no special action to retrieve statements
from a cache. Instead, whenever you call prepareStatement() or
prepareCall(), JDBC automatically checks the cache for a matching statement
and returns it if found.
With explicit statement caching, you use specialized Oracle "WithKey" methods to
cache and retrieve statement objects.
Implicit statement caching uses the SQL string of a prepared or callable statement as
the key, requiring no action on your part. Explicit statement caching requires you to
provide a Java string, which it uses as the key.
During implicit statement caching, if the JDBC driver cannot find a statement in
cache, it will automatically create one. During explicit statement caching, if the
JDBC driver cannot find a matching statement in cache, it will return a null value.
Table 14–1 compares the different methods employed in implicit and explicit
statement caching.
In either case, the argument you supply is the maximum number of statements in
the cache; an argument of 0 specifies no caching. To check the cache size, use the
getStatementCacheSize() method.
System.out.println("Stmt Cache size is " +
((OracleConnection)conn).getStatementCacheSize());
Notes:
■ You enable implicit and explicit caching for a particular
physical connection independently. Therefore, it is possible to
do statement caching both implicitly and explicitly during the
same session.
■ Implicit and explicit statement caching share the same cache.
Remember this when you set the statement cache size.
If you call the creationState() method on the pstmt statement object, the
method returns IMPLICIT. If the pstmt statement object was not in cache, then the
creationState() method returns NEW to indicate a new statement was recently
created by the JDBC driver.
Table 14–2 describes the methods used to allocate statements and retrieve implicitly
cached statements.
Table 14–2 Methods Used in Statement Allocation and Implicit Statement Caching
Method Functionality for Implicit Statement Caching
prepareStatement() Triggers a cache search that either finds and returns the
desired cached OraclePreparedStatement object or
allocates a new OraclePreparedStatement object if a
match is not found
prepareCall() Triggers a cache search that either finds and returns the
desired cached OracleCallableStatement object or
allocates a new OracleCallableStatement object if a
match is not found
If you call the creationState() method on the pstmt statement object, the
method returns EXPLICIT.
Table 14–3 describes the methods used to retrieve explicitly cached statements.
Overview
A distributed transaction, sometimes referred to as a global transaction, is a set of two
or more related transactions that must be managed in a coordinated way. The
transactions that constitute a distributed transaction might be in the same database,
but more typically are in different databases and often in different locations. Each
individual transaction of a distributed transaction is referred to as a transaction
branch.
For example, a distributed transaction might consist of money being transferred
from an account in one bank to an account in another bank. You would not want
either transaction committed without assurance that both will complete
successfully.
In the JDBC 2.0 extension API, distributed transaction functionality is built on top of
connection pooling functionality, described under "Connection Pooling" on
page 16-11. This distributed transaction functionality is also built upon the open XA
standard for distributed transactions. (XA is part of the X/Open standard and is not
specific to Java.)
JDBC is used to connect to database resources. However, to include all changes to
multiple databases within a transaction, you must use the JDBC connections within
a JTA global transaction. The process of including database SQL updates within a
transaction is referred to as enlisting a database resource.
The remainder of this overview covers the following topics:
■ Distributed Transaction Components and Scenarios
■ Distributed Transaction Concepts
■ Switching Between Global and Local Transactions
■ Oracle XA Packages
For further introductory and general information about distributed transactions and
XA, refer to the Sun Microsystems specifications for the JDBC 2.0 Optional Package
and the Java Transaction API.
There will be one XA data source instance for each resource manager (database)
that will be used in the distributed transaction. You will typically create XA
data source instances (using the class constructor) in your middle-tier software.
XA data sources produce XA connections.
■ XA connections—These are extensions of pooled connections, and similar in
concept and functionality. An XA connection encapsulates a physical database
connection; individual connection instances are temporary handles to these
physical connections.
An XA connection instance corresponds to a single Oracle session, although the
session can be used in sequence by multiple logical connection instances (one at
a time), as with pooled connection instances.
You will typically get an XA connection instance from an XA data source
instance (using a get method) in your middle-tier software. You can get
multiple XA connection instances from a single XA data source instance if the
distributed transaction will involve multiple sessions (multiple physical
connections) in the same database.
XA connections produce XA resource instances and JDBC connection instances.
■ XA resources—These are used by a transaction manager in coordinating the
transaction branches of a distributed transaction.
You will get one XA resource instance from each XA connection instance (using
a get method), typically in your middle-tier software. There is a one-to-one
correlation between XA resource instances and XA connection instances;
equivalently, there is a one-to-one correlation between XA resource instances
and Oracle sessions (physical connections).
In a typical scenario, the middle-tier component will hand off XA resource
instances to the transaction manager, for use in coordinating distributed
transactions.
Because each XA resource instance corresponds to a single Oracle session, there
can be only a single active transaction branch associated with an XA resource
instance at any given time. There can be additional suspended transaction
branches, however—see "XA Resource Method Functionality and Input
Parameters" on page 15-11.
Each XA resource instance has the functionality to start, end, prepare, commit,
or roll back the operations of the transaction branch running in the session with
which the XA resource instance is associated.
The "prepare" step is the first step of a two-phase COMMIT operation. The
transaction manager will issue a prepare to each XA resource instance. Once
the transaction manager sees that the operations of each transaction branch
have prepared successfully (essentially, that the databases can be accessed
without error), it will issue a COMMIT to each XA resource instance to commit
all the changes.
■ Transaction IDs—These are used to identify transaction branches. Each ID
includes a transaction branch ID component and a distributed transaction ID
component—this is how a branch is associated with a distributed transaction.
All XA resource instances associated with a given distributed transaction would
have a transaction ID that includes the same distributed transaction ID
component.
If none of the rules above is applicable, the mode does not change.
Oracle XA Packages
Oracle supplies the following three packages that have classes to implement
distributed transaction functionality according to the XA standard:
■ oracle.jdbc.xa (OracleXid and OracleXAException classes)
■ oracle.jdbc.xa.client
■ oracle.jdbc.xa.server
Classes for XA data sources, XA connections, and XA resources are in both the
client package and the server package. (An abstract class for each is in the
top-level package.) The OracleXid and OracleXAException classes are in the
top-level oracle.jdbc.xa package, because their functionality does not depend
on where the code is running.
In middle-tier scenarios, you will import OracleXid, OracleXAException, and
the oracle.jdbc.xa.client package.
If you intend your XA code to run in the target Oracle database, however, you will
import the oracle.jdbc.xa.server package instead of the client package.
If code that will run inside a target database must also access remote databases,
then do not import either package—instead, you must fully qualify the names of
any classes that you use from the client package (to access a remote database) or
from the server package (to access the local database). Class names are duplicated
between these packages.
XA Components
This section discusses the XA components—standard XA interfaces specified in the
JDBC 2.0 Optional Package, and the Oracle classes that implement them. The
following topics are covered:
■ XA Data Source Interface and Oracle Implementation
■ XA Connection Interface and Oracle Implementation
■ XA Resource Interface and Oracle Implementation
■ XA Resource Method Functionality and Input Parameters
■ XA ID Interface and Oracle Implementation
Note: You can register XA data sources in JNDI using the same
naming conventions as discussed previously for non-pooling data
sources in "Register the Data Source" on page 16-9.
Notes:
■ Because there must always be a one-to-one correlation between
XA connection instances and XA resource instances, an XA
resource instance is implicitly closed when the associated XA
connection instance is closed.
■ If a transaction is opened by a given XA resource instance, it
must also be closed by the same XA resource instance.
Start Start work on behalf of a transaction branch, associating the transaction branch
with a distributed transaction.
void start(Xid xid, int flags)
End End work on behalf of the transaction branch specified by xid, disassociating
the transaction branch from its distributed transaction.
void end(Xid xid, int flags)
Notes:
■ Instead of using the end() method with TMSUSPEND, the
transaction manager can cast to an OracleXAResource
instance and use the suspend(Xid xid) method, an Oracle
extension.
■ This XA functionality to suspend a transaction provides a way
to switch between various transactions within a single JDBC
connection. You can use the XA classes to accomplish this, even
if you are not in a distributed transaction environment and
would otherwise have no need for the XA classes.
■ If you use TMSUSPEND, you must also use TMNOMIGRATE, as in
end(xid, XAResource.TMSUSPEND |
OracleXAResource.TMNOMIGRATE);. This prevents the application’s
receiving the error ORA 1002: fetch out of sequence.
Prepare Prepare the changes performed in the transaction branch specified by xid.
This is the first phase of a two-phase COMMIT operation, to ensure that the database
is accessible and that the changes can be committed successfully.
int prepare(Xid xid)
Notes:
■ Always call the end() method on a branch before calling the
prepare() method.
■ If there is only one transaction branch in a distributed
transaction, then there is no need to call the prepare()
method. You can call the XA resource commit() method
without preparing first.
Commit Commit prepared changes in the transaction branch specified by xid. This
is the second phase of a two-phase COMMIT and is performed only after all
transaction branches have been successfully prepared.
void commit(Xid xid, boolean onePhase)
Roll back Rolls back prepared changes in the transaction branch specified by xid.
void rollback(Xid xid)
Recover The transaction manager calls this method during recovery to obtain the list
of transaction branches that are currently in prepared or heuristically completed
states.
public Xid[] recover(int flag)
The resource manager returns zero or more Xids for the transaction branches that
are currently in a prepared or heuristically completed state. If an error occurs
during the operation, the resource manager throws the appropriate XAException.
A transaction manager can use this method regarding certain Oracle optimizations,
as "Oracle XA Optimizations" on page 15-20 explains.
Note: Oracle8i 8.1.7 does not require the use of OracleXid for
Oracle XA resource calls. Instead, use any class that implements
javax.transaction.xa.Xid interface.
Where fId is an integer value for the format identifier, gId[] is a byte array for the
global transaction identifier, and bId[] is a byte array for the branch qualifier.
The Xid interface specifies the following getter methods:
■ public int getFormatId()
■ public byte[] getGlobalTransactionId()
■ public type[] getBranchQualifier()
or:
public OracleXAException(int error)
The error value is an error code that combines an Oracle SQL error value and an XA
error value. (The JDBC driver determines exactly how to combine the Oracle and
XA error values.)
The OracleXAException class has the following methods:
■ public int getOracleError()
This method returns the Oracle SQL error code pertaining to the exception—a
standard ORA error number (or 0 if there is no Oracle SQL error).
■ public int getXAError()
This method returns the XA error code pertaining to the exception. XA error
values are defined in the javax.transaction.xa.XAException class; refer
to its Javadoc at the Sun Microsystems Web site for more information.
XA Error Handling
The following example uses the OracleXAException class to process an XA
exception:
try {
...
...Perform XA operations...
...
} catch(OracleXAException oxae) {
int oraerr = oxae.getOracleError();
System.out.println("Error " + oraerr);
}
catch(XAException xae)
{...Process generic XA exception...}
In case the XA operations did not throw an Oracle-specific XA exception, the code
drops through to process a generic XA exception.
Oracle XA Optimizations
Oracle JDBC has functionality to improve performance if two or more branches of a
distributed transaction use the same database instance—meaning that the XA
resource instances associated with these branches are associated with the same
resource manager.
In such a circumstance, the prepare() method of only one of these XA resource
instances will return XA_OK (or failure); the rest will return XA_RDONLY, even if
updates are made. This allows the transaction manager to implicitly join all the
transaction branches and commit (or roll back, if failure) the joined transaction
through the XA resource instance that returned XA_OK (or failure).
The transaction manager can use the OracleXAResource class isSameRM()
method to determine if two XA resource instances are using the same resource
manager. This way it can interpret the meaning of XA_RDONLY return values.
(And if you intend to access only the database in which the code runs, you would
not need the oracle.jdbc.xa.client classes.)
The client and server packages each have versions of the
OracleXADataSource, OracleXAConnection, and OracleXAResource
classes. Abstract versions of these three classes are in the top-level
oracle.jdbc.xa package.
class XA4
{
public static void main (String args [])
throws SQLException
{
try
{
String URL1 = "jdbc:oracle:oci:@";
String URL2 ="jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))";
DriverManager.registerDriver(new OracleDriver());
// You can put a database name after the @ sign in the connection URL.
Connection conna =
DriverManager.getConnection (URL1, "scott", "tiger");
Connection connb =
DriverManager.getConnection (URL2, "scott", "tiger");
try
{
// Drop the test table
stmta.execute ("drop table my_table");
}
catch (SQLException e)
{
// Ignore an error here
}
try
{
// Create a test table
stmta.execute ("create table my_table (col1 int)");
}
catch (SQLException e)
{
// Ignore an error here too
}
try
{
// Drop the test table
stmtb.execute ("drop table my_tab");
}
catch (SQLException e)
{
// Ignore an error here
}
try
{
// Create a test table
stmtb.execute ("create table my_tab (col1 char(30))");
}
catch (SQLException e)
{
oxds2.setURL("jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))");
oxds2.setUser("scott");
oxds2.setPassword("tiger");
if (prp1 == XAResource.XA_OK)
if (do_commit)
oxar1.commit (xid1, false);
else
oxar1.rollback (xid1);
if (prp2 == XAResource.XA_OK)
if (do_commit)
oxar2.commit (xid2, false);
else
oxar2.rollback (xid2);
// Close connections
conn1.close();
conn1 = null;
conn2.close();
conn2 = null;
pc1.close();
pc1 = null;
pc2.close();
pc2 = null;
rset.close();
rset = null;
rset.close();
rset = null;
stmta.close();
stmta = null;
stmtb.close();
stmtb = null;
conna.close();
conna = null;
connb.close();
connb = null;
This chapter covers the Oracle JDBC implementations of (1) data sources, a
standard facility for specifying resources to use, including databases; (2) connection
pooling, which is a framework for caches of database connections; and (3)
connection caching, including documentation of a sample Oracle implementation.
You will also find related discussion of Oracle JDBC support for the standard Java
Naming and Directory Interface (JNDI).
The following topics, which apply to all Oracle JDBC drivers, are described in this
chapter:
■ Data Sources
■ Connection Pooling
■ Connection Caching
For further information on listed topics, refer to the Sun Microsystems specification
for the JDBC 2.0 Standard Extension API. For information about additional
connection pooling functionality specific to the OCI driver, see "OCI Driver
Connection Pooling" on page 17-2.
Data Sources
The JDBC 2.0 extension API introduced the concept of data sources, which are
standard, general-use objects for specifying databases or other resources to use.
Data sources can optionally be bound to Java Naming and Directory Interface
(JNDI) entities so that you can access databases by logical names, for convenience
and portability.
This functionality is a more standard and versatile alternative to the connection
functionality described under "Open a Connection to a Database" on page 3-3. The
data source facility provides a complete replacement for the previous JDBC
DriverManager facility.
You can use both facilities in the same application, but ultimately developers will be
encouraged to use data sources for their connections, regardless of whether
connection pooling or distributed transactions are required. Eventually, Sun
Microsystems will probably deprecate DriverManager and related classes and
functionality.
For further introductory and general information about data sources and JNDI,
refer to the Sun Microsystems specification for the JDBC 2.0 Optional Package.
The OracleDataSource class implements the following setter and getter methods
for the standard properties:
■ public synchronized void setDatabaseName(String dbname)
■ public synchronized String getDatabaseName()
■ public synchronized void setDataSourceName(String dsname)
■ public synchronized String getDataSourceName()
■ public synchronized void setDescription(String desc)
■ public synchronized String getDescription()
■ public synchronized void setNetworkProtocol(String np)
■ public synchronized String getNetworkProtocol()
■ public synchronized void setPassword(String pwd)
■ public synchronized void setPortNumber(int pn)
■ public synchronized int getPortNumber()
■ public synchronized void setServerName(String sn)
■ public synchronized String getServerName()
■ public synchronized void setUser(String user)
■ public synchronized String getUser()
Note that there is no getPassword() method, for security reasons.
■ Settings for user and password are required, either directly, through the URL
setting, or through the getConnection() call. The user and password
settings in a getConnection() call take precedence over any property
settings.
■ If the url property is set, then any tnsEntry, driverType, portNumber,
networkProtocol, serverName, and databaseName property settings are
ignored.
■ If the tnsEntry property is set (which presumes the url property is not set),
then any databaseName, serverName, portNumber, and
networkProtocol settings are ignored.
■ If you are using an OCI driver (which presumes the driverType property is
set to oci) and the networkProtocol is set to ipc, then any other property
settings are ignored.
ods.setDriverType("oci");
ods.setServerName("dlsun999");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("816");
ods.setPortNumber(1521);
ods.setUser("scott");
ods.setPassword("tiger");
ods.setDriverType("oci");
ods.setServerName("dlsun999");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("816");
ods.setPortNumber(1521);
ods.setUser("scott");
ods.setPassword("tiger");
...
Notes: The JDBC 2.0 Specification requires that all JDBC data
sources be registered in the jdbc naming subcontext of a JNDI
namespace or in a child subcontext of the jdbc subcontext.
Open a Connection
To perform a lookup and open a connection to the database logically bound to the
JNDI name, use the logical JNDI name. Doing this requires casting the lookup result
(which is otherwise simply a Java Object) to a new OracleDataSource instance
and then using its getConnection() method to open the connection.
Here is an example:
...
OracleDataSource odsconn = (OracleDataSource)ctx.lookup("jdbc/sampledb");
Connection conn = odsconn.getConnection();
...
Notes:
■ When a data source instance is created, logging is disabled by
default (the log stream name is initially null).
■ Messages written to a log stream registered to a data source
instance are not written to the log stream normally maintained
by DriverManager.
■ An OracleDataSource instance obtained from a JNDI name
lookup will not have its PrinterWriter set, even if the
PrintWriter was set when a data source instance was first
bound to this JNDI name.
Connection Pooling
Connection pooling in the JDBC 2.0 extension API is a framework for caching
database connections. This allows reuse of physical connections and reduced
overhead for your application. Connection pooling functionality minimizes
expensive operations in the creation and closing of sessions.
The following are central concepts:
■ Connection pool data sources—similar in concept and functionality to the data
sources described previously, but with methods to return pooled connection
instances, instead of normal connection instances.
■ Pooled connections—a pooled connection instance represents a single physical
connection to a database, remaining open during use by a series of logical
connection instances.
A logical connection instance is a simple connection instance (such as a
standard Connection instance or an OracleConnection instance) returned
by a pooled connection instance. Each logical connection instance acts as a
temporary handle to the physical connection represented by the pooled
connection instance.
For connection pooling information specific to OCI drivers, see "OCI Driver
Connection Pooling" on page 17-2. For further introductory and general information
about connection pooling, refer to the Sun Microsystems specification for the JDBC
2.0 Optional Package.
Note: You can register connection pool data sources in JNDI using
the same naming conventions as discussed for non-pooling data
sources in "Register the Data Source" on page 16-9.
(Event listeners are used in connection caching and are discussed in "Typical Steps
in Using a Connection Cache" on page 16-20.)
Oracle JDBC implements the PooledConnection interface with the
oracle.jdbc.pool.OraclePooledConnection class. The getConnection()
method returns an OracleConnection instance.
A pooled connection instance will typically be asked to produce a series of
connection instances during its existence, but only one of these connection instances
can be open at any particular time.
Each time a pooled connection instance getConnection() method is called, it
returns a new connection instance that exhibits the default behavior, and it closes
any previous connection instance that still exists and has been returned by the same
pooled connection instance. You should explicitly close any previous connection
instance before opening a new one, however.
Calling the close() method of a pooled connection instance closes the physical
connection to the database. The middle-tier layer typically performs this.
The OraclePooledConnection class includes methods to enable statement
caching for a pooled connection. The cache for statements is maintained for the
pooled connection as a whole, and all logical connections obtained from the pooled
connection share it. Therefore, when statement caching is enabled, a statement you
create on one logical connection can be re-used on another logical connection. For
the same reason, you cannot enable or disable statement caching on individual
logical connections. This function applies to both implicit and explicit statement
caching.
The following are OraclePooledConnection method definitions for statement
caching:
public void setStmtCacheSize (int size)
throws SQLException
See Chapter 14, "Statement Caching", for more details on statement caching.
ocpds.setDriverType("oci");
ocpds.setServerName("dlsun999");
ocpds.setNetworkProtocol("tcp");
ocpds.setDatabaseName("816");
ocpds.setPortNumber(1521);
ocpds.setUser("scott");
ocpds.setPassword("tiger");
PooledConnection pc = ocpds.getPooledConnection();
Connection Caching
Connection caching, generally implemented in a middle tier, is a means of keeping
and using caches of physical database connections.
Connection caching uses the connection pooling framework—such as connection
pool data sources and pooled connections—in much of its operations. "Connection
Pooling", starting on page 16-11, describes this framework.
The JDBC 2.0 specification does not mandate a connection caching implementation,
but Oracle provides a simple implementation to serve at least as an example.
This section is divided into the following topics:
■ Overview of Connection Caching
■ Typical Steps in Using a Connection Cache
■ Oracle Connection Cache Specification: OracleConnectionCache Interface
■ Oracle Connection Cache Implementation: OracleConnectionCacheImpl Class
■ Oracle Connection Event Listener: OracleConnectionEventListener Class
Implementation Scenarios
Middle-tier developers have the option of implementing their own connection
cache class and connection event listener class.
For convenience, however, Oracle provides the following, all in the
oracle.jdbc.pool package:
■ a connection cache interface: OracleConnectionCache
■ a connection cache class: OracleConnectionCacheImpl
■ a connection event listener class: OracleConnectionEventListener
The OracleConnectionCacheImpl class is a simple connection cache class
implementation that Oracle supplies as an example, providing sufficient but
minimal functionality. It implements the OracleConnectionCache interface and
uses instances of the OracleConnectionEventListener class for connection
events.
If you want more functionality than OracleConnectionCacheImpl has to offer
but still want to use OracleConnectionEventListener for connection events,
then you can create your own class that implements OracleConnectionCache.
Or you can create your own connection cache class and connection event listener
class from scratch.
or:
■ It can use the default OracleConnectionCacheImpl constructor (which
takes no input) and then the setConnectionPoolDataSource() method,
which takes an existing connection pool data source instance as input. Again,
this is convenient if the middle tier already has a connection pool data source
instance with its connection properties set. For example, where cpds is a
connection pool data source instance:
OracleConnectionCacheImpl ocacheimpl = new OracleConnectionCacheImpl();
ocacheimpl.setConnectionPoolDataSource(cpds);
Notes:
■ You can also use the setConnectionPoolDataSource()
method to override a previously set pooled connection data
source or previously set connection properties.
■ If you call setConnectionPoolDataSource() when there
is already a connection pool data source with associated logical
connections in use, then an exception will be thrown if the new
connection pool data source specifies a different database
schema than the old connection pool data source.
or:
■ It can use the default OracleConnectionCacheImpl constructor and then set
the properties individually, using setter methods. For example:
OracleConnectionCacheImpl ocacheimpl = new OracleConnectionCacheImpl();
ocacheimpl.setDriverType("oci");
ocacheimpl.setServerName("dlsun999");
ocacheimpl.setNetworkProtocol("tcp");
ocacheimpl.setDatabaseName("816");
ocacheimpl.setPortNumber(1521);
ocacheimpl.setUser("scott");
ocacheimpl.setPassword("tiger");
There is also a default constructor that takes no input and can be used in
conjunction with the OracleConnectionEventListener class
setDataSource() method:
OracleConnectionEventListener ocel = new OracleConnectionEventListener();
...
ocel.setDataSource(ds);
A JDBC application can have multiple pools at the same time. Multiple pools can
correspond to multiple application servers, or pools to different data sources. The
connection pooling provided by OCI in Oracle9i allows applications to have many
logical connections, all using a small set of physical connections. Each call on this
logical connection will be routed on the physical connection that is available at that
time. Call-duration based pooling of connections is a more scalable connection
pooling solution.
For information about Oracle JDBC connection pooling and caching features that
apply to all Oracle JDBC drivers, see Chapter 16, "Connection Pooling and
Caching".
and these connections (including the pool of dedicated database server processes)
are shared among all the threads in the middle tier.
* @return
*
* Notes: Choose a userid and password that can act as proxy for the users
* in the getProxyConnection() method.
*/
/*
* This will use the user-id, password and connection pool name values set
LATER using the methods setUser, setPassword, setConnectionPoolName.
* @return
*
* Notes:
represents a connection. See "Data Sources" on page 16-2 for database connection
descriptions that apply to all JDBC drivers.
Since the OracleOCIConnection class extends OracleConnection class, it has
the funtionality of this class too. Close the OracleOCIConnection objects once
the user session is over, otherwise, they are closed when the pool instance is closed.
There are two ways of calling getConnection():
■ OracleConnection getConnection(String user, String
password) : Get a logical connection identified with the specified user and
password, which can be different from that used for pool creation.
■ OracleConnection getConnection() : If you do not supply the user
name and password, then the default user name and password used for the
creation of the connection pool are used while creating the connection objects.
As an enhancement to OracleConnection, the following new method is added
into OracleOCIConnection as a way to change password for the user:
void passwordChange (String user, String oldPassword, String newPassword)
The following code shows how an application uses connection pool with
re-configuration:
import oracle.jdbc.oci.*;
import oracle.jdbc.pool.*;
/* create virtual connection objects from the connection pool "cpool." The
poolConfig can be null when using default values of min = 1, max = 1, and
increment = 0, otherwise needs to set the properties mentioned earlier */
OracleOCIConnection conn1 = (OracleOCIConnection) cpool.getConnection
("user1", password1");
throws SQLException
/*
* For getting a connection to the database.
*
* @param us Connection user-id
* @param p Connection password
* @return connection object
*/
public synchronized OracleConnection getConnection(String us, String p)
throws SQLException
/**
*
* @param size Size of the Cache
* @param clearMetaData Whether the state has to be cleared or not
* @exception SQLException
*/
public synchronized void setStmtCacheSize (int size, boolean clearMetaData)
/**
/*
* Check whether Statement
* Caching is enabled for this pool or Not.
*/
public synchronized boolean isStmtCacheEnabled ()
Then the method allows you to connect as "jeff" using the already
authenticated credentials of "scott". It is sometimes a security concern for the
middle tier to know the passwords of all the database users. Though the created
session will behave much like "jeff" was connected normally (using
"jeff"/"jeff-password"), "jeff" will not have to divulge its password to
the middle tier. The schema which this proxy session has access to is schema of
"jeff" plus what is indicated in the list of roles. Therefore, if "scott" wants
"jeff" to access its table EMP, the following code can be used:
create role role1;
grant select on EMP to role1;
The role clause can also be thought as limiting "jeff ’s" access to only those
database objects of "scott" mentioned in the list of the roles. The list of roles
can be empty.
■ For accounting purposes. The transactions made via proxy sessions can be
better accounted by proxying the user ("jeff"), under different users such as
"scott", "scott2" assuming "scott"and "scott2" are authenticated.
Transactions made under these different proxy sessions by "jeff" can be
logged separately.
There are three ways to create proxy sessions in the OCI driver. Roles can be
associated with any of the following options:
■ USER NAME : This is done by supplying the user name and/or the password.
The reason why the "password" option exists is so that database operations
made by the user ("jeff"), can be accounted. The SQL clause is:
alter user jeff grant connect through scott authenticated using password;
’CN=jeff,OU=americas,O=oracle,L=redwoodshores,ST=ca,C=us';
The string after the "globally as" clause is the distinguished name. It is then
necessary to authenticate as:
alter user jeff grant connect through scott authenticated using
distinguished name;
PROXYTYPE_DISTINGUISHED_NAME
- This will specify the distinguished name of the user
in proxyUser
PROXYTYPE_CERTIFICATE
- This will specify the proxy certificate
If PROXYTYPE_USER_NAME
PROXY_USER_NAME and/or PROXY_USER_PASSWORD depending
on how the connection-pool owner was authenticated
to act as proxy for this proxy user
PROXY_USER_NAME (String) = user to be proxied for
PROXY_PASSWORD (String) = password of the user to be proxied for
else if PROXYTYPE_DISTINGUISHED_NAME
PROXY_DISTINGUISHED_NAME (String) = (global) distinguished name of the
PROXY_ROLES (String[]) Set of roles which this proxy connection can use.
Roles can be null, and can be associated
with any of the above proxy methods.
*
* @return connection object
*
* Notes: The user and password used to create OracleOCIConnectionPool()
* must be allowed to act as proxy for user 'us'.
*/
public synchronized OracleConnection getProxyConnection(String proxyType,
Properties prop)
throws SQLException
TAF Callbacks
TAF callbacks are used in the event of the failure of one database connection, and
failover to another database connection. TAF callbacks are callbacks that are
registered in case of failover. The callback is called during the failover to notify the
JDBC application of events generated. The application also has some control of
failover.
OCI HeteroRM XA
Unlike the regular JDBC XA feature which works only with Oracle8i 8.1.6 and later
databases, JDBC HeteroRM XA also allows you to do XA operations in Oracle8i
releases prior to 8.1.6. In general, the HeteroRM XA is recommended for use
whenever possible.
HeteroRM XA is enabled through the use of the tnsEntry and nativeXA
properties of the OracleXADataSource class. Table 16–2, "Oracle Extended Data
Source Properties" on page 16-6 explains these properties in detail.
For a complete discussion of XA, see Chapter 15, "Distributed Transactions".
Exception Handling
When using the HeteroRM XA feature in distributed transactions, it is
recommended that the application simply check for XAException or
SQLException, rather than OracleXAException or OracleSQLException.
See "HeteroRM XA Messages" on page B-15 for a listing of HeteroRM XA messages.
Overview
The Oracle JDBC OCI driver supports PL/SQL index-by tables of scalar datatypes.
Table 17–1 displays the supported scalar types and the corresponding JDBC
typecodes.
Note: Oracle JDBC does not support RAW, DATE, and PL/SQL
RECORD as element types.
Typical Oracle JDBC input binding, output registration, and data-access methods do
not support PL/SQL index-by tables. This chapter introduces additional methods to
support these types.
The OraclePreparedStatement and OracleCallableStatement classes
define the additional methods. These methods include the following:
■ setPlsqlIndexTable()
■ registerIndexTableOutParameter()
■ getOraclePlsqlIndexTable()
■ getPlsqlIndexTable()
These methods handle PL/SQL index-by tables as IN, OUT (including function
return values), or IN OUT parameters. For general information about PL/SQL
syntax, see the PL/SQL User’s Guide and Reference.
The following sections describe the methods used to bind and register PL/SQL
index-by tables.
Binding IN Parameters
To bind a PL/SQL index-by table parameter in the IN parameter mode, use the
setPlsqlIndexTable() method defined in the OraclePreparedStatement
and OracleCallableStatement classes.
synchronized public void setPlsqlIndexTable
(int paramIndex, Object arrayData, int maxLen, int curLen, int elemSqlType,
int elemMaxLen) throws SQLException
The return value is a Java array. The elements of this array are of the default Java
type corresponding to the SQL type of the elements. For example, for an index-by
table with elements of NUMERIC typecode, the element values are mapped to
BigDecimal by the Oracle JDBC driver, and the getPlsqlIndexTable()
method returns a BigDecimal[] array. For a JDBC application, you must cast the
return value to a BigDecimal[] array to access the table element values. (See
"Datatype Mappings" on page 3-16 for a list of default mappings.)
The following code example uses the getPlsqlIndexTable() method to return
index-by table elements with JDBC default mapping:
// access the value using JDBC default mapping
BigDecimal[] values =
(BigDecimal[]) procout.getPlsqlIndexTable (1);
The return value is an oracle.sql.Datum array and the elements in the Datum
array will be the default Datum type corresponding to the SQL type of the element.
For example, the element values of an index-by table of numeric elements are
mapped to the oracle.sql.NUMBER type in Oracle mapping, and the
getOraclePlsqlIndexTable() method returns an oracle.sql.Datum array
that contains oracle.sql.NUMBER elements.
The following code example uses the getOraclePlsqlIndexTable() method to
access the elements of a PL/SQL index-by table OUT parameter, using Oracle
mapping. (The code for registration is omitted.)
// Prepare the statement
OracleCallableStatement procout = (OracleCallableStatement)
conn.prepareCall ("begin procout (?); end;");
...
Java Primitive Type Mappings The getPlsqlIndexTable() method with the (int,
Class) signature returns index-by table elements in Java primitive types. The
return value is a Java array.
synchronized public Object getPlsqlIndexTable
(int paramIndex, Class primitiveType) throws SQLException
funcnone.execute ();
Notes:
■ The driver uses UTF-8 as the character set to minimize the
number of conversions it performs in Java.
■ The change to UTF-8 is for the JDBC application process only.
Language and Territory The Thin driver obtains language and territory settings (NLS_
LANGUAGE and NLS_TERRITORY ) from the Java locale in the JVM user.language
property. The date format (NLS_DATE_FORMAT) is set according to the territory
setting.
Character Set If the database character set is US7ASCII or WE8ISO8859P1, then the
data is transferred to the client without any conversion. The driver then converts
the character set to UTF-16 in Java.
If the database character set is something other than US7ASCII or WE8ISO8859P1,
then the server first translates the data to UTF-8 before transferring it to the client.
On the client, the JDBC Thin driver converts the data to UTF-16 in Java.
object or collection type. See "Oracle Character Datatypes Support" on page 6-28 for
a description of CHAR and NCHAR datatypes.
However, in the case of the CHAR and VARCHAR data portion of Oracle objects and
collections, the JDBC class files provide support for only the following commonly
used character sets:
■ US7ASCII
■ WE8DEC
■ ISO-LATIN-1
■ UTF-8
To provide support for all character sets, the Oracle JDBC driver installation
includes two additional files: nls_charset12.zip for JDK 1.2.x and nls_
charset11.zip for JDK 1.1.x. The OCI and Thin drivers require these files to
support all Oracle characters sets for CHAR and VARCHAR data in Oracle object types
and collections. To obtain this support, you must add the appropriate nls_
charset*.zip file to your CLASSPATH.
It is important to note that the nls_charset*.zip files are very large, because
they must support a large number of character sets. To save space, you might want
to keep only the classes you need from the nls_charset*.zip file. If you want to
do this, follow these steps:
1. Unzip the appropriate nls_charset*.zip file.
2. Add only the needed character set classes to the CLASSPATH.
3. Remove the unneeded character set files from your system.
The character set extension class files are named in the following format:
CharacterConverter<OracleCharacterSetId>.class
Table 18–1 Maximum CHAR and NCHAR Bind Sizes, Thin Driver
Max Size Allowed by Formula for Thin Driver Max
Oracle Version Datatype Database (bytes) Bind Size (UTF-8 bytes)
Oracle8 and later CHAR 2000 4000/exp_factor
Oracle8 and later VARCHAR2 4000 4000/exp_factor
31
Oracle8 and later LONG 2 -1 (231 - 1)/exp_factor
Oracle7 CHAR 255 255
Oracle7 VARCHAR2 2000 2000/exp_factor
The formulas guarantee that after the data is converted from UTF-8 to the database
character set, the size will not exceed the database maximum size.
The number of UTF-16 characters that can be supported is determined by the
number of bytes per character in the data. All ASCII characters are one byte long in
UTF-8 encoding. Other character types can be two or three bytes long.
Expansion Factors and Calculated Size Restrictions for Common Character Sets
Table 18–2 lists the expansion factors of some common server character sets, then
shows the Thin driver maximum bind sizes for SQL CHAR data for each character
set, as determined by using the expansion factor in the appropriate formula.
Again, maximum bind sizes are for UTF-8 encoding, in bytes.
Table 18–2 Expansion Factors and Size Limits, Oracle8, Common Character Sets
Thin Driver Max
Expansion SQL CHAR Bind
Server Character Set Factor Size (UTF-8 bytes)
WE8DEC 1 4000
JA16SJIS 2 2000
WE8ISO8859P1 3 1333
AL32UTF8 1 4000
This table shows, for example, that if encryption is requested by the client, but
rejected by the server, it is disabled. The same is true for integrity. As another
example, if encryption is accepted by the client and requested by the server, it is
enabled. And, again, the same is true for integrity.
The general settings are further discussed in the Oracle Advanced Security
Administrator’s Guide. How to set them for a JDBC application is described in the
following subsections.
Table 18–4 OCI Driver Client Parameters for Encryption and Integrity
Parameter Description Parameter Name Possible Settings
Client encryption level SQLNET.ENCRYPTION_CLIENT REJECTED
ACCEPTED
REQUESTED
REQUIRED
Client encryption selected SQLNET.ENCRYPTION_TYPES_CLIENT RC4_40
list RC4_56
DES
DES40
(see note below)
Client integrity level SQLNET.CRYPTO_CHECKSUM_CLIENT REJECTED
ACCEPTED
REQUESTED
REQUIRED
Client integrity selected list SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT MD5
These settings, and corresponding settings in the server, are further discussed in
Appendix A of the Oracle Advanced Security Administrator’s Guide.
Table 18–5 Thin Driver Client Parameters for Encryption and Integrity
Parameter Parameter
Parameter Name Type Class Possible Settings
oracle.net.encryption_client string static REJECTED
ACCEPTED
REQUESTED
REQUIRED
oracle.net.encryption_types_client string static RC4_40
RC4_56
DES40C
DES56C
oracle.net.crypto_checksum_client string static REJECTED
ACCEPTED
REQUESTED
REQUIRED
oracle.net.crypto_checksum_types_client string static MD5
Notes:
■ Because Oracle Advanced Security support for the Thin driver
is incorporated directly into the JDBC classes ZIP file, there is
only one version, not separate domestic and export editions.
Only parameter settings that would be suitable for an export
edition are possible.
■ The "C" in DES40C and DES56C refers to CBC (cipher block
chaining) mode.
class Employee
{
public static void main (String args [])
throws Exception
{
try {
FileInputStream defaultStream = new FileInputStream(args[0]);
props.load(defaultStream);
// You can put a database name after the @ sign in the connection URL.
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@dlsun608.us.oracle.com:1521:main", props);
// Create a Statement
Statement stmt = conn.createStatement ();
conn.close();
}
JDBC in Applets
This section describes some of the basics of working with Oracle JDBC applets,
which must use the JDBC Thin driver so that an Oracle installation is not required
on the client. The Thin driver connects to the database with TCP/IP protocol.
Aside from having to use the Thin driver, and being mindful of applet connection
and security issues, there is essentially no difference between coding a JDBC applet
and a JDBC application. There is also no difference between coding for a JDK 1.2.x
browser or a JDK 1.1.x browser, other than general JDK 1.1.x to 1.2.x migration
issues discussed in "Migration from JDK 1.1.x to JDK 1.2.x" on page 4-5.
This section describes what you must do for the applet to connect to a database,
including how to use the Oracle Connection Manager or signed applets if you are
connecting to a database not running on the same host as the Web server. It also
describes how your applet can connect to a database through a firewall. The section
concludes with how to package and deploy the applet.
The following topics are covered:
■ Connecting to the Database through the Applet
■ Connecting to a Database on a Different Host Than the Web Server
■ Using Applets with Firewalls
■ Packaging Applets
■ Specifying an Applet in an HTML Page
For general information about connecting to the database, see "Open a Connection
to a Database" on page 3-3.
without these steps, your applet can connect only to a database that is running on
the same host as the Web server.
If your database and Web server are running on the same host, then there is no issue
and no special steps are required. You can connect to the database as you would
from an application.
As with connecting from an application, there are two ways in which you can
specify the connection information to the driver. You can provide it in the form of
host:port:sid or in the form of a TNS keyword-value syntax.
For example, if the database to which you want to connect resides on host
prodHost, at port 1521 , and SID ORCL, and you want to connect with user name
scott with password tiger, then use either of the two following connect strings:
using host:port:sid syntax:
String connString="jdbc:oracle:thin:@prodHost:1521:ORCL";
conn = DriverManager.getConnection(connString, "scott", "tiger");
If you use the TNS keyword-value pair to specify the connection information to the
JDBC Thin driver, then you must declare the protocol as TCP.
However, a Web server and an Oracle database server both require many resources;
you seldom find both servers running on the same machine. Usually, your applet
connects to a database on a host other than the one on which the Web server runs.
There are two possible ways in which you can work around the security restriction:
■ You can connect to the database by using the Oracle Connection Manager.
or:
■ You can use a signed applet to connect to the database directly.
These options are discussed in the next section, "Connecting to a Database on a
Different Host Than the Web Server".
webHost oraHost
Installing and Running the Oracle Connection Manager You must install the Connection
Manager, available on the Oracle9i distribution media, onto the Web server host.
You can find the installation instructions in the Oracle Net Services Administrator’s
Guide.
cman_profile = (parameter_list =
(MAXIMUM_RELAYS=512)
(LOG_LEVEL=1)
(TRACING=YES)
(RELAY_STATISTICS=YES)
(SHOW_TNS_INFO=YES)
(USE_ASYNC_CALL=YES)
(AUTHENTICATION_LEVEL=0)
)
Note that the Java Oracle Net version inside the JDBC Thin driver does not have
authentication service support. This means that the AUTHENTICATION_LEVEL
configuration parameter in the CMAN.ORA file must be set to 0.
After you create the file, start the Connection Manager at the operating system
prompt with this command:
cmctl start
To use your applet, you must now write the connect string for it.
Writing the Connect String that Targets the Connection Manager This section describes
how to write the connect string in your applet so that the applet connects to the
Connection Manager, and the Connection Manager connects with the database. In
the connect string, you specify an address list that lists the protocol, port, and name
of the Web server host on which the Connection Manager is running, followed by
the protocol, port, and name of the host on which the database is running.
The following example describes the configuration illustrated in Figure 18–1. The
Web server on which the Connection Manager is running is on host webHost and is
listening on port 1610. The database to which you want to connect is running on
host oraHost, listening on port 1521, and SID ORCL . You write the connect string
in TNS keyword-value format:
Connection conn =
DriverManager.getConnection ("jdbc:oracle:thin:" +
"@(description=(address_list=" +
"(address=(protocol=tcp)(host=webHost)(port=1610))" +
"(address=(protocol=tcp)(host=oraHost)(port=1521)))" +
"(source_route=yes)" +
"(connect_data=(INSTANCE_NAME=orcl)))", "scott", "tiger");
The first element in the address_list entry represents the connection to the
Connection Manager. The second element represents the database to which you
want to connect. The order in which you list the addresses is important.
Notice that you can also write the same connect string in this format:
String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1610)(host=webHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(INSTANCE_NAME=orcl))
(source_route=yes))";
Connection conn = DriverManager.getConnection(connString, "scott", "tiger");
When your applet uses a connect string such as the one above, it will behave exactly
as if it were connected directly to the database on the host oraHost.
For more information on the parameters that you specify in the connect string, see
the Oracle Net Services Administrator’s Guide.
Connecting through Multiple Connection Managers Your applet can reach its target
database even if it first has to go through multiple Connection Managers (for
example, if the Connection Managers form a "proxy chain"). To do this, add the
addresses of the Connection Managers to the address list, in the order that you plan
to access them. The database listener should be the last address on this list. See the
Oracle Net Services Administrator’s Guide for more information about source_
route addressing.
1. Sign the applet. For information on the steps you must follow to sign an applet,
see Sun Microsystem’s Signed Applet Example at:
http://java.sun.com/security/signExample/index.html
2. Include applet code that asks for appropriate permission before opening a
socket.
If you are using Netscape, then your code would include a statement like this:
netscape.security.PrivilegeManager.enablePrivilege("UniversalConnect");
connection = DriverManager.getConnection
("jdbc:oracle:thin:scott/tiger@dlsun511:1721:orcl");
For information about the Java Security API, including signed applet examples
under JDK 1.2.x and 1.1.x, see the following Sun Microsystems site:
http://java.sun.com/security
You can solve the firewall issue by using an Oracle Net-compliant firewall and
connection strings that comply with the firewall configuration. Oracle
Net-compliant firewalls are available from many leading vendors; a more detailed
discussion of these firewalls is beyond the scope of this manual.
An unsigned applet can access only the same host from which it was downloaded.
In this case, the Oracle Net-compliant firewall must be installed on that host. In
contrast, a signed applet can connect to any host. In this case, the firewall on the
target host controls the access.
Connecting through a firewall requires two steps, described in the following
sections:
■ Configuring a Firewall for Applets that use the JDBC Thin Driver
■ Writing a Connect String to Connect through a Firewall
Configuring a Firewall for Applets that use the JDBC Thin Driver
The instructions in this section assume that you are running an Oracle
Net-compliant firewall.
Java applets do not have access to the local system—that is, they cannot get the
hostname or environment variables locally—because of security limitations. As a
result, the JDBC Thin driver cannot access the hostname on which it is running. The
firewall cannot be provided with the hostname. To allow requests from JDBC Thin
clients to go through the firewall, you must do the following two things to the
firewall’s list of rules:
■ Add the IP address (not the hostname) of the host on which the JDBC applet is
running.
■ Ensure that the hostname "__jdbc__" never appears in the firewall’s rules.
This hostname has been hard-coded as a false hostname inside the driver to
force an IP address lookup. If you do enter this hostname in the list of rules,
then every applet using Oracle's JDBC Thin driver will be able to go through
your firewall.
By not including the Thin driver’s hostname, the firewall is forced to do an IP
address lookup and base its access decision on the IP address, instead of the
hostname.
The first element in the address_list represents the connection to the firewall.
The second element represents the database to which you want to connect. Note
that the order in which you specify the addresses is important.
Notice that you can also write the preceding connect string in this format:
String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1600)(host=fireWallHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(INSTANCE_NAME=orcl))
(source_route=yes))";
Connection conn = DriverManager.getConnection(connString, "scott", "tiger");
When your applet uses a connect string similar to the one above, it will behave as if
it were connected to the database on host oraHost.
For more information on the parameters used in the above example, see the Oracle
Net Services Administrator’s Guide. For more information on how to configure a
firewall, please see your firewall’s documentation or contact your firewall vendor.
Packaging Applets
After you have coded your applet, you must package it and make it available to
users. To package an applet, you will need your applet class files and the JDBC
driver class files (these will be contained in either classes12.zip, if you are
targeting a browser that incorporates a JDK 1.2.x version, or classes111.zip, for
a browser incorporating a JDK 1.1.x version).
Follow these steps:
1. Move the JDBC driver classes file classes12.zip (or classes111.zip) to
an empty directory.
If your applet will connect to a database with a non-US7ASCII and
non-WE8ISO8859P1 character set, then also move the nls_charset12.zip
or nls_charset11.zip file to the same directory.
2. Unzip the JDBC driver classes ZIP file (and character set ZIP file, if applicable).
3. Add your applet classes files to the directory, and any other files the applet
might require.
4. Zip the applet classes and driver classes together into a single ZIP or JAR file.
The single zip file should contain the following:
■ class files from classes12.zip or classes111.zip (and required class
files from nls_charset12.zip or nls_charset11.zip if the applet
requires Globalization Support)
■ your applet classes
Additionally, if you are using DatabaseMetaData entry points in your applet,
include the oracle/jdbc/driver/OracleDatabaseMetaData.class file.
Note that this file is very large and might have a negative impact on
performance. If you do not use DatabaseMetaData methods, omit this file.
5. Ensure that the ZIP or JAR file is not compressed.
You can now make the applet available to users. One way to do this is to add the
APPLET tag to the HTML page from which the applet will be run. For example:
<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet ARCHIVE=JdbcApplet.zip
CODEBASE=Applet_Samples
</APPLET>
You can find a description of the APPLET, CODE, ARCHIVE, CODEBASE, WIDTH, and
HEIGHT parameters in the next section.
If you use this form of the CODE tag, then the classes for the applet and the classes
for the JDBC Thin driver must be in the same directory as the HTML page.
Notice that in the CODE specification, you do not include the file name extension
".class".
CODEBASE
The CODEBASE parameter is optional and specifies the base URL of the applet; that
is, the name of the directory that contains the applet’s code. If it is not specified,
then the document’s URL is used. This means that the classes for the applet and the
JDBC Thin driver must be in the same directory as the HTML page. For example, if
the current directory is my_Dir:
<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet CODEBASE="."
</APPLET>
The entry CODEBASE="." indicates that the applet resides in the current directory
(my_Dir). If the value of codebase was set to Applet_Samples, for example:
CODEBASE="Applet_Samples"
ARCHIVE
The ARCHIVE parameter is optional and specifies the name of the archive file (either
a .zip or .jar file), if applicable, that contains the applet classes and resources the
applet needs. Oracle recommends using a .zip file or .jar file, which saves many
extra roundtrips to the server.
The .zip (or .jar) file will be preloaded. If you have more than one archive in the
list, separate them with commas. In the following example, the class files are stored
in the archive file JdbcApplet.zip:
<APPLET CODE="JdbcApplet" ARCHIVE="JdbcApplet.zip" WIDTH=500 HEIGHT=200>
</APPLET>
class JDBCConnection
{
public static Connection connect() throws SQLException
{
Connection conn = null;
try {
// connect with the server-side internal driver
OracleDriver ora = new OracleDriver();
conn = ora.defaultConnection();
}
Note that there is no conn.close() call in the example. When JDBC code is
running inside the target server, the connection is an implicit data channel, not an
explicit connection instance as from a client. It should typically not be closed.
If you do call the close() method, be aware of the following:
■ All connection instances obtained through the defaultConnection()
method, which actually all reference the same connection object, will be closed
and unavailable for further use, with state and resource cleanup as appropriate.
or:
DriverManager.getConnection("jdbc:default:connection:");
Any user name or password you include in the URL string is ignored in connecting
to the server default connection.
The DriverManager.getConnection() method returns a new Java
Connection object every time you call it. Note that although the method is not
creating a new physical connection (only a single implicit connection is used), it is
returning a new object.
The fact that DriverManager.getConnection() returns a new connection
object every time you call it is significant if you are working with object maps (or
"type maps"). A type map is associated with a specific Connection object and with
any state that is part of the object. If you want to use multiple type maps as part of
your program, then you can call getConnection() to create a new Connection
object for each type map.
System.out.println(e.getNumParameters());
// prints "1"
or:
conn.rollback();
The advantage of using this method is that you must change only a short string in
your original program. The disadvantage is that you still must provide the user,
password, and database information, even though the driver will discard it. In
addition, if you issue the getConnection() method again, the driver will create
another new (and unnecessary) connection object.
However, if you connect with defaultConnection(), the preferred method of
connecting to the database from the server-side internal driver, you do not have to
enter any user, password, or database information. You can delete these statements
from your program.
class JdbcCheckup
{
public static void main (String args []) throws SQLException, IOException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
new oracle.jdbc.OracleDriver ().defaultConnection ();
// Create a statement
Statement stmt = conn.createStatement ();
or:
loadjava -user scott/tiger Foo*.class
or:
loadjava -user scott/tiger Foo.jar
Or use the following command to load with the Thin driver (specifying the -thin
option and an appropriate URL):
loadjava -thin -user scott/tiger@localhost:1521:ORCL Foo.jar
(Whether to use an OCI driver or the Thin driver to load classes depends on your
particular environment and which performs better for you.)
Or use the following command to load with the Thin driver (specifying the -thin
option and an appropriate URL):
loadjava -thin -user scott/tiger@localhost:1521:ORCL -resolve Foo.java
Either of these will result in appropriate class schema objects being created in
addition to the source schema object.
Where number_of_threads is the number of threads that you want to create, and
share specifies that you want the threads to share the connection. If you do not
specify the number of threads, then the program creates 10 by default.
/*
* This sample is a multi-threaded JDBC program.
*/
import java.sql.*;
import oracle.jdbc.OracleStatement;
int m_myId;
if (args.length > 1)
{
share_connection = true;
System.out.println
("All threads will be sharing the same connection");
}
// spawn threads
for (int i = 0; i < NUM_OF_THREADS; i++)
{
threadList[i] = new JdbcMTSample();
threadList[i].start();
}
if (share_connection)
{
s_conn.close();
s_conn = null;
}
}
catch (Exception e)
{
e.printStackTrace();
}
public JdbcMTSample()
{
super();
// Assign an Id to the thread
m_myId = getNextId();
}
try
{
// Get the connection
if (share_connection)
stmt = s_conn.createStatement (); // Create a Statement
else
{
conn = DriverManager.getConnection("jdbc:oracle:oci:@",
"scott","tiger");
stmt = conn.createStatement (); // Create a Statement
}
while (!getGreenLight())
yield();
Performance Optimization
You can significantly enhance the performance of your JDBC programs by using
any of these features:
■ Disabling Auto-Commit Mode
■ Standard Fetch Size and Oracle Row Prefetching
■ Standard and Oracle Update Batching
Example: Disabling AutoCommit The following example illustrates loading the driver
and connecting to the database. Because new connections are in auto-commit mode
by default, this example shows how to disable auto-commit. In the example, conn
represents the Connection object, and stmt represents the Statement object.
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
// Create a Statement
Statement stmt = conn.createStatement ();
...
Common Problems
This section describes some common problems that you might encounter while
using the Oracle JDBC drivers. These problems include:
■ Space Padding for CHAR Columns Defined as OUT or IN/OUT Variables
■ Memory Leaks and Running Out of Cursors
■ Boolean Parameters in PL/SQL Stored Procedures
■ Opening More Than 16 OCI Connections for a Process
important to note that one JDBC-OCI connection can use more than one file
descriptor (it might use anywhere between 3 and 4 file descriptors).
If the server allows more than 16 processes, then the problem could be with the
per-process file descriptor limit. The possible solution would be to increase this
limit.
Note: The trace facility uses a large amount of disk space and
might have significant impact upon system performance. Therefore,
enable tracing only when necessary.
Client-Side Tracing
Set the following parameters in the SQLNET.ORA file on the client system.
TRACE_LEVEL_CLIENT
TRACE_DIRECTORY_CLIENT
TRACE_FILE_CLIENT
Note: Ensure that the name you choose for the TRACE_FILE_
CLIENT file is different from the name you choose for the TRACE_
FILE_SERVER file.
TRACE_UNIQUE_CLIENT
Purpose: Gives each client-side trace a unique name to prevent each trace file from
being overwritten with the next occurrence of a client trace. The PID is
attached to the end of the file name.
Default Value: OFF
Purpose: Gives each client-side trace a unique name to prevent each trace file from
being overwritten with the next occurrence of a client trace. The PID is
attached to the end of the file name.
Example: TRACE_UNIQUE_CLIENT = ON
Server-Side Tracing
Set the following parameters in the SQLNET.ORA file on the server system. Each
connection will generate a separate file with a unique file name.
TRACE_LEVEL_SERVER
TRACE_DIRECTORY_SERVER
TRACE_FILE_SERVER
Note: Ensure that the name you choose for the TRACE_FILE_
SERVER file is different from the name you choose for the TRACE_
FILE_CLIENT file.
This chapter contains detailed JDBC reference information, including the following
topics:
■ Valid SQL-JDBC Datatype Mappings
■ Supported SQL and PL/SQL Datatypes
■ Embedded SQL92 Syntax
■ Oracle JDBC Notes and Limitations
■ Related Information
Notes:
■ For the following SQL datatypes, oracle.sql.ORAData or
oracle.sql.Datum can be materialized as java types.
■ For classes where oracle.sql.ORAData appears in italic,
these can be generated by JPublisher.
Notes:
■ The type UROWID is not supported.
■ The oracle.sql.Datum class is abstract. The value passed to
a parameter of type oracle.sql.Datum must be of the Java
type corresponding to the underlying SQL type. Likewise, the
value returned by a method with return type
oracle.sql.Datum must be of the Java type corresponding
to the underlying SQL type.
■ The mappings to oracle.sql classes are optimal if no
conversion from SQL format to Java format is necessary.
Table 20–3 describes Oracle JDBC driver and SQLJ support for the ANSI-supported
SQL datatypes.
Table 20–4 describes Oracle JDBC driver and SQLJ support for SQL User-Defined
types.
Table 20–5 describes Oracle JDBC driver and SQLJ support for PL/SQL datatypes.
Note that PL/SQL datatypes include these categories:
■ scalar types
■ scalar character types (includes boolean and date datatypes)
■ composite types
■ reference types
■ LOB types
Notes:
■ The types NATURAL, NATURALn, POSITIVE, POSITIVEn, and
SIGNTYPE are subtypes of BINARY INTEGER .
■ The types DEC, DECIMAL, DOUBLE PRECISION, FLOAT, INT,
INTEGER, NUMERIC , REAL, and SMALLINT are subtypes of
NUMBER.
Date Literals
The JDBC drivers support date literals in SQL statements written in the format:
{d ’yyyy-mm-dd’}
The JDBC drivers will replace this escape clause with the equivalent Oracle
representation: "22 OCT 1995".
This code snippet contains an example of using a date literal in a SQL statement.
// Connect to the database
// You can put a database name after the @ sign in the connection URL.
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci:@", "scott", "tiger");
// Create a Statement
Statement stmt = conn.createStatement ();
// Select the ename column from the emp table where the hiredate is Jan-23-1982
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {d '1982-01-23'}");
Time Literals
The JDBC drivers support time literals in SQL statements written in the format:
{t ’hh:mm:ss’}
The JDBC drivers will replace this escape clause with the equivalent Oracle
representation: "05:10:45".
If the time is specified as:
{t ’14:20:50’}
Then the equivalent Oracle representation would be "14:20:50", assuming the server
is using a 24-hour clock.
This code snippet contains an example of using a time literal in a SQL statement.
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {t '12:00:00'}");
Timestamp Literals
The JDBC drivers support timestamp literals in SQL statements written in the
format:
{ts 'yyyy-mm-dd hh:mm:ss.f...'}
Scalar Functions
The Oracle JDBC drivers do not support all scalar functions. To find out which
functions the drivers support, use the following methods supported by the
Oracle-specific oracle.jdbc.OracleDatabaseMetaData class and the
standard Java java.sql.DatabaseMetadata interface:
■ getNumericFunctions(): Returns a comma-separated list of math functions
supported by the driver. For example, ABS(number), COS(float),
SQRT(float).
■ getStringFunctions(): Returns a comma-separated list of string functions
supported by the driver. For example, ASCII(string), LOCATE(string1 ,
string2, start ).
■ getSystemFunctions(): Returns a comma-separated list of system functions
supported by the driver. For example, DATABASE(), IFNULL(expression ,
value), USER().
■ getTimeDateFunctions(): Returns a comma-separated list of time and date
functions supported by the driver. For example, CURDATE(),
DAYOFYEAR(date ), HOUR(time).
Oracle's JDBC drivers do not support the function keyword, 'fn'. If you try to use
this keyword, for example:
{fn concat ("Oracle", "8i") }
Then you will get the error "Non supported SQL92 token at position xx:
fn" when you run your Java application. The workaround is to use Oracle SQL
syntax.
For example, instead of using the fn keyword in embedded SQL92 syntax:
Statement stmt = conn.createStatement ();
stmt.executeUpdate("UPDATE emp SET ename = {fn CONCAT('My', 'Name')}");
// Select the empno column from the emp table where the ename starts with '_'
ResultSet rset = stmt.executeQuery
("SELECT empno FROM emp WHERE ename LIKE '&_%' {ESCAPE '&'}");
Outer Joins
Oracle's JDBC drivers do not support outer join syntax: {oj outer-join}. The
workaround is to use Oracle outer join syntax:
Instead of:
Statement stmt = conn.createStatement ();
The following code is the output that prints the comparable SQL syntax.
{call foo(?, ?)} => BEGIN foo(:1, :2); END;
{? = call bar (?, ?)} => BEGIN :1 := bar (:2, :3); END;
{d '1998-10-22'} => TO_DATE ('1998-10-22', 'YYYY-MM-DD')
{t '16:22:34'} => TO_DATE ('16:22:34', 'HH24:MI:SS')
{ts '1998-10-22 16:22:34'} => TO_DATE ('1998-10-22 16:22:34', 'YYYY-MM-DD
HH24:MI:SS')
CursorName
Oracle JDBC drivers do not support the get getCursorName() and
setCursorName() methods, because there is no convenient way to map them to
Oracle constructs. Oracle recommends using ROWID instead. For more information
on how to use and manipulate ROWIDs, see "Oracle ROWID Type" on page 6-33.
SQLWarning Class
The java.sql.SQLWarning class provides information on a database access
warning. Warnings typically contain a description of the warning and a code that
identifies the warning. Warnings are silently chained to the object whose method
caused it to be reported. The Oracle JDBC drivers generally do not support
SQLWarning. (As an exception to this, scrollable result set operations do generate
SQL warnings, but the SQLWarning instance is created on the client, not in the
database.)
For information on how the Oracle JDBC drivers handle errors, see "Processing SQL
Exceptions" on page 3-34.
Bind by Name
Binding by name is not supported. Under certain circumstances, previous versions
of the Oracle JDBC drivers have allowed binding statement variables by name. In
the following statement, the named variable EmpId would be bound to the integer
314159.
PreparedStatement p = conn.prepareStatement
This capability to bind by name is not part of the JDBC specification, either 1.0 or
2.0, and Oracle does not support it. The JDBC drivers can throw a SQLException
or produce unexpected results.
Prior releases of the Oracle JDBC drivers did not retain bound values from one call
of execute to the next as specified in JDBC 1.0. Bound values are now retained. For
example:
PreparedStatement p = conn.prepareStatement
("SELECT name FROM emp WHERE id = :? AND dept = :?");
p.setInt(1, 314159);
p.setString(2, "SALES");
ResultSet r1 = p.execute();
p.setInt(1, 425260);
ResultSet r2 = p.execute();
Related Information
This section lists Web sites that contain useful information for JDBC programmers.
Many of the sites are referenced in other sections of this manual. In this list you can
find references to the Oracle JDBC drivers, Oracle SQLJ, Java technology, the Java
Developer’s Kit APIs (for versions 1.2.x and 1.1.x), the Java Security API, and
resources to help you write signed applets.
Java Technology
Java Technology Home Page (Sun Microsystems, Inc.):
http://www.javasoft.com
Introduction
A row set is an object which encapsulates a set of rows. These rows are accessible
though the javax.sql.RowSet interface. This interface supports component
models of development, like JavaBeans, and is part of JDBC optional package by
JavaSoft.
Three kinds of row set are supported by JavaSoft:
■ Cached row set
■ JDBC row set
■ Web row set
Note: Oracle implements cached row set and JDBC row set, but
not Web row set.
All the row set implementation is in the oracle.jdbc.rowset package. Web row
set is a semi-connected row set. It has a servlet which has a connection open and the
WebRowSet interface translates the user calls to appropriate request to the servlet
over HTTP. This is targeted at Thin clients which have only HTTP implementation
in them.
Note: The row set feature is available only in JDK 1.2 or later.
The RowSet interface provides a set of properties which can be altered to access the
data in the database through a single interface. It supports properties and events
which forms the core of JavaBeans. It has various properties like connect string, user
name, password, type of connection, the query string itself, and also the parameters
passed to the query. The following code executes a simple query:
...
rowset.setUrl ("jdbc:oracle:oci:@");
rowset.setUsername ("SCOTT");
rowset.setPassword ("TIGER");
rowset.setCommand (
"SELECT empno, ename, sal FROM emp WHERE empno = ?");
In the above example, the URL, user name, password, SQL query, and bind
parameter required for the query are set as the command properties to retrieve the
employee name and salary. Also, the row set would contain empno, ename, and
sal for the employee with the empno as 7839 and whose name is KING.
This might also be set in the project properties in case you are using an IDE like
Jdeveloper.
Oracle row set interfaces are implemented in the oracle.jdbc.rowset package.
Import this package to use any of the Oracle row set implementations.
The OracleCachedRowSet and OracleJDBCRowSet classes implement the
javax.sql.RowSet interface, which extends java.sql.ResultSet. Row set
not only provides the interfaces of result set, but also some of the properties of the
java.sql.Connection and java.sql.PreparedStatement interfaces.
Connections and prepared statements are totally abstracted by this interface.
CachedRowSet is serializable. This class implements the
java.io.Serializable interface. This enables the OracleCachedRowSet class
to be moved over the network or other JVM sessions.
Also available is the oracle.jdbc.rowset.OracleRowSetListenerAdapter
class.
Applications which handle only a few events can implement only the required
events by using the OracleRowSetAdapter class, which is an abstract class with
empty implementation for all the event handling methods.
In the following code, only the rowSetChanged event is handled. The remaining
events are not handled by the application.
rowset.addRowSetListener (new OracleRowSetAdapter ()
{
public void rowSetChanged(RowSetEvent event)
{
// your action for rowsetChanged
}
}
);
In the above example, a ResultSet object is obtained by executing a query and the
retrieved ResultSet object is passed to the populate() method of the cached
row set to populate the contents of the result set into cached row set.
To populate a CachedRowSet object with an already available result set, complete
the following steps:
1. Instantiate OracleCachedRowSet.
2. Pass the already available ResultSet object to the populate() method to
populate the RowSet object.
All the interfaces provided by the ResultSet interface are implemented in
RowSet. The following code shows how to scroll through a row set:
/**
* Scrolling forward, and printing the empno in
* the order in which it was fetched.
*/
// going to the first row of the rowset
rowset.beforeFirst ();
while (rowset.next ())
System.out.println ("empno: " +rowset.getInt (1));
In the example above, the cursor position is initialized to the position before the first
row of the row set by the beforeFirst() method. The rows are retrieved in
forward direction using the next() method.
/**
* Scrolling backward, and printing the empno in
* the reverse order as it was fetched.
*/
//going to the last row of the rowset
rowset.afterLast ();
while (rowset.previous ())
System.out.println ("empno: " +rowset.getInt (1));
In the above example, the cursor position is initialized to the position after the last
row of the RowSet . The rows are retrieved in reverse direction using the
previous() method of RowSet.
Inserting, updating, and deleting rows are supported by the row set feature as they
are in the result set feature. The following code illustrates the insertion of a row at
the fifth position of a row set:
/**
* Inserting a row in the 5th position of the rowset.
*/
// moving the cursor to the 5th position in the rowset
if (rowset.absolute(5))
{
rowset.moveToInsertRow ();
rowset.updateInt (1, 193);
rowset.updateString (2, "Ashok");
rowset.updateInt (3, 7200);
In the above example, a call to the absolute() method with a parameter 5 takes
the cursor to the fifth position of the row set and a call to the
moveToInsertRow() method creates a place for the insertion of a new row into
the row set. The updateXXX() methods are used to update the newly created row.
When all the columns of the row are updated, the insertRow() is called to update
the row set. The changes are committed through acceptChanges() method.
The following code shows how an OracleCachedRowSet object is serialized to a
file and then retrieved:
// writing the serialized OracleCachedRowSet object
{
FileOutputStream fileOutputStream =
new FileOutputStream ("emp_tab.dmp");
CachedRowSet Constraints
All the constraints which apply to updatable result set are applicable here, except
serialization, since OracleCachedRowSet is serializable. The SQL query has the
following constraints:
■ References only a single table in the database
■ Contain no join operations
■ Selects the primary key of the table it references
In addition, a SQL query should also satisfy the conditions below if inserts are to be
performed:
■ Selects all of the non-nullable columns in the underlying table
■ Selects all columns that do not have a default value
Properties which apply to the connection cannot be set after populating the row set
since the properties cannot be applied to the connection after retrieving the data
from the same like, transaction isolation and concurrency mode of the result set.
The JDBC row set is a connected row set which has a live connection to the database
and all the calls on the JDBC row set are percolated to the mapping call in JDBC
connection, statement, or result set. A cached row set does not have any connection
to the database open.
JDBC row set requires the presence of JDBC drivers where a cached row set does
not require JDBC drivers during manipulation, but during population of the row set
and the committing the changes of the row set.
The following code shows how a JDBC row set is used:
RowSet rowset = new OracleJDBCRowSet ();
rowset.setUrl ("java:oracle:oci:@");
rowset.setUsername ("SCOTT");
rowset.setPassword ("TIGER");
rowset.setCommand (
"SELECT empno, ename, sal FROM emp");
rowset.execute ();
while (rowset.next ())
{
System.out.println ("empno: " + rowset.getInt (1));
System.out.println ("ename: "
+ rowset.getString (2));
System.out.println ("sal: " + rowset.getInt (3));
}
In the above example, the connection URL, username, password, and the SQL
query is set as the connection properties to the row set and the query is executed
through the execute() method and the rows are retrieved and printed.
This appendix briefly discusses the general structure of JDBC error messages, then
lists general JDBC error messages and TTC error messages that the Oracle JDBC
drivers can return. The appendix is organized as follows:
■ General Structure of JDBC Error Messages
■ General JDBC Messages
■ TTC Messages
Each of the two message lists is first sorted by ORA number, and then alphabetically.
For general information about processing JDBC exceptions, see "Processing SQL
Exceptions" on page 3-34.
This indicates that the exception was thrown during a call to the next() method
(of a result set object).
In some cases, the user can find the same information in a stack trace.
HeteroRM XA Messages
The following are the JDBC error messages that are specific to the HeteroRM XA
feature.
TTC Messages
This section lists TTC error messages, first sorted by ORA number, and then
alphabetically.
Index-1
BatchUpdateException, 12-16 passing LOB locators, 8-5
beforeFirst() method, A-10 using getOracleObject() method, 7-5
beforeFirst() method (result sets), 13-13 cancelRowUpdates() method (result set), 13-20
BFILE casting return values, 7-10
accessing data, 8-25 catalog arguments (DatabaseMetaData), 20-17
class, 6-12 CHAR class
creating and populating columns, 8-23 conversions with KPRB driver, 18-33
defined, 3-29 CHAR columns
introduction, 8-2 globalization size restrictions, Thin, 18-6
locators, 8-20 space padding, 19-8
getting from a result set, 8-20 using setFixedCHAR() to match in
getting from callable statement, 8-21 WHERE, 7-17
passing to callable statements, 8-21 character sets, 6-32
passing to prepared statements, 8-21 conversions with KPRB driver, 18-33
manipulating data, 8-25 checksums
reading data, 8-22 code example, 18-13
BFILE locator, selecting, 6-13 setting parameters in Java, 18-13
BigDecimal mapping (for attributes), 9-47 support by OCI drivers, 18-11
BLOB, 8-5 support by Thin driver, 18-12
class, 6-12 Class.forName method, 3-3
creating and populating, 8-10 CLASSPATH, specifying, 2-7
creating columns, 8-11 clearBatch() method, 12-14
getting locators, 8-3 clearClientIdentifier() method, 6-19
introduction, 8-2 clearDefines() method, 12-24
locators clearMetaData parameter, 17-11
getting from result set, 8-4 client installation, 1-10
selecting, 6-13 CLOB
manipulating data, 8-12 class, 6-12
populating columns, 8-11 creating and populating, 8-10
reading data, 8-6, 8-8 creating columns, 8-11
writing data, 8-9 introduction, 8-2
Boolean parameters, restrictions, 19-9 locators, 8-3
branch qualifier (distributed transactions), 15-16 getting from result set, 8-4
passing to callable statements, 8-5
passing to prepared statement, 8-5
C locators, selecting, 6-13
cache schemes (connection cache), 16-26 manipulating data, 8-12
CachedRowSet, A-9 populating columns, 8-11
caching, client-side reading data, 8-6, 8-9
custom use for scrollable result sets, 13-6 writing data, 8-9
Oracle use for scrollable result sets, 13-5 close(), 14-4
callable statement close() method, 6-20, 6-21, 6-22, 19-8
getting a BFILE locator, 8-21 for caching statements, 14-7, 14-8
getting LOB locators, 8-4 for OracleConnectionCache interface, 16-23
passing BFILE locator, 8-21 closeFile() method, 8-26
Index-2
closePooledConnection() method, 16-23 connection event listener, 16-21
closeWithKey(), 14-4 Connection Manager, 18-16
closeWithKey() method, 14-9, 14-10 installing, 18-17
CMAN.ORA file, creating, 18-18 starting, 18-18
CODE, parameter for APPLET tag, 18-24 using, 18-17
CODEBASE, parameter for APPLET tag, 18-24 using multiple managers, 18-19
collections writing the connect string, 18-18
defined, 11-2 connection methods, JDBC 2.0 result sets, 13-32
collections (nested tables and arrays), 11-11 connection pooling
column types concepts, 16-11
defining, 12-23 creating data source and connecting, 16-14
redefining, 12-20 introduction, 16-11
commit a distributed transaction branch, 15-15 Oracle data source implementation, 16-12
commit changes to database, 3-13 pooled connections, 16-13
CONCUR_READ_ONLY result sets, 13-9 standard data source interface, 16-12
CONCUR_UPDATABLE result sets, 13-9 connection properties
concurrency types in result sets, 13-4 database, 3-7
connect string defaultBatchValue, 3-7
Connection Manager, 18-18 defaultRowPrefetch, 3-7
for KPRB driver, 18-28 includeSynonyms, 3-7
connection internal_logon, 3-7
closing, 3-14 sysdba, 3-8
from KPRB driver, 1-13 sysoper, 3-8
opening, 3-3 password, 3-7
opening for JDBC OCI driver, 3-9 put() method, 3-9
opening for JDBC Thin driver, 3-10 remarksReporting, 3-7
Properties object, 3-6 user, 3-7
connection caching connectionClosed() method (connection event
adding connection event listener, 16-21 listener), 16-28
basics, accessing the cache, 16-17 connectionErrorOccurred() method (connection
basics, closing connections, 16-18 event listener), 16-28
basics, opening connections, 16-17 connections
basics, setting up a cache, 16-16 read-only, 19-15
cache instance getConnection() method, 16-17 constants for SQL types, 6-23
connection events, 16-18 CREATE DIRECTORY statement
creating connection event listener, 16-21 for BFILEs, 8-23
implementation scenarios, 16-19 CREATE TABLE statement
OracleConnectionCache interface, 16-23 to create BFILE columns, 8-23
OracleConnectionCacheImpl class, 16-24 to create BLOB, CLOB columns, 8-11
OracleConnectionEventListener class, 16-28 CREATE TYPE command, 9-53, 9-55, 9-63
overview, 16-16 CREATE TYPE statement, 9-29, 9-52
preliminary steps, 16-20 create() method
removing connection event listener, 16-22 for ORADataFactory interface, 9-21
steps in closing a connection, 16-22 createDescriptor() method, 9-5, 9-61, 11-14
steps in opening a connection, 16-20 createStatement(), 14-4
Index-3
createStatement() method, 6-19, 14-10 database URL
createStatementWithKey() method, 14-11 including userid and password, 3-5
createTemporary() method, 8-18 database URL, specifying, 3-5
creationState() method, 14-6 DatabaseMetaData calls, 20-17
code example, 14-7 DatabaseMetaData class, 20-12
CursorName entry points for applets, 18-23
limitations, 20-16 datatype classes, 6-8
cursors, 19-8 datatype mappings, 3-16
custom collection classes datatypes
and JPublisher, 11-27 Java, 3-16
defined, 11-2, 11-27 Java native, 3-16
custom Java classes, 6-4 JDBC, 3-16
defined, 9-2 Oracle SQL, 3-16
custom object classes DATE class, 6-13
creating, 9-10 DBMS_LOB package, 8-6
defined, 9-2 debugging JDBC programs, 19-11
custom reference classes DEFAULT_CHARSET character set value, 6-31
and JPublisher, 10-10 defaultBatchValue connection property, 3-7
defined, 10-2, 10-10 defaultConnection() method, 18-26
defaultRowPrefetch connection property, 3-7
defineColumnType() method, 3-25, 6-20, 12-24
D DELETE in a result set, 13-18
data conversions, 7-2 deleteRow() method (result set), 13-18
LONG, 3-21 deletesAreDetected() method (database meta
LONG RAW, 3-21 data), 13-29
data sources deserialization
creating and connecting (with JNDI), 16-8 ArrayDescriptor object, 11-15
creating and connecting (without JNDI), 16-7 creating a StructDescriptor object, 9-6
logging and tracing, 16-10 creating an ArrayDescriptor object, 11-15
Oracle implementation, 16-3 definition of, 9-6, 11-15
PrintWriter, 16-10 StructDescriptor object, 9-6
properties, 16-4 disabling
standard interface, 16-3 escape processing, 3-7
data streaming distributed transaction ID component, 15-16
avoiding, 3-24 distributed transactions
database branch qualifier, 15-16
connecting check for same resource manager, 15-16
from an applet, 18-15 commit a transaction branch, 15-15
via multiple Connection Managers, 18-19 components and scenarios, 15-3
with server-side internal driver, 18-26 concepts, 15-3
connection testing, 2-9 distributed transaction ID component, 15-16
database connection end a transaction branch, 15-13
connection property, 3-7 example of implementation, 15-21
database meta data methods, JDBC 2.0 result global transaction identifier, 15-16
sets, 13-35 ID format identifier, 15-16
Index-4
introduction, 15-2 retrieving SQL state, 3-34
Oracle XA connection implementation, 15-9 execute() method, A-16
Oracle XA data source implementation, 15-8 executeBatch() method, 12-12
Oracle XA ID implementation, 15-16 executeQuery() method, 6-20
Oracle XA optimizations, 15-20 executeUpdate() method, 12-9
Oracle XA resource implementation, 15-10 expansion factor
prepare a transaction branch, 15-14 and globalization, 18-6
roll back a transaction branch, 15-15 explicit statement caching
start a transaction branch, 15-12 definition of, 14-3
transaction branch ID component, 15-16 null data, 14-10
XA connection interface, 15-9 extensions to JDBC, Oracle, 6-1, 7-1, 9-1, 10-1, 11-1,
XA data source interface, 15-8 12-1
XA error handling, 15-19 external changes (result set)
XA exception classes, 15-18 defined, 13-27
XA ID interface, 15-16 seeing, 13-28
XA resource functionality, 15-11 visibility vs. detection, 13-29
XA resource interface, 15-10 external file
DriverManager class, 3-3 defined, 3-29
driverType, 16-6 EXTERNAL NAME clause, 9-55
dynamic SQL, 1-2
DYNAMIC_SCHEME (connection cache), 16-27
F
fetch direction in result sets, 13-17
E fetch size, result sets, 13-24
encryption finalizer methods, 19-8
code example, 18-13 firewalls
overview, 18-10 configuring for applets, 18-21
setting parameters in Java, 18-13 connect string, 18-22
support by OCI drivers, 18-11 described, 18-20
support by Thin driver, 18-12 required rule list items, 18-21
end a distributed transaction branch, 15-13 using with applets, 1-11, 18-20
Enterprise Java Beans (EJB), A-13 first() method (result sets), 13-14
environment variables FIXED_RETURN_NULL_SCHEME (connection
specifying, 2-6 cache), 16-27
errors floating-point compliance, 20-17
general JDBC message structure, B-2 format identifier, transaction ID, 15-16
general JDBC messages, listed, B-3 forward-only result sets, 13-3
processing exceptions, 3-34 freeTemporary() method, 8-18
TTC messages, listed, B-17 function call syntax, SQL92 syntax, 20-14
escape processing
disabling, 3-7
exceptions
G
printing stack trace, 3-35 getActiveSize() method (connection cache), 16-27
retrieving error code, 3-34 getARRAY() method, 11-16
retrieving message, 3-34 getArray() method, 11-6, 11-10, 11-16
Index-5
using type maps, 11-18 getExecuteBatch() method, 6-21, 12-6, 12-7
getArrayType() method, 11-14 getFetchSize() method, 13-24
getAsciiOutputStream() method, 8-15 getJavaSQLConnection() method, 9-4, 11-6
for writing CLOB data, 8-7 getJavaSqlConnection() method, 6-26
getAsciiStream() method, 8-15 getLanguage() method, 9-62
for reading CLOB data, 8-7 getMaxLength() method, 11-14
getAttributes() method, 9-3 getMessage() method (SQLException), 3-34
used by Structs, 9-15 getMetaData() method, 9-62
getAutoBuffering() method getName() method, 8-25, 8-26
of the oracle.sql.ARRAY class, 11-9 getNumericFunctions() method, 20-12
of the oracle.sql.STRUCT class, 9-9 getObject() method
getBaseName() method, 11-14 casting return values, 7-10
getBaseType() method, 11-6, 11-14, 11-20 for object references, 10-6
getBaseTypeName() method, 10-4, 11-6 for ORAData objects, 9-22
getBinaryOutputStream() method, 8-14 for SQLInput streams, 9-16
for writing BLOB data, 8-7 for SQLOutput streams, 9-17
getBinaryStream() method, 3-23, 8-14, 8-26 for Struct objects, 9-7
for reading BFILE data, 8-22 return types, 7-4, 7-6
for reading BLOB data, 8-6 to get BFILE locators, 8-20
getBufferSize() method, 8-14, 8-15 to get Oracle objects, 9-7
getBytes() method, 3-24, 6-10, 8-14, 8-26 used with ORAData interface, 9-24
getCacheSize() method (connection cache), 16-27 getOracleArray() method, 11-6, 11-16, 11-19
getCallWithKey(), 14-4 getOracleAttributes() method, 9-4, 9-8
getCallWithKey() method, 14-10, 14-11 getOracleObject() method, 6-21, 6-22
getCharacterOutputStream() method, 8-15 casting return values, 7-10
for writing CLOB data, 8-7 return types, 7-4, 7-6
getCharacterStream() method, 8-15 using in callable statement, 7-5
for reading CLOB data, 8-7 using in result set, 7-5
getChars() method, 8-15 getOraclePlsqlIndexTable() method, 17-22, 17-25,
getChunkSize() method, 8-14, 8-16 17-26
getColumnCount() method, 7-19 argument
getColumnName() method, 7-19 int paramIndex, 17-26
getColumns() method, 12-26 code example, 17-27
getColumnType() method, 7-19 getORAData() method, 9-22, 9-24
getColumnTypeName() method, 7-19 getPassword() method, 16-5
getConcurrency() method (result set), 13-12 getPlsqlIndexTable() method, 17-22, 17-25, 17-27
getConnection() method, 3-4, 11-15, 17-10, 18-26 arguments
getCursor() method, 6-35, 6-36 Class primitiveType, 17-28
getCursorName() method int paramIndex, 17-28
limitations, 20-16 code example, 17-26, 17-28
getDefaultExecuteBatch() method, 6-19, 12-7 getProcedureColumns() method, 12-26
getDefaultRowPrefetch() method, 6-19, 12-21 getProcedures() method, 12-26
getDescriptor() method, 9-4, 11-6 getREF() method, 10-7
getDirAlias() method, 8-25, 8-27 getRemarksReporting() method, 6-20
getErrorCode() method (SQLException), 3-34 getResultSet() method, 6-20, 11-6
Index-6
getRow() method (result set), 13-15 H
getRowPrefetch() method, 6-20, 12-21
getSQLState() method (SQLException), 3-34 HEIGHT, parameter for APPLET tag, 18-24
getSQLTypeName() method, 9-3, 11-6, 11-20 HeteroRM XA, 17-19
getStatementCacheSize() method HTML tags, to deploy applets, 18-24
code example, 14-6 http
getStatementWithKey(), 14-4 //www.ansi.org/, 9-53
getStatementWithKey() method, 14-10, 14-11 HTTP protocol, 1-5
getString() method, 6-31
to get ROWIDs, 6-33 I
getStringFunctions() method, 20-12
IEEE 754 floating-point compliance, 20-17
getStringWithReplacement() method, 6-32
implicit statement caching
getSTRUCT() method, 9-7
definition of, 14-2
getSubString() method, 8-16
Least Recently Used (LRU) scheme, 14-3
for reading CLOB data, 8-7
IN OUT parameter mode, 17-24
getSystemFunctions() method, 20-12
IN parameter mode, 17-22
getTimeDateFunctions() method, 20-12
includeSynonyms connection property, 3-7
getTransactionIsolation() method, 6-19, 19-15
INSERT in a result set, 13-21
getType() method (result set), 13-12
INSERT INTO statement
getTypeMap() method, 6-19, 9-13
for creating BFILE columns, 8-24
getUpdateCounts() method
insertRow() method (result set), 13-22
(BatchUpdateException), 12-16
insertsAreDetected() method (database meta
getValue() method, 10-5
data), 13-29
for object references, 10-6
installation
getXXX() methods
client, 1-10
casting return values, 7-10
directories and files, 2-5
for specific datatypes, 7-7
verifying on the client, 2-5
Oracle extended properties, 16-6
integrity
global transaction identifier (distributed
code example, 18-13
transactions), 15-16
overview, 18-10
global transactions, 15-2
setting parameters in Java, 18-13
globalization
support by OCI drivers, 18-11
and JDBC drivers, 18-3
support by Thin driver, 18-12
conversions, 18-3
internal changes (result set)
for JDBC OCI drivers, 18-3
defined, 13-27
for JDBC Thin drivers, 18-4
seeing, 13-27
for KPRB driver, 18-4
internal_logon connection property, 3-7
expansion factor, 18-6
sysdba, 3-8
Java methods that employ, 18-2
sysoper, 3-8
Thin driver CHAR/VARCHAR2 size
isAfterLast() method (result set), 13-15
restrictions, 18-6
isBeforeFirst() method (result set), 13-15
using, 18-2
isFileOpen() method, 8-27
isFirst() method (result set), 13-15
isLast() method (result set), 13-15
Index-7
isSameRM() (distributed transactions), 15-16 applications, 1-10
isTemporary() method, 8-18 choosing a driver for your needs, 1-8
common features, 1-4
common problems, 19-8
J compatibilities, 2-2
Java determining driver version, 2-8
compiling and running, 2-8 introduction, 1-4
datatypes, 3-16 registering, 3-3
native datatypes, 3-16 requirements, 2-2
stored procedures, 3-33 restrictions, 19-9
stream data, 3-20 SQL92 syntax, 20-10
Java Naming and Directory Interface (JNDI), 16-2 JDBC mapping (for attributes), 9-46
Java Sockets, 1-5 JdbcCheckup program, 2-9
Java virtual machine (JVM), 1-8, 18-26 JDBCSpy, 19-14
JavaBeans, A-2 JDBCTest, 19-14
java.math, Java math packages, 3-2 JDeveloper, 1-15
JavaSoft, A-2 Jdeveloper, A-4
java.sql, JDBC packages, 3-2 JDK
java.sql.SQLData, 9-53 migration from 1.1.x to 1.2.x, 4-5
java.sql.SQLException() method, 3-34 versions supported, 1-14
java.sql.Types class, 12-24 JNDI
java.util.Dictionary class looking up data source, 16-9
used by type maps, 9-12 overview of Oracle support, 16-2
java.util.Map class, 11-19 registering data source, 16-9
java.util.Properties, 17-7 JPublisher, 6-4, 9-25, 9-45
JDBC JPublisher utility, 6-4, 9-10
and IDEs, 1-15 creating custom collection classes, 11-27
basic program, 3-2 creating custom Java classes, 9-45
datatypes, 3-16 creating custom reference classes, 10-10
defined, 1-2 SQL type categories and mapping options, 9-46
guidelines for using, 1-3 type mapping modes and settings, 9-46
importing packages, 3-2 type mappings, 9-45
limitations of Oracle extensions, 20-16 JVM, 1-8, 18-26
sample files, 2-8
testing, 2-9
JDBC 2.0 support K
datatype support, 4-3 KPRB driver
extended feature support, 4-5 connection string for, 18-28
introduction, 4-2, 5-2 described, 1-8
JDK 1.2.x vs. JDK 1.1.x, 4-3, 5-3 globalization considerations, 18-4
overview of features, 4-7, 5-4 relation to the SQL engine, 18-26
standard feature support, 4-4 session context, 18-30
JDBC drivers testing, 18-30
and globalization, 18-3 transaction context, 18-30
applets, 1-10
Index-8
L N
last() method (result set), 13-14 named arrays, 11-2
LD_LIBRARY_PATH variable, specifying, 2-7 defined, 11-11
Least Recently Used (LRU) scheme, 14-3, 17-8 Native Method Interface, 1-14
length() method, 8-14, 8-16, 8-27, 11-6 nativeXA, 16-6, 17-19
libheteroxa9_g.so Solaris shared library, 17-19 NC, A-13
libheteroxa9.so Solaris shared library, 17-19 Network Computer (NC), A-13
LIKE escape characters, SQL92 syntax, 20-13 network events, trapping, 19-11
limitations on setBytes() and setString(), use of next() method, A-10
streams to avoid, 3-31 next() method (result set), 13-15
loadjava tool, 9-55 NLS_LANG environment variable, 18-3
LOB NMI (Native Method Interface), 1-14
defined, 3-27 NULL data
introduction, 8-2 converting, 7-2
locators, 8-2 null data
reading data, 8-6 explicit statement caching, 14-10
LOB locators NUMBER class, 6-13
getting from callable statements, 8-4
passing, 8-5
LOBs
O
empty, 8-17 object references
locators accessing object values, 10-7, 10-9
getting for BFILEs, 8-20 described, 10-2
getting for BLOBs, 8-3 passing to prepared statements, 10-8
getting for CLOBs, 8-3 retrieving, 10-6
LOB, 8-2 retrieving from callable statement, 10-7
passing to callable statements, 8-5 updating object values, 10-7, 10-9
passing to prepared statement, 8-5 object-JDBC mapping (for attributes), 9-46
logging with a data source, 16-10 OCI driver
logical connection instance, 16-11 applications, 1-10
LONG described, 1-6
data conversions, 3-21 globalization considerations, 18-3
LONG RAW ODBCSpy, 19-14
data conversions, 3-21 ODBCTest, 19-14
LRU scheme, 14-3, 17-8 openFile() method, 8-26
optimization, performance, 19-6
Oracle Advanced Security, 1-10
M support by JDBC, 18-8
make() method, 6-30 support by OCI drivers, 18-8
memory leaks, 19-8 support by Thin driver, 18-9
migration from JDK 1.1.x to 1.2.x, 4-5 Oracle Connection Manager, 1-10, 18-16
moveToCurrentRow() method (result set), 13-21 Oracle datatypes
moveToInsertRow() method (result set), 13-21 using, 7-1
mutable arrays, 11-27 Oracle extensions
Index-9
datatype support, 6-3 OracleConnection class, 6-18
limitations, 20-16 OracleConnection interface, 17-4
catalog arguments to DatabaseMetaData OracleConnection object, 14-2
calls, 20-17 OracleConnectionCache interface, 16-23
CursorName, 20-16 close() method, 16-23
IEEE 754 floating-point compliance, 20-17 closePooledConnection() method, 16-23
PL/SQL TABLE, BOOLEAN, RECORD reusePooledConnection() method, 16-23
types, 20-16 OracleConnectionCacheImpl class, 16-24, 16-26
read-only connection, 19-15 getActiveSize() method, 16-27
SQL92 outer join escapes, 20-16 getCacheSize() method, 16-27
SQLWarning class, 20-17 instantiating and setting properties, 16-24
object support, 6-4 schemes for new pooled connections, 16-26
packages, 6-2 setCacheScheme() method, 16-27
result sets, 7-3 setConnectionPoolDataSource() method, 16-25
schema naming support, 6-5 setMaxLimit() method
statements, 7-3 setMaxLimit() method (connection
support under 8.0.x/7.3.x drivers, 6-36 cache), 16-26
to JDBC, 6-1, 7-1, 9-1, 10-1, 11-1, 12-1 setMinLimit() method
Oracle mapping (for attributes), 9-46 setMinLimit() method (connection
Oracle Net cache), 16-26
name-value pair, 3-4 setting maximum pooled connections, 16-25
protocol, 1-5 setting minimum pooled connections, 16-26
Oracle objects OracleConnectionCacheImpl interface, 17-4
and JDBC, 9-2 OracleConnectionEventListener
converting with ORAData interface, 9-21 connectionClosed() method, 16-28
converting with SQLData interface, 9-15 OracleConnectionEventListener class, 16-28
getting with getObject() method, 9-7 connectionErrorOccurred() method, 16-28
Java classes which support, 9-3 instantiating, 16-28
mapping to custom object classes, 9-10 setDataSource() method, 16-28
reading data by using SQLData interface, 9-17 OracleConnectionPoolDataSouorce class, 16-12
working with, 9-2 OracleDatabaseMetaData class, 20-12
writing data by using SQLData interface, 9-20 and applets, 18-23
Oracle SQL datatypes, 3-16 OracleDataSource class, 16-3, 17-4
OracleCallableStatement interface, 6-21 OracleDriver class, 6-18
getOraclePlsqlIndexTable() method, 17-22 oracle.jdbc. package, 6-16
getPlsqlIndexTable() method, 17-22 oracle.jdbc., Oracle JDBC extensions, 3-3
getTIMESTAMP(), 6-14 oracle.jdbc2 package, described, 6-27
getTIMESTAMPLTZ(), 6-14 oracle.jdbc2.Struct class, 6-11
getTIMESTAMPTZ(), 6-14 getAttributes() method, 9-3
getXXX() methods, 7-7 getSQLTypeName() method, 9-3
registerIndexTableOutParameter() oracle.jdbc.OracleCallableStatement interface, 6-21
method, 17-22, 17-24 close() method, 6-22
registerOutParameter() method, 7-13 getOracleObject() method, 6-21
setPlsqlIndexTable() method, 17-21, 17-22 getXXX() methods, 6-21, 6-23
OracleCallableStatement object, 14-2, 14-3 registerOutParameter() method, 6-22
Index-10
setNull() method, 6-22 setRowPrefetch() method, 6-20
setOracleObject() methods, 6-22 oracle.jdbc.OracleTypes class, 6-23, 12-24
setXXX() methods, 6-22 oracle.jdbc.pool package, 16-14, 17-5
oracle.jdbc.OracleConnection interface, 6-18 oracle.jdbc.StructMetaData, 9-62
clearClientIdentifier() method, 6-19 oracle.jdbc.StructMetaData interface, 9-61
createStatement() method, 6-19 oracle.jdbc.xa package and subpackages, 15-7
getDefaultExecuteBatch() method, 6-19 OracleOCIConnection class, 17-4
getDefaultRowPrefetch() method, 6-19 OracleOCIConnectionPool class, 17-2, 17-4
getRemarksReporting() method, 6-20 OracleOCIFailover interface, 17-5
getTransactionIsolation() method, 6-19, 19-15 OraclePooledConnection class, 16-13, 16-14, 17-2
getTypeMap() method, 6-19 OraclePooledConnection method
prepareCall() method, 6-19 definitions, 16-14
prepareStatement() method, 6-19 OraclePooledConnection object, 14-2
setClientIdentifier() method, 6-19 OraclePreparedStatement interface, 6-20
setDefaultExecuteBatch() method, 6-19 getOraclePlsqlIndexTable() method, 17-22
setDefaultRowPrefetch() method, 6-19 getPlsqlIndexTable() method, 17-22
setRemarksReporting() method, 6-20 registerIndexTableOutParameter()
setTransactionIsolation() method, 6-19, 19-15 method, 17-22
setTypeMap() method, 6-19 setPlsqlIndexTable() method, 17-21, 17-22
oracle.jdbc.OracleDriver class, 6-18 setTIMESTAMP(), 6-14
oracle.jdbc.OraclePreparedStatement setTIMESTAMPLTZ(), 6-14
interface, 6-20 setTIMESTAMPTZ(), 6-14
close() method, 6-21 OraclePreparedStatement object, 14-2, 14-3
getExecuteBatch() method, 6-21 OracleResultSet interface, 6-22
setExecuteBatch() method, 6-21 getXXX() methods, 7-7
setNull() method, 6-21 OracleResultSetCache interface, 13-6
setOracleObject() method, 6-21 OracleResultSetMetaData interface, 6-23
setORAData() method, 6-21 OracleServerDriver class
setXXX() methods, 6-21 defaultConnection() method, 18-27
oracle.jdbc.OracleResultSet interface, 6-22 oracle.sql datatype classes, 6-8
getOracleObject() method, 6-22 oracle.sql package
oracle.jdbc.OracleResultSetMetaData data conversions, 7-2
interface, 6-23, 7-19 described, 6-7
getColumnCount() method, 7-19 oracle.sql.ARRAY class, 11-2
getColumnName() method, 7-19 and nested tables, 6-12
getColumnType() method, 7-19 and VARRAYs, 6-12
getColumnTypeName() method, 7-19 createDescriptor() method, 11-14
using, 7-19 getArray() method, 11-6
oracle.jdbc.OracleSql class, 20-14 getArrayType() method, 11-14
oracle.jdbc.OracleStatement interface, 6-20 getAutoBuffering() method, 11-9
close() method, 6-20 getBaseType() method, 11-6
defineColumnType(), 6-20 getBaseTypeName() method, 11-6
executeQuery() method, 6-20 getDescriptor() method, 11-6
getResultSet() method, 6-20 getJavaSQLConnection() method, 11-6, 11-15
getRowPrefetch() method, 6-20 getMaxLength() method, 11-14
Index-11
getOracleArray() method, 11-6 putChars() method, 8-16
getResultSet() method, 11-6 putString() method, 8-16
getSQLTypeName() method, 11-6 supported character sets, 8-13
length() method, 11-6 oracle.sql.datatypes
methods for Java primitive types, 11-8 support, 6-10
setAutoBuffering() method, 11-9 oracle.sql.DATE class, 6-13
setAutoIndexing() method, 11-10 oracle.sql.Datum array, 17-26
oracle.sql.ArrayDescriptor class oracle.sql.Datum class, described, 6-7
getBaseName() method, 11-14 oracle.sql.NUMBER class, 6-13
getBaseType() method, 11-14 oracle.sql.ORAData, 9-53
oracle.sql.BFILE class, 6-12 oracle.sql.ORAData interface, 9-21
closeFile() method, 8-26 oracle.sql.ORADataFactory, 9-53
getBinaryStream() method, 8-26 oracle.sql.ORADataFactory interface, 9-21
getBytes() method, 8-26 OracleSql.parse() method, 20-14
getDirAlias() method, 8-27 oracle.sql.RAW class, 6-13
getName() method, 8-26 oracle.sql.REF class, 6-12, 10-2
isFileOpen() method, 8-27 getBaseTypeName() method, 10-4
length() method, 8-27 getValue() method, 10-5
openFile() method, 8-26 setValue() method, 10-5
position() method, 8-27 oracle.sql.ROWID class, 6-10, 6-15, 6-33
oracle.sql.BLOB class, 6-12 oracle.sql.STRUCT class, 6-10, 9-3
getBinaryOutputStream() method, 8-14 getAutoBuffering() method, 9-9
getBinaryStream() method, 8-14 getDescriptor() method, 9-4
getBufferSize() method, 8-14 getJavaSQLConnection() method, 9-4
getBytes() method, 8-14 getOracleAttributes() method, 9-4
getChunkSize() method, 8-14 setAutoBuffering() method, 9-9
length() method, 8-14 toJDBC() method, 9-4
position() method, 8-14 oracle.sql.StructDescriptor class, 9-61
putBytes() method, 8-14 createDescriptor() method, 9-5
oracle.sql.CHAR class, 18-33 OracleStatement interface, 6-20
getString() method, 6-31 OracleTypes class, 6-23
getStringWithReplacement() method, 6-32 OracleTypes class for typecodes, 6-23
toString() method, 6-31 OracleTypes.CURSOR variable, 6-36
oracle.sql.CharacterSet class, 6-30 OracleXAConnection class, 15-9
oracle.sql.CLOB class, 6-12 OracleXADataSource class, 15-8
getAsciiOutputStream() method, 8-15 OracleXAResource class, 15-10, 15-11
getAsciiStream() method, 8-15 OracleXid class, 15-16
getBufferSize() method, 8-15 ORAData interface, 6-4
getCharacterOutputStream() method, 8-15 additional uses, 9-26
getCharacterStream() method, 8-15 advantages, 9-11
getChars() method, 8-15 Oracle object types, 9-1
getChunkSize() method, 8-16 reading data, 9-23
getSubString() method, 8-16 writing data, 9-25
length() method, 8-16 othersDeletesAreVisible() method (database meta
position() method, 8-16 data), 13-28
Index-12
othersInsertsAreVisible() method (database meta Oracle implementation, 16-13
data), 13-28 standard interface, 16-13
othersUpdatesAreVisible() method (database meta populate() method, A-10
data), 13-28 position() method, 8-14, 8-16, 8-27
OUT parameter mode, 17-24, 17-25 positioning in result sets, 13-2
outer joins, SQL92 syntax, 20-13 prefetching rows, 12-20
ownDeletesAreVisible() method (database meta suggested default, 12-23
deta), 13-27 prepare a distributed transaction branch, 15-14
ownInsertsAreVisible() method (database meta prepareCall(), 14-4
data), 13-28 prepareCall() method, 6-19, 14-8, 14-9, 14-10
ownUpdatesAreVisible() method (database meta prepared statement
data), 13-27 passing BFILE locator, 8-21
passing LOB locators, 8-5
using setObject() method, 7-12
P using setOracleObject() method, 7-12
parameter modes PreparedStatement object
IN, 17-22 creating, 3-12
IN OUT, 17-24 prepareStatement(), 14-4
OUT, 17-24, 17-25 prepareStatement() method, 6-19, 14-8, 14-9, 14-10
password connection property, 3-7 code example, 14-8
password, specifying, 3-5 previous() method (result set), 13-15
PATH variable, specifying, 2-7 printStackTrace() method (SQLException), 3-35
PDA, A-13 PrintWriter for a data source, 16-10
performance enhancements, standard vs. processEscapes
Oracle, 4-5 connection property, 3-7
performance extensions put() method
defining column types, 12-23 for Properties object, 3-9
prefetching rows, 12-20 for type maps, 9-13
TABLE_REMARKS reporting, 12-26 putBytes() method, 8-14
performance optimization, 19-6 putChars() method, 8-16
Personal Digital Assistant (PDA), A-13 putString() method, 8-16
PL/SQL
IN parameter, 9-59
OUT parameters, 9-60 Q
restrictions, 19-9 query, executing, 3-11
space padding, 19-8
stored procedures, 3-32
PL/SQL index-by tables
R
mapping, 17-25 RAW class, 6-13
scalar datatypes, 17-21 RDBMS, 1-5
PL/SQL types read-only result set concurrency type, 13-4
corresponding JDBC types, 17-21 readSQL() method, 9-15, 9-16, 9-54, 9-61
limitations, 20-16 implementing, 9-16
PoolConfig() method, 17-7 REF class, 6-12
pooled connections REF CURSORs, 6-35
Index-13
materialized as result set objects, 6-35 seeing external changes, 13-28
refetching rows into a result set, 13-26, 13-29 seeing internal changes, 13-27
refreshRow() method (result set), 13-26 sensitivity to database changes, 13-2
registerDriver() method, 6-18 specifying scrollability, updatability, 13-8
registerIndexTableOutParameter() method, 17-22, summary of methods, 13-32
17-24 summary of visibility of changes, 13-30
arguments updatability, 13-4
int elemMaxLen, 17-24 updating result sets, 13-18
int elemSqlType, 17-24 visibility vs. detection of external
int maxLen, 17-24 changes, 13-29
int paramIndex, 17-24 result set fetch size, 13-24
code example, 17-25 result set methods, JDBC 2.0, 13-32
registering Oracle JDBC drivers, class for, 6-18 result set object
registerOutParameter() method, 6-22, 7-13, 9-61 closing, 3-12
Relational Database Management System result set types for scrollability and
(RDBMS), 1-5 sensitivity, 13-3
relative positioning in result sets, 13-2 result set, processing, 3-11
relative() method (result set), 13-14 ResultSet class, 3-11
remarksReporting connection property, 3-7 ResultSet() method, 11-10
remarksReporting flag, 12-20 ResultSetMetaData class, 9-62
Remote Method Invocation (RMI), A-12 return types
removeConnectionEventListener method for getXXX() methods, 7-7
(connection cache), 16-22 getObject() method, 7-6
resource managers, 15-3 getOracleObject() method, 7-6
result set return values
auto-commit mode, 19-6 casting, 7-10
getting BFILE locators, 8-20 reusePooledConnection() method, 16-23
getting LOB locators, 8-4 RMI, A-12
metadata, 6-23 roll back a distributed transaction branch, 15-15
Oracle extensions, 7-3 roll back changes to database, 3-13
using getOracleObject() method, 7-5 row prefetching, 12-20
result set enhancemennts and data streams, 3-31
positioning result sets, 13-13 ROWID class, 6-15
result set enhancements CursorName methods, 20-16
concurrency types, 13-4 defined, 6-33
downgrade rules, 13-11 ROWID, use for result set updates, 13-5
fetch size, 13-24
limitations, 13-10
Oracle scrollability requirements, 13-5
S
Oracle updatability requirements, 13-5 scalar functions, SQL92 syntax, 20-12
positioning, 13-2 schema naming conventions, 6-5
processing result sets, 13-16 scrollability in result sets, 13-2
refetching rows, 13-26, 13-29 scrollable result sets
result set types, 13-3 creating, 13-8
scrollability, 13-2 fetch direction, 13-17
Index-14
implementation of scroll-sensitivity, 13-30 setBlob() method, JDK 1.2.x, 8-5
positioning, 13-13 setBytes() limitations, using streams to avoid, 3-31
processing backward/forward, 13-16 setCacheScheme() method (connection
refetching rows, 13-26, 13-29 cache), 16-27
scroll-insensitive result sets, 13-3 setCharacterStream() method, 7-16
scroll-sensitive result sets, 13-3 setClientIdentifier() method, 6-19
seeing external changes, 13-28 setCLOB() method, 8-5
visibility vs. detection of external setClob() method, 1.1.x, 8-5
changes, 13-29 setClob() method, JDK 1.2.x, 8-5
scroll-sensitive result sets setConnection() method
limitations, 13-10 ArrayDescriptor object, 11-15
security StructDescriptor object, 9-6
authentication, 18-9 setConnectionPoolDataSource method (connection
encryption, 18-10 cache), 16-25
integrity, 18-10 setCursorName() method, 20-16
Oracle Advanced Security support, 18-8 setDataSource() method (connection event
overview, 18-8 listener), 16-28
SELECT statement setDate() method, 7-16
to retrieve object references, 10-6 setDefaultExecuteBatch() method, 6-19, 12-5
to select LOB locator, 8-12 setDefaultRowPrefetch() method, 6-19, 12-21
sendBatch() method, 12-7, 12-9 setDisableStatementCaching() method, 14-8
sensitivity in result sets to database changes, 13-2 setEscapeProcessing() method, 20-10
serialization setExecuteBatch() method, 6-21, 12-6
ArrayDescriptor object, 11-15 setFetchSize() method, 13-24
definition of, 9-6, 11-15 setFixedCHAR() method, 7-17
StructDescriptor object, 9-6 setFormOfUse() method, 6-28
server-side internal driver setMaxFieldSize() method, 12-24, 19-8
connection to database, 18-26 setNull() method, 6-21, 6-22, 7-13
server-side Thin driver, described, 1-7 setObejct() method, 7-11
session context, 1-13 setObject() method
for KPRB driver, 18-30 for BFILES, 8-21
setAsciiStream() method, 7-16 for BLOBs and CLOBs, 8-5
setAutoBuffering() method for CustomDatum objects, 9-23
of the oracle.sql.ARRAY class, 11-9 for object references, 10-8
of the oracle.sql.STRUCT class, 9-9 for STRUCT objects, 9-8
setAutoCommit() method, 19-6 to write object data, 9-26
setAutoIndexing() method, 11-10 using in prepared statements, 7-12
direction parameter values setOracleObject() method, 6-21, 6-22, 7-11
ARRAY.ACCESS_FORWARD, 11-10 for BFILES, 8-21
ARRAY.ACCESS_REVERSE, 11-10 for BLOBs and CLOBs, 8-5
ARRAY.ACCESS_UNKNOWN, 11-10 using in prepared statements, 7-12
setBFILE() method, 8-21 setORAData() method, 6-21, 9-22, 9-26
setBinaryStream() method, 7-16 setPlsqlIndexTable() method, 17-21, 17-22
setBLOB() method, 8-5 arguments
setBlob() method, JDK 1.1.x, 8-5 int curLen, 17-23
Index-15
int elemMaxLen, 17-23 translating to SQL example, 20-14
int elemSqlType, 17-23 SQLData interface, 6-4
int maxLen, 17-22 advantages, 9-11
int paramIndex, 17-22, 17-26 described, 9-15
Object arrayData, 17-22 Oracle implementation, 6-27
code example, 17-23 Oracle object types, 9-1
setPoolConfig() method, 17-7 reading data from Oracle objects, 9-17
setREF() method, 10-8 using with type map, 9-15
setRemarksReporting() method, 6-20, 12-26 writing data from Oracle objects, 9-20
setResultSetCache() method, 13-6 SQLInput interface, 9-15
setRowPrefetch() method, 6-20, 12-21 described, 9-16
setStmtCacheSize() method, 17-10 SQLInput streams, 9-16
setString() limitations, using streams to avoid, 3-31 SQLJ
setString() method guidelines for using, 1-3
to bind ROWIDs, 6-33 SQLJ object type, 9-52
setTime() method, 7-17 SQLNET.ORA
setTimestamp() method, 7-17 parameters for tracing, 19-11
setTransactionIsolation() method, 6-19, 19-15 SQLOutput interface, 9-15
setTypeMap() method, 6-19 described, 9-16
setUnicodeStream() method, 7-16 SQLOutput streams, 9-17
setValue() method, 10-5 SQLWarning class, limitations, 20-17
setXXX() methods start a distributed transaction branch, 15-12
Oracle extended properties, 16-6 statement caching
setXXX() methods, for empty LOBs, 8-17 explicit
setXXX() methods, for specific datatypes, 7-12 definition of, 14-3
signed applets, 1-10 null data, 14-10
Solaris implicit
shared libraries definition of, 14-2
libheteroxa9_g.so, 17-19 Least Recently Used (LRU) scheme, 14-3
libheteroxa9.so, 17-19 statement methods, JDBC 2.0 result sets, 13-35
SQL Statement object
data converting to Java datatypes, 7-2 closing, 3-12
primitive types, 6-7 creating, 3-11
structured types, 6-7 statements
types, constants for, 6-23 Oracle extensions, 7-3
SQL engine static SQL, 1-2
relation to the KPRB driver, 18-26 stored procedures
SQL syntax (Oracle), 20-10 Java, 3-33
SQL*Plus, 9-55, 9-56, 9-59 PL/SQL, 3-32
SQL92 syntax, 20-10 stream data, 3-20, 8-6
function call syntax, 20-14 CHAR columns, 3-25
LIKE escape characters, 20-13 closing, 3-29
outer joins, 20-13 example, 3-22
scalar functions, 20-12 external files, 3-28
time and date literals, 20-10 LOBs, 3-28
Index-16
LONG columns, 3-20 tnsEntry, 16-6, 17-19
LONG RAW columns, 3-20 TNSNAMES entries, 3-4
multiple columns, 3-26 toDatum() method, 9-54
precautions, 3-29 applied to CustomDatum objects, 9-11, 9-21
RAW columns, 3-25 called by setORAData() method, 9-26
row prefetching, 3-31 toJDBC() method, 9-4
UPDATE/COMMIT statements, 8-8 toJdbc() method, 6-10
use to avoid setBytes() and setString() toString() method, 6-31
limitations, 3-31 trace facility, 19-11
VARCHAR columns, 3-25 trace parameters
stream data column client-side, 19-12
bypassing, 3-27 server-side, 19-13
STRUCT class, 6-10 tracing with a data source, 16-10
STRUCT descriptor, 9-4, 9-5 transaction branch, 15-2
STRUCT object, 6-11 transaction branch ID component, 15-16
attributes, 6-11 transaction context, 1-13
creating, 9-4, 9-5 for KPRB driver, 18-30
embedded object, 9-7 transaction IDs (distributed transactions), 15-5
nested objects, 6-11 transaction managers, 15-3
retrieving, 9-6 transactions
retrieving attributes as oracle.sql types, 9-8 switching between local and global, 15-5 to 15-7
StructDescriptor object Transparent Application Failover (TAF), definition
creating, 9-5 of, 17-16
deserialization, 9-6 TTC error messages, listed, B-17
get methods, 9-5 TTC protocol, 1-5, 1-6
serialization, 9-6 type map, 6-4, 7-4
setConnection() method, 9-6 adding entries, 9-13
StructMetaData interface, 9-62 and STRUCTs, 9-15
creating a new map, 9-14
used with arrays, 11-18
T used with SQLData interface, 9-15
TABLE_REMARKS columns, 12-20 using with arrays, 11-25
TABLE_REMARKS reporting type map (SQL to Java), 9-10
restrictions on, 12-26 type mapping
TAF, definition of, 17-16 BigDecimal mapping, 9-47
TCP/IP protocol, 1-5, 3-10 JDBC mapping, 9-46
Thin driver object JDBC mapping, 9-46
applets, 1-10, 18-15 Oracle mapping, 9-46
applications, 1-10 type mappings
CHAR/VARCHAR2 globalization size JPublisher options, 9-45
restrictions, 18-6 type maps
described, 1-5 relationship to database connection, 18-28
globalization considerations, 18-4 TYPE_FORWARD_ONLY result sets, 13-8
server-side, described, 1-7 TYPE_SCROLL_INSENSITIVE result sets, 13-8
time and date literals, SQL92 syntax, 20-10 TYPE_SCROLL_SENSITIVE result sets, 13-8
Index-17
typecodes, Oracle extensions, 6-23 update conflicts in result sets, 13-23
update counts
Oracle update batching, 12-9
U standard update batching, 12-15
unicode data, 6-28 upon error (standard batching), 12-17
updatability in result sets, 13-4 UPDATE in a result set, 13-19
updatable result set concurrency type, 13-4 updateRow() method (result set), 13-20
updatable result sets updatesAreDetected() method (database meta
creating, 13-8 data), 13-29
DELETE operations, 13-18 updateXXX() methods (result set), 13-19, 13-21
INSERT operations, 13-21 updateXXX() methods for empty LOBs, 8-17
limitations, 13-10 updating result sets, 13-18
refetching rows, 13-26, 13-29 url, 16-6
seeing internal changes, 13-27 user connection property, 3-7
update conflicts, 13-23 userid, specifying, 3-5
UPDATE operations, 13-19
update batching
overview, Oracle vs. standard model, 12-2 V
overview, statements supported, 12-3 VARCHAR2 columns, 19-8
update batching (Oracle model) globalization size restrictions, Thin, 18-6
batch value, checking, 12-7
batch value, overriding, 12-7
committing changes, 12-8
W
connection batch value, setting, 12-5 WIDTH, parameter for APPLET tag, 18-24
connection vs. statement batch value, 12-4 window, scroll-sensitive result sets, 13-30
default batch value, 12-5 writeSQL() method, 9-15, 9-17, 9-54, 9-61
disable auto-commit, 12-4 implementing, 9-16
example, 12-9
limitations and characteristics, 12-5
overview, 12-4
statement batch value, setting, 12-6
stream types not allowed, 12-5
update counts, 12-9
update batching (standard model)
adding to batch, 12-11
clearing the batch, 12-14
committing changes, 12-14
error handling, 12-16
example, 12-15
executing the batch, 12-12
intermixing batched and non-batched, 12-17
overview, 12-10
stream types not allowed, 12-11
update counts, 12-15
update counts upon error, 12-17
Index-18
X
XA
connection implementation, 15-9
connections (definition), 15-4
data source implementation, 15-8
data sources (definition), 15-3
definition, 15-2
error handling, 15-19
example of implementation, 15-21
exception classes, 15-18
Oracle optimizations, 15-20
Oracle transaction ID implementation, 15-16
resource implementation, 15-10
resources (definition), 15-4
transaction ID interface, 15-16
XAException, 15-16
Xids, 15-16
Index-19
Index-20