JDBC 3.0—Java Database Connectivity

Bernard Van Haecke

Published by M&T Books An imprint of Hungry Minds, Inc. 909 Third Avenue New York, NY 10022 www.hungryminds.com

Copyright © 2002 Hungry Minds, Inc. All rights reserved. No part of this book, including interior design, cover design, and icons, may be reproduced or transmitted in any form, by any means (electronic, photocopying, recording, or otherwise) without the prior written permission of the publisher.

Library of Congress Control Number: 2001092927

ISBN: 0-7645-4875-1

10 9 8 7 6 5 4 3 2 1

1B/RV/QR/QS/IN

Distributed in the United States by Hungry Minds, Inc.

Distributed by CDG Books Canada Inc. for Canada; by Transworld Publishers Limited in the United Kingdom; by IDG Norge Books for Norway; by IDG Sweden Books for Sweden; by IDG Books Australia Publishing Corporation Pty. Ltd. for Australia and New Zealand; by TransQuest Publishers Pte Ltd. for Singapore, Malaysia, Thailand, Indonesia, and Hong Kong; by Gotop Information Inc. for Taiwan; by ICG Muse, Inc. for Japan; by Intersoft for South Africa; by Eyrolles for France; by International Thomson Publishing for Germany, Austria, and Switzerland; by Distribuidora Cuspide for Argentina; by LR International for Brazil; by Galileo Libros for Chile; by Ediciones ZETA S.C.R. Ltda. for Peru; by WS Computer Publishing Corporation, Inc., for the Philippines; by Contemporanea de Ediciones for Venezuela; by Express Computer Distributors for the Caribbean and West Indies; by Micronesia Media Distributor, Inc. for Micronesia; by Chips Computadoras S.A. de C.V. for Mexico; by Editorial Norma de Panama S.A. for Panama; by American Bookshops for Finland.

For general information on Hungry Minds’ products and services please contact our Customer Care department within the U.S. at 800-762-2974, outside the U.S. at 317-572-3993 or fax 317-572-4002.

For sales inquiries and reseller information, including discounts, premium and bulk quantity sales, and foreign-language translations, please contact our Customer Care department at 800-434-3422, fax 317-572-4002 or write to Hungry Minds, Inc., Attn: Customer Care Department, 10475 Crosspoint Boulevard, Indianapolis, IN 46256.

For information on licensing foreign or domestic rights, please contact our Sub-Rights Customer Care department at 212-884-5000.

For information on using Hungry Minds’ products and services in the classroom or for ordering examination copies, please contact our Educational Sales department at 800-434-2086 or fax 317-572-4005.

For press review copies, author interviews, or other publicity information, please contact our Public Relations department at 317-572-3168 or fax 317-572-4168.

For authorization to photocopy items for corporate, personal, or educational use, please contact Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, or fax 978-750-4470.

LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND AUTHOR HAVE USED THEIR BEST EFFORTS IN PREPARING THIS BOOK. THE PUBLISHER AND AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS BOOK AND SPECIFICALLY DISCLAIM ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. THERE ARE NO WARRANTIES WHICH EXTEND BEYOND THE DESCRIPTIONS CONTAINED IN THIS PARAGRAPH. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES REPRESENTATIVES OR WRITTEN SALES MATERIALS. THE ACCURACY AND COMPLETENESS OF THE INFORMATION PROVIDED HEREIN AND THE OPINIONS STATED HEREIN ARE NOT GUARANTEED OR WARRANTED TO PRODUCE ANY PARTICULAR RESULTS, AND THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY INDIVIDUAL. NEITHER THE PUBLISHER NOR AUTHOR SHALL BE LIABLE FOR ANY LOSS OF PROFIT OR ANY OTHER COMMERCIAL DAMAGES, INCLUDING BUT NOT LIMITED TO SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR OTHER DAMAGES.

Trademarks: Hungry Minds, the Hungry Minds logo, M&T Books, the M&T Books logo, and Professional Mindware are trademarks or registered trademarks of Hungry Minds, Inc. in the United States and other countries and may not be used without written permission. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc., in the U.S. and other countries. All other trademarks are the property of their respective owners. Hungry Minds, Inc., is not associated with any product or vendor mentioned in this book.

About the Author

Bernard Van Haecke leads the Sun Java Center in Belgium and Luxembourg, a Sun Professional Services consulting practice where he helps customers build and implement complex software applications based on Java and J2EE. He focused on Java since the day it was made publicly available by Sun in May 1995 and started writing one of the first books on JDBC for IDG Books Worldwide (now Hungry Minds) the next year. He then leveraged many of the new APIs, including enterprise APIs, in customer projects for more than half a decade, which led to the development of an avant-garde E-banking and E-trading system in 1997, the re-architecture of IT environments in financial institutions centered on new paradigms, the realization of numerous Java pilots in various fields of the industry, and several coaching and mentoring missions.

Credits

Senior Acquisitions Editor
Grace Buechlein

Senior Project Editor
Jodi Jensen

Development Editor
Dana Lesh

Technical Editor
Ashutosh Bhonsle

Copy Editors
Dana Lesh and Sara Shlaer

Editorial Manager
Mary Beth Wakefield

Senior Vice President, Technical Publishing
Richard Swadley

Vice President and Publisher
Joseph B. Wikert

Project Coordinator
Regina Snyder

Graphics and Production Specialists
Melanie DesJardins
Joyce Haughey
LeAndra Johnson
Jill Piscitelli
Betty Schulte
Jeremey Unger

Quality Control Technician
Andy Hollandbeck
Susan Moritz

Proofreader
Christine Sabooni

Indexing
TECHBOOKS Production Services

Cover Image
© Noma/Images.com

Acknowledgments

Among the many individuals who helped with this project, I first want to thank my family and friends who brought me their continued support for a long time. I thank very sincerely everyone who played an instrumental role before and during the writing of this edition and those who were key to the first edition. Special thanks to Dana Lesh who, as development editor and copy editor, played a key role in enhancing the manuscript in such a great way and in making it much more readable!

Thanks to Greg Croy, Hungry Minds acquisitions manager, Grace Buechlein, senior acquisitions editor, Jodi Jensen, my project editor, Sara Shlaer, copy editor, Ashutosh Bhonsle, technical editor, Christy Clinton of acquisitions assistant, Arlene Joy Pilkington, former acquisitions editor, and everyone else involved in the making and publication of the book that you now have in your hands. I am infinitely grateful to you all.

I also want to thank all the great people at Sun who make Java, JDBC, J2EE, Jini, etc. so cool, and all my colleagues who turn these into real successes when designing and building systems for customers. Special thanks to Stu Stern, VP Worldwide Sun Java Centers, and Staffan Calais, manager of Sun Java Centers Northern Europe, for leading these efforts!

Next


Untitled Document

Table of Contents
 | JDBC 3.0—Java Database Connectivity
 | Preface
 | Part I - An Introduction to Java Database Programming
 | Chapter 1 | - | Java as an Enterprise Platform
 | Chapter 2 | - | Database Fundamentals
 | Chapter 3 | - | Integrating Databases with JDBC
 | Chapter 4 | - | JDBC’s Role in Java 2 Enterprise Edition
 | Part II - Exploring JDBC
 | Chapter 5 | - | Getting Started with JDBC
 | Chapter 6 | - | Database Connectivity, Step by Step
 | Chapter 7 | - | Refining JDBC Queries and Updates
 | Chapter 8 | - | Advanced Techniques
 | Chapter 9 | - | Accessing Database Metadata
 | Chapter 10 | - | Accessing Databases with Enterprise JavaBeans
 | Part III - Learning from Examples
 | Chapter 11 | - | Examples of Java Applications
 | Chapter 12 | - | Complex Examples of Java Applications
 | Part IV - JDBC API Quick Reference
 | JDBC API Reference
 | JDBC Extension Reference
 | Index
 | List of Figures
 | List of Tables
 | List of Listings


Preface

JDBC 3.0 is the latest revision of Sun’s Java Database Connectivity API. Since its introduction on the market in the mid-90s, Java has evolved from a language and environment suited for applets to a rich enterprise platform. JDBC played a determinant role in Java’s maturation. JDBC is now used as a core technology to integrate companies’ databases and leverage legacy data to provide unprecedented access to new applications via emerging channels such as the wireless Internet and WebServices.

JDBC provides a rich set of features to store, retrieve, search, and update various types of data formats in traditional databases. Java is a language for object-oriented (OO) programmers, and traditional databases as such aren’t very object-oriented. JDBC doesn’t bridge the gap entirely by itself, but it provides the foundation for persistence mechanisms such as J2EE’s Enterprise JavaBeans. JDBC is one of the most important bricks in the whole distributed component technology stack.

This book, which is an update of JDBC: Java Database Connectivity from IDG Books Worldwide (now Hungry Minds, Inc.) by the same author, provides a tutorial approach and comprehensive examples on every aspect of integrating with databases using a call level interface such as Java’s JDBC. From simple queries and updates to transactions, cursors, batch processing, prepared statements, stored procedures, and database metadata, you will learn anything necessary to design and write great professional applications. An API reference covering JDBC and its extensions is provided at the end of the book.

Who Should Read This Book

This book is targeted at developers who are new to Java and who want to use JDBC to deliver database-enabled robust Internet-based applications, WebServices, N-tiered applications, and traditional client/server applications. Knowing the Java language is a prerequisite for this book: In general, an academic knowledge will be sufficient. Although this book doesn’t provide a complete SQL and relational database reference, developers who are new to these should be able to understand most of the techniques discussed. Developers not familiar with SQL may want to take the SQL Primer available online from Sun as a companion when reading this book.

Previous Next


Hardware and Software Requirements

The minimum hardware requirements to run Java programs and a small database are a recent personal computer with 64MB of RAM, but 128MB to 256MB are recommended if you foresee running an application server. At least 300MB of hard drive space is necessary to install a JDK and development environment such as Borland JBuilder, WebGain Café, or Sun’s Forte-For-Java, in addition to a personal database.

The following are necessary or recommended, as specified, for writing and testing JDBC programs. Java 2 version 1.4 (available from http://java.sun.com/products), which bundles JDBC 1.3, is mandatory. A personal database such as Cloudscape or Hypersonic SQL, mSQL, Oracle Lite, or Sybase Lite is recommended. The simplest JDBC programs will run with the JDBC-ODBC Bridge from Sun Microsystems and Microsoft Access, but the remaining 50 percent of the API won’t work with such a database. Having access to an Oracle, a Sybase, an Informix, or DB2 server for development would be helpful, but isn’t mandatory when developing with JDBC. JDBC 3 drivers can be purchased from database vendors, but you better refer to the informative pages of their respective Web sites to get the latest information about support of this version of the API.


How This Book Is Organized

The chapters of this book will guide you through the Java Database Connectivity API with the help of many small examples and code snippets. Part III provides a quick reference for all Core JDBC and JDBC Extension APIs.


The Companion Web Site

This book offers a companion Web site from which you can get code examples and the sample applications used in the book, including the ISQL Client, BLOB examples, JDBC Explorer using SWING, and a simple RMI-based sample.

All the code is in a single WinZip file that you can download by going to www.hungryminds.com/extras/ and selecting the JDBC 3.0: Java Database Connectivity link. After you download the file, named JDBC30.zip, you can open it and extract the contents by double-clicking it if you have WinZip on your system. If you don’t currently have WinZip, you can download an evaluation version from www.winzip.com. You can use unzip, gzip, or gunzip on UNIX and Sun Solaris if you are working in such environments.

When extracting the files, use WinZip’s default options (confirm that the Use Folder Names option is checked) and extract the JDBC30.zip file to a drive on your system that has about 1MB of available space. The extraction process creates a folder called JDBC30. As long as the Use Folder Names option is checked in the Extract dialog box, an entire folder structure will be created within the JDBC30 folder.


Conventions

Here are some conventions that I use throughout the book to help you use it more efficiently:

  • Italics indicate a new term that I’m defining, represent placeholder text (especially when used in code), or add emphasis.

  • Bold text indicates something that you should type.

  • A special monofont typeface is used throughout the book to indicate code, a Java keyword, a filename or pathname, or an Internet address.


Navigating This Book

If you’re completely new to JDBC, start at the beginning and work your way through to the end. Each chapter assumes that you’re familiar with the contents of the chapters before it. Intermediate-to-advanced developers should read the chapters and sections that appeal to them based on the table of contents and introductory text in all the chapters. Keep in mind, however, that some topics just don’t stand well on their own, so the book includes a lot of information within the overall text. I suggest that you look through the index to reference the appropriate bits of information that you’re interested in. Finally, the reference section is here to help you find minimal information about classes, interfaces, and their attributes and methods.

Icons appear in the text to indicate important or especially helpful items. Here’s a list of the icons and their functions:

Note

provide additional or critical information and technical data on the current topic.

Tip

icons offer useful techniques and helpful hints.

Cross-Reference

icons point you to someplace where you can find more information on a particular topic.

Caution

icon is your warning of a potential problem or pitfall.

On the Web

icon indicates that the companion Web site for the book contains a related file or additional information.


Further Information

I will be happy to receive any comments and suggestions at the following e-mail address: bernard@vanhaecke.net.


Part I: An Introduction to Java Database Programming

Chapter List

Chapter 1: Java as an Enterprise Platform
Chapter 2: Database Fundamentals
Chapter 3: Integrating Databases with JDBC
Chapter 4: JDBC’s Role in Java 2 Enterprise Edition


Chapter 1: Java as an Enterprise Platform

Java is a programming language that is especially well suited for Internet and intranet applications. The Standard Edition of its runtime environment contains a variety of Application Programming Interfaces (APIs) for graphical user interfaces, handling of distributed objects, input/output, math routines, networking, security, and database access. This variety of APIs enables programmers to write powerful applications without having to purchase and learn lots of third-party libraries. The Enterprise Edition packages even more functionality: It contains essential APIs to build applications based on distributed components such as Enterprise JavaBeans (EJBs), servlets, Java Server Pages (JSP), and a Java Messaging Service (JMS). This chapter introduces you to Java and topics such as these; if you aren’t new to Java, you may want to go directly to Chapter 2.

A Feature-Rich Enterprise Platform

Java and its environment were introduced in 1995 by Sun Microsystems, Inc. (www.sun.com and http://java.sun.com). Java was designed to meet the challenges of development in incompatible but networked environments.

Most modern programming languages already have some of the features present in Java, but none have all the features. A majority of developers, analysts, designers, administrators, and executives agree that Java is the long-awaited enabling computing technology. Much of the early discussion on the need for a Java-like language happened in Usenet newsgroups on the Internet. Now every major player has endorsed the technology and has delivered Java programs or even “Javatized” hardware. The reason is simple: Java’s features make it the best choice as an enterprise platform. Most of the features of Java and its environment are discussed in this section; however, Table 1-1 summarizes Java’s feature set.

Table 1-1: JAVA AND ITS APIS: THE BIG PICTURE
API | Description
AWT | Abstract Window Toolkit
JAAS | Java Authentication and Authorization Service
JAI | Java Advanced Imaging API
JAIN APIs | A set of APIs to develop integrated network services
Java 2 | The object-oriented (OO) language for distributed computing
Java 2D | 2D graphical routines
Java 3D | 3D graphical routines
JavaBeans | The Java component framework
JavaCard | A set of APIs to program smartcards
Java COMM | Serial communications (RS-232 and so on)
JDMK | Java Dynamic Management Kit, which leverages the Simple Network Management Protocol (SNMP)
JavaIDL | A Common Object Request Broker Architecture (CORBA) Internet Inter-Orb Protocol (IIOP) implementation
JavaMail | Internet mail libraries
JavaPhone | An interface for telephones
JavaSpaces | A technology that enables dynamic communication and the sharing of Java objects
JavaSpeech | A voice synthesis and recognition API
JavaTV | An interface for television and set-top boxes
JCE | Java Cryptography Extension
JDBC | Java Database Connectivity
JFC | Java Foundation Classes
Jini | A framework to develop distributed services
JMS | Java Messaging Service
JMX | Java Management Extensions
API | Description
JNDI | Java Naming and Directory Interface
JNI | Java Native Interface
JSDT | Java Shared Data Toolkit, which is a collaboration and multimedia API
JSP | Java Server Pages
JTA | Java Transaction API
JTAPI | Java Telephony call control API
JTS | Java Transaction Service
J2EE | Java 2 Enterprise Edition (including EJBs, JSPs, servlets, JMS)
J2ME CLDC | Java 2 Micro Edition for Connected, Limited Device Configuration (CLDC)
J2ME CVM | The virtual machine of Java 2 Micro Edition for devices supporting CLDC
J2ME KVM | The virtual machine of Java 2 Micro Edition for devices such as Palm handhelds
J2SE | Java 2 Standard Edition (core Java)
EJB | Enterprise JavaBean
RMI | Remote Method Invocation
Servlet | Serving markup language content
XML APIs | Java APIs for XML Pack (JAXP), Java APIs for XML Binding (JAXB), Java APIs for XML Messaging (JAXM), Java APIs for XML Remote Procedure Calls (JAX RPC), and Java APIs for XML Registries (JAXR)

First and foremost, Java is definitely object-oriented. It is somewhat similar to C++, but its programming supplants functional and procedural styles. Java programmers manipulate only objects, data members, accessors, and mutators. Extra features such as automatic garbage collection (a garbage collector keeps track of the object instances and frees them when they are no longer used), object references replacing arithmetic address pointers, and native or nonnative multithreading add to Java’s simplicity and power.

Java is a truly object-oriented programming language. It fully supports encapsulation, polymorphism, inheritance, and dynamic bindings. The main benefit for the programmer is that his or her programming model will be close to the real-world objects, making the model easier to implement. Software reuse also benefits from this orientation, as is the case for many well-known C++ libraries.

These object-oriented qualities also apply to the numerous APIs, including JDBC. Although there is some impedance mismatch between OO programming and the world of relational databases and SQL (the language used to query those databases), the JDBC API helps you bridge the gap between both worlds. A good application design enables developers to define components to wrap and access databases in an elegant and reusable fashion. Furthermore, because JDBC doesn’t focus on a particular database vendor, the components are reusable across database products, too. With the combination of JDBC and the variety of APIs, Java is a real enterprise platform.


Write Once, Run Anywhere

Java is architecture-neutral, portable, and robust in that it can run on various platforms and anywhere on a network, regardless of which graphic subsystem is in use. Java is independent of hardware, operating systems, and graphical user interfaces (GUIs). The design of the Java Virtual Machine (JVM), as well as all the standard and enterprise APIs, makes Java portable — much more portable than C or C++ — which greatly simplifies deployment issues. This is why Java has such presence in the industry. Although there are still a number of issues when porting application code from platform to platform, those issues are minor when compared to the problems of porting C++ code from UNIX to the Macintosh OS, for example, not only for multithreading, networking, or UI aspects, but also when proprietary database APIs come in the picture. JDBC tries to preserve development efforts by abstracting almost all aspects of interfacing programs with relational databases. As a result, it won’t be that hard for a programmer to switch from, say, Oracle to Sybase, or vice versa, or from mSQL to DB2. Java 2 Enterprise Edition and the Enterprise JavaBeans actually benefit from database independence a lot, as a good part of this framework heavily relies on database access.

As discussed in the following sections, there are various places where JDBC can be leveraged to integrate databases. This can be on the client side or on any server tier or integration tier — and even on smartcards and Palmtops because lightweight databases are now available on those platforms, too. JDBC is an interface specification designed to be platform independent and is truly portable. Depending on what is done at the application side and how it is done, the whole may be fully or partially portable. You won’t be necessarily constrained to use the very basic features of relational databases to build portable applications. Indeed, JDBC’s coverage is broad enough to provide naming, connection, querying, transaction management, type mapping, database metadata, cursors, and several other facilities in a totally database-independent manner. It is up to database vendors and third parties to implement fully compliant drivers for specific databases.

However, you shouldn’t underestimate several aspects of integrating with databases. As a developer, you cannot always control all the environmental conditions in which the applications will have to run and behave properly. Here are some of these aspects:

  • The JDBC driver’s compliance to the standard API

  • The JDBC driver’s type, which may be fully Java or may use native libraries

  • Whether the JDBC driver is multithread-safe

  • The JDBC driver’s capability to tunnel networking protocols through HTTP

  • The JDBC driver’s naming scheme for databases

  • The JDBC driver’s and database’s limitations for data types and maximum type sizes

  • The database locking strategy (row versus page)


N-tiered Computing

N-tiered computing is more than a trend or a fashion. The way that systems are designed has matured enough to let most developers abandon the old fat-client, fat-database pattern to the early ages of IT systems (not to mention even dumb terminals and monolithic mainframe applications). N-tiered computing obliges developers to design components according to a business schema that represents entities, relationships, activities, roles, and rules, thereby enabling them to distribute functionality across logical and physical tiers, allowing better utilization of hardware and platform resources, as well as the sharing of those resources and the components that they support to serve several large applications at the same time.

Another aspect of splitting tiers is that application deployers and administrators are able to identify bottlenecks and throw hardware at them to enable load-balancing and fail-over of certain nodes.

A few examples, which are further elaborated on in this section, are the splits made between application logic components, security logic and presentation logic, computational-intensive and I/O-intensive components, and so on.

Because I’m discussing integrating with databases, I’ll list a few consequences of splitting components across tiers:

  • Accounting and order-processing components must all access database entities, whether or not they are located on the same logical or physical tier.

  • Presentation logic components may have to look up tables for reference, decoration, or localization purposes.

  • Security logic may have to access Access Control Lists (ACLs) residing in tables, in read-only mode.

  • Logging may be accomplished by using relational database tables to facilitate querying, for example.

  • Single-logon necessitates the preservation of the connection state across requests to functions of the whole system; this may happen in a session table, also featuring a session timeout using timestamps.

  • Back-end integration logic may necessitate looking up credentials/ identifiers in a relational table.

  • Lots of business logic may have to be reused from legacy stored procedures.

  • All of the preceding may have to be performed in one single transaction.

The most common approach used when designing N-tiered systems is the three-tier architecture. In a three-tier architecture, the application responsibilities are layered as follows:

  • Presentation logic: Supporting various presentation devices, such as HTML browsers, Wireless Application Protocol (WAP) devices, or rich clients, should not affect the whole application. This is the reason why code related to presentation is usually designed as components separate from the rest of the application.

  • Business logic: This excludes all presentation logic, although it is made accessible to the users only via the first tier. Business logic mostly implements business processes, workflow, rules, and such. This tier doesn’t handle database access logic but uses the next tier when data sources need to be accessed.

  • Data logic (also called the resource tier): This third tier integrates databases by providing, for example, object-relational mapping. It provides a certain degree of data source independence to the other tiers by hiding these integration mechanisms to them.

Three-tier and N-tier notions are similar, although N-tiered architectures provide finer-grained layers. Architects often decide to lay out much more than three tiers to deploy services: An infrastructure that supports three-tier is often made of several machines and services whose functionalities aren’t part of the three-tier design (Web servers and Public Key Infrastructure [PKI] servers, for example).

Ubiquitous database connectivity is definitely needed when developing N-tiered applications that run on many nodes and various operating systems. JDBC really offers everything necessary to achieve this goal. Of course, some of the nice features such as transparent load-balancing and fail-over of access to data components, drag-and-drop deployment of such components, distributed transaction coordination, and so on aren’t provided by JDBC per se. Java 2 Enterprise Edition and J2EE-compliant application servers exist for these purposes.


Database Aspects in J2EE

Webtop computing really emerged when Web browsers became universally available on the desktops at the office, at home, or on the road and when technologies to serve dynamic pages matured enough to serve the needs of professional applications. Webtop computing is what makes e-business really work. It enables secured access to corporate resources such as application suites, enterprise databases, and documents from any authorized Web browser from anywhere. It serves a large audience that may be composed of employees, partners, suppliers, customers, distributors, and resellers — who all want everything but fat legacy applications on their desktops.

Webtop computing enables Application Service Providers (ASPs) to leverage the same infrastructure to serve applications to a wider audience than a single user group in a given company. This drastically reduces platform and application investments as well as the management of platforms and applications. One of the main advantages of the Webtop approach is the ease of support of various client platforms and distribution of new releases of the applications without affecting those clients.

Webtop computing was really made possible thanks to Java 2 Enterprise Edition (J2EE). J2EE is a set of APIs from Sun Microsystems that forms a robust framework for N-tiered applications. The best proof of its worldwide adoption is the number of high-end vendors who offer J2EE-compliant application servers as core products along with their ordinary line of software. Most database vendors have developed application servers; nearly all middleware vendors have done so, too. J2EE is becoming mainstream.

J2EE defines the logical tiers for N-tiered applications by providing rich APIs and container services that distributed component-holding presentation logic or business logic can use. Several specific services are especially interesting for anyone having to integrate with databases because they take care of certain technical aspects that developers often forget or have no time to implement themselves; those services are the following:

  • Connection pooling

  • Distributed transaction management (or transaction coordination)

  • Transparent persistence for objects that represent business data

Connection pooling is quite useful in an environment in which many components deal with their own logic and database objects. Connection pooling is of extreme importance to provide concurrency and scalability to three-tier applications. J2EE application servers that provide this sort of pooling hide all the complexity of maintaining connections to back ends such as databases and allowing transactions to go one way or the other.

Connection pooling is simple from a component developer perspective: Application servers are typically able to maintain pools of connections to databases and allow components to access those connections when necessary. The advantage is that referring to a connection pool while programming enables developers to forget about accessing specific databases when they implement components, at least for the connection establishment aspects, because they can simply refer to connection pools known only at deployment time by providing some sort of naming in deployment descriptors. Database connections will be provided to those components at deployment time. The application server will make sure that the connections are used in an optimal manner by making the pool grow or shrink, depending on the demand for new connections.

Distributed transaction management provides ACID properties to groups of operations made on tables residing on several databases. ACID stands for Atomicity, Consistency, Isolation, Durability and is normally provided by the database engines themselves for local transactions. A commit/rollback mechanism is used to ensure those properties. However, when dealing with several databases, something called a two-phase commit is necessary. A two-phase commit isn’t provided by JDBC drivers and database engines; it is a feature of transaction managers. Transactions that span on multiple databases either succeed on each database or fail on each database: This ensures the consistency of data updates in distributed systems.

The third aspect is transparent persistence for objects. J2EE defines what is called bean-managed persistence requires developers to program those operations with JDBC.


The Tools That You Need to Get Started

Even developing the simplest JDBC programs requires a number of tools. Although it isn’t the purpose of this book to recommend and provide information about products that are commercially available, I list a few of them that may be mandatory or just useful to program with JDBC.

Most of the examples provided in this book are quite simple and run in fairly limited environments. However, as big castles are made out of little stones, large applications will often be made of very lightweight components that can also be developed and tested in limited environments. Assembling the set of components may cause the whole to require large investments in tools, but again, they aren’t required at all for the purpose of learning JDBC 3.0 using this book.

The most essential tools are as follows:

  • A programming editor (vi, XEmacs, or such) or IDE (Forte For Java, Kawa, JBuilder, or so mething similar).

Note

An IDE isn’t essential but eases development, compilation, and run tests for developers who aren’t familiar with operating system–level commands (that is, shells) or who don’t have access to a shell (MacOS, for example).

  • JDK version 1.4 with JDBC 3.0.

  • JDBC 3.0–compliant drivers for the database that you intend to use. There are no JDBC 3.0 drivers at the time of this writing, but these will undoubtedly be made available by the database vendors themselves. Refer to their Web sites for more information about their intention to support JDBC 3.0.

  • A database engine, such as MiniSQL, mSQL, Oracle, Sybase, DB2, SQL Server, Microsoft Access.

  • It might be useful to have access to administration tools and DBA manuals to import/export data (for example, to create database users and roles) because those tasks won’t be performed with JDBC.

Other tools that developers may use to develop applications go beyond simple standalone programs. Here are a few examples of such tools:

  • Small footprint databases for Palm handhelds and for JavaCard.

  • Lightweight object databases written in Java enabling complex object graphs to be made persistent and retrieved in a very simple way.

  • Object-relational bridges that enable the viewing of relational databases as object databases and the use of the Object Query Language (OQL) defined by the Object Database Management Group (ODMG, www.odmg.org).

  • Transaction-processing monitors written in Java, which allow large Online Transaction Processing (OLTP) applications to use a single database without the help of J2EE and its transaction management facilities.

  • J2EE application servers, to start writing distributed applications in a standard fashion.


Summary

Java is well suited for networked computing, and thanks to JDBC and J2EE, it is complete enough to build robust, enterprise-class applications for intranets or the Internet. The tools needed for this purpose don’t necessarily involve huge investments from the programmers.

The next chapter discusses fundamental database concepts such as SQL and database access interfaces.


Chapter 2: Database Fundamentals

This chapter discusses fundamental concepts such as relational databases, SQL, and database access programming interfaces.

Relational Databases

Almost all enterprise applications use a database to store and retrieve data belonging to the business domain. These databases are often managed by a relational database management system (RDBMS) and less often by an object database management system. Whichever database management system (DBMS) is used, its role in the corporate information system is predominant. The DBMS offers a lot of features other than a centralized view of what may be a distributed database architecture. DBMSs ensure availability, integrity, consistency, concurrency, security of the corporate data through access control, and a lot more. Such DBMS facilities lighten all client programs because they aren’t involved in these issues.

The Java Database Connectivity (JDBC) interface allows Java applets, servlets, and applications to access data in popular database management systems. The standard for accessing data is SQL, which permits maximum interoperability; SQL is the language used with JDBC. JDBC is a software layer that enables developers to write real client/server projects in Java. JDBC doesn’t concern itself with specific DBMS functions.

Relational databases are the most common DBMSs. A main characteristic of a relational database is the absolute separation between physical and logical data. Data is accessed through the associated logical model to avoid supplying physical storage locations and to reduce the limitations imposed by using physical information. Relational databases enable the definition of relations and integrity rules between data sets. E.F. Codd developed this model at the IBM San Jose Research Lab in the 1970s. SQL, a language to handle, define, and control data, was also developed at the IBM lab. SQL stands for Structured Query Language; it is a query language that interacts with a DBMS. It enables data access without supplying physical access plans, data retrieval as sets of records, and performing complex computations on the data.


Client/Server Concepts

The first generation of client/server architectures that use a database is called two-tiered. This type of architecture contains two active components: the client, which requests data, and the server, which delivers data. Basically, the application’s processing is done separately for database queries and updates and for business logic processing and user interface presentation. Usually the network binds the back end to the front end, although both tiers can be present on the same hardware. For example, hundreds or thousands of airline seat reservation applications can connect to a central DBMS to request, insert, or modify data. While the clients process the graphics and data entry validation, the DBMS does all the data processing.

In traditional client/server applications, the clients establish connections with the server, and these connections are kept open until the clients terminate. The communication protocols are often proprietary: Examples are SQL-NET for Oracle and TDS for Sybase. Both clients and servers use database-specific libraries to communicate with each other. Security is entirely managed by the database engine. Logins are controlled by the database, such as user roles and permissions on database objects. The typical client/server architecture is shown in Figure 2-1.

Click To expand
Figure 2-1: The typical client/server architecture with a DBMS.

If users connect from several remote sites, network latency may affect the application’s response time in a noticeable manner. One possible solution is to replicate the database(s). The synchronization of data between replications is typically performed by the database engines themselves: It isn’t a concern of the client applications. Another possible solution to the poor response time problem is the paging of data.

A feature called database cursors may be used in this case. This approach obviously affects application code, especially on the client side.

Sometimes the application logic (the real business logic) is located in both the client program and in the database itself. Quite often, the business logic is merged into pesentation logic on the client side. As a result, code maintenance and reusability aren’t easily achieved, at least for what resides on the client side. On the database side, logic is often developed using stored procedures (a technique that allows developers to write procedures in a proprietary language and to deploy them in the database itself). To date, some vendors support Java as language to develop stored procedures. However, doing so isn’t recommended, because access to database objects remains somewhat proprietary even when the procedure’s language is Java. Reusability is hard to achieve if pieces of business logic must be distributed across systems and several databases are involved.

Figure 2-2 illustrates the two-tier architecture.

Click To expand
Figure 2-2: The two-tier architecture.

Although the two-tiered architecture is common, another type of architecture is being used more and more often as a pattern to build distributed systems. To avoid embedding the application’s logic at both the database side and the client side, a third software tier is inserted. In three-tiered architectures, most of the business logic is located in the middle tier. In this architecture, when the business activity or business rules change, only the middle tier must be modified. Figure 2-3 illustrates the three-tier architecture.

Click To expand
Figure 2-3: The three-tier architecture.


Database Standards

Database vendors are numerous, and they all have developed proprietary protocols and languages. Fortunately, though, there are some industry standards.

SQL

SQL isn’t a complete programming language usable to build complex applications. It is commonly used within a host language that offers specific features for building complete applications. However, SQL is an industry standard to access databases. It enables data definition, manipulation, and management; access protection; and transaction control. SQL’s roots are in relational databases, and it handles many relational database objects, including tables, indexes, keys, rows, and columns. The American National Standards Institute (ANSI) standardized SQL in 1986 and defined it to be independent of any programming language and database management system.

The ANSI 1989 standard defines three programmatic interfaces to SQL:

  • Modules: Separate compiled modules may define procedures and then call them from a traditional programming language.

  • Embedded SQL: The specification defines embedded statements for a few traditional programming languages. It enables embedding static SQL statements within complete programs.

  • Direct invocation: Access is implementation-defined.

Although embedded SQL was the most popular choice a few years ago, it isn’t the best answer to the problem of querying databases in client/server environments. It is static, and this limitation makes it unsuitable for newer software architectures using the J2EE framework, for example. In fact, embedded SQL is supported when Java is the host language, too, but this depends on database types and isn’t fully portable.

SQL-92, the newer ANSI specification, addresses modern environment needs. It contains new features, such as support for dynamic SQL and for an advanced technique to access result sets called scrollable cursors. Although dynamic SQL isn’t as efficient as static SQL, it does enable SQL statements to be prepared, to include parameters, and to be generated at runtime. In the case of prepared statements, performance may be increased. In fact, dynamic SQL allows the database to prepare an access plan before the execution. This access plan is reused each time the statement is called.

The SQL language is usable for a variety of purposes, including the following:

  • Querying a database by entering SQL text directly

  • Querying a database within a program

  • Defining data organization

  • Administering data

  • Accessing multiple data servers

  • Managing transactions

Databases use SQL as a language for both data definition and data manipulation (called DDL [Data Definition Language] and DML [Data Manipulation Language]).

A simple SQL primer

The SQL language supports a set of verbs used to define, store, manipulate, and retrieve data. Following are the basic SQL verbs used to build SQL clauses for such data manipulation.

To create a table, use the following syntax:

CREATE TABLE table
(column type         [ NOT NULL | PRIMARY KEY | UNIQUE | ... ]
[, column type       [ NOT NULL | PRIMARY KEY | UNIQUE | ... ]]*)

For example, to create a table of employees, you can use the following:

CREATE TABLE employees
(id           int PRIMARY KEY,
 name         char(25) NOT NULL,
 salary       int)

To drop a table, use the following syntax:

DROP TABLE table

Here’s an example:

DROP TABLE employees

To supply new record values, use the following syntax:

INSERT INTO table [ (column [, column ]*)]
VALUES (expr [, expr ]*)

For example, to add Jones as employee number one, with a salary of $60,000/year, you can use the following code:

INSERT INTO employees
VALUES ("1", "JONES", 60000)

To delete rows, use the following syntax:

DELETE FROM table
WHERE column [ < | > | = | <= | >= | <> | LIKE ] expr
[ AND | OR... ]*

Here’s an example of deleting all employees earning more than $150,000 a year:

DELETE FROM employees
WHERE salary > 150000

To retrieve data, use the following syntax:

SELECT [ DISTINCT ] [table.]column [, [table.]column ]*
FROM table [= name] [, table [=name] ]*
[ WHERE [table.]column [ < | > | = | <= | >= | <> | LIKE ] expr
[ AND | OR ... ]*]
[ ORDER BY [table.]column [ ASC | DESC ]
[, [table.]column [ ASC | DESC ]]]
[ HAVING ... ]

For example, to retrieve all employees earning more than $50,000, sorted by salary (highest first) and name, you can use this:

SELECT * FROM employees
WHERE salary > 50000
ORDER BY salary DESC, name

To modify data, use the following syntax:

UPDATE table SET column = expr [, column = expr ]*
WHERE [table.]column [ < | > | = | <= | >= | <> | LIKE ] expr
[ AND | OR ... ]*

The following example raises Jones’ salary to $70,000 (Jones is employee number one):

UPDATE employees SET salary = 70000
WHERE id = 1

To create an index, use the following syntax:

CREATE [ UNIQUE ] INDEX index
ON table (column [, column ]*)

For example, you can use the following to create an index on the name field:

CREATE INDEX idx_employees
ON employees (name)

To create a stored procedure, use the following syntax:

CREATE PROCEDURE procedure
[[(]@parameter type [= default ] [ IN | OUT | INOUT ]
[, @parameter type [= default ]
[ IN | OUT | INOUT ]]* [)]] [ WITH RECOMPILE ]
AS sqlstatement

For example, the following code creates a stored procedure returning the highest salary via a parameter:

CREATE PROCEDURE maxsalary (@themax int OUT)
AS SELECT @themax = MAX(salary)
FROM employees
Note

For more in-depth information about SQL syntax and complex operations such
as table joins and so on, you can refer to the Web page http://developer.java.sun.com/developer/onlineTraining/Database/JDBCShortCourse/jdbc/sql.html. This page also recommends some good books. In addition, DBMS reference books and manuals such as Sybase SQL Server 11 DBA Survival Guide from Sams Publishing may help by providing more details about specific implementations of SQL, which are often required when dealing with various databases.

SAG-X/Open CLI

The X/Open and SQL Access Group defined the call level interface (CLI). CLI is a library of function calls that support SQL statements. For example, Microsoft’s Open Database Connectivity (ODBC) is a call level interface. JDBC is also a call level interface. Most database vendors have optimized CLI implementations for their database management system products. ODBC and JDBC are less proprietary interfaces, although they intensively use these specific CLIs to access databases. The most important benefit for programmers using the ODBC CLI or the JDBC CLI is interoperability: All clients adhere to a standard programming interface. CLI requires neither host variables nor other embedded SQL concepts that would make it less flexible from a programmer’s perspective. It is still possible, however, to maintain and use specific functions of a database management system when accessing the database through a CLI.


An Industry Standard: ODBC

ODBC is Microsoft’s implementation of a CLI. It enables a programmer to develop, compile, and deploy an application without targeting a specific DBMS. Modules called drivers link the application to the database of their choice. For this reason and because ODBC is independent of the network layer protocols, ODBC permits maximum interoperability. The availability of specific drivers for almost all relational database management systems has determined its success. The JDBC mechanisms are very close to the ODBC, but are adapted for Java. In designing an appropriate interface for direct use from Java, issues such as security, implementation, robustness, and portability were addressed.

The ODBC interface

The ODBC interface defines a library of function calls that allow an application to connect to a DBMS, execute SQL statements, and retrieve results. Its syntax is based on the X/Open and SQL Access Group SQL Common Applications Environment (CAE) specification (1992), which defines a standard set of error codes, a standard way to initiate a connection, and a standard representation for data types. In addition to the core functions based on the X/Open and SQL Access Group Call Level Specification, ODBC provides extended functions for handling scrollable cursors and asynchronous processing.

ODBC components

The ODBC interface defines the possible interactions between the user application and the driver manager. Figure 2-4 shows the relationship between the four ODBC components.

Click To expand
Figure 2-4: The four ODBC components.

The Application

The user application calls ODBC functions to send SQL statements to the database and retrieve results. It performs these tasks:

  • Requests a connection with a data source

  • Sends SQL statements to the data source

  • Defines storage areas and data types for the result sets

  • Requests results

  • Processes errors

  • Controls transactions; requests commit or rollback operations

  • Closes the connection

The Driver Manager

The driver manager’s primary purpose is to load specific drivers on behalf of the user application. It may also do the following:

  • Performs a lookup in an ODBC configuration file or system Registry to map the ODBC Data Source Name (DSN) to a specific DBMS driver

  • Processes ODBC initialization calls

  • Provides entry points to ODBC functions for each specific driver

  • Performs parameter and sequence validation for ODBC calls

The Driver

The driver processes ODBC function calls, sends SQL statements to a specific data source, and returns results back to the application. When necessary, the driver translates and/or optimizes requests so that the request conforms to the syntax supported by the specific DBMS. The driver performs the following tasks:

  • Establishes a connection to a data source

  • Sends requests to the data source

  • Performs translations when requested by the user application

  • Returns results to the user application

  • Formats errors in standard ODBC error codes

  • Manipulates cursors if necessary

  • Initiates transactions if they are explicitly required

There are two types of ODBC drivers:

  • Single-tier drivers: Process ODBC calls and SQL statements; no real database is involved. Such drivers usually implement a small database engine themselves and rely on flat files to store the data. Some of them are able to use another application’s file format. dBASE, XLS, and FoxPro files are the most common examples.

  • Multiple-tier drivers: Process ODBC calls and send SQL statements to the data source, which is the real database. Such drivers are available from database vendors. They either use platform-specific Inter-Process Communication (IPC) mechanisms such as shared memory or portable TCP/IP socket connections to communicate with their host database.

The Data source

The data source consists of the data the user application wants to access and its associated parameters — that is, the type of operating system, DBMS, and network layer (if any) used to access the DBMS.

JDBC versus ODBC

JDBC is very similar to ODBC: It is a portable, open, and published API that uses drivers to target particular databases. However, unlike ODBC, JDBC can’t be used from C or other languages. The JDBC API is much more object-oriented in its nature and use than ODBC.


Summary

This chapter covered fundamental concepts such as relational databases, SQL, and database access programming interfaces.

The next chapter discusses the Java Database Connectivity API’s role, components, and possible alternatives to it.


Chapter 3: Integrating Databases with JDBC

This chapter discusses how to integrate databases with Java using Java Database Connectivity (JDBC) and other techniques.

The Role of JDBC

Java Database Connectivity classes and interfaces allow an application to send SQL statements to a database management system (DBMS) and retrieve the results. JDBC functions in the same way as Open Database Connectivity (ODBC). One of JDBC’s strengths is interoperability: A developer can create JDBC applications without targeting a specific DBMS. Users can use specific JDBC drivers to target a specific database. Interoperability on the client side is also provided when using all Java JDBC drivers. Figure 3-1 shows Java clients running on different platforms.

Click To expand
Figure 3-1: Java clients running on different platforms.

The JDBC interface provides the application with a set of methods that enable database connections, queries, and result retrievals. It is the interface between specific database drivers and the Java user application, applet, or servlet.

The functions a user application can call are methods of connection, statements, or results object classes. Java is an object-oriented programming language, and the problems of impedance mismatch between Structured Query Language (SQL) and object-oriented programming (OOP) languages have been minimized but are still noticeable.

JDBC characteristics

The JDBC characteristics are as follows:

  • JDBC is a call level SQL interface for Java. This interface is totally independent of the available database management systems. It is a low-level Application Programming Interface (API) that allows a Java program to issue SQL statements and retrieve their results. JDBC also provides methods for error and warning messages management. As shown in Figure 3-2, simple client/server scenarios require JDBC at the client side.

Click To expand
Figure 3-2: JDBC is located on the client side.

  • JDBC doesn’t restrict the type of SQL queries passed to an underlying DBMS driver. An application may use as much SQL functionality as needed. The underlying drivers are authorized to claim JDBC compliance on the condition that they fully support ANSI SQL-92 Entry Level. SQL-2

  • Entry Level conformance is widely supported today and guarantees a wide level of portability.

  • JDBC may be implemented on top of common SQL level APIs, in particular on top of ODBC.

  • JDBC provides a Java interface that stays consistent with the rest of the Java system. There are no conflicts because of opposed philosophies expressed by the impedance mismatch between the object-oriented world (Java) and the tabular world (SQL).

  • The JDBC mechanisms are simple to understand and use. This simplicity doesn’t mean that functionality suffers.

  • JDBC uses strong, static typing whenever possible. This approach enables more error checking at compile time.

  • The concept of “one functionality, one method” has been adopted by JDBC, as opposed to many other DBMS SQL level APIs, to keep it simple yet powerful for the beginner as well as the experienced developer.

  • JDBC can serve as a base for higher-level APIs such as embedded SQL for Java. DBMSs implement SQL, which is designed specifically for use with databases. JDBC requires that the SQL statements be passed as strings to Java methods. An embedded SQL preprocessor enables a programmer to instead mix SQL statements directly with Java: For example, a Java variable can be used in a SQL statement to receive or provide SQL values. The embedded SQL preprocessor then translates this Java/SQL mix into Java with JDBC calls.

  • JavaSoft and others have announced plans to implement a direct mapping of relational database tables to Java classes. In this object/relational mapping, each row of the table becomes an instance of that class, and each column value corresponds to an attribute of that instance. Programmers can then operate directly on Java objects; the required SQL calls to fetch and store data are automatically generated “beneath the covers.” More sophisticated mappings are also provided — for example, where rows of multiple tables are combined in a Java class.

JDBC components

The following are the JDBC components:

  • The application

  • The driver manager

  • The driver

  • The data source

The application

The user application invokes JDBC methods to send SQL statements to the database and retrieve results. It performs these tasks:

  • Requests a connection with a data source

  • Sends SQL statements to the data source

  • Defines storage areas and data types for the result sets

  • Requests results

  • Processes errors

  • Controls transactions by requesting commit or rollback operations

  • Closes the connection

Listing 3-1 provides a short example illustrating the use of JDBC to access a database and perform a simple update of a table. This example renumbers the records of a table. Note that there may be other techniques to renumber the records of a table in a more efficient way; the goal here is only to provide an example. The remaining parts of this book go into further details of every feature set of JDBC.

Listing 3-1: An Example of a JDBC Program
Start example
// updating data in a database table
import java.sql.*;
class SimpleExample
{
    public static void main(String args[])
    {
        String url = "jdbc:odbc:mysource";
        Connection myConnection = null;
        try
        {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            myConnection = DriverManager.getConnection(url, "javauser",
            "hotjava");
            myConnection.setAutoCommit(false);

            Statement firstStmt = myConnection.createStatement();
            Statement secondStmt = myConnection.createStatement();

            ResultSet rs = firstStmt.executeQuery("SELECT * FROM friends
            ORDER BY name, firstname FOR UPDATE");

            String cursor = rs.getCursorName();

            // scan the result set
            int i = 0;
            while (rs.next())
            {
                secondStmt.executeUpdate(
                 "UPDATE friends SET id = " + i + " WHERE CURRENT OF " + cursor);
            }
            rs.close();
            firstStmt.close();
            secondStmt.close();
            myConnection.commit();
        }
        catch(java.lang.Exception ex)
        {
            myConnection.rollback();
            ex.printStackTrace();
        }
        finally
        {
            myConnection.close();
        }
    }
}
End example

The driver manager

The driver manager’s primary purpose is to load specific drivers for the user application. It may also perform the following tasks:

  • Locates a driver for a particular database

  • Processes JDBC initialization calls

  • Provides entry points to JDBC functions for each specific driver

  • Performs parameter and sequence validation for JDBC calls

The driver

The driver processes JDBC methods invocations, sends SQL statements to a specific data source, and returns results back to the application. When necessary, the driver translates and/or optimizes requests so that requests conform to the syntax supported by the specific DBMS. The driver performs the following:

  • Establishes a connection to a data source

  • Sends requests to the data source

  • Performs translations when requested by the user application

  • Returns results to the user application

  • Formats errors in standard JDBC error codes

  • Manipulates cursors if necessary

  • Initiates transactions, if explicitly required

The data source

The data source consists of the data the user application wants to access and its associated parameters — that is, the type of DBMS and network layer (if any) used to access the DBMS.

New features of JDBC 3.0

Version 3.0 of JDBC introduced several new features and changes. Previous versions already enabled developers to write complete and rich database-driven applications. The latest revision provides even more functionality: Truly professional database applications can be written in Java. Here is a summary of the changes and additions to JDBC 3.0:

  • Transactions can be rolled back to savepoints.

  • Prepared statements are reusable by connection pools.

  • It has enriched connection pool properties.

  • It has a new metadata interface for parameters of prepared statements and calls to stored procedures.

  • The retrieval of auto-generated keys is now possible.

  • Parameters can be passed by name to a prepared statement or called to a stored procedure.

  • It features holdable cursor support.

  • It has new java.sql.Types.BOOLEAN and java.sql.Types.DATALINK data types.

  • Blob and Clob objects can be altered in a simpler manner.

  • It enables the retrieval of objects referenced by Ref objects.

  • SQL BLOB, CLOB, ARRAY, and REF columns can now be updated in a simpler way.

  • Metadata provides information about transform groups and type mapping.

  • SQL type hierarchies are now retrievable.

  • A relationship between JDBC and the J2EE Connector Architecture has been established.

JDBC driver types

There are several types of JDBC drivers; the different types are shown in Table 3-1. Some are written in Java and are entirely portable; others are partly Java and make use of proprietary libraries to communicate with a specific database. A special type is the JDBC-ODBC Bridge, which enables developers to use existing ODBC drivers to make connections to databases on either Microsoft Windows platforms or UNIX.

Table 3-1: JDBC DRIVER TYPES
Type | Description
Type 1 | Bridge drivers (for example, the JDBC-ODBC Bridge)
Type 2 | Partly Java and partly native code drivers
Type 3 | Pure Java client drivers that use a native middleware peer on the server side
Type 4 | Pure Java client drivers that connect directly to the database

Type 1 drivers

A Type 1 JDBC driver doesn’t implement a communication protocol for a particular database; it only provides a mapping to another database connectivity API. The JDBC-ODBC Bridge is such a driver: It enables the use of existing ODBC drivers to provide the connection to a given database without requiring developers to use ODBC calls from within their programs. Figure 3-3 shows the layering in place with Type 1 drivers. In most cases, the ODBC driver relies on a native driver, which in turn relies on a Net driver. Whereas the role of a native driver is to provide functional access to a specific database engine, the role of the Net driver is to provide a communication protocol for TCP/IP or Inter-Process Communication (IPC) mechanisms, for example.

Click To expand
Figure 3-3: The JDBC-ODBC Bridge driver.

The advantage of this type of driver is that you can quickly set up a database connection, provided that an ODBC driver is available on the platform. The drawback is that using ODBC isn’t always the fastest way to communicate with the database because many layers of code are involved: the JDBC-ODBC Bridge, the ODBC driver manager, the ODBC driver, and the Net library used by the ODBC driver.

Type 2 drivers

With Type 2 drivers, a native API driver forwards the calls to a locally installed library, which may be developed in C, for example, and provided by the database vendor. The local library may be a Dynamic Link Library (DLL) on Microsoft operating systems or a .so shared library on UNIX. Figure 3-4 shows native API, partly Java drivers. Type 2 drivers rely on a native driver (the library), which in turn often relies on a Net driver. This Net driver usually provides support for various communication protocols.

Click To expand
Figure 3-4: Native API, partly Java drivers.

Type 2 drivers are the most efficient because they use libraries that are supposed to be optimized for the database that the libraries target, but because the libraries are native, the solution won’t be portable. The solution requires a full installation and configuration of the libraries.

Type 3 drivers

Type 3 drivers are DBMS-independent all-Java Net drivers, and they use a DBMS-independent network protocol. They are very portable because they are 100 percent Java and lightweight because they implement only a thin layer of communication with a peer middleware that resides on the server. Figure 3-5 shows the Net driver.

Click To expand
Figure 3-5: The Net driver.

Because the driver part is 100 percent Java, the solution is portable. In some cases, the driver supports HTTP tunneling, which means that clients may still be able to connect to the database by using Web proxies and firewalls allowing HTTP traffic only. The disadvantage is that this type of driver necessitates the peer middleware being installed on the server side. This server side piece of software may use the JDBC-ODBC Bridge, pure Java, or native drivers to connect to the database.

Type 4 drivers

Type 4 drivers are native-protocol, all-Java drives that implement in Java all the layers necessary to communicate with the database. They are fully portable because they don’t use local libraries or other native code. Figure 3-6 shows native-protocol, all–Java drivers.

Click To expand
Figure 3-6: Native-protocol, all-Java drivers.

Type 4 drivers are the most portable drivers because they contain only Java classes. They are able to connect to the database without additional pieces of software on the client side as well as on the server side because they implement the wire protocol of the database. Type 4 drivers are the easiest to set up and deploy.

Examples of drivers

Table 3-2 contains several driver vendor names of each type. Notice that, at the time of writing, none of these drivers are actually JDBC 3.0 compliant. However, due to the broad use of Java and JDBC in the programmer community, such drivers will soon become available on the market. A complete list is available at http://java.sun.com/products/jdbc/.

Table 3-2: EXAMPLES OF DRIVERS
DBMS | Type 1 | Type 2 | Type 3 | Type 4
Adabas | - | - | - | SAS/ACCESS
Cloudscape | - | - | - | Cloudscape
DB2 | - | IBM | IBM, Intersolv, Hit Software | -
DMSII | - | - | Asgard | -
Essentia | - | - | Intersoft | -
Hypersonic | - | - | - | Hypersonic
Informix | - | - | Informix, Agave, IDS, I-Kinetics, Intersolv, OpenLink, SCO | SAS/ACCESS
Ingres | - | - | Caribou, Intersolv, OpenLink, SCO | SAS/ACCESS
InterBase | - | - | SCO | Borland
mSQL | - | - | - | Imaginary
Oracle | - | Intersolv, BEA | Agave, IDS, BEA, I-Kinetics, Intersolv, OpenLink, SCO Symantec | Oracle, SAS/ACCESS
PointBase | - | - | - | PointBase
Postgress | - | - | OpenLink | -
SAS | - | - | - | SAS
Sybase | - | Intersolv, BEA I-Kinetics, Sybase, Intersolv, OpenLink, SCO, Symantec | Agave, IDS, BEA, | Connect SW, Sybase
SQL Server | - | BEA | IDS, Intersolv, OpenLink, Symantec | -
Unify | - | - | OpenLink | -
Watcom | - | - | Sybase, Symantec | Sybase
Yard SQL | - | - | - | Yard Software
Via ODBC | JavaSoft | - | Agave, DataRamp, IDS, I-Kinetics, StormCloud, Symantec, Borland, BEA | -

Type 4 drivers are by far the most popular drivers because they are fully Java and don’t need additional OS-specific libraries and middleware. In addition, the

enhanced performance of Java 2 (JDK 1.3 and 1.4) shows no visible difference with native code drivers: Java is as fast as native code and sometimes faster than compiled C++ code.

The big picture

The JDBC interface defines the possible interactions between the user application and the driver manager. Figure 3-7 shows the relationship between the four JDBC components (the application, the JDBC driver manager, the various types of JDBC drivers, and the data source).

Click To expand
Figure 3-7: The complete JDBC architecture.


JDBC Package Contents

The main package of the JBDC API is java.sql. All classes and interfaces belong to this package, which is part of the core Java. (All packages beginning with java.* are part of the core.) JDBC drivers must implement the interfaces while application developers use the interfaces. Using JDBC in your own programs doesn’t mean that you need to implement any of the JDBC interfaces yourself. It is never necessary to deal with implementation classes of specific drivers when developing with JDBC. The following are the contents of java.sql:

  • The interface java.sql.Array: Handles array types in queries and result sets.

  • The class java.sql.BatchUpdateException: An exception that can be thrown when doing batch updates.

  • The interface java.sql.Blob: Handles binary large objects in queries and result sets.

  • The interface java.sql.CallableStatement: A statement object used when making a call to a database stored procedure.

  • The interface java.sql.Clob: Handles character large objects in queries and result sets.

  • The interface java.sql.Connection: A connection object used to represent the state of a session or connection in the database.

  • The class java.sql.DataTruncation: An exception thrown whenever data truncation happens when the driver returns results after performing a query.

  • The interface java.sql.DatabaseMetaData: Obtains various information about the database engine and its capabilities.

  • The class java.sql.Date: Handles date types in queries and result sets.

  • The interface java.sql.Driver: A driver that implements the various database access functions for a specific database product; it also implements a particular wire protocol to communicate with the database.

  • The class java.sql.DriverManager: Loads and handles drivers whenever necessary.

  • The class java.sql.DriverPropertyInfo: Represents connection information that is set before a session is established.

  • The interface java.sql.ParameterMetaData: Obtains information about parameter sets when calling stored procedures or dynamic statements.

  • The interface java.sql.PreparedStatement: Enables the use of dynamic SQL.

  • The interface java.sql.Ref: Handles the reference types of objects in queries and result sets.

  • The interface java.sql.ResultSet: Holds rows of data and is typically retrieved after a query is made.

  • The interface java.sql.ResultSetMetaData: Obtains information about result sets’ contents (the number of rows, column types, and so on).

  • The interface java.sql.Savepoint: When dealing with transactions, enables intermediate commits and rollbacks.

  • The interface java.sql.SQLData: Enables the custom mapping of SQL user-defined types.

  • The class java.sql.SQLException: An exception thrown by the JDBC driver when a problem occurs in the driver itself or in the database.

  • The interface java.sql.SQLInput: An input stream that contains a stream of values representing an instance of a SQL structured or distinct type.

  • The interface java.sql.SQLOutput: An output stream for writing the attributes of a user-defined type back to the database.

  • The interface java.sql.SQLPermission: Represents permissions to use the log writer facility; it is checked in applet environments only.

  • The class java.sql.SQLWarning: A warning is thrown whenever a noncritical event happens during a query or update.

  • The interface java.sql.Statement: Builds a SQL query or update before sending it for processing.

  • The interface java.sql.Struct: Handles SQL structured types in queries and result sets.

  • The class java.sql.Time: Handles time types in queries and result sets.

  • The class java.sql.Timestamp: Handles timestamp types in queries and result sets.

  • The class java.sql.Types: X/OPEN constants used to identify SQL types.


JDBC Package Extensions

JDBC also contains an extension package, called javax.sql, which isn’t part of the core Java. JDBC driver vendors aren’t obliged to implement this package; their drivers will still be JDBC 3.0 compliant without it. javax.sql contains the following:

  • The class javax.sql.ConnectionEvent: Provides information about the source of a PooledConnection related event.

  • The interface javax.sql.ConnectionEventListener: An object that registers itself to receive events generated by a PooledConnection.

  • The interface javax.sql.ConnectionPoolDataSource: A factory for PooledConnection objects.

  • The interface javax.sql.DataSource: A factory for Connection objects.

  • The interface javax.sql.PooledConnection: A connection object that represents a physical connection to the database; it provides hooks for connection pool management.

  • The interface javax.sql.RowSet: Supports the JavaBeans component model in combination with the JDBC API.

  • The class javax.sql.RowSetEvent: Reflects changes in the state of a RowSet instance.

  • The interface javax.sql.RowSetInternal: Allows RowSet readers and writers to access and modify internal attributes of a RowSet.

  • The interface javax.sql.RowSetListener: Allows RowSets to call back methods in objects that are listening to changes within the RowSet.

  • The interface javax.sql.RowSetMetaData: Allows the driver to construct a ResultSetMetaData object for a RowSet.

  • The interface javax.sql.RowSetReader: Reads new content of a RowSet.

  • The interface javax.sql.RowSetWriter: Allows a database to reflect changes made in a RowSet.

  • The interface javax.sql.XAConnection: Allows the connection to participate in distributed transactions.

  • The interface javax.sql.XADataSource: A factory to create XAConnection objects.


Summary

This chapter discussed the integration of databases with Java using JDBC and gave an overview of the JDBC package content. It covered the following:

  • The role of JDBC

  • The components of JDBC, their characteristics, and driver types

  • Package contents

The next chapter discusses the role of JDBC in Java 2 Enterprise Edition.


Chapter 4: JDBC’s Role in Java 2 Enterprise Edition

This chapter discusses the role of JDBC in Java 2 Enterprise Edition (J2EE). J2EE is a set of APIs used to develop distributed applications in a reusable component fashion. This chapter explains the relationship between these components and how JDBC is used in conjunction with Enterprise JavaBeans (EJBs).

J2EE’s Layered Architecture

Before covering the world of programming with JDBC, I briefly discuss in this chapter design practices common when developing distributed applications for intranets, extranets, or the Internet. J2EE addresses these practices by providing a rich API and framework that is well suited for building and maintaining solutions that target a Web browser-based audience.

One of the motivations for the use of J2EE is the need for reducing development and maintenance time for individual pieces of code that represent data entities or a part of the application logic. Another key reason for the use of J2EE is the importance of letting developers focus on their core task: the implementation of the business logic. J2EE allows commonly available software modules to take care of most, if not all, horizontal services such as database connection pooling, transactions, access to database objects as objects, security and access control, support for Web markup languages, and transport protocols.

To understand what distributed component computing is, you need to know the basic parts frequently found in a software application, which are the following:

  • A graphical user interface (GUI) to interact with the user, validate data entry or selection, receive commands, and display results.

  • Data that must be processed in some way to achieve certain results.

  • Data access logic and data management.

  • Business logic that consists of operations or functions of the program.

This is a simplistic view of what is used within a computer program. In the case of fat clients, all four of these functions are merged in the client code.

When you are designing an application that needs to be available, say, on both an intranet with fixed seat users and an extranet for mobile workers, it is important to consider particular aspects such as client platform capabilities, manageability, and total control over these platforms, network bandwidth, and so on. Using pure HTML interfaces solves many distribution, manageability, and even network issues; therefore, I’ll assume that the application in this example conforms to this characteristic. There won’t be any database, GUI code, or even application logic code on the client. In addition, I’ll assume that the application must be open enough to enable future users to access and process the data using non-HTML devices such as Wireless Application Protocol (WAP) phones. Such phones support a markup language known as Wireless Markup Language (WML). As a last requirement, I want total freedom of choice for the relational database brand and dedication to the application being designed. Finally, the application will provide open interfaces to let other programs access parts of its functionalities.

All these requirements lead to so many constraints that you can no longer design and develop a single and monolithic fat client application that is heavily linked to a particular database. This is where J2EE comes in. By splitting the application in tiers and functionalities in components, J2EE enables developers to address all these constraints at the same time. Because I am discussing database access with JDBC in particular, I show in this section that JDBC is in fact no longer used everywhere, as would have been the case with monolithic applications.

The layers that I am focusing on are the following:

  • The client tier

  • The presentation tier

  • The application logic tier

  • The integration tier

  • The resource tier

The client tier

The client tier is the platform that provides the users with the graphical elements necessary to access the application data and functionalities. An example is a Web browser. Another example is a wireless phone WAP browser. J2EE supports markup language browsers without restrictions. There is obviously no need for a database and local database access on the client tier itself.

The only software part needed on the client tier is an HTML or WML browser. No database or drivers are needed.

The presentation tier

The presentation tier focuses only on generating appropriate user interface elements for the clients. For example, the presentation tier may generate HTML for Web browsers and WML for WAP phones. Servlets and Java Server Pages (JSPs) are both J2EE APIs used in presentation tiers. They can produce HTML, for example, in a dynamic way, but won’t typically hold any of the application logic (the core processing of the application) because doing so would inevitably cause code overlap. If the case would arise where WML must be provided in a dynamic way, too, in addition to the already-existing generation of HTML, the same SQL queries would have to be placed in the code for the generation of WML as for the generation of HTML.

Therefore, the presentation tier uses only the following:

  • Servlets

  • Java Server Pages

No database or drivers are needed.

The application logic tier

The application logic tier includes the core logic of the application. This logic is common to the different channels used to access the application: Servlets and Java Server Pages components leverage this logic when necessary. The J2EE standard for implementing business logic is Enterprise JavaBeans (EJBs). EJBs are distributed components that use the Remote Method Invocation (RMI) of Java to call themselves or to be called from servlets and JSPs, for example. Because the application logic usually processes data, it needs to access this data in some way. In fact, the data itself can also be represented as business components by using EJBs called entity beans. Business logic itself is implemented using session beans and normally accesses data only through entity beans. Note that there are two ways of integrating databases with entity beans: One involves development with JDBC to map entity beans to rows in database tables, and the other provides an automatic mapping to the database tables. In the latter case, there is no need to write JDBC code because it is generated by the J2EE container that runs the EJBs.

So, on the application logic tier, only the following components are needed:

  • Session beans for the data-processing logic.

  • Entity beans to represent data.

  • Custom or generated JDBC code to map entity beans to the database.

No database and drivers are needed.

The integration tier

The integration tier typically consists of J2EE connectors to legacy systems. Such connectors may use the Java Messaging Service (JMS) to access mainframes via a Message Oriented Middleware (MOM), for example, or anything else needed to communicate with external systems managing either data or legacy business logic or both. In fact, you may think that the integration tier is a good place to set up, deploy, and run pools of JDBC connections to databases, and indeed, it is a good place for this purpose. Pools of JDBC connections, when deployed in a J2EE environment, are registered in a Java Naming and Directory Interface (JNDI) sort of name space. J2EE containers enable system managers to monitor the pools and set their characteristics, such as minimum and maximum size, auto-increment, and shrinking of connections, without affecting the Java code of all other components.

For simplicity, I’ll assume that the integration tier consists of the following:

  • JDBC connection pools

  • JDBC drivers used by the pools

Still no database needed! More complex environments necessitate a transaction manager, also called a transaction coordinator. Others may require message-oriented middleware to communicate with other systems.

The resource tier

Finally, the resource tier takes care of data stores such as databases. The resource tier isn’t exactly a J2EE component because there is no particular API for it. It merely represents any data source used by the integration tier.

Therefore, the resource tier may be composed of the following:

  • Relational databases

  • Hierarchical databases

  • Back-end systems, mainframe applications, and so on


JDBC’s Relationship to Enterprise JavaBeans

For a J2EE developer, the most relevant application layer to program with JDBC is within Enterprise JavaBeans. Indeed, because EJBs either act on data directly or represent data in an object-oriented way, database access, querying, updating, deleting, and inserting happen at this layer.

To better understand this section, consider the simple case of a piece of code that implements a money transfer within a bank. The functionality is limited to transferring an amount of money from account A to account B, with the simple constraint that, if either debiting account A or crediting account B fails, the whole operation fails, and both accounts remain unchanged. This means that both operations must be performed within a single transaction that must either commit or roll back.

In a traditional world, this may have been implemented as a single database stored procedure. A client program simply calls the stored procedure with the amount and account A and account B parameters and waits until the operation is completed.

Using J2EE in a simple way, consider that there are three components: Account A, Account B, and a Transfer facility. Accounts A and B are business data components; Transfer is a business logic component.

Business logic components

The Transfer facility doesn’t represent data, yet it must access data. I’ll call this component TransferService. Because TransferService doesn’t represent data, this component is a session bean and not an entity bean. The only business method that it provides is transfer(int fromAccountNumber, int toAccountNumber, float amount).

It is the TransferService component’s job to find Accounts A and B and perform the transfer operation by debiting A and crediting B within the scope of a transaction. Transactions can be entirely managed by the J2EE container, so there is no need to define anything particular to handle commits and rollbacks in the code.

Business data components

Accounts A and B are entity beans and may be looked up using a specific EJB API method; because all accounts represent real data, they don’t reside in memory in a permanent way. Looking up entity beans causes some SQL code to be executed to retrieve the data present in the database and build the entity’s instance in memory.

Both beans have the same interface — that is, they offer simple, bean-related methods such as debit(float amount) and credit(float amount). J2EE defines two methods to provide database mapping code for entity beans: container-managed persistence and bean-managed persistence. Container-managed persistence enables the developer of the bean to concentrate on the bean attributes and forces the J2EE container to provide the mechanisms to map the bean with a row in a database table, whereas bean-managed persistence forces the developer to write the entire code needed to mirror the bean’s attribute in a database.

XREF

For more information about container-managed persistence and bean-managed persistence, see

In some way, both credit(float amount) and debit(float amount) cause SQL to be executed to update the account balance values in the database tables.

In the J2EE framework, there is no SQL code writing involved outside the entity beans; there is even the possibility to not write any SQL at all by using container-managed persistence.


Summary

This chapter discussed the layered architecture used by the Java 2 Enterprise Edition framework and briefly explained the role JDBC plays in it.

The next chapter explains how to get started with JDBC.


Part II: Exploring JDBC

Chapter List

Chapter 5: Getting Started with JDBC
Chapter 6: Database Connectivity, Step by Step
Chapter 7: Refining JDBC Queries and Updates
Chapter 8: Advanced Techniques
Chapter 9: Accessing Database Metadata
Chapter 10: Accessing Databases with Enterprise JavaBeans


Chapter 5: Getting Started with JDBC

This chapter discusses the mechanisms used by Java Database Connectivity (JDBC), its programming interfaces, and some typical uses of JDBC.

JDBC is a set of programming interfaces. In this chapter, I discuss which Application Programming Interfaces (APIs) are of interest to database application developers.

The JDBC Mechanisms

The two major components of JDBC are the JDBC API and the JDBC Driver API. As Figure 5-1 shows, the JDBC API is a programming interface for database applications developers, whereas the JDBC Driver API is a lower-level programming interface for developers of specific drivers. I focus on the JDBC API.

Click To expand
Figure 5-1: The JDBC APIs.

To write a successful database application with the Java Language Environment and JDBC, you must take certain steps. These steps are similar to those taken by C programmers using a call level interface (CLI).

The first step is to create a method for connecting to the database, equivalent to a connection context, associated with a specific database driver. Eventually, parameters are provided to locate a specific database, to enable sign-on as a recognized user giving identification and authentication, and to target a specific database managed by the database management system (DBMS). After a connection is established, various actions are allowed, such as closing the connection and sending queries, updates, and any kind of SQL statement, including requests to execute a precompiled SQL statement and stored procedures. Of course, a mechanism to access the result set is also provided. Figure 5-2 depicts the basic actions performed on the client and database sides.

Click To expand
Figure 5-2: Actions performed on the client and DBMS sides.

A mechanism to handle errors is also provided. Exception management addresses this issue in Java by enabling the developer to call specific procedures after an error occurs.

The next section describes JDBC API interfaces in greater detail.


The JDBC Interfaces

The methods discussed in the prior section are expressed as Java interfaces that are implemented by specific database drivers. Database application developers use the following JDBC interfaces:

  • java.sql.DriverManager: A class that provides methods to load drivers and to support the creation of database connections by using methods expressed in the java.sql.Driver interface.

  • java.sql.Connection: Represents a particular connection on which further actions are allowed.

  • java.sql.Statement: Associated to a connection, this allows SQL statements to be sent to the database.

  • java.sql.CallableStatement: This has the same role as java.sql.Statement but in the context of database stored procedures.

  • java.sql.PreparedStatement: This also has the same role as java.sql.Statement but in the context of precompiled SQL.

  • java.sql.ResultSet: Allows access to the rows of a previously executed statement.

  • java.sql.ResultSetMetaData: Gives information such as the type and properties of the columns in a result set.

  • java.sql.DatabaseMetaData: Provides information about the database as a whole.

Figure 5-3 is a simplified view of the relationship between the driver manager and the connection, statement, and result set objects.

Click To expand
Figure 5-3: The relationship between the main JDBC interfaces.


Typical Uses of JDBC

You can make design choices between options that offer different qualities and drawbacks based on the targeted user community. To help you evaluate the pros and cons of each choice, this section and the section “ODBC versus Specific Drivers as a Subprotocol,” later in this chapter, explore different scenarios and show what is the best solution to address their problems.

Applets

You can use JDBC from within applications as well as from applets. Java’s initial fame was its use of applets downloaded from the Internet. Although the types of application are virtually unrestricted, there are still a few matters to consider for applets.

The differences between applets and traditional applications can be summarized as follows:

  • A distrusted applet cannot access local files or open arbitrary network connections to remote hosts without using a browser proprietary security manager interface to request such access. An application accesses the local file system according to the permissions granted the user.

  • A distrusted applet cannot easily rely on specific facilities provided or located in the underlying operating system, such as a local Registry, to locate a database. Applications often rely on such facilities; for example, Open Database Connectivity (ODBC) uses an .ini file or the Registry, and most proprietary APIs use specific properties files. Using property files is common for Java applications.

  • Using applets, response times to download the necessary classes and JDBC driver may be arbitrary when traffic peaks arise on the Internet. In addition, using non-Type 4 drivers necessitates the local installation of native libraries. For this reason, using a full Java Type 4 driver from within an applet is the most appropriate choice.

  • Making applets available on the Internet provides no way to estimate the maximum number of simultaneous database connections that may be established at the same time.

  • Applets may be restricted to using the HTTP protocol via a Web proxy to communicate with a database server. This is especially the case when a firewall is in place and allows only HTTP traffic to go in and out through a Web proxy. In such cases, it is preferable to let the applet communicate with a server-side component such as a servlet using HTTP and to execute all databases access from within this servlet.

As Figure 5-4 shows, an applet is highly dependent on components that aren’t present in the traditional fat-client scenario. Communication channels are used for both the download of classes and for query data and result set transmission.

Click To expand
Figure 5-4: An applet communicating with a server.

These differences aren’t necessarily serious drawbacks. Indeed, it is neither necessary nor preferable for applets to look in local files to find out about a database’s server name, IP address, and so on. Complicated connection information may be provided, using parameters passed to the applet from within the HTML page, so the users won’t have to handle long and cryptic URLs to open the JDBC connection. This kind of information can be pushed to the client.

Applets in three-tier architectures

Another approach to using JDBC from within applets is the three-tier architecture, in which a server actually uses JDBC to perform the calls to the database. This approach solves a number of the applet’s common problems. Eventually, the applet makes a connection to the middle-tier server and requests or calls an action on a particular object using Remote Method Invocation (RMI), for example. This request triggers a conversation between this middle tier and the database management system. In this case, connection information such as database identification may be excluded from the applet’s code. Figure 5-5 depicts such a three-tiered architecture.

Click To expand
Figure 5-5: Three-tier design.
Note

Java 1.1’s RMI provides an HTTP-tunneling feature that enables RMI communication to go through firewalls and Web proxies. (A java-rmi.cgi program is available in the bin subdirectory of the Java 1.1.x distribution.)

Rich-client applications

Java standalone applications are suitable within intranets and are deployable to specific users across the Internet, provided that those users are allowed to make use of distribution products such as Marimba Castanet. These applications run trusted code and are allowed to access the local file system and open network connections to arbitrary hosts, just as normal applications do. Figure 5-6 represents the parts of a standalone application.

Click To expand
Figure 5-6: The parts of a standalone Java application.

Thin-client applications

A final approach that requires only a Web browser on the client side is more and more seen as the most flexible solution. Thin-client applications are made of pure HTML pages or WML pages generated by server-side components. The entire functionality of these applications is provided through the Web interface, while servlets and Java Server Pages (JSPs) integrate with databases and dynamically generate the pages.

In such cases, JDBC runs only on the server side. The type of JDBC driver used in this approach is totally independent from the browser’s platforms. Another advantage is that the database integration logic may serve different types of devices because servlets can easily produce HTML at first and then XML, WML, or Palm Web Clippings without needing to rewrite the entire database access logic.


ODBC versus Specific Drivers as a Subprotocol

ODBC is available on a wide variety of platforms, including the Windows, UNIX, and Macintosh environments. This wide use isn’t enough to make a Java-based project totally portable, but it is sufficient in many cases.

Using an ODBC leads to the same problem of deploying a non-Java, native underlying layer. It is very difficult to use such solutions in uncontrolled environments because the support for ODBC may be limited or not available at all, but you may consider using an ODBC bridge or a native driver during the development phase, for example.

The reasons such solutions are difficult to use are as follows:

  • ODBC is a native component dependent on the platform.

  • ODBC uses a local Registry or configuration file to look up data source names.

  • ODBC uses native drivers that are dependent on the platform.

  • ODBC is software that must be administered on each client platform separately.

On the other hand, a Java native-protocol driver, eventually using a third tier that does most of the job, offers these benefits:

  • It is independent of the platform it is running on.

  • It uses a universal mechanism to name data sources — JDBC URLs.

  • It may be upgraded automatically (in the case of applets using Type 4 drivers).


Summary

This chapter discussed JDBC’s mechanisms, its programming interfaces, and some of its typical uses.

The next chapter explains how to program with JDBC.


Chapter 6: Database Connectivity, Step by Step

This chapter explains how to make a successful connection to a database, how to send SQL statements to this database, and how to retrieve the results. The procedure is very straightforward; typically, every database application developed using Java and JDBC uses this procedure.

First Steps

JDBC is composed of a set of interfaces and classes that implement the functions needed to deal with a database management system (DBMS). I use these interfaces and classes in this chapter:

  • java.sql.DriverManager

  • java.sql.Driver

  • java.sql.Connection

  • java.sql.Statement

  • java.sql.ResultSet

  • java.sql.Date

  • java.sql.Time

  • java.sql.Timestamp

  • java.sql.Types

  • java.sql.DataTruncation

First, it is important to make sure that the JDBC Application Programming Interface (API) classes and specific drivers implementations are available on your system and are reachable by scanning the value of the CLASSPATH environment variable. Note that if you are using the JDBC-ODBC Bridge, which is included in the JDK, the CLASSPATH shouldn’t include additional driver classes. This environment variable should normally point to one or more directories where the Java classes are located. If necessary, update it or move the JDBC and drivers package subdirectories to an appropriate location on your hard drive. When done, the Java class loader will be able to find these classes on the file system.

XREF

A list of JDBC drivers is provided in http://java.sun.com/products/jdbc.

Typically, you will see a subtree resembling Listing 6-1 when scanning your CLASSPATH environment variable. (jdbc/odbc/... was used for Listing 6-1; you may choose not to install it.)

Listing 6-1: A Typical Package Tree
Start example
classes/
+--      java/
|         +--    .../
|         |
|         +--    sql/
|                         CallableStatement.class
|                         Connection.class
|                         DatabaseMetaData.class
|                         DataTruncation.class
|                         Date.class
|                         Driver.class
|                         DriverInfo.class
|                         DriverManager.class
|                         DriverPropertyInfo.class
|                         PreparedStatement.class
|                         ResultSet.class
|                         ResultSetMetaData.class
|                         SQLException.class
|                         SQLWarning.class
|                         Statement.class
|                         Time.class
|                         Timestamp.class
|                         Types.class
+--      jdbc/
          +--    odbc/
                         JdbcOdbc.class
                         JdbcOdbcBoundCol.class
                         JdbcOdbcBoundParam.class
                         ...
                         ...
End example

To make the JDBC classes available to the current class using the abbreviated name, you use the import statement in source programs. The code is more readable if you don’t use the fully qualified names. However, as explained later in this chapter, in the section "Specifying a JDBC driver," there is no need to import the packages of any specific JDBC driver implementation classes. So you should include the following line at the top of the Java program, applet, or servlet:

import java.sql.*;

The usual command line to compile Java source code will be used for all examples in this book:

% javac example.java

As usual, you can use the classpath parameter to specify additional Java classes that aren’t reachable through the CLASSPATH environment variable. In case the JDBC driver that you intend to use isn’t pure Java, it is mandatory to have the related native libraries available in either the LD_LIBRARY_PATH in UNIX (Solaris) or the PATH in Microsoft Windows. In UNIX, shared libraries end with .so, whereas in Windows, DLLs end with the well-known .dll. I advise you to look for those files when using an impure Java JDBC driver.


Connecting to the Database

To access a database, a connection must be initiated. The connection is a Java object containing methods that access the database. The connection class also holds information on the state of connections. Various connection parameters are necessary, for example, to locate the database, to specify drivers and protocols, and to specify a user account and password in the DBMS. The format of these parameters and how to set them is discussed in the following section, “JDBC’s database naming scheme.”

As shown in Figure 6-1, the first step is the establishment of a connection. The last step will, of course, be the termination (“closing”) of the connection. Opening and closing the connection usually creates and releases user resources within the database management system and driver.

Click To expand
Figure 6-1: An overview of the connection.

To create an instance of a connection, it is necessary to understand the JDBC naming scheme. The next subsection explains this in detail.

JDBC’s database naming scheme

JDBC uses a particular syntax to name a database. The designers wanted to use a well-known and supported convention: the uniform resource locator (URL) syntax. In this case, the JDBC URL has the following form:

jdbc:<subprotocol>:<subname>

In this form, jdbc means that the protocol is JDBC, the subprotocol field is the name of the JDBC driver to be used, and the subname is a parameter string that is dependent on the subprotocol. Figure 6-2 illustrates the JDBC URL naming mechanism.

Click To expand
Figure 6-2: JDBC mechanism to name a data source.

The following examples show some of the uses of database URLs:

jdbc:odbc:sampledb

A JDBC-Open Database Connectivity (ODBC) bridge will be used, and the ODBC Data Source Name (DSN) is sampledb.

jdbc:odbc:sampledb;UID=javauser;PWD=hotjava

This URL is the same as the previous one, but adds a user ID and password. Other attributes can also be added. Note that the format of JDBC URLs is a little bit arbitrary. JDBC driver vendors may choose to use their own proprietary format. For example, such a format might be the following:

jdbc:mydbdrv://www.mydomain.net:8192/mydb

In this case, the subprotocol is called mydbdrv. The database engine is running on the www.mydomain.net host (the subname field), the Transmission Control Protocol/Internet Protocol (TCP/IP) port that should be used is 8192, and mydb is the name of the database to be accessed. The significance of these parameters is somewhat arbitrary. For example, if the subprotocol (the driver) always uses the same port number, it is unnecessary to provide it in the URL. In this example, mydb, called a sub-subname, refers to a specific database instance. Other types of JDBC drivers may interpret the sub-subname as something else other than a specific database instance name.

jdbc:dcenaming:employees

This URL suggests that a local Distributed Computing Environment (DCE) naming service should be used to locate the database named employees. This service resolves employees into a particular name more appropriate to locate the database engine. Another type of network naming protocol can be used — for example, Network Information System (NIS).

Note that the ODBC subprotocol URL should always conform to the following syntax:

jdbc:odbc:<dsn>[;<attribute-name>=<attribute-value>]*

The JDBC URL syntax is flexible enough to allow specific drivers to interpret their own syntax.

Table 6-1 contains a few JDBC URLs recognized by commercial database products. Please check the documentation for more details and options that are specific to each database.

Table 6-1: SAMPLE JDBC URLS
Database | JDBC URL
DB2 | jdbc:db2://host:4100/mydb;
Cloudscape | jdbc:cloudscape:HelloWorldDB;create=true
Connect SW | jdbc:sybase://host.domain.com:8192
Hypersonic | jdbc:HypersonicSQL:testdb
Informix | jdbc:informix-sqli://host:1526/mydb:INFORMIXSERVER= server_ol;
MiniSQL | jdbc:msql://athens.imaginary.com:4333/Testdb
ODBC Bridge | jdbc:odbc:data-source-name
Oracle | jdbc:oracle://host:1521/ORACLE_SID;
Oracle Lite | jdbc:polite:data_sourcename
Sybase | jdbc:sybase:Tds:host.domain.com:8192

The format of URLs is not defined by the JDBC specification. It is up to the vendors to determine a format; you should therefore refer to a driver’s documentation for specific details about URLs.

Specifying a JDBC driver

A specific database is usually reachable through one or more drivers. The driver manager and driver objects provide methods to load a driver and handle driver properties. JDBC must have some knowledge about the available drivers. This knowledge comes from the jdbc.drivers system property. It can be set via the Java interpreter command line or via a property file.

Here’s how to specify the jdbc.drivers system property via the command line (which can be included in a shell script or batch file for greater convenience when invoking standalone programs):

% java -Djdbc.drivers=vendor1.driver1 example

Here’s how to specify the jdbc.drivers system property via a file — for example, when using the applet viewer or Sun’s HotJava browser:

# On Unix, this file is ~/.hotjava/properties
jdbc.drivers=vendor1.driver1

Although the database URL specifies the database and protocol to be used, it is sometimes preferable to let the JDBC driver manager choose between two or more drivers. In this case, it is possible to specify a driver list in the property called jdbc.drivers. The list of driver class names should be colon separated — for example:

‘vendor1.dbdrv:vendor2.sql.foodriver:vendor3.db.connectdrv’

The driver manager tries to use each of the drivers listed in jdbc.drivers until it finds one that can successfully connect to the given URL. Drivers that aren’t trusted code are skipped. The driver registers itself with the driver manager to allow connections to be made.

In case the jdbc.driver system property is unavailable, there is a way to force a particular driver to be loaded. For example, the following line loads a JDBC-ODBC Bridge driver:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Another method is to use the following statements, which register the bridge driver class with the driver manager:

Driver myDriver = new sun.jdbc.odbc.JdbcOdbcDriver();
java.sql.DriverManager.registerDriver(myDriver);

Table 6-2 contains a few examples of JDBC driver class names for commercial database products. Please check the documentation, as the package names may have changed.

Table 6-2: SAMPLE JDBC DRIVERS
Database | JDBC Driver Class Name
DB2 | com.ibm.DB2.JdbcDriver
Cloudscape | COM.cloudscape.core.JDBCDriver
Connect SW | connect.sybase.SybaseDriver
Hypersonic | org.hsql.jdbcDriver
Informix | com.informix.jdbc.IfxDriver
MiniSQL | COM.imaginary.sql.msql.MsqlDriver
ODBC Bridge | sun.jdbc.odbc.JdbcOdbcDriver
Oracle | com.oracle.jdbc.OracleDriver
Oracle Lite | oracle.pol.poljdbc.POLJDBCDriver
Sybase | com.sybase.jdbc.SybDriver

The exact JDBC driver class names are not standardized; I therefore recommend that you check the driver’s documentation to know the latest correct class name for it.

Creating a connection

Before creating a connection, it is necessary to declare it. Declaring a connection is quite simple; just say that you need a connection object and name it:

Connection myConnection;

In this example, the connection object is named myConnection.

To connect to the data source, the connection object must be made. The method that provides this functionality is as follows:

java.sql.DriverManager.getConnection();

The following statement creates a connection object that sends statements to the database. The URL naming convention is used with the getConnection() method and is the way to specify the data source that is targeted.

String url = "jdbc:odbc:mysource";
Connection myConnection = DriverManager.getConnection(url, "javauser", "hotjava");

This example shows how to pass the URL string to the driver manager plus specific arguments to the driver itself. In this case:

  • The protocol used is JDBC.

  • The driver is a JDBC-ODBC Bridge.

  • The ODBC DSN is mysource.

  • A username is provided: javauser.

  • A password is provided: hotjava.

In some cases, the ODBC data source doesn’t need a login and password. In such cases, the getConnection(String url) method is sufficient.

The driver manager tries to find a registered JDBC driver that is allowed to reach the data source that is specified in the URL.

The following are other methods that enable the user to establish a connection to the database. They have the same name but different parameters.

DriverManager’s getConnection Methods

Connection getConnection(String url);
Connection getConnection(String url, String user, String password);
Connection getConnection(String url, java.util.Properties info);

The getConnection(String url) method doesn’t use specific parameters to provide the username and password. If necessary, and if allowed by the specific driver, these values may be passed within the URL string as shown in this example:

String url = "jdbc:odbc:mysource;UID=javauser;PWD=hotjava";
Connection myConnection = DriverManager.getConnection(url);

The getConnection(String url, String user, String password) method sends the second and third parameters to the driver, and the driver usually interprets them as the username and password to connect to the data source.

In the case of the getConnection(String url, java.util.Properties info) method, the second parameter is a list of arbitrary string pairs such as user and its value and password and its value. These two connection arguments should be included in the list. The list of such properties should be included in the driver’s documentation. However, it is preferable to pass as much information as possible within the database URL.

What you have learned so far enables you to begin your first Java standalone application. Listing 6-2 shows how to open a connection.

Listing 6-2: Opening a Connection
Start example
// opening a connection
import java.sql.*;
class SimpleExample
{
         public static void main(String args[]) {
                  try {
                          String url = "jdbc:odbc:mysource";
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                          DriverManager.getConnection(url,
                          "javauser", "hotjava");
                          // ...
                  } catch (java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

Closing a connection

Closing connections is as important as opening connections. If connections are never closed, the database keeps unnecessary connection context in memory and eventually runs out of connections. The following shows how to proceed to close connections:

Connection Closing Methods

void close();
boolean isClosed();
void setAutoClose(boolean autoclose);
boolean getAutoClose();

These methods all apply to a connection instance.

The close() method in the first line simply closes the current connection. Normally, a connection closes automatically when it is garbage-collected or when certain fatal errors occur. It is a good programming practice to close connections when they’re no longer needed.

isClosed returns true if the connection is currently closed and false if it is open.

A connection is normally in autoclose mode by default. Because other objects may depend on specific connections (for example, statements and result set objects, which are discussed later in the “Sending statements” sections), it may be necessary to keep a connection open after a transaction has been committed or rolled back (canceled). setAutoClose() enables you to disable autoclosing.

The getAutoClose() method returns true in case the connection is in autoclose state and false in the opposite case.

Listing 6-3 shows how to close a connection.

Listing 6-3: Closing a Connection
Start example
// closing a connection
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                  try {
                          // ...
                          String url = "jdbc:odbc:mysource";
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                          DriverManager.getConnection(url,
                          "javauser", "hotjava");
                          // ...
                          if (!myConnection.isClosed())
                                    myConnection.close();
                          // ...
                  } catch (java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

Adjusting properties

It is possible to set and query connection properties that affect the general behavior of commands to be performed within the connection.

The methods available to set and query the connection object are listed in the following:

Connection Behavior

void setReadOnly(boolean readonly);
boolean isReadOnly();
void setCatalog(String catalog);
String getCatalog();

It may be necessary to put a connection in read-only mode, as in the first line of the preceding. By default, a connection isn’t set as read-only. Setting it in read-only mode may sometimes be practical and may enable database optimizations where the connection won’t be used for database updates.

For the second method, boolean isReadOnly();, the return is true if the connection has been set in read-only mode. Use isReadOnly to test the connection mode.

A catalog is a database subspace containing the database objects affected by the operations performed within the connection. Some DBMSs manage multiple databases at the same time. It is possible to restrict the subspace to one or another database using the setCatalog() method, as in the third method of the preceding. In cases where the DBMS or the driver associated with the connection doesn’t support catalogs, this method silently ignores all calls to it.

The getCatalog() method in the last line gives the catalog name that is currently in use or a null value.

Note

The notion of database catalogs is database independent. Some databases support it, and others don’t. In general, a catalog means a logical subspace of a database server instance.

Listing 6-4 shows how to adjust connection properties.

Listing 6-4: Adjusting Connection Properties
Start example
// adjusting connection properties
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                  try {
                          // ...
                          String url = "jdbc:odbc:mysource";
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                          DriverManager.getConnection(url,
                          "javauser", "hotjava");
                          if (myConnection.isReadOnly()) {
                               System.out.println("Connection is read only");
                          } else {
                               myConnection.setReadOnly(true);
                          }
                          System.out.println("Default catalog: " +
                          myConnection.getCatalog());
                          // use the pubs2 database
                          myConnection.setCatalog("pubs2");
                          // ...
                          if (!myConnection.isClosed())
                               myConnection.close();
                          // ...
                  } catch (java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

Putting it all together

The essential steps in every Java project that uses JDBC to obtain and terminate a connection to a DBMS are the following:

  • Import the java.sql.* package classes.

  • Build a JDBC URL.

  • Load one or more specific JDBC driver with Class.forName() or DriverManager.registerDriver().

  • If necessary, adjust the connection properties.

  • Open a connection with getConnection().

  • Terminate the connection with close().

The example in Listing 6-5 does nothing but open a connection and close it. The JDBC log stream is set to the standard output to trace everything that happens. Note that this is a deprecated method; therefore, it must be used with caution.

Listing 6-5: A Do-Nothing Client
Start example
// a do-nothing client
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                  String url = "jdbc:odbc:mysource";
                  try {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          // set the log stream (deprecated)
                          DriverManager.setLogStream(java.lang.System.out);
                          Connection myConnection =
                          DriverManager.getConnection(url,
                          "javauser", "hotjava");
                          myConnection.close();
                  } catch(java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

Note that code to catch java.lang.Exception is explicitly included. I point out what this means later in this chapter, in the section "Managing Errors and Warnings." For the moment, just note that the compiler will complain if you don’t catch this exception:

2 errors
compiling: ex.java
ex.java(13): Exception java.lang.ClassNotFoundException must be caught, or it
must be declared in the throws clause of this method.
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
^
ex.java(15): Exception java.sql.SQLException must be caught, or it must be
declared in the throws clause of this method.
DriverManager.getConnection(url,
^

What happens? The lines shown in Listing 6-6 are printed to the JDBC log stream during the execution of this small Java program.

Listing 6-6: The JDBC Log Stream
Start example
DriverManager.getConnection("jdbc:odbc:mysource")
trying driver[className=sun.jdbc.odbc.JdbcOdbcDriver,context=null,
jdbc.odbc.JdbcOdbcDriver@1393878]
*Driver.connect (jdbc:odbc:mysource)
JDBC to ODBC Bridge: Checking security
No SecurityManager present, assuming trusted application/applet
JDBC to ODBC Bridge 1.0
Current Date/Time: Wed Aug 07 19:42:19 1996
Loading JdbcOdbc library
Allocating Environment handle (SQLAllocEnv)
hEnv=5308508
Allocating Connection handle (SQLAllocConnect)
hDbc=5310680
Connecting (SQLDriverConnect), hDbc=5310680,
szConnStrIn=DSN=mysource;UID=javauser;PWD=hotjava
RETCODE = 1
getConnection returning
driver[className=sun.jdbc.odbc.JdbcOdbcDriver,context=null,
sun.jdbc.odbc.JdbcOdbcDriver@1393878]
*Connection.close
Disconnecting (SQLDisconnect), hDbc=5310680
Closing connection (SQLFreeConnect), hDbc=5310680
Closing environment (SQLFreeEnv), hEnv=5308508
End example

The JDBC log is quite long, and you actually did nothing but open and close a connection. It is interesting to see all the silently performed actions.


Sending SQL Statements

The connection object sends SQL statements to the database engine. There are different methods to perform this, depending on the kind of operation needed. In this chapter, I focus on sending normal SQL statements. Unlike prepared statements or calls to stored procedures, which are discussed in

Building statements

The step that directly follows the creation of the connection is the creation of a SQL statement. This doesn’t mean that it is forbidden to build a SQL query string before opening the connection. You are free to do this. The exact meaning is that a JDBC statement is an object associated to a connection, and it will be used later to request an execution of a SQL string within this connection environment space in the DBMS.

As shown in Figure 6-3, the step order is very simple.

Click To expand
Figure 6-3: Overview: Building a SQL statement.

Closing the SQL statement releases all the data associated with the statement. The following is the method to build a statement object:

Connection’s Factory Method for Statement Objects

Statement createStatement();

The statement object is obtained by calling this method on the connection instance, as shown in Listing 6-7.

Listing 6-7: Creating a Statement
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
                          "javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
myConnection.close();
...
...
End example

Sending statements

The SQL statement is sent to the DBMS, where it is parsed, optimized, and executed. But you haven’t yet built the statement text. Indeed, the SQL string passes to the database when the call for execution of the statement is issued, as shown in Figure 6-4.

Click To expand
Figure 6-4: Sending a SQL statement.

The driver converts this SQL string into the DBMS native SQL grammar. It is possible to see the converted string without sending it to the database, as shown in the following. Usually, you won’t use this facility, but sometimes it is necessary to know what the native translation of a query is prior to sending it.

Connection’s Method to Print Native SQL

String nativeSQL(String sql);

The method is applied to the connection object because it is DBMS-dependent. Indeed, a connection is associated to one and only one DBMS through its driver.

The string passed as an argument is the “user” SQL statement; nativeSQL() returns the native form of this statement. The native form is the form understood by the underlying database. Drivers usually translate SQL statements to native forms when necessary. Listing 6-8 shows the language to obtain the native SQL translation.

Listing 6-8: Native SQL Translation
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
"javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
String myQuery("SELECT * FROM employees ORDER BY salary DESCENDING");
System.out.println("This query: " + myQuery);
System.out.println("is sent to the DBMS as: " +
myConnection.nativeSQL(myQuery));
myConnection.close();
...
...
End example

All the previous steps, opening a connection and creating a statement, are necessary before executing a query. None of them can be skipped. Figure 6-5, although still somewhat simple, shows the current action sequence.

Click To expand
Figure 6-5: An overview of sending a SQL statement.

The method chosen to send a SQL statement to the database depends on the type of statement and type of data it returns. Statements can be composed of SQL queries, SQL updates, or both. There are specific methods to handle each case, as shown in the following:

Statement’s Execute methods

ResultSet executeQuery(String sql);
int executeUpdate(String sql);
boolean execute(String sql);

If the query returns rows of data, you should use executeQuery(). In this case, the query is typically a static SQL SELECT statement. The SQL text is simply passed as a string argument. It doesn’t have to be translated to the native form with nativeSQL(). This method returns a ResultSet object, which is discussed in the section "Handling Results," later in this chapter.

The method executeUpdate(String sql) is used for SQL statements that return an update count, such as SQL updates, inserts, and deletes. If the SQL statement returns nothing (returning nothing is different than returning zero [0] rows) or returns an integer value, as is the case with SQL INSERT, UPDATE, or DELETE clauses, you should use executeUpdate, as in the second line of the preceding. The call returns the integer value or 0 (zero) for statements that return nothing.

When a SQL statement returns more than one result, execute() has to be used to request execution of the statement, as in the third line of the preceding (boolean execute(String sql);). The subsection "Managing multiple result types" discusses this issue in detail.

Listing 6-9 shows how to execute a query.

Listing 6-9: Executing a Query
Start example
// how to execute a query
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                  String url = "jdbc:odbc:mysource";
                  try {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          Statement myStatement =
                                  myConnection.createStatement();
                          ResultSet rs = myStatement.executeQuery(
                                  "SELECT name, id, salary FROM employees" +
                                  " ORDER BY salary DESC");
                          myConnection.close();
                  } catch(java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

The example in Listing 6-10 illustrates the executeUpdate() method:

Listing 6-10: Performing an Update
Start example
// how to execute an update
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                  String url = "jdbc:odbc:mysource";
                  try {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          Statement myStatement =
                                  myConnection.createStatement();
                          int res = myStatement.executeUpdate("UPDATE" +
                                  "employees SET salary = salary*1.1" +
                                  "WHERE id = 1");
                          myConnection.close();
                  } catch(java.lang.Exception ex) {
                          ex.printStackTrace();
                  }
         }
}
End example

Closing statements

It is often necessary to close explicitly a statement after the DBMS executes it. Indeed, database context and JDBC statement resources stay open until the connection is closed or the statement is garbage-collected, depending on the driver. It isn’t desirable to consume resources when there is no reason to do so. Closing the statement also closes the returned result set.

Statement’s Closing Method

void close();

The close() method is simply called on a statement object and takes no arguments.

Storing BLOBs and CLOBs

It is sometimes necessary to record pictures, sound, or other multimedia files in a database. This kind of object is called a binary large object (BLOB). Although BLOB has absolutely nothing to do with Java objects (or C++ or any other object-oriented programming [OOP] language object), BLOB isn’t restricted to images, sound, and multimedia content. For example, a multikilobyte or multimegabyte text can be a BLOB. BLOBs don’t have to be ASCII or Unicode; they can be pure binary. Character-only large objects are called character large objects (CLOBs).

Insertion, update, or retrieval of very large values is usually performed by passing values in small chunks of data. This approach is often more convenient for programmers. JDBC, however, uses data streams. JDBC provides three kinds of streams: ASCII streams, Unicode streams, and binary streams.

Because there is no way to send streams within a simple SQL statement, the streams are passed as parameters. Refer to the dynamic SQL section to find out how to send BLOBs to the database.

Adjusting properties

There are properties that change the default behavior of JDBC or of the driver. They can be set before sending the SQL statement to the database.

Data truncation happens when inserting or updating data in the database. This truncation is dependent on the DBMS and driver that fixes the maximum size for data types. An error usually happens if the truncation occurs during a database write. JDBC provides a method to limit the size of a field to a maximum value, which is shown in the following; if the limit is exceeded, JDBC raises a SQLException.

Statement’s Maximum Field Size

void setMaxFieldSize(int max);
int getMaxFieldSize();

The method setMaxFieldSize() enables the programmer to set a maximum field size that is valid for the current statement. The parameter is the number of bytes allowed.

The method getMaxFieldSize(), as shown in the second line of the preceding, returns the maximum size allowed for the current statement.

Listing 6-11 shows data truncation on write.

Note

JDBC drivers perform data truncation on write when too many bytes are passed to a table’s column.

Listing 6-11: Data Truncation on Write
Start example
// data truncation on write
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                 String url = "jdbc:odbc:mysource";
                 try {
                         ...
                         ...
                         Connection myConnection =
                                 DriverManager.getConnection(url, "javauser",
                                 "hotjava");
                         Statement myStatement = myConnection.createStatement();
                         myStatement.setMaxFieldSize(12);
                         int res = myStatement.executeUpdate("UPDATE
                                 employees SET comment = ‘The quick br...’ WHERE
                                 name=’jones’");
                         ...
                         ...
                 } catch(java.lang.Exception ex) {
                         ex.printStackTrace();
                 }
         }
}
End example

Setting time-outs

The execution of a statement may be delayed for one of several reasons. A mechanism called a time-out exists so that programmers have a way to handle such situations. The query time-out is the time the JDBC driver waits for a statement to execute. If the limit is exceeded, the driver raises an exception. This exception may be caught and one or more retries initiated. The following methods are available for dealing with time-outs:

Statement’s Time-outs

void setQueryTimeout(int seconds);
int getQueryTimeout();

void setQueryTimeout(int seconds) is the method used to set a limit to the time-out mechanism. The parameter is the number of seconds that it waits before raising the SQLException. A zero value means no limit.

The method getQueryTimeout(), as shown in the second line of the preceding, returns the number of seconds corresponding to the time-out limit. A zero value again means that there is no limit and that the driver can wait forever if necessary.

Listing 6-12 provides an example of a time-out being set on the statement.

Listing 6-12: Setting a Statement Time-out
Start example
// time-outs
...
...
Connection myConnection =
         DriverManager.getConnection(url, "javauser", "hotjava");
         Statement myStatement = myConnection.createStatement();
         // we do not want to wait forever
         myStatement.setQueryTimeout(10);
         int res = myStatement.executeUpdate("UPDATE
         employees SET salary = 1000000 WHERE name=’jones’");
...
...
End example

Another property may prove useful when sending data to the database: the setting for the escape sequence, as shown in the following.

Statement’s Escape Processing

void setEscapeProcessing(boolean enable);

This statement enables or disables escape substitution by the driver. Escape substitution is the default behavior and occurs before sending the SQL statement to the database. When enabled, the driver translates escape syntax strings to native SQL (see Chapter 7).


What You Have Done So Far

This section reviews what has been covered thus far:

  • Import java.sql.* to avoid having to write long member names.

  • Build a JDBC URL.

  • Load one or more specific JDBC drivers with class.forName().

  • If necessary, adjust the connection properties.

  • Open a connection with getConnection().

  • Create a statement object.

  • Build a SQL statement.

  • Execute the SQL statement.

  • Close the statement.

  • Terminate the connection with close().

Listing 6-13 contains an example that summarizes all these steps. This example opens a connection to the database, sends a SQL query to a database with a time-out value of 180 seconds and then closes the statement and connection.

Listing 6-13: Executing a Statement
Start example
// executing a statement
import java.sql.*;
class SimpleExample {
         public static void main(String args[]) {
                 String url = "jdbc:odbc:mysource";
                 try {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          Statement myStatement = myConnection.createStatement();
                          myStatement.setQueryTimeout(180);
                          ResultSet rs = myStatement.executeQuery("SELECT * FROM
                          employees");
                          myStatement.close();
                          myConnection.close();
                 } catch(java.lang.Exception ex) {
                          ex.printStackTrace();
                 }
         }
}
End example


Handling Results

A DBMS usually returns results after executing a statement. The results are of different types. The executeQuery() method returns a result set object, and the executeUpdate() returns an integer. Of course, because the result of the executeQuery() method will always be used within the program, it would be useless to discard the result of a SQL query. In the case of an update, you should also use the result, at least to verify that everything happened as expected and to discover how many rows of data were affected by the update.

Fetchable result types

The SQL clauses listed in Table 6-3 return known result types: rows of data and/or an integer value.

Table 6-3: DIFFERENT STATEMENTS RETURN DIFFERENT RESULT TYPES
Type of SQL Statement | Type Returned
CREATE TABLE employees (...) | Nothing
SELECT * FROM employees | Rows and an integer
SELECT MAX(salary) FROM employees | Rows and an integer
UPDATE employees SET salary = 70000 | An integer WHERE name = "Jones"
INSERT INTO employees VALUES (...) | An integer
DELETE FROM employees WHERE salary > 150000 | An integer

In summary, there are two possible result set return types: an integer and a result set composed of zero or more rows of table data. Of course, there are different methods for handling such results, and there is even a way to discover the result type of an unknown SQL query, as explained in the section “Managing multiple result types,” later in this chapter.

Getting the result set

SQL statements that return an integer such as DELETE, UPDATE, and INSERT don’t need additional processing. The method to send them returns an integer and is usually interpreted as a counter. Other SQL statements normally don’t return rows of data or a counter.

SELECT queries return normal rows of data. The result set is composed of zero or more rows coming from the database. The next operation is scanning this result set, row by row, until all rows have been fetched. This operation is done within a loop, as shown in Figure 6-6. I show you how to analyze the data that composes rows in the "Accessing columns" section, later in this chapter.

Click To expand
Figure 6-6: An overview of getting the result set.

The result set object is created when sending the statement to the DBMS. It is created by executing the statement object. Closing the result set releases all data associated with the result set.

Retrieving rows

Result sets are composed of rows. The ResultSet.next() method is used in the loop to access these rows, as shown in the following.

ResultSet’s next() Method

boolean next();

Figure 6-7 illustrates the mechanism used to scan the rows in a result set instance named resultSet.

Click To expand
Figure 6-7: The next() method is used to scan a result set.

It is important to position the cursor before the first row of the result set. The method next() needs to be called first to access the first row. After the first call, the first row becomes the current row, and it is ready to be processed. Successive calls to next() make the next rows current, row by row, of course.

Listing 6-14 shows how to scan a result set.

Listing 6-14: Scanning a Result Set
Start example
...
Connection myConnection = DriverManager.getConnection(url,
         "javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
ResultSet rs = myStatement.executeQuery(sqlQuery);
while (rs.next())
{
         // we got a row
}
myStatement.close();
myConnection.close();
...
...
End example

Getting the number and label of columns

A row is usually composed of table data that may be organized in different columns of different types. It may be important to discover the properties of the result set’s rows, the number of columns, and the type of data in each column. I show in the following section, “Accessing columns,” how to get such information about result sets. Here, I’ll use only the column number and column labels.

ResultSet’s Metadata Information for Columns

int getMetaData().getColumnCount();
String getMetaData().getColumnLabel(int i);

The getMetaData() method returns a ResultSetMetaData object that is explained later (in Chapter 9) because it is quite complex. Calling getColumnCount() on this object returns the expected value.

The return type for the first line of the preceding is integer and is the number of columns in the rows composing this result set.

For the second line, String getMetaData().getColumnLabel(int i);, the parameter is the column index where a value of 1 indicates the first column. The method obviously returns the label for the column at this index.

It may be more efficient to store the ResultSetMetaData object once instead of calling the method to create it each time it is necessary to access a property. The

driver may provide caching, but it is often preferable not to abuse such features when not really needed.

Listing 6-15 shows how to call getColumnCount() and getColumnLabel().

Listing 6-15: Getting the Number and Label of Columns
Start example
...
Connection myConnection = DriverManager.getConnection(url,
                          "javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
ResultSet rs = myStatement.executeQuery(sqlQuery);
int maxColumns = rs.getMetaData().getColumnCount();
for (int i = 1; i <= maxColumns; i++)
{
         if (i > 1) System.out.print(", ");
         System.out.print(rs.getMetaData().getColumnLabel(i));
}
System.out.println("====================================");
while (rs.next())
{
         // we got a row
}
myStatement.close();
myConnection.close();
...
...
End example

Accessing columns

As shown in Figure 6-8, columns must be fetched one by one, in left-to-right order. Fetching may be done in a loop using the column indexes or column names discovered by the ResultSetMetaData object.

Click To expand
Figure 6-8: An overview of accessing columns.

The row’s contents are accessible via getXXX() methods that allow the extraction of the various values of the columns of rows in the result set.

There are two ways of accessing columns: by column index or by column name. Accessing a column by name is more convenient but less efficient because it internally needs comparisons of strings before finding the column. Certain SQL statements return tables without column names or with multiple identical column names; it is absolutely necessary to use column numbers in these cases. Figure 6-9 illustrates the access to a row’s columns.

Click To expand
Figure 6-9: Accessing columns with getXXX().

All columns within a row must be read in left-to-right order, and each column must be read only once. This rule may not be true with some JDBC drivers, but it is preferable to observe it to ensure maximum portability.

By column indexes

The following is the list of getXXX() methods available to fetch columns in a row.

ResultSet’s Methods to Access Columns by Index

String getString(int columnIndex);
boolean getBoolean(int columnIndex);
byte getByte(int columnIndex);
short getShort(int columnIndex);
int getInt(int columnIndex);
long getLong(int columnIndex);
float getFloat(int columnIndex);
double getDouble(int columnIndex);
byte[] getBytes(int columnIndex);
java.sql.Date getDate(int columnIndex);
java.sql.Date getDate(int columnIndex, java.util.Calendar cal);
java.sql.Time getTime(int columnIndex);
java.sql.Timestamp getTimestamp(int columnIndex);
java.sql.Timestamp getTimestamp(int columnIndex, java.util.Calendar cal);
java.io.InputStream getAsciiStream(int columnIndex);
java.io.InputStream getBinaryStream(int columnIndex);
Object getObject(int columnIndex);
Object getObject(int columnIndex, java.util.Map map);
java.sql.Array getArray(int columnIndex);
java.math.BigDecimal getBigDecimal(int columnIndex);
java.sql.Blob getBlob(int columnIndex);
java.sql.Clob getClob(int columnIndex);
java.io.Reader getCharacterStream(int columnIndex);
java.sql.Ref getRef(int columnIndex);
java.net.URL getURL(int columnIndex);
return_type getXXX(int columnIndex);

All these methods return the column value in the current row. Column indexes are integers.

The example in Listing 6-16 shows how to execute a SQL statement and retrieve the results using column indexes. Note that the rows are always read from left-to-right and that columns are read only once.

Listing 6-16: Using Column Indexes
Start example
...
java.sql.Statement myStatement = myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary
                          FROM employees");
while (rs.next()) {
         // print the columns of the row that was retrieved
         String empName = rs.getString(1);
         String empTitle = rs.getString(2);
         long empSalary = rs.getLong(3);
         System.out.println("Employee " + empName + " is " + empTitle + "
                          and earns $" + empSalary);
}
...
...
End example

By column names

Column names may be more convenient to use than column indexes. The following are the getXXX() methods supporting column names.

ResultSet’s Methods to Access Columns by Name

String getString(String columnName);
boolean getBoolean(String columnName);
byte getByte(String columnName);
short getShort(String columnName);
int getInt(String columnName);
long getLong(String columnName);
float getFloat(String columnName);
double getDouble(String columnName);
byte[] getBytes(String columnName);
java.sql.Date getDate(String columnName);
java.sql.Date getDate(String columnName, java.util.Calendar cal);
java.sql.Time getTime(String columnName);
java.sql.Timestamp getTimestamp(String columnName);
java.sql.Timestamp getTimestamp(String columnName, java.util.Calendar cal);
java.io.InputStream getAsciiStream(String columnName);
java.io.InputStream getBinaryStream(String columnName);
Object getObject(String columnName);
Object getObject(String columnName, java.util.Map map);
java.sql.Array getArray(String columnName);
java.math.BigDecimal getBigDecimal(String columnName);
java.sql.Blob getBlob(String columnName);
java.sql.Clob getClob(String columnName);
java.io.Reader getCharacterStream(String columnName);
java.sql.Ref getRef(String columnName);
java.net.URL getURL(String columnName);
return_type getXXX(String columnName);

The parameter should match exactly with the row’s column name that needs to be accessed.

Listing 6-17 contains the same example as Listing 6-16, except using column names instead of column indexes.

Listing 6-17: Using Column Names
Start example
...
java.sql.Statement myStatement =
myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary FROM
employees");
while (rs.next()) {
         // print the columns of the row that was retrieved
         String empName = rs.getString("name");
         String empTitle = rs.getString("title");
         long empSalary = rs.getLong("salary");
         System.out.println("Employee " + empName + " is " + empTitle +
         " and earns $" + empSalary);
}
...
...
End example

Managing multiple result types

As discussed earlier, the methods that send SQL queries and SQL updates are different. SQL queries return result sets; SQL updates return a count of the rows updated. SQL statements normally execute using query and update methods. However, under some circumstances, it may be difficult to estimate the type of result. An application may not know whether a given SQL statement will return a result set or a counter until the statement executes, as, for example, in the case of an interactive query tool or when calling a stored procedure.

A mechanism is provided to accommodate these needs. It allows an application to execute statements and then process an arbitrary collection of sets of rows and single update counts. Figure 6-10 gives an idea of the steps performed in this scenario.

How is it possible to distinguish the difference between return types? The following methods provide the answer.

Statement’s Methods for Dealing with Multiple Result Types

boolean execute(String sql);
ResultSet getResultSet();
int getUpdateCount();
boolean getMoreResults();
boolean getMoreResults(int current);

Figure 6-10 provides an overview of the logic needed to manage multiple result types.

Click To expand
Figure 6-10: An overview of managing multiple result types.

The SQL string passed as a parameter to the method boolean execute(String sql); is a statement that may return multiple results or a statement whose return type is unknown in advance, programmatically speaking. Simple SQL statements usually return either an update count or a result set. However, certain stored procedures may return update counts or result sets, sometimes mixed together. This method gives an indication on the form of the result or of the first result, in case multiple results are returned. This method returns true if a result set is available or false if the result of the execution of the SQL string is an integer such as an update count.

The method getResultSet() in the second line of the preceding returns the current result as a ResultSet. It can be called only once per result. The result set is then scanned by the usual method. This method may also be used to verify that the current result is a result set, in which case it doesn’t return null. A null return means that there are no more results or the result is an update count, in which case it should be fetched with the getUpdateCount() method.

The method getUpdateCount() in the third line of the preceding returns the current result, which should be an integer value or -1 if it is a result set or if there are no more results. It should be called only once per result.

The method in the following two lines moves to a statement’s next result:

boolean getMoreResults();
boolean getMoreResults(int current);

In case the statement’s next result is a result set, these methods return true. They return false if the result is an integer or there are no more results. The getMoreResults() method implicitly closes a current result set obtained with getResultSet(). When used with an integer argument, the getMoreResults() method can preserve the latest result set. There are three possible values for this argument:

  • CLOSE_CURRENT_RESULT: The current result set is closed as soon as a new result set is returned.

  • KEEP_CURRENT_RESULT: The current result set isn’t closed while fetching the next one.

  • CLOSE_ALL_RESULTS: All previous result sets will be closed when the next result is returned.

There are no more results after (!getMoreResults() && (getUpdateCount() == -1)).

Listing 6-18 best illustrates the mechanism used to discover the result type of a statement.

Listing 6-18: Discovering the Result Type
Start example
...
Connection myConnection = DriverManager.getConnection(url,
                          "javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
ResultSet rs;
if (myStatement.execute(sqlStatement))
{
         // we have a ResultSet
         rs = myStatement.getResultSet();
         while (rs.next())
         {
                 // process the rows
         }
}
else
{
         // we have an update count
         System.out.println(myStatement.getUpdateCount());
}
myStatement.close();
myConnection.close();
...
...
End example

The example in Listing 6-19 is adapted to process the results of a statement that returns multiple results — both result sets and update counts in arbitrary order.

Listing 6-19: Handling Multiple Result Types
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
    "javauser", "hotjava");
Statement myStatement = myConnection.createStatement();
boolean resultSetIsAvailable;
boolean moreResultsAvailable;
int i = 0;
int res=0;
resultSetIsAvailable = myStatement.execute(sqlText);
ResultSet rs = null;
for (moreResultsAvailable = true; moreResultsAvailable; )
{
         if (resultSetIsAvailable)
         {
                 if ((rs = myStatement.getResultSet()) != null) {
                          // we have a resultset
                          ResultSetMetaData rsmd = rs.getMetaData();
                          int numCols = rsmd.getColumnCount();
                          // display column headers
                          for (i = 1; i <= numCols; i++)
                          {
                                  if (i > 1) System.out.print(", ");
                                  System.out.print(
                                  rsmd.getColumnLabel(i));
                          }
                          System.out.println("");
                          // step through the rows
                          while (rs.next())
                          {
                                  // process the columns
                                  for (i = 1; i <= numCols; i++)
                                  {
                                           if (i > 1)
                                           System.out.print(", ");
                                           System.out.print(rs.getString(i));
                                  }
                                  System.out.println("");
                          }
                 }
         }
         else
         {
                 if ((res = curStmt.getUpdateCount()) != -1)
                 {
                          // we have an updatecount
                          System.out.println(res + " row(s) affected.");
                 }
                 // else no more results
                 else
                 {
                          moreResultsAvailable = false;
                 }
         }
         if (moreResultsAvailable)
         {
                 resultSetIsAvailable =
                    myStatement.getMoreResults(Statement.CLOSE_ALL_RESULTS);
         }
}
if (rs != null) rs.close();
myStatement.close();
...
...
End example

Canceling unwanted results

It may happen that a statement’s result is no longer needed for one or another reason. In this case, closing the result set will usually be sufficient (see the close() method in the next section, "Closing the result set"). However, a cancel() method exists and may be called on the statement object, as shown in the following. It may be called from a thread to cancel a statement being executed within another thread.

Statement’s Cancel Method

void cancel();

The cancel() method, shown in Listing 6-20, cancels a statement being executed.

Note

Note that the cancel() method is applicable only to statements that return either a single result set or multiple results — not to statements that are composed of a single SQL update, insert, or delete.

Listing 6-20: Canceling Unwanted Results
Start example
...
java.sql.Statement myStatement =
myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary FROM
employees");
int i = 0;
while (rs.next()) {
         // increment the counter
         i++;
         // print the columns of the row that was retrieved
         String empName = rs.getString("name");
         String empTitle = rs.getString("title");
         long empSalary = rs.getLong("salary");
         System.out.println("Employee " + empName + " is " + empTitle + "
                          and earns $" + empSalary);
         // cancel all results if 100 rows of data were already
         // retrieved
         if (i >= 100) myStatement.cancel();
}
...
...
End example

Closing the result set

As in the case with statements and connections, result sets must be closed when no longer needed.

ResultSet’s Close Method

void close();

This method closes the result set and releases database and JDBC resources associated with it. When a statement object is closed, re-executed, or used to retrieve the next result of multiple result sets, its result set is automatically closed.

Converting types

Depending on the situation, it may be necessary to perform automatic conversions between SQL types used in a specific result set column and Java types. For example, you can use getString() to access an element of SQL type DATE. The short example in Listing 6-21 shows how to force a conversion of SQL type DATE to Java String.

Listing 6-21: Type Conversion of DATE to String
Start example
...
java.sql.Statement myStatement = myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, datehired, salary FROM
employees");
while (rs.next()) {
         // print the values of the row that was retrieved
         String empName = rs.getString("name");
         String empDateHired = rs.getString("datehired");
         long empSalary = rs.getLong("salary");
         System.out.println("Employee " + empName + " was hired on the " +
                 empDateHired + " and earns $" + empSalary);
}
...
...
End example

Table 6-4 shows the supported conversions via the getXXX() methods. Unsupported conversions usually raise a SQLException when attempted.

Table 6-4: JAVA TO SQL TYPE CONVERSIONS
 | TINYINT | SMALLINT | INTEGER | BIGINT | REAL | FLOAT |
 | DOUBLE | DECIMAL | NUMERIC | BIT | CHAR | VARCHAR |
 | DOUBLE | DECIMAL | NUMERIC | BIT | CHAR | VARCHAR |
 | LONGVARCHAR | BINARY | VARBINARY | LONGVARBINARY |  |  |
 | DATE | TIME | TIMESTAMP |  |  |  |
 | DATE | TIME | TIMESTAMP |  |  |  |
 | CLOB | BLOB | ARRAY | REF | DATALINK | STRUCT | JAVA_OBJECT
getByte() | J | K | K | K | K | K |
getShort() | K | J | K | K | K | K |
getInt() | K | K | J | K | K | K |
getLong() | K | K | K | J | K | K |
getFloat() | K | K | K | K | J | K |
getDouble() | K | K | K | K | K | J |
getBigDecimal() | K | K | K | K | K | K |
getBoolean() | K | K | K | K | K | K |
getString() | K | K | K | K | K | K |
getBytes() | - | - | - | - | - | - |
getDate() | - | - | - | - | - | - |
getTime() | - | - | - | - | - | - |
getTimestamp() | - | - | - | - | - | - |
getAsciiStream() | - | - | - | - | - | - |
getCharacterStream() | - | - | - | - | - | - |
getBinaryStream() | - | - | - | - | - | - |
getObject() | K | K | K | K | K | K |
getClob() | - | - | - | - | - | - |
getBlob() | - | - | - | - | - | - |
getArray() | - | - | - | - | - | - |
getRef() | - | - | - | - | - | - |
getURL() | - | - | - | - | - | - |
getByte() | K | K | K | K | K | K |
getShort() | K | K | K | K | K | K |
getInt() | K | K | K | K | K | K |
getLong() | K | K | K | K | K | K |
getFloat() | K | K | K | K | K | K |
getDouble() | J | K | K | K | K | K |
getBigDecimal() | K | J | J | K | K | K |
getBoolean() | K | K | K | J | K | K |
getString() | K | K | K | K | J | J |
getBytes() | - | - | - | - | - | - |
getDate() | - | - | - | - | K | K |
getTime() | - | - | - | - | K | K |
getTimestamp() | - | - | - | - | K | K |
getAsciiStream() | - | - | - | - | K | K |
getCharacterStream() | - | - | - | - | K | K |
getBinaryStream() | - | - | - | - | - | - |
getObject() | K | K | K | K | K | K |
getClob() | - | - | - | - | - | - |
getBlob() | - | - | - | - | - | - |
getArray() | - | - | - | - | - | - |
getRef() | - | - | - | - | - | - |
getURL() | - | - | - | - | - | - |
getByte() | K | - | - | - |  |  |
getShort() | K | - | - | - |  |  |
getInt() | K | - | - | - |  |  |
getLong() | K | - | - | - |  |  |
getFloat() | K | - | - | - |  |  |
getDouble() | K | - | - | - |  |  |
getBigDecimal() | K | - | - | - |  |  |
getBoolean() | K | - | - | - |  |  |
getString() | K | K | K | K |  |  |
getBytes() | - | J | J | K |  |  |
getDate() | K | - | - | - |  |  |
getTime() | K | - | - | - |  |  |
getTimestamp() | K | - | - | - |  |  |
getAsciiStream() | J | K | K | K |  |  |
getCharacterStream() | J | K | K | K |  |  |
getBinaryStream() | - | K | K | J |  |  |
getObject() | K | K | K | K |  |  |
getClob() | - | - | - | - |  |  |
getBlob() | - | - | - | - |  |  |
getArray() | - | - | - | - |  |  |
getRef() | - | - | - | - |  |  |
getURL() | - | - | - | - |  |  |
getByte() | - | - | - |  |  |  |
getShort() | - | - | - |  |  |  |
getInt() |  | - | - |  |  |  |
getLong() | - | - | - |  |  |  |
getFloat() | - | - | - |  |  |  |
getDouble() | - | - | - |  |  |  |
getBigDecimal() | - | - | - |  |  |  |
getBoolean() | - | - | - |  |  |  |
getString() | K | K | K |  |  |  |
getBytes() | - | - | - |  |  |  |
getDate() | J | - | K |  |  |  |
getTime() | - | J | K |  |  |  |
getTimestamp() | K | - | J |  |  |  |
getAsciiStream() | - | - | - |  |  |  |
getCharacterStream() | - | - | - |  |  |  |
getBinaryStream() | - | - | - |  |  |  |
getObject() | K | K | K |  |  |  |
getClob() | - | - | - |  |  |  |
getBlob() | - | - | - |  |  |  |
getArray() | - | - | - |  |  |  |
getRef() | - | - | - |  |  |  |
getURL() | - | - | - |  |  |  |
getByte() | - | - | - | - | - | - | -
getShort() | - | - | - | - | - | - | -
getInt() | - | - | - | - | - | - | -
getLong() | - | - | - | - | - | - | -
getFloat() | - | - | - | - | - | - | -
getDouble() | - | - | - | - | - | - | -
getBigDecimal() | - | - | - | - | - | - | -
getBoolean() | - | - | - | - | - | - | -
getString() | - | - | - | - | - | - | -
getBytes() | - | - | - | - | - | - | -
getDate() | - | - | - | - | - | - | -
getTime() | - | - | - | - | - | - | -
getTimestamp() | - | - | - | - | - | - | -
getAsciiStream() | - | - | - | - | - | - | -
getCharacterStream() | - | - | - | - | - | - | -
getBinaryStream() | - | - | - | - | - | - | -
getObject() | - | - | - | - | - | J | J
getClob() | J | - | - | - | - | - | -
getBlob() | - | J | - | - | - | - | -
getArray() | - | - | J | - | - | - | -
getRef() | - | - | - | J | - | - | -
getURL() | - | - | - | - | J |  |

J means that the corresponding method is recommended.

K means that the corresponding get method can be used.

Note that it may be convenient to convert all SQL types to a string when retrieving data to display it in tabular format. The getString() method accepts any type and always does the implicit conversion to a Java string. Chapter 7 provides more information on SQL data types and Java types.

Receiving BLOBs

Retrieving pictures, sounds, and movies from a database is an expected JDBC function. It makes sense in the context of applets delivered via Web pages, but because Java has a fair set of multimedia facilities, it makes sense in standalone Java applications as well.

As for sending such binary large objects, Java streams are used to retrieve LONGVARBINARY or LONGVARCHAR data. However, you can also retrieve the data in fixed-size chunks. The limits are imposed by the Statement.getMaxFieldSize() value. Another limitation due to underlying implementation constraints is that each stream must be accessed immediately after the get method. Indeed, the streams will be closed on successive get calls on the result set.

Three separate methods support the retrieval of streams:

  • getBinaryStream(): The returned stream supports raw bytes. It doesn’t perform any conversion.

  • getAsciiStream(): Returns a stream providing 1-byte wide ASCII characters.

  • getUnicodeStream(): Returns a stream providing 2-byte wide Unicode characters.

These methods are listed in the earlier section “Accessing columns.”

Listing 6-22 shows how to retrieve binary large objects from a database. The fields containing a BLOB are emp_pict and emp_welcome.

Listing 6-22: Retrieving BLOBs
Start example
...
java.sql.Statement myStatement = myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, emp_pict, emp_welcome FROM
employees");
// we retrieve in 4K chunks
byte[] buffer = new byte[4096];
int size;
while (rs.next()) {
         // fetch employee’s name
         String empName = rs.getString("name");
         // fetch employee’s picture
         java.io.InputStream strin = rs.getBinaryStream("emp_pict");
         for (;;)
         {
                 size = strin.read(buffer);
                 if (size == 0)
                 {
                          break;
                 }
                 // Send the buffer to some output stream
                 output.write(buffer, 0, size);
         }
         // fetch employee’s voicemail welcome message
         java.io.InputStream strin2 = rs.getBinaryStream("emp_welcome");
         for (;;)
         {
                 size = strin2.read(buffer);
                 if (size == 0)
                 {
                          break;
                 }
                 // Send the buffer to some output stream
                 output.write(buffer, 0, size);
         }
}
...
...
End example

Adjusting properties

Properties that affect result sets may be set or queried through various methods. Always verify that the settings are as independent of the data source as possible.

Data truncation on reads

Data truncation may happen when reading data from a database. How it is handled depends on the circumstances. Normally, data truncation results in a warning. However, if the maximum field size is set to a certain value and if the application attempts to read a field larger than the limit, the data will be silently truncated to the maximum limit. (The setMaxFieldSize() and getMaxFieldSize() are explained in the "Sending SQL Statements" section, earlier in this chapter.)

Statement’s Methods to Specify a Maximum Field Size

void setMaxFieldSize(int max);
int getMaxFieldSize();

Listing 6-23 shows how to manage data truncation on reads.

Listing 6-23: Managing Data Truncation on Reads
Start example
...
java.sql.Statement myStatement =
myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary FROM
employees");
myStatement.setMaxFieldSize(128);
while (rs.next()) {
         // print the columns of the row that was retrieved
         String empName = rs.getString("name");
         String empTitle = rs.getString("title");
         long empSalary = rs.getLong("salary");
         System.out.println("Employee " + empName + " is " +
                 empTitle + " and earns $" + empSalary);
}
...
...
End example

Limiting the number of rows

Under some circumstances, it may not be useful or preferable to retrieve thousands or more of rows of data. One such circumstance is if the data destination is the user’s screen. Although you should always build and send queries that make sense to be able to exploit their result, it may happen that the number of returned rows is unpredictable. In this case, it is possible to set a limit for the number of rows returned. The following methods are used to set and get this limit.

Statement’s Limit for the Number of Rows in a Result Set

void setMaxRows(int max);
int getMaxRows();

The method in the first line of the preceding sets the maximum limit to max. In other words, max is the maximum number of rows that a result set can contain. If the limit is exceeded, the excess rows will be silently dropped from the result set.

The code in the second line of the preceding returns the current value of the limit. A value of zero means no limit at all.

Listing 6-24 shows how to limit the number of rows returned by a query.

Listing 6-24: Limiting the Number of Rows Returned by a Query
Start example
...
...
java.sql.Statement myStatement =
myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary FROM
employees");
// we do not want more than 1000 rows of data retrieved
myStatement.setMaxRows(1000);
while (rs.next()) {
         // print the columns of the row that was retrieved
         String empName = rs.getString("name");
         String empTitle = rs.getString("title");
         long empSalary = rs.getLong("salary");
         System.out.println("Employee " + empName + " is " +
                 empTitle + " and earns $" + empSalary);
}
...
...
End example

Examining the results

The following two methods are useful for examining and navigating through a resulting row of data.

ResultSet’s Methods for Examining Results

boolean wasNull();
int findColumn(String columnName);

In case a column has the value of SQL NULL, the method in the first line of the preceding returns true. Note that it should be called after calling the getXXX() method to access the column.

The method in the second line of the preceding attempts to find the index of the column name passed in a parameter. It returns the column index as an integer. If the column name doesn’t exist, either a -1 value is returned or a SQLException is thrown by the driver. The specification doesn’t enforce one or the other approach.

Listing 6-25 shows how to examine the columns of a result set.

Listing 6-25: Examining the Columns of a Result Set
Start example
...
...
java.sql.Statement myStatement =
myConnection.createStatement();
ResultSet rs = myStatement.executeQuery("SELECT name, title, salary FROM
employees");
while (rs.next()) {
         // print the columns of the row that was retrieved
         String empName = rs.getString("name");
         if rs.wasNull() System.out.println("Ooops, column " +
                 rs.findColumn("name") + " is NULL!");
         String empTitle = rs.getString("title");
         if rs.wasNull() System.out.println("Ooops, column " +
                 rs.findColumn("title") + " is NULL!");
         long empSalary = rs.getLong("salary");
         if rs.wasNull() System.out.println("Ooops, column " +
                 rs.findColumn("salary") + " is NULL!");
         System.out.println("Employee " + empName + " is " +
                 empTitle + " and earns $" + empSalary);
}
...
...
End example

Creating SQL cursors

Cursors are often used when programming database applications. They offer a practical way of scanning the result sets and perform positioned delete and updates. Cursors are also quite useful when navigating a result set: They allow for results to be transferred per chunks from the database engine to the driver instead of the complete set of rows returned by a particular query. The following method is used to obtain the name of the cursor for a given result set:

ResultSet’s Method for Cursor Support

String getCursorName();

When a result table is retrieved, a named cursor is created. This cursor is used when stepping through the result set rows and can be used to update or delete data pointed to by the cursor. This use of cursors is called positioned update/positioned delete. JDBC supports this feature by giving the name of the SQL cursor used by a result set. Note that if positioned update/delete isn’t supported by the DBMS, a SQLException will be thrown.

Putting it all together again

Figure 6-11 summarizes all the steps covered in this chapter. They are the essential steps for communicating with a database, sending queries and updates, and retrieving the results from Java.

Listing 6-26 provides an example of all the steps discussed so far in this chapter.

Click To expand
Figure 6-11: An overview of all the steps for communicating with a database.
Listing 6-26: Retrieving Results
Start example
// retrieving results
// the SQL statement is taken from the standard input
import java.sql.*;
import java.io.*;
class SimpleExample
{
    public static void main(String argv[])
    {
        String url = "jdbc:odbc:mysource";
        try {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            Connection myConnection =
                DriverManager.getConnection(url, "javauser",
                                            "hotjava");
            Statement myStatement = myConnection.createStatement();
            boolean resultSetIsAvailable;
            boolean moreResultsAvailable;
            int i = 0;
            int res=0;
            String sqlText =
                (new DataInputStream(System.in)).readLine();
            resultSetIsAvailable = myStatement.execute(sqlText);
            ResultSet rs = null;
            for (moreResultsAvailable = true; moreResultsAvailable; ) {
                if (resultSetIsAvailable) {
                    if ((rs = myStatement.getResultSet()) != null) {
                        // we have a resultset
                        ResultSetMetaData rsmd = rs.getMetaData();
                        int numCols = rsmd.getColumnCount();
                        // display column headers
                        for (i = 1; i <= numCols; i++) {
                            if (i > 1)
                                System.out.print(",");

                            System.out.print(rsmd.getColumnLabel(i));
                        }
                        System.out.println("");
                        // step through the rows
                        while (rs.next()) {
                                // process the columns
                            for (i = 1; i <= numCols; i++) {
                                if (i > 1)
                                    System.out.print(", ");
                                System.out.print rs.getString(i));
                        }
                        System.out.println("");
                    }
                } else {
                    if ((res = myStatement.getUpdateCount()) != -1) {
                        // we have an updatecount
                        System.out.println(res + " row(s) affected.");
                    }
                                // else no more results
                    else {
                        moreResultsAvailable = false;
                    }
                }
                if (moreResultsAvailable) {
                    resultSetIsAvailable =
                        myStatement.getMoreResults();
                }
            }
            if (rs != null) rs.close();
            myStatement.close();
            myConnection.close();
        } catch(java.lang.Exception ex) {
            ex.printStackTrace();
        }
    }
}
End example


Managing Errors and Warnings

JDBC uses the exception mechanism to pass error or warning information to programs. This mechanism signals an abnormal condition that may be handled to prevent a program termination. The exception mechanism is used when a recoverable error occurs and it must be caught to correct the situation.

SQLException

When a database access error occurs, a SQLException is thrown that provides information on the error. Each SQLException provides several kinds of information:

  • A description of the error, used as the Java Exception message.

  • A SQLstate string that conforms to the XOPEN SQLstate conventions.

  • A vendor-specific error code, usually the actual DBMS error code.

  • A chain to a next exception, if any.

SQLExceptions can occur when trying to connect to a database with an invalid login or password or when trying to access a nonexistent database object such as a table, a table’s column, or a stored procedure. They can also occur during SQL updates and inserts when values provided for the columns are too large, for example, or when types don’t match or can’t be converted implicitly. There can be several other reasons for SQLExceptions to occur; you should refer to the driver’s documentation for specific exception codes and exception messages.

The following methods may be used within a program on a SQLException object:

SQLException Methods

String getMessage();
String getSQLState();
int getErrorCode();
SQLException getNextException();

The message that is used as the Java exception message is available via the method in the first line of the preceding and is returned as a string.

The method getSQLstate in the second line of the preceding conforms to the XOPEN SQLstate definition.

The method in the third line of the preceding returns the vendor-specific exception code. You should refer to the driver documentation for more information about the possible error codes.

The method in the last line of the preceding, SQLException getNextException();, is used to get the SQLException chained to the current one. Indeed, several SQLExceptions can be chained together when a problem causes other problems to arise within the database or driver.

In all the earlier listing examples in this chapter, you are able to catch SQLExceptions without doing anything special after you catch them. The next example, Listing 6-27, shows how to use exception information. Because exceptions signal an abnormal condition, you use the provided information to try to continue the program execution.

Listing 6-27: Catching SQLExceptions
Start example
// catching SQLExceptions
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                            DriverManager.getConnection(url,
                            "javauser", "hotjava");
                          Statement myStatement = myConnection.createStatement();
                          ResultSet rs = myStatement.executeQuery(
                            "SELECT * FROM employees");
                          // ...
                          myStatement.close();
                          myConnection.close();
                 }
                 catch(SQLException ex)
                 {
                          // there may be multiple error objects
                          // chained together
                          System.out.println("\n*** SQLException caught ***\n");
                          while (ex != null)
                          {
                                  System.out.println("SQLState: "
                                    + ex.getSQLState());
                                  System.out.println("Message: "
                                    + ex.getMessage());
                                  System.out.println("Vendor Code: "
                                    + ex.getErrorCode());
                                  System.out.println("");
                                  ex.getNextException();
                          }
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

SQLWarning

The SQLWarning class provides information on database access warnings. Such warnings are silently chained to the class instance whose method caused it to be reported until they are fetched with the following method.

SQLWarnings can happen when implicit data type conversions occur during a SQL insert or update, for example, and when the conversions cause data precision loss. If decimal digits are lost, the driver may throw a SQLWarning. This is driver dependent, so I recommend that you verify which SQLWarnings can be thrown in the manuals of your specific JDBC driver.

Connection, Statement, or ResultSet’s getWarnings Method

SQLWarning getWarnings();

SQLWarning getWarnings() returns a SQLWarning object or null if no warning occurred.

The SQLWarning class, which extends SQLException, provides the following methods.

SQLWarning’s Methods

String getMessage();
String getSQLState();
int getErrorCode();
SQLWarning getNextWarning();

The warning message is available via the method in the first line of the preceding and is returned as a string.

The method getSQLstate in the second line of the preceding conforms to the XOPEN SQLstate definition.

The method in the third line of the preceding returns the vendor-specific warning code. Refer to the vendor’s documentation for more information.

This method in the last line of the preceding, SQLWarning getNextWarning();, is used to get the SQLWarning chained to the current one.

The example in Listing 6-28 shows how to check for warnings. You explicitly call the getWarnings() method on the Connection, statement, and result set objects. The code for checkWarnings() is a generic method to handle all warnings that may occur during the program execution.

Listing 6-28: Checking SQLWarnings
Start example
// checking SQLWarnings
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                            DriverManager.getConnection(url,
                          "javauser", "hotjava");
                          checkWarnings(myConnection.getWarnings());
                          Statement myStatement = myConnection.createStatement();
                          checkWarnings(myStatement.getWarnings());
                          ResultSet rs = myStatement.executeQuery(
                            "SELECT * FROM employees");
                          checkWarnings(rs.getWarnings());
                          // ...
                          myStatement.close();
                          myConnection.close();
                 }
                 catch(SQLException ex)
                 {
                          // there may be multiple error objects
                          // chained together
                          System.out.println("\n*** SQLException caught ***\n");
                          while (ex != null)
                          {
                                  System.out.println("SQLState: "
                                    + ex.getSQLState());
                                  System.out.println("Message: "
                                    + ex.getMessage());
                                  System.out.println("Vendor Code: "
                                    + ex.getErrorCode());
                                  System.out.println("");
                                  ex.getNextException();
                          }
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }

         private static void checkWarnings(SQLWarning warn) throws SQLException
         {
                 if (warn != null)
                 {
                          // there may be multiple warnings chained
                          // together
                          System.out.println("\n*** SQLWarning caught ***\n");
                          while (warn != null)
                          {
                                  System.out.println("SQLState: "
                                    + warn.getSQLState());
                                  System.out.println("Message: "
                                    + warn.getMessage());
                                  System.out.println("Vendor Code: "
                                    + warn.getErrorCode());
                                  System.out.println("");
                                  warn.getNextWarning();
                          }
                 }
         }
}
End example

Data truncation

When JDBC unexpectedly truncates data on a read, a data truncation warning is reported. When it occurs on a write, a data truncation exception is thrown. In both cases, the SQLstate is set to 01004.

The following set of methods is available to discover what happened:

DataTruncation’s Methods

int getDataSize();
int getTransferSize();
int getIndex();
boolean getParameter();
boolean getRead();

The method in the first line of the preceding returns the number of bytes that should have been transferred. It returns -1 if the size is unknown. The size may be an approximation if data conversions occurred.

The method in the second line of the preceding returns the number of bytes actually transferred. A -1 means that the size is unknown.

The method in the third line of the preceding gets the index of the column or parameter that was truncated. A -1 means that the index is unknown, in which case the next two methods in this list should be ignored.

boolean getParameter(); returns true if the value truncated was passed through a statement’s parameter. It returns false if it was returned by a column.

boolean getRead(); returns true if the data truncation occurred on a database read. It returns false if the data was truncated on a write. Listing 6-29 shows how to catch a data truncation exception.

Listing 6-29: Catching a Data Truncation Exception
Start example
...
...
{
try
{
         // initiate a connection,
         // then execute a statement
         // ...
}
catch(DataTruncation ex)
{
         System.out.println("\n*** DataTruncationexception caught ***\n");
         int idx = ex.getIndex();
         System.out.print("Index: " + idx);
         if (idx != -1)
         {
                 if (ex.getParameter())
                 {
                          // the truncation happened
                          // in a parameter
                          System.out.print(" of the set of parameters");
                 }
                 else
                 {
                          // the truncation happened
                          // on a resultset column
                          System.out.print(" in the resultset");
                 }
         }
         if (ex.getRead())
         {
                 // the truncation happened
                 // on a read
                 System.out.println(" was truncated on a read");
         }
         else
         {
                 // the truncation happened
                 // on a write
                 System.out.println(" was truncated on a write");
         }
         System.out.println("It was: " + ex.getDataSize() + " bytes long");
         System.out.println("Actual size: " + ex.getTransferSize()
           + " bytes transferred");
         System.out.println("");
}
...
...
End example


Summary

In this chapter, you discovered the essential steps for communicating with a database:

  • Import java.sql.* to avoid long member names.

  • Build a JDBC URL.

  • Load one or more specific JDBC drivers with class.forName().

  • If necessary, adjust the connection properties.

  • Open a connection with getConnection().

  • Create a statement object.

  • Build a SQL statement.

  • Execute the SQL statement.

  • Manage multiple result sets.

  • Fetch rows of data in cases of a result set of rows.

  • Fetch columns of rows by column name or column index.

  • Fetch integer results.

  • Check for warnings.

  • Manage data truncation errors.

  • Close the result set.

  • Close the statement.

  • Terminate the connection with close().

  • Catch exceptions.

The next chapter discusses data type conversions, how to use the SQL escape syntax, what a database transaction is, and in which context programmers use transactions and also provides examples of using SQL cursors.


Chapter 7: Refining JDBC Queries and Updates

This chapter discusses advanced techniques for fine-tuning database queries and updates from JDBC.

The Internals of Driver and DriverManager

You can obtain detailed information from Driver and DriverManager through a set of methods. They are advanced functions, and a programmer usually won’t use Driver or DriveManager unless he wants to discover or set specific JDBC behaviors. Only those functions that are of the most interest to an application developer are listed in the following, the others being more useful for JDBC driver developers:

DriverManager’s Methods

void setLoginTimeout(int seconds);
int getLoginTimeout();
void setLogStream(java.io.PrintStream out);
java.io.PrintStream getLogStream();
void println(String logmessage);

The method in the first line of the preceding sets the maximum time allowed when attempting to log in to a database. All registered JDBC drivers use the time-out value, expressed in seconds. An exception occurs whenever the timer expires.

The method getLoginTimeout() in the second line of the preceding returns the current time-out value.

The JDBC logging facility, as shown in the third line of the preceding, is used in listings in other chapters. It allows the tracing of all JDBC activity during program execution by providing a PrintStream. After the log stream has been set, you can disable the tracing facility by providing a null parameter to the setLogStream() method. Note that this method is now deprecated.

The method getLogStream() in the fourth line of the preceding (java.io. PrintStream getLogStream();) returns the current JDBC logging PrintStream or null if logging is disabled. This method is now deprecated.

The method in the last line of the preceding (void println(String logmessage);) is used on the DriverManager object to print a message on the current JDBC log stream. DriverManager is very talkative, and this facility may be useful for inserting your own messages in the log stream. println() is now deprecated.

Driver’s Methods

boolean acceptsURL(String url);
int getMajorVersion();
int getMinorVersion();
boolean jdbcCompliant();
DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info);

In some cases, it may be of interest to know if a particular driver is able to connect to the given uniform resource locator (URL). The method in the first line of the preceding returns true if the driver is able to understand the subprotocol specified in the URL.

The method in the second line of the preceding returns the driver’s major version number.

The method in the third line of the preceding returns the driver’s minor version number.

In case the driver fully supports the JDBC API and SQL 92 Entry Level, the method in the fourth line of the preceding returns true. Using the jdbcCompliant() method is a good way to verify that a driver is JDBC compliant. As shown in Listing 7-1, it may be a good exercise to get driver information for a few JDBC drivers that you intend to use.

Listing 7-1: Getting Information about the Driver
Start example
// getting driver info
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 try
                 {
                          Driver myDriver = new jdbc.foobar.MyDriver();
                          DriverManager.registerDriver(myDriver);
                          DriverManager.setLogStream(
                                  java.lang.System.out);
                          System.out.println("Connection to" +
                                  "jdbc:mydriver://javabank.com/ possible? " +
                                  myDriver.acceptsURL
                                  ("jdbc:mydriver://javabank.com/"));
                          System.out.println("Major Version: " +
                                  myDriver.getMajorVersion());
                          System.out.println("Minor Version: " +
                                  myDriver.getMinorVersion());
                          System.out.println("JDBC COMPLIANT driver? "
                                  + myDriver.jdbcCompliant());
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

The method in the line

DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info);

returns an array of DriverPropertyInfo objects describing the driver’s possible properties. It takes the URL as an argument as well as a proposed list of property name/value pairs that will be sent to open the connection. An empty array is returned when no properties are required. Note that the name/value pair is arbitrary and depends on the driver.

The getPropertyInfo() method is used to discover what properties should be provided to make a connection to a database. It can, for example, be used within a generic graphical user interface (GUI) tool that has no prior knowledge about the properties that it should prompt a user for to get the connection. The DriverPropertyInfo objects should be analyzed to discover the possible properties, both those that are required and those that are optional. It may be necessary to iterate through several calls to the getPropertyInfo() method because additional property values may become necessary, as soon as the values are supplied.

The DriverPropertyInfo class is composed of the following members:

DriverPropertyInfo’s Attributes

String DriverPropertyInfo.name;
String DriverPropertyInfo.description;
boolean DriverPropertyInfo.required;
String DriverPropertyInfo.value;
String[] DriverPropertyInfo.choices;

String DriverPropertyInfo.name is the name of the property. This keyword enables you to uniquely name a specific property. The properties are arbitrary name/value pairs; therefore, no mandatory properties exist. Refer to the JDBC driver documentation to find out about its specific properties.

String DriverPropertyInfo.description gives a description of the property. It may be null.

boolean DriverPropertyInfo.required is set to true if a value must be supplied to the property during a Driver.connect(). false means that the property isn’t mandatory to establish a connection using this specific JDBC driver.

String DriverPropertyInfo.value is the current value of the property or null if no value is known.

If the property can be chosen from a set of values, the array in the last line of the preceding (String[] DriverPropertyInfo.choices) contains the possible choices as String values.


SQL Data Type Conversions

Java data types aren’t exactly isomorphic to SQL data types. However, mapping SQL data types into Java enables users to store and retrieve data without losing information.

Mapping data types to Java

When types are known at compile time, the mappings shown in this section are used. Note that JDBC also provides a mechanism to fully support dynamically typed data access when result and parameter types aren’t known at compile time (see 9).

Character strings

There are three SQL data types for SQL strings:

  • CHAR

  • VARCHAR

  • LONGVARCHAR

In Java, the String and char[] types hold these SQL data types. String is used as the default mapping because it is possible to convert a String to a char[] and a char[] to a String. Thus reading and writing data can be achieved without knowing the exact data type expected.

Space padding is automatically done whenever dealing with fixed-length types such as SQL CHAR(n). Spaces are added to the end of a string to set its length to n when a SQL CHAR(n) must be sent to the database. When a SQL CHAR(n) field is retrieved, additional padding is performed to get a string of length n.

Note that a LONGVARCHAR may overflow a string when retrieved using ResultSet.getString(). In this case, I advise retrieving the LONGVARCHAR field in small chunks by using a Java input stream. Overflow may occur when retrieving BLOBs (binary large objects) from the database.

Numbers

SQL integer types allow for 1- (TINYINT), 2- (SMALLINT), 4- (INTEGER), and 8-byte-wide values (BIGINT). They can, therefore, be mapped to Java types such as Java byte, short, int, and long, respectively.

Fixed-point numbers can be expressed as SQL DECIMAL and SQL NUMERIC, where absolute precision is preserved. They can be mapped to java.math.BigDecimal without losing precision. SQL DECIMAL and SQL NUMERIC can be used to perform addition, subtraction, multiplication, and division. Note that these SQL types can also be accessed as Java strings, although it is difficult to perform math on strings.

Floating-point numbers are mapped as follows: SQL REAL, which requires 7 digits of mantissa precision, to Java float and SQL FLOAT and SQL DOUBLE, which require 15 digits of mantissa precision, to Java double. Note that any character or numeric type data can be retrieved from the result set as String and then converted to the required numeric type.

XREF

ResultSetMetaData in Chapter 9 provides ways for finding out the data types of fields at runtime.

Binary types

SQL types BINARY, VARBINARY, and LONGVARBINARY can be expressed as byte arrays in Java. As with LONGVARCHAR fields, LONGVARBINARY fields can be retrieved using Java streams for multimegabyte data values.

The SQL BIT data type can be mapped to the Java boolean type.

Time-related types

The SQL DATE, TIME, and TIMESTAMP data types are time-related types. They can be expressed as java.sql.Date (yyyy-mm-dd), java.sql.Time (hh:mm:ss), and java.sql.Timestamp (yyyy-mm-dd hh:mm:ss.nanosecond), respectively.

Note that java.sql.Date, java.sql.Time, and java.sql.Timestamp are three subclasses of java.util.date. Depending on which one is in use, different java.util.date members are affected. These subclasses include the following:

  • java.sql.Date sets the java.util.date.hour, .minute, .second, and .milliseconds fields to zero.

  • java.sql.Time sets the java.util.date.year, .month, and .day fields according to 1970, January 1st.

  • java.sql.Timestamp has a similar behavior as java.sql.Time but also sets a nanosecond field.

BLOB and CLOB

You can use the java.sql.BLOB and java.sql.CLOB values to set and retrieve large objects containing bytes and characters, respectively. Objects of these types can be passed as parameter of prepared statements. Refer to Chapter 8’s coverage of Dynamic SQL for more information on how to use prepared statements. ResultSet.getBlob(int columnIndex) can be used to retrieve a BLOB value; ResultSet.getClob(int columnIndex) can be used to retrieve a CLOB value from a result set.

ARRAY

You can use the java.sql.Array value to set and retrieve SQL ARRAY values. You can pass objects of these types as parameter of prepared statements. Refer to Chapter 8’s coverage of Dynamic SQL for more information on how to use prepared statements. ResultSet.getArray(int columnIndex) can be used to retrieve a SQL ARRAY value.

REF

You can use the java.sql.Ref type to set and retrieve referenced values. In this case, the reference is similar to a pointer to an object. Ref ref = ResultSet.getRef(int columnIndex) returns the reference, and (Customer) ref.getValue() returns the actual object referenced by ref (in this case, an instance of Customer). Structured types referenced by a Ref object are set using maps, as explained in the section "Type mapping tables," later in this chapter.

DISTINCT

SQL DISTINCT values must be set and retrieved using the appropriate setXXX() and getXXX() method for the type on which the DISTINCT type is based. For example, a custom type called MONEY and defined as NUMERIC(10, 2) can be accessed as a java.math.BigDecimal.

STRUCT

A java.sql.Struct value must be set and retrieved using setObject() and getObject() methods. The Struct interface provides a getAttributes() method to access the attributes of a structured type as an array of java.lang.Object values.

DATALINK

SQL DATALINK types refer to data residing outside the database. The value for a DATALINK is a filename, for example. With JDBC, DATALINK values are represented as URLs using java.net.URL; therefore the getURL() and setURL() methods are used to access this type of value. Note that getString() or getObject() can be used as well.

Type mapping tables

Table 7-1 shows the standard mapping from SQL data types to Java types. Although they are common SQL data types, some databases may not support them.

Table 7-1: MAPPING TABLE FROM SQL TYPES TO JAVA TYPES
SQL Type | Java Type | Java Object Type
CHAR | String | String
VARCHAR | String | String
LONGVARCHAR | String | String
NUMERIC | java.math.BigDecimal | java.math.BigDecimal
DECIMAL | java.math.BigDecimal | java.math.BigDecimal
BIT | boolean | Boolean
BOOLEAN | boolean | Boolean
TINYINT | byte | Integer
SMALLINT | short | Integer
INTEGER | int | Integer
BIGINT | long | Long
REAL | float | Float
FLOAT | double | Double
DOUBLE | double | Double
BINARY | byte[] | byte[]
VARBINARY | byte[] | byte[]
LONGVARBINARY | byte[] | byte[]
DATE | java.sql.Date | java.sql.Date
TIME | java.sql.Time | java.sql.Time
TIMESTAMP | java.sql.Timestamp | java.sql.Timestamp
CLOB | Clob | Clob
BLOB | Blob | Blob
ARRAY | Array | Array
DISTINCT | Mapping of underlying type | Mapping of underlying type
STRUCT | Struct | Struct or SQLData
REF | Ref | Ref
DATALINK | java.net.URL | java.net.URL
JAVA_OBJECT | Underlying Java class | Underlying Java class

Table 7-2 shows the default mapping from Java types to SQL data types. The mapping from String is normally VARCHAR. Where the String length exceeds the driver’s limit on VARCHAR values, it becomes LONGVARCHAR. The same occurs with byte[] and BINARY, VARBINARY, and LONGVARBINARY.

Table 7-1: MAPPING TABLE FROM JAVA TYPES TO SQL TYPES
Java Type | SQL Type
String | VARCHAR or LONGVARCHAR
java.math.BigDecimal | NUMERIC
boolean | BIT or BOOLEAN
Boolean | BIT or BOOLEAN
byte | TINYINT
short | SMALLINT
int | INTEGER
Integer | INTEGER
Java Type | SQL Type
long | BIGINT
Long | BIGINT
float | REAL
Float | REAL
double | DOUBLE
Double | DOUBLE
byte[] | BINARY, VARBINARY, or LONGVARBINARY
java.sql.Date | DATE
java.sql.Time | TIME
java.sql.Timestamp | TIMESTAMP
Clob | CLOB
Blob | BLOB
Array | ARRAY
Struct | STRUCT
Ref | REF
java.net.URL | DATALINK
Java class | JAVA_OBJECT

Customizing type mapping

Type mapping is used with SQL user-defined types (UDTs). It is a technique that enables Java developers to map SQL structured and distinct types to Java classes. By default, a SQL STRUCT type is mapped to the java.sql.Struct interface, and a SQL DISTINCT type is mapped to the associated Java class. However, when dealing with custom maps, the JDBC Driver will use the custom mapping instead of the default when STRUCT or DISTINCT types are accessed with the getObject() and setObject() methods.

Defining a type map

Consider the EMPLOYEE user-defined type. In this example, I assume that EMPLOYEE is defined as the following:

ID INTEGER,
FIRSTNAME VARCHAR(50),
LASTNAME VARCHAR(50),
DEPT INTEGER,
HIREDATE DATE

To use type mapping, you must first implement a Java class that maps to the SQL user-defined type. This class must implement the java.sql.SQLData interface because the JDBC Driver looks for two specific methods to do the mapping; these methods are readSQL(SQLInput stream, String type) and writeSQL(SQLOutput stream). Listing 7-2 provides an example matching with the EMPLOYEE UDT.

Listing 7-2: Customized Type Mapping
Start example
import java.sql.*;
public class Employee implements SQLData {
         public int id;
         public String firstname;
         public String lastname;
         public int dept;
         public Date hireDate;

         private String sql_type;
         public String getSQLTypeName() { return sql_type; }

         public void readSQL(SQLInput stream, String type) throws SQLException {
                 sql_type = type;
                 id = stream.readInt();
                 firstname = stream.readString();
                 lastname = stream.readString();
                 dept = stream.readInt();
                 hireDate = stream.readDate();
         }

         public void writeSQL(SQLOutput stream) throws SQLException {
                 stream.writeInt(id);
                 stream.writeString(firstname);
                 stream.writeString(lastname);
                 stream.writeInt(dept);
                 stream.writeDate(hireDate);
         }
}
End example

The next step after implementing the map consists of defining the map to be used when accessing data typed as SQL UDT EMPLOYEE. This is fairly simple, as shown in Listing 7-3. The Employee class is associated to the EMPLOYEE user type using a java.util.Map object.

Listing 7-3: Setting the Map
Start example
// establish connection
// ...
try {
         java.util.Map map = conn.getTypeMap();
         // associate the Employee mapping class to the EMPLOYEE table
         map.put("shemaname.EMPLOYEE", Class.forName("Employee"));
         conn.setTypeMap(map);
         // ...
} catch (ClassNotFoundException e) {
         System.out.println(e.getMessage());
         exit();
}
End example

Accessing data using a type map

Accessing data using a type map is simply done with the getObject() and setObject() methods. The following example in Listing 7-4 illustrates how an EMPLOYEE user data type value is fetched with the Employee class as customized mapping.

Listing 7-4: Accessing Data Using a Type Map
Start example
// establish connection
// ...
try {
         java.util.Map map = conn.getTypeMap();
         map.put("shemaname.EMPLOYEE", Class.forName("Employee"));
         conn.setTypeMap(map);
         Statement st = conn.createStatement();
         ResultSet rs = st.executeQuery("SELECT empl from personnel");
         Employee empl;
         while (rs.next()) {
                 empl = (Employee) rs.getObject(1);
                 // ...
         }
} catch (Exception e) {
         System.out.println(e.getMessage());
         exit();
}
End example

SQL inheritance

Inheritance is possible for SQL structured types. For example, a user-defined type for DEVELOPER might extend EMPLOYEE and add a programming language attribute. You can access values of type DEVELOPER by using a customized type mapping, provided that the readSQL() and writeSQL() methods manage the inherited and noninherited attributes in the correct order.


The SQL Escape Syntax

To be JDBC-compliant, a database driver must support both SQL-2 entry level and semantics for some parts of the ANSI SQL-2 transitional level. Because the syntax used for this level is often different across DBMSs, JDBC provides an escape syntax for these semantics. The JDBC drivers convert the escape syntax into a DBMS-specific syntax, enabling portability of programs that require these features.

The escape syntax is the same as the escape syntax of Open Database Connectivity (ODBC). However, it may not be the same as the ANSI one. Its form is as follows:

{keyword parameters}

For stored procedures

The following escape syntax is adopted to call stored procedures. The ?= may be dropped when the stored procedure doesn’t return a result. The procedure parameters can be IN and/or OUT or simple literals.

{[?=] call stored_procedure_name [param1[, param2 ...]]}

For example, a stored procedure that returns a value and takes two parameters would be called as shown here:

{?= call proc_purge_employees employees, emp_messages}
XREF

Examples of Java programs calling stored procedures are provided in Chapter 8.

For the time and date

JDBC supports ISO standard formats for date, time, and timestamp. They must be escaped as shown here to be interpreted as expected:

{d ‘yyyy-mm-dd’}: To specify a date

{t ‘hh:mm:ss’}: To specify a time literal

{ts ‘yyyy-mm-dd hh:mm:ss.f...’} or {ts ‘yyyy-mm-dd hh:mm:ss’}: To specify a timestamp

For scalar functions

Scalar functions and their arguments must be escaped and preceded by the fn keyword. In JDBC, the following scalar functions, if supported by the driver, are translated into the DBMS’s specific syntax for these functions:

{fn function(args, ...)}: For scalar functions

System functions

{fn database()}: The database name

{fn user()}: The user’s name

Numeric functions

{fn abs(number)}

{fn acos(float)}

{fn asin(float)}

{fn atan(float)}

{fn atan2(float1, float2)}

{fn ceiling(number)}

{fn cos(float)}

{fn cot(float)}

{fn degrees(number)}

{fn exp(float)}

{fn floor(number)}

{fn log(float)}

{fn log10(float)}

{fn mod(int1, int2)}

{fn pi()}

{fn power(number, power)}

{fn radians(number)}

{fn rand(int)}

{fn round(number, places)}

{fn sign(number)}

{fn sin(float)}

{fn sqrt(float)}

{fn tan(float)}

{fn truncate(number, places)}

String functions

{fn ascii(string)}

{fn char(code)}

{fn concat(str1, str2)}

{fn difference(str1, str2)}

{fn insert(str1, start, len, str2)}

{fn lcase(string)}

{fn left(string, count)}

{fn length(string)}

{fn locate(str1, str2, start)}

{fn ltrim(string)}

{fn repeat(string, count)}

{fn replace(str1, str2, str3)}

{fn right(string, count)}

{fn rtrim(string)}

{fn soundex(string)}

{fn space(count)}

{fn substring(string, start, len)}

{fn ucase(string)}

Date and time functions

{fn curdate()}

{fn curtime()}

{fn dayname(date)}

{fn dayofmonth(date)}

{fn dayofweek(date)}

{fn dayofyear(date)}

{fn hour(time)}

{fn minute(time)}

{fn month(date)}

{fn monthname(date)}

{fn now()}

{fn quarter(date)}

{fn second(time)}

{fn timestampadd(interval, count, timestamp)}

{fn timestampdiff(interval, tstp1, tstp2)}

{fn week(date)}

{fn year(date)}

Other functions

{fn ifnull(expr, value)}

{fn convert(value, type)}: type can be any SQL datatype

For characters that have a special meaning

Special characters used for character matching, such as % and _ in LIKE clauses, must be escaped with an escape character to be interpreted literally. This escape character must be declared as

{escape ‘escapechar’}

This declaration must be included at the end of any SQL text where these characters have to be interpreted literally. In the example that follows, the qualification clause matches any value of field_n that begins with an underscore character:

SELECT * FROM table WHERE field_n LIKE ‘\_%’ {escape ‘\’}

For outer joins

Grammar for outer joins is database-dependent, but JDBC provides a portable way of using them. The JDBC escape syntax for outer joins is

{oj outerjoin}

where outerjoin includes the following:

table LEFT OUTER JOIN {table | outerjoin} ON searchcondition

For example, the following query can be used to list all employees and their pending messages (0 or more). Even employees who don’t have message entries will be returned by the query:

SELECT employees.name, emp_messages.message
FROM {oj employees LEFT OUTER JOIN emp_messages
ON employees.emp_id = emp_messages.emp_id}

For Sybase XI, this SQL statement would translate to the following query:

SELECT employees.name, emp_messages.message
FROM employees, emp_messages
WHERE employees.emp_id *= emp_messages.emp_id

Other DBMSs would translate the code into their specific dialect.

Note

Remember that the Connection.nativeSQL (String anySqlString) can be used to discover the translation of all escaped syntaxes for your own DBMS.


Transaction Management

JDBC supports database transaction management. Transactions provide a way to group SQL statements so that they are treated as a whole: Either all statements in the group are executed or no statements are executed. All statements within a transaction are treated as a work unit. Transactions are thus useful to guarantee, among other things, data consistency. Transactions’ well-known properties are the ACID properties. ACID stands for Atomicity, Consistency, Isolation, and Durability. Atomicity means that several data updates performed within a transaction will either all be performed as a whole or simply not done. Data is kept consistent by ensuring that if any of the individual data updates fails, all the other updates will fail as well. Isolation means that data being updated won’t be affected by other transactions by means of locks while the update is running. Finally, durability indicates that after a transaction has succeeded, all its updates are persistent and won’t be undone within the scope of that transaction.

Completing a transaction is called committing the transaction, while aborting it is called rolling back the transaction. A rollback undoes the whole transaction. A transaction’s boundaries are the beginning of its block and the commit or rollback. After a commit has been issued, the transaction cannot be rolled back. Note that some DBMSs support nested transactions as well as intermediate markers within a transaction to indicate a point to which it can be rolled back.

Transaction modes

Two transaction modes are usually supported by commercial DBMSs: the unchained mode and the ANSI-compatible chained mode, which are described in the following. Check your DBMS’s documentation to determine which is the default.

  • The unchained mode requires explicit statements to identify the beginning of a transaction block and its end, which is always either a commit or rollback statement. The transaction block can be composed of any SQL statements.

  • The chained mode doesn’t require explicit statements to delimit the transaction statements because it implicitly begins a transaction before any SQL statement that retrieves or modifies data. The transaction must still be explicitly ended with a transaction commit or rollback.

Caution

Be aware that stored procedures that use the unchained transaction mode may be incompatible with other chained mode transactions.

Transaction isolation levels

ANSI defines three standard levels of transaction isolation, which are described in the following list. Transaction isolation makes sense when concurrent transactions execute simultaneously. The ANSI specification defines restrictions on the kinds of action permitted in concurrent transactions so as to prevent dirty reads, nonrepeatable reads, and phantoms.

  • Level 1: No dirty reads. Dirty reads occur when a transaction updates a row and then a second transaction reads that row before the first transaction commits. If the first transaction rolls back the change, the information read by the second transaction becomes invalid.

  • Level 2: No nonrepeatable reads. Nonrepeatable reads occur when a transaction reads a row and then another transaction updates the same row. If the second transaction commits, subsequent reads by the first transaction get different values than the original read.

  • Level 3: No phantoms. Phantoms occur when a transaction reads a set of rows that satisfy a search condition and then another transaction updates, inserts, or deletes one or more rows that satisfy the first transaction’s search condition. In this case, if the first transaction performs subsequent reads with the same search condition, it reads a different set of rows.

The higher levels include restrictions imposed by all the lower levels. In practice, compatibility with all the transaction isolation levels is achieved using locking techniques. Check your database documentation for information on these techniques and see how they can affect performances in a multiuser environment. As a general rule, the higher the transaction isolation level, the broader locks are held.

Managing transactions with JDBC

JDBC always opens connections in autocommit mode. This opening mode means that each statement is executed as a separate transaction without needing to supply commit or rollback commands. In this default mode, it isn’t possible to perform rollbacks.

JDBC provides methods to turn off autocommit mode, set the transaction isolation level, and commit or rollback transactions. JDBC transactions begin as soon as the autocommit mode is disabled. In this case, an implicit transaction is associated with the connection, and it is completed or aborted with commit and rollback methods. The commit or rollback starts a new implicit transaction. The commit and rollback make JDBC close all PreparedStatements, CallableStatements, and ResultSets opened during the transaction. Simple statement objects stay open. This is the default behavior, but it can be disabled.

Note

Note that some database engines prevent deadlocks from occurring when two transactions are blocking each other.

The JDBC methods to manage transactions are the following:

Connection’s Transaction Management Methods

void setTransactionIsolation(int isolationlevel);
int getTransactionIsolation();
void setAutoCommit(boolean autocommit);
boolean getAutoCommit();
void commit();
void rollback();
void setAutoClose(boolean autoClose);
boolean getAutoClose();

The method in the first line of the preceding sets the transaction isolation level. The possible JDBC transaction isolation levels are the following:

  • TRANSACTION_READ_UNCOMMITTED: Dirty reads are allowed.

  • TRANSACTION_READ_COMMITTED: Reads on a row are blocked until the transaction is committed.

  • TRANSACTION_REPEATABLE_READ: Repeated reads on a row return the originally read data, regardless of any updates by other users prior to commitment of the transaction.

  • TRANSACTION_SERIALIZABLE: All reads are disallowed until the transaction is committed.

  • TRANSACTION_NONE: Transactions aren’t supported. This method cannot be called while in the middle of a transaction.

int getTransactionIsolation(); returns the current transaction isolation levels. A value of zero means that transactions aren’t supported.

In the third line of the preceding, void setAutoCommit(boolean autocommit);, the method setAutoCommit(false) implicitly begins a new transaction. Either commit() or rollback() must be used to terminate the transaction.

The method in the line boolean getAutoCommit(); returns the current autocommit state. false means that user transactions are in use.

The method in the line void commit(); completes the transaction. All changes made since the previous transaction termination (committed or rolled back) are made permanent and all transaction locks are released.

In the line void rollback();, all changes made since the previous transaction termination (committed or rolled back) are dropped. This method undoes the current transaction statements, and all transaction locks are released.

With the line void setAutoClose(boolean autoClose);, when the connection is in autoclose mode, all its PreparedStatements, CallableStatements, and ResultSets are closed when the transaction is committed or rolled back. This is the default behavior, but it can be disabled by passing false as a parameter. Some databases allow these objects to remain open across commits, whereas other databases close them.

The method in the line boolean getAutoClose(); returns the current autoclose state for this connection.

Listing 7-5 provides an example of a transaction where two SQL UPDATE statements are issued. In this example, you want to ensure that both updates are executed and that dirty reads, nonrepeatable reads, and phantom reads aren’t possible for other transactions that may happen at the same time.

Listing 7-5: An Example of SQL DELETEs Grouped in a Transaction
Start example
// transactions
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          Statement firstStmt =
                                  myConnection.createStatement();
                          Statement secondStmt =
                                  myConnection.createStatement();

                          myConnection.setTransactionIsolation(
                                  Connection.TRANSACTION_SERIALIZABLE);
                          myConnection.setAutoCommit(false);
                          firstStmt.executeUpdate(
                                  "DELETE emp_messages WHERE id IN
                                  (SELECT id FROM employees WHERE name =
                                  ‘Jones’)");
                          firstStmt.close();
                          secondStmt.executeUpdate(
                                  "DELETE employees WHERE name = ‘Jones’");

                          secondStmt.close();
                          myConnection.commit();
                          myConnection.setTransactionIsolation(
                                  Connection.TRANSACTION_NONE);

                          myConnection.close();
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

Transaction savepoints

You can use transaction savepoints to mark intermediate steps within a transaction. Using savepoints, you can roll back small parts of a bigger transaction without affecting the whole transaction. A rollback to a savepoint won’t undo the work done prior to the position of the savepoint. This technique is possible thanks to the three following methods of java.sql.Connection.

Connection’s Methods for Savepoint Support

Savepoint setSavepoint(String savepoint);
void rollback(Savepoint savepoint);
void releaseSavepoint(Savepoint savepoint);

The first line of the preceding is used to set the savepoint. It can be used more than once if needed, which is why savepoints have a name. You can define several savepoints within a single transaction.

void rollback(Savepoint savepoint) is used to roll back all statements performed after the savepoint that is passed as a parameter.

void releaseSavepoint(Savepoint savepoint) is used to release a previously set savepoint.

Note that a normal rollback performs a rollback of the whole transaction. All savepoints are released when the transaction terminates by either commit or rollback.

The example in Listing 7-6 illustrates the savepoint mechanism.

Listing 7-6: Using Transaction Savepoints
Start example
// transactions savepoints
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          Statement firstStmt = myConnection.createStatement();

                          myConnection.setTransactionIsolation(
                                  Connection.TRANSACTION_SERIALIZABLE);
                          myConnection.setAutoCommit(false);

                          firstStmt.executeUpdate(
                                  "DELETE emp_messages WHERE id IN
                                  (SELECT id FROM employees WHERE name =
                                  ‘Jones’)");
                          firstStmt.close();

                          Savepoint savepoint =
                                  myConnection.setSavepoint("ALL_MSG_DELETED ");

                          Statement secondStmt = myConnection.createStatement();
                          secondStmt.executeUpdate(
                                  "DELETE employees WHERE id NOT IN (SELECT
                                  DISTINCT id FROM emp_messages)");
                          secondStmt.close();

                          // oops... we deleted too many employees!
                          myConnection.rollback(savepoint);

                          Statement thirdStmt = myConnection.createStatement();
                          thirdStmt.executeUpdate(
                                  "DELETE employees WHERE name = ‘Jones’");
                          thirdStmt.close();

                          myConnection.commit();
                          myConnection.setTransactionIsolation(
                                  Connection.TRANSACTION_NONE);

                          myConnection.close();
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

Distributed transactions

Sometimes transactions involve database operations on several connections to one or more data sources. In this case, a mechanism called a two-phase commit is needed to ensure the ACID properties of the transaction. This mechanism is provided by a transaction coordinator, or transaction manager. Different connections to data sources identify transaction participants, or resources, to the coordinator. The two- phase commit protocol ensures that a transaction can be either committed or roll backed for every single transaction participant. Before committing a distributed transaction, a transaction manager requests every participant to indicate if the part of the transaction that it must manage can be committed. This is called the Prepare step. If all participants can commit, the whole transaction can therefore commit. If any single resource must roll back, the whole transaction rolls back.

Communication between the transaction manager and the different resources is standardized by the X/Open XA protocol. JDBC supports XA through the javax.sql.XAConnection and javax.sql.XADataSource objects, which are provided in the javax.sql extension package to JDBC. Resources that are participating in the transaction must be registered with the transaction manager with javax.transaction.xa.XAResource interfaces. From a JDBC client application perspective, all participating XADataSource instances will be accessed through the javax.sql.DataSource interface that provides getConnection() methods. Those return the usual java.sql.Connection instances.

Listing 7-7 provides an example of how to deal with distributed transactions from within client code such as a servlet in an application server.

Listing 7-7: Distributed Transactions
Start example
// Obtain the context object from the environment we are running in
Context ic = new InitialContext("java:comp/env");
// Obtain a handle on a user transaction from the environment we are running in
UserTransaction ut =
(UserTransaction) ic.lookup("java:comp/UserTransaction");
try {
         ut.begin();
         DataSource db1 = (DataSource) ic.lookup("OrdersDB");
         DataSource db2 = (DataSource) ic.lookup("InventoryDB");
         Connection con1 = db1.getConnection();
         Connection con2 = db2.getConnection();
         // perform transactional work here
         // ...
         ut.commit();
} catch (RollbackException ex) {
         // the transaction has been implicitly or explicitly rolled backed
         // ...
}
End example


Types of ResultSets

ResultSets are used to scan the results of a SQL query. The basic way of scanning results is done using the next() method on a result set. However, it is also possible to navigate result sets and to update individual rows within a result set. This section provides details on different types of result sets for these advanced techniques.

Navigating a ResultSet

JDBC provides several methods to set the current position within a result set. This position is managed by using a cursor; however, there is no need to deal with SQL cursors in JDBC. When the underlying database permits, the following methods can be used to navigate results.

ResultSet’s Methods for Navigating Rows

boolean next();
boolean previous();
boolean first();
boolean last();
void beforeFirst();
void afterLast();
boolean relative(int n);
boolean absolute(int n);

boolean next() makes the current position within the result set go to the next row. If no data row is available after the current position, a false value is returned; otherwise, a true value is returned.

boolean previous() makes the current position within the result set go to the previous row. If this row is the first row within the result set, false is returned; otherwise, true is returned.

boolean first() makes the current position within the result set go to the first row of data. If no such row exists (that is, the result set is empty), false is returned.

boolean last() makes the current position within the result set go to the last row of data. If the result set doesn’t contain any rows, false is returned.

void beforeFirst() makes the current position within the result set go before the first row of data, so it can be fetched with the next call to next().

void afterLast() makes the current position within the result set go after the last row of data.

boolean relative(int n) jumps to n rows forward or backward within the result set, depending on the sign of n: Negative values scroll backward from the current position, and positive values scroll forward from the current position. If the new position is located before the first row or after the last row of data, false is returned; otherwise, true is returned.

boolean absolute(int n) jumps to row number n within the result set if n is positive, or to row n counted backward from the end of the result set if n is negative. false is returned if the current position is either after the last row or before the first row of data within the result set.

Note that except next(), all other methods used to navigate result sets require that a special option is set on the ResultSet. These are discussed in the next section.

Three types of ResultSets

One version of the createStatement(), prepareStatement(), and prepareCall() methods of java.sql.Connection specifies a type for the result set that is used to access the

results of SQL statements such as queries. These types specify whether the result set is scrollable and if the result set rows are a snapshot of database rows at one point in time or if result set rows reflect the actual data in the table at various times when the result set is being navigated.

There are three types of options for ResultSets:

  • TYPE_FORWARD_ONLY: Navigation is prohibited; the result set can be scanned only with the next() method.

  • TYPE_SCROLL_INSENSITIVE: Navigating the result set is allowed, but the rows that it contains are static: They reflect the database state at the time the query is made or when the data is first fetched.

  • TYPE_SCROLL_SENSITIVE: Navigating the result set is allowed, and the rows that it contains are dynamic: If the database content matching with the query changes, such changes will be visible when navigating the result set.

Preserving ResultSets across transactions

ResultSets are normally closed after a commit or rollback occurs within a transaction. However, as it may be useful to continue using the result set’s data after a transaction commits or aborts, JDBC provides an option in the form of methods of java.sql.Connection: createStatement(), prepareStatement(), and prepareCall(). The result set holdability values for this option are as follows:

  • HOLD_CURSORS_OVER_COMMIT: ResultSet’s content is still accessible outside the transaction boundaries.

  • CLOSE_CURSORS_AT_COMMIT: ResultSet’s content is discarded after a transaction commits or rollbacks.

Setting the concurrency level

As explained in the sections “Updating a ResultSet without using cursors" and "Updating a ResultSet using cursors," rows in a result set can be updated, and the changes will be propagated to the underlying database columns. In order to do so, it is necessary to tell the JDBC Driver that it must maintain a link between data in the database and rows in a result set, but more important, also use some locking mechanism to protect this data while an update on a result set occurs. Concurrency levels are used for this purpose and are set with overloaded methods of java.sql.Connection: createStatement(), prepareStatement(), and prepareCall().

There are two possible concurrency levels:

  • CONCUR_READ_ONLY: Disallows data updates on ResultSets

  • CONCUR_UPDATABLE: Allows data updates on ResultSets

Setting ResultSet options

All the options described in this section (“Types of ResultSets”) are set using overloaded createStatement(), prepareStatement(), and prepareCall() methods of java.sql.Connection. The following is the detailed interface:

Connection’s Methods for Specifying a Type to ResultSets

Statement createStatement(int resultSetType, int concurrencyLevel)
Statement createStatement(int resultSetType, int concurrencyLevel,
 int resultSetHoldability)
PreparedStatement prepareStatement(String sql, int resultSetType,
 int concurrencyLevel)
PreparedStatement prepareStatement(String sql, int resultSetType,
 int concurrencyLevel, int resultSetHoldability)
CallableStatement prepareCall(String sql, int resultSetType, int concurrencyLevel)
CallableStatement prepareCall(String sql, int resultSetType,
 int concurrencyLevel, int resultSetHoldability)

The integer parameters in the six preceding methods support the constant values TYPE_FORWARD_ONLY and such discussed earlier. Such values are static data members in the ResultSet interface.

Updating a ResultSet without using cursors

A row contained in a result set can be updated with the updateXXX() methods of the ResultSet interface. An updateXXX() method exists for types such as Array, AsciiStream, BigDecimal, BinaryStream , Blob, and String. After the update is done, an invocation of updateRow() on ResultSet will make it durable. The method rowUpdated() returns true if an update occurred.

The example provided in Listing 7-8 illustrates how to update a ResultSet using cursors.

Listing 7-8: Updating a ResultSet without Using Cursors
Start example
// updating resultsets
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url, "javauser",
                                  "hotjava");
                          Statement stmt = myConnection.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
                          ResultSet rs = stmt.executeQuery("SELECT phone FROM
                          employees WHERE location = ‘Paris’");
                          while (rs.next()) {
                                  String phone = rs.getString(1);
                                  if (!phone.equals("")) {
                                           // add a telephone prefix
                                           rs.updateString("phone", "+31 " +
                                           phone);
                                           rs.updateRow();
                                  }
                          }
                          rs.close();
                          stmt.close();
                          myConnection.close();
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}

It is also possible to delete rows and insert rows using the ResultSet interface. Deleting a row is performed with ResultSet.deleteRow(). The current position within the ResultSet will be set after the row just deleted. Inserting a row is performed with ResultSet.moveToInsertRow(), which actually creates a logical row in the result set. Using the updateXXX() methods on this row sets values for each column in that row. ResultSet.insertRow() is then used to physically send that row to the database.

End example

Updating a ResultSet using cursors

Cursors are used to access a set of rows returned by a SQL SELECT statement. They are associated with query statements and have a symbolic name that can be used to access individual rows of data. Associated with cursors are cursor result sets and cursor positions. Note that some DBMSs don’t support cursors, such as Microsoft Access, but you wouldn’t use that as a real DBMS.

Thus, a cursor

  • Is associated with a SELECT statement

  • Has a name

  • Has a position

  • May affect ResultSets by positioned update/positioned delete statements using the cursor name

The cursor mechanism is illustrated in Figure 7-1.

Click To expand
Figure 7-1: The cursor mechanism.

How to use a cursor

JDBC supports simple cursors that can be used in positioned update or positioned delete statements. They remain valid until the ResultSets or their parent Statements are closed. The JDBC methods for this purpose are part of the Statement interface and are listed in the following:

Statement’s Methods for Cursor Support

void ResultSet.setCursorName(String name);
String ResultSet.getCursorName();
boolean DatabaseMetaData.supportsPositionedDelete();
boolean DatabaseMetaData.supportsPositionedUpdate();

The method in the first line of the preceding is used to give a statement a specific cursor name. Cursor names should be unique. Note that a cursor name is automatically provided by default, which is often sufficient. You can see the default name by using the getCursorName() method.

The getCursorName() method in the second line of the preceding returns the current ResultSet’s cursor name. This cursor name can be used later for positioned updates and positioned deletes.

The DatabaseMetaData method in the third line of the preceding returns true when the database supports positioned deletes.

The method in the last line of the preceding (boolean DatabaseMetaData. supportsPositionedUpdate();) should be used prior to performing a positioned update. It returns true when the database supports it.

Practical examples

The examples in Listings 7-9 and 7-10 are somewhat simplified. They illustrate the cursor mechanism for positioned updates and positioned deletes. In a real-world application, the SELECT statement would have a WHERE clause to limit the cursor scope. The condition that is tested before doing the positioned delete or positioned update is usually more elaborate than what is done here.

Listing 7-9: A Positioned Delete
Start example
// cursors: positioned delete
import java.sql.*;
class SimpleExample
{
        public static void main(String args[])
        {
                String url = "jdbc:odbc:mysource";
                try
                {
                         Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                         Connection myConnection =
                         DriverManager.getConnection(url, "javauser", "hotjava");
                         Statement firstStmt = myConnection.createStatement();
                         Statement secondStmt = myConnection.createStatement();

                         ResultSet rs = firstStmt.executeQuery(
                         "SELECT * FROM employees FOR UPDATE");

                         String cursor = rs.getCursorName();

                         // scan the resultset
                         while (rs.next())
                         {
                                 String phone = rs.getString("phone");
                                 // activate positioned delete
                                 // for employees outside of Belgium and France
                                 if (!phone.startsWith("+31") ||
                                 !phone.startsWith("+32"))
                                 {
                                          secondStmt.executeUpdate(
                                          "DELETE employees WHERE CURRENT OF " +
                                          cursor);
                                 }
                         }
                         rs.close();
                         firstStmt.close();
                         secondStmt.close();
                          myConnection.close();
                 }
                 catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

The same remark concerning the WHERE clause is valid for the positioned update example shown in Listing 7-10. However, the example still illustrates how a positioned update can be performed.

Listing 7-10: A Positioned Update
Start example
// cursors: positioned update
import java.sql.*;
class SimpleExample
{
        public static void main(String args[])
        {
                String url = "jdbc:odbc:mysource";
                try
                {
                         Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                         Connection myConnection =
                         DriverManager.getConnection(url,
                         "javauser", "hotjava");
                         Statement firstStmt = myConnection.createStatement();
                         Statement secondStmt = myConnection.createStatement();

                         ResultSet rs = firstStmt.executeQuery("SELECT * FROM
                         employees FOR UPDATE");

                         String cursor = rs.getCursorName();

                         // scan the resultset
                         while (rs.next())
                         {
                                 String phone = rs.getString("phone");
                                 // activate positioned update
                                 // to convert salary to EURO currency
                                 if (phone.startsWith("+31"))
                                 {
                                          secondStmt.executeUpdate(
                                          "UPDATE employees SET salary = salary /
                                          6.666 WHERE CURRENT OF " + cursor);
                                 }
                                 else if (phone.startsWith("+32"))
                                 {
                                          secondStmt.executeUpdate(
                                          "UPDATE employees SET salary = salary /
                                          40.000 WHERE CURRENT OF " + cursor);
                                 }
                         }
                         rs.close();
                         firstStmt.close();
                         secondStmt.close();
                         myConnection.close();
                }
                catch(java.lang.Exception ex)
                {
                         ex.printStackTrace();
                }
        }
}
End example


Performing Batch Updates

With JDBC, you can prepare several database update statements and execute them at once. This is called batch updates. The addBatch() method of Statement, PreparedStatement, and CallableStatement is used to add individual statements to the batch. executeBatch() is used to start the execution of all the statements grouped together.

executeBatch() returns an array of integers, and each element of the array represents the update count for the respective update statement. The possible values for update counts are as follows:

  • EXECUTE_FAILED: The associated statement in the batch failed and a BatchUpdateException has been thrown.

  • SUCCESS_NO_INFO: The associated statement didn’t return an update count value.

  • 0 or greater: The update count value.

The example provided in Listing 7-11 illustrates how batch updates are done. Note that in this example, if an update fails within the batch, all the other updates will be rolled back. I recommend letting the application developer decide whether to commit or roll back the whole set of updates when a failure occurs.

Listing 7-11: Performing Batch Updates
Start example
// batch updates
import java.sql.*;
import java.io.*;
class SimpleExample
{
        static DataInputStream stdin = new DataInputStream(System.in);

        public static void main(String args[])
        {
                String url = "jdbc:odbc:mysource";
                try
                {
                         Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                         Connection myConnection =
                         DriverManager.getConnection(url, "javauser", "hotjava");
                         myConnection.setAutoCommit(false);

                         Statement stmt = myConnection.createStatement();

                         String record = null;
                         try {
                                 while ((record = stdin.readLine()) != null) {
                                          String currency = record.substring(0,
                                                  record.indexOf(","));
                                          String rate =
record.substring(record.indexOf(",") + 1);

                                          String sql = "UPDATE currencies SET
                                                  rate = " +
                                                  rate + " WHERE currency = ‘" +
                                                   currency + "‘";
                                          stmt.addBatch(sql);
                                 }
                                 stmt.executeBatch();
                                 myConnection.commit();
                         } catch (BatchUpdateException e) {
                                 System.out.println("An exception occurred after
                                 " + e.getUpdateCounts() + " updates.");
                                 myConnection.rollback();
                         }
                         myConnection.close();
                }
                catch(java.lang.Exception ex)
                {
                         ex.printStackTrace();
                }
        }
}
End example

In this example, I assume that a file containing comma-delimited values for currencies is redirected to the standard input of the Java Virtual Machine. This file should look as follows:

BEF, 0.025
FFR, 0.150
GBP, 1.625
USD, 1.125
...


Summary

This chapter covered using Driver- and DriverManager-specific methods, performing SQL data type conversions, and using the SQL escape syntax. It also covered transactions, types of result sets that you can use with JDBC, and how to perform batch updates.

The next chapter discusses more advanced techniques such as data source and connection pooling, callable statements, dynamic SQL, using rowsets, and auto-generated keys.


Chapter 8: Advanced Techniques

This chapter introduces and shows you how to deal with some advanced techniques of Structured Query Language (SQL) and Java Database Connectivity (JDBC). With these techniques, you can add flexibility, better performance, and dynamic features to your applications.

Using DataSource Objects and Connection Pooling

In earlier chapters, you use JDBC Driver, the DriverManager, and Connection objects to obtain connections to a database. These provide a simple way to establish a session, execute SQL statements, retrieve results, and close the connection. This was the usual way of working with databases at the time client/server architectures were in place: Connections were established as soon as clients had to access data, whatever the number of involved clients was.

As soon as three-tiered applications appeared (especially applications that were Web-driven), opening and closing connections all the time, possibly for every Web request, was no longer an option. Indeed, opening and closing connections involves a lot of processing in both the JDBC driver and the database itself. Both have to allocate resources and maintain some state about connections and then release them when the connections are closed. A simple solution to circumvent this was easily achieved by using pooled connections. In such systems, a middle tier opens a number of connections at startup and maintains them in a pool. Connection pools enable you to set a minimum of connections that must remain open, an increment value, a connection time-out, and a shrinking value, for example.

A connection is taken out of the pool as soon as a request that necessitates database access comes in and is returned to the pool as soon as the request has been serviced. The pool basically maintains a list of free connections and used connections. In general, all recent Java 2 Enterprise Edition (J2EE) application servers such as iPlanet Application Server, BEA Weblogic, or IBM WebSphere provide a pool of connections. Such connections are all opened for a specific user. This means that some kind of global account must be created in the database. It is actually no more required or recommended to use a different database account (user login and password) for every user of the system. Only one login to the database is sufficient to serve the needs of accessing persistent data, using several connections in parallel. Of course, an application may use several pools for different purposes or for different types or classes of users because some requests may necessitate more access rights than others. The big difference between this approach and former approaches is that connections are maintained outside of the application code, also called business logic.

You can imagine the enormous performance advantage of using connection pooling in a scenario in which thousands of simultaneous Web users perform requests that necessitate database access. As Web requests are usually handled in a stateless manner, opening and closing the connections for each one of those requests simply isn’t feasible. Another advantage of using data sources and connection pools is that in some cases, caching of prepared statements is also provided.

The benefits of using the DataSource object is that a DataSource is registered in a Java Naming and Directory Interface (JNDI) namespace. This namespace may be provided by a Lightweight Directory Access Protocol (LDAP) directory server or an internal Registry of a given application server. The advantage of this is that the application code no longer refers to a specific JDBC driver, but rather to a data source. The link between the data source name and an actual JDBC driver is usually provided as a deployment parameter to a J2EE component or as a configuration setting of the application server. A DataSource may be a pooled data source or not; this is totally transparent to the developer.

The base interface of javax.sql.DataSource is quite simple, as shown in the following.

DataSource’s Connection Methods

Connection getConnection()
Connection getConnection(String login, String password)

getConnection() and getConnection(String login, String password) return a Connection object from the pool. This object can be used as usual. As soon as the application no longer needs this connection, it releases it using connection.close(), which returns the connection to the pool.


Handling Stored Procedures with Callable Statements

Callable statements are SQL statements that invoke stored procedures, which are also called database Remote Procedure Calls (RPCs). The RPC is popular in the UNIX system programming world. It is used here in the sense of invoking remote code that is stored in the database as stored procedures. Such procedures, when supported by the DBMS, enable the storing of user statements containing SQL text in the database. These procedures are usually stored for reuse from user session to user session. They are useful for embedding application logic at the database side. Another benefit of using callable statements is that after being deployed within a database, the procedure’s statements are optimized and precompiled in the database. As a result, interpreting the SQL text of stored procedures is no longer required at invocation time, and execution of the precompiled code occurs much faster. Figure 8-1 illustrates the invocation mechanism for stored procedures.

Click To expand
Figure 8-1: Invoking a stored procedure.

Statements that invoke stored procedures should use the JDBC CallableStatement class. A dedicated method must be called to prepare the callable statement, as shown in the following. The usual methods are then used to execute the statement.

Connection’s Method to Create a Statement for Calling Stored Procedures

CallableStatement prepareCall(String sql);

In this, the argument is of the following form:

"{? =call stored_procedure_name ?, ?, ....}"

The prepareCall(String sql) method prepares a callable statement. It returns a CallableStatement object. Why something more elaborate than a simple Statement object is needed is discussed in the following paragraph.

Stored procedures can return multiple result types because they can be composed of SQL statements that return diverse result types: result sets and update counts. The usual methods are used to retrieve these results. However, when a procedure returns both multiple results and OUT parameter values, the OUT parameters should be retrieved last. Stored procedures can be called with parameters; they provide maximum flexibility by enabling values to be passed from and to the user’s application. There are two types of such parameters: IN and OUT. IN parameters pass data to the stored procedure, and OUT parameters are values returned by the procedure code. Special JDBC methods exist to set and access these parameters. As Figure 8-2 shows, setting IN values and registering OUT parameters must be done before the callable statement is executed. Figure 8-2 illustrates how to handle the parameters of callable statements.

Click To expand
Figure 8-2: An overview of dealing with parameters.

After the statement has been executed, all its OUT parameters can be explored, one by one, in left-to-right order. Note that Figure 8-2 illustrates the processing that must be done for a stored procedure that doesn’t return ResultSets. If it returns a ResultSet, you would simply add a loop to fetch the result set before accessing the OUT parameters.

Setting parameters

IN and OUT parameters must be set or registered prior to executing a callable statement.

IN parameters

IN parameters receive a value from the user’s application. They are set via setXXX() methods that take two arguments: the parameter index, beginning at 1, and the value to set. The following methods are used to set values corresponding to their parameters’ specific types.

CallableStatement’s Methods for Setting IN Parameters

void setNull(int parameterIndex, int sqlType);
void setBoolean(int parameterIndex, boolean x);
void setByte(int parameterIndex, byte x);
void setShort(int parameterIndex, short x);
void setInt(int parameterIndex, int x);
void setLong(int parameterIndex, long x);
void setFloat(int parameterIndex, float x);
void setDouble(int parameterIndex, double x);
void set BigDecimal(int parameterIndex);
void setString(int parameterIndex, String x);
void setBytes(int parameterIndex, byte x[]);
void setDate(int parameterIndex, java.sql.Date x);
void setDate(int parameterIndex, java.sql.Date x, java.util.Calendar cal);
void setTime(int parameterIndex, java.sql.Time x);
void setTime(int parameterIndex, java.sql.Time x, java.util.Calendar cal);
void setTimestamp(int parameterIndex, java.sql.Timestamp x);
void setTimestamp(int parameterIndex, java.sql.Timestamp x,
 java.util.Calendar cal);
void setAsciiStream(int parameterIndex, java.io.InputStream x, int length);
void setBinaryStream(int parameterIndex, java.io.InputStream x, int length);
void setCharacterStream(int parameterIndex, java.io.Reader r, int length);
void setObject(int parameterIndex, Object x);
void setObject(int parameterIndex, Object x, int targetSqlType);
void setObject(int parameterIndex, Object x, int targetSqlType, int scale);
void setRef(int parameterIndex, Ref r);
void setBlob(int parameterIndex, Blob b);
void setClob(int parameterIndex, Clob c);
void setArray(int parameterIndex, Array a);
void setNull(int parameterIndex, int sqlType, String typeName);
void setURL(int parameterIndex, java.net.URL url);
void clearParameters();
void setObject(...);

The setObject() methods belong to advanced JDBC features. They allow given Java objects to be stored in the database. However, they are converted to the database target SQL data type before they are actually sent to the database.

Note

Note that it is possible to pass database-specific abstract data types by using a driver-specific Java type and using a targetSqlType of java.sql.types.OTHER with the setObject(int parameterIndex, Object x, int targetSqlType) and the setObject(int parameter Index, Object x, int targetSqlType, int scale) methods.

Normally, parameter values remain unaffected for repeated use of a statement. When invoked, the method in void clearParameters(); immediately releases the resources used by the current parameters, and their values are cleared.

OUT parameters

OUT parameters must be registered prior to executing the callable statement. This registration is the way to specify their type. The following methods are available to register OUT parameters.

CallableStatement’s Methods for Registering OUT Parameters

void registerOutParameter(int parameterIndex, int sqlType);
void registerOutParameter(int parameterIndex, int sqlType, int scale);
void registerOutParameter(int parameterIndex, int sqlType, String typeName);

In the first method of the preceding, the first argument is the parameter index, beginning at 1. The type argument must be defined in java.sql.Types.

The method in the second line of the preceding is used to register OUT parameters of type SQL numeric or decimal. The scale argument represents the desired number of digits to the right of the decimal point.

The method in the third line of the preceding enables you to specify user-named types or REF types, such as STRUCT, DISTINCT, or JAVA_OBJECT.

Accessing parameters

It is necessary to access parameters in left-to-right order and with the method that matches their type. The following methods are provided for this purpose.

CallableStatement’s Methods for Accessing Parameters

boolean wasNull();
String getString(int parameterIndex);
boolean getBoolean(int parameterIndex);
byte getByte(int parameterIndex);
short getShort(int parameterIndex);
int getInt(int parameterIndex);
long getLong(int parameterIndex);
float getFloat(int parameterIndex);
double getDouble(int parameterIndex);
java.math.BigDecimal getBigDecimal(int parameterIndex);
byte[] getBytes(int parameterIndex);
java.sql.Date getDate(int parameterIndex);
java.sql.Time getTime(int parameterIndex);
java.sql.Timestamp getTimestamp(int parameterIndex);
Object getObject(int parameterIndex);
Object getObject(int parameterIndex, java.util.Map);
Ref getRef(int parameterIndex);
Blob getBlob(int parameterIndex);
Clob getClob(int parameterIndex);
Array getArray(int parameterIndex);
java.net.URL getURL(int parameterIndex);

When an OUT parameter has a null value, the method in the line boolean wasNull(); returns true. Note that you must call the corresponding getXXX() method before calling wasNull().

An example of handling stored procedures

Listing 8-1 illustrates how to prepare a callable statement, how to set IN parameters, how to register OUT parameters, how to execute the statement, and how to access the OUT parameters. In this example, the first parameter is an IN parameter used to pass a value to the stored procedure. The second one is an OUT parameter used to retrieve a value after the execution of the stored procedure.

Note

I recommend that you check your database’s documentation for help with creating stored procedures. Stored procedures are the ideal place for database-specific, rich SQL code, such as Oracle’s PL-SQL or Sybase’s Transact-SQL.
Listing 8-1: Dealing with Stored Procedure Parameters
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
        "javauser", "hotjava");
CallableStatement myStmt = myConnection.prepareCall(
        "{call my_stored_procedure ?, ?}");
myStmt.setString(1, "Hotjava");
myStmt.registerOutParameter(2, java.sql.Types.VARCHAR);
int res = myStmt.executeUpdate();
String outParam = myStmt.getString(2);
myStmt.close();
myConnection.close();
...
...
End example


Creating Dynamic SQL with Prepared Statements

A prepared statement is a SQL statement that is sent to the database prior to its execution. Unlike stored procedures, prepared statements won’t remain in the database after the resources associated with them are freed. They may be called a number of times with different parameter values. Like stored procedures, the SQL text of the prepared statement is optimized and precompiled by the database prior to its execution(s). In addition to the performance gain of using prepared statements compared to normal statements, the prepared statements can be used to execute SQL queries and updates whose parameters are known only at runtime. Figures 8-3 and 8-4 illustrate some differences between the execution of simple SQL statements and the execution of prepared statements.

In Figure 8-3, the SQL text is sent to the database along with specific values and literals. This example illustrates an INSERT prepared statement.

Click To expand
Figure 8-3: Sending a static statement.
Click To expand
Figure 8-4: Sending parameters to a prepared statement.

When executing a prepared statement (see Figure 8-4), the SQL statement is already at the database side. Only parameter values are passed.

As Figure 8-5 shows, five steps must be followed to use prepared statements with JDBC:

Click To expand
Figure 8-5: An overview of prepared statements.

  1. Prepare the SQL statement.

  2. Set IN parameters.

  3. Execute the statement.

  4. Get the results, if any.

  5. If necessary, set new IN parameter values and reexecute the statement.

The last step is optional, but in many cases prepared statements are used for this facility.

A prepared statement is created from a Connection object as shown in the following. It usually doesn’t outlive the connection that created it.

Connection’s Method for Creating a Prepared Statement

PreparedStatement prepareStatement(String sql);

This method is used to get a PreparedStatement object for later execution. Parameters are symbolized by ? characters.

Passing IN parameters

As with callable statements, prepared statement IN parameters must be set one by one. The following methods are available for this purpose.

PreparedStatement’s Methods for Setting IN Parameters

void setNull(int parameterIndex, int sqlType);
void setBoolean(int parameterIndex, boolean x);
void setByte(int parameterIndex, byte x);
void setShort(int parameterIndex, short x);
void setInt(int parameterIndex, int x);
void setLong(int parameterIndex, long x);
void setFloat(int parameterIndex, float x);
void setDouble(int parameterIndex, double x);
void set BigDecimal(int parameterIndex);
void setString(int parameterIndex, String x);
void setBytes(int parameterIndex, byte x[]);
void setDate(int parameterIndex, java.sql.Date x);
void setDate(int parameterIndex, java.sql.Date x, java.util.Calendar cal);
void setTime(int parameterIndex, java.sql.Time x);
void setTime(int parameterIndex, java.sql.Time x, java.util.Calendar cal);
void setTimestamp(int parameterIndex, java.sql.Timestamp x);
void setTimestamp(int parameterIndex, java.sql.Timestamp x,
 java.util.Calendar cal);
void setAsciiStream(int parameterIndex, java.io.InputStream x, int length);
void setBinaryStream(int parameterIndex, java.io.InputStream x, int length);
void setCharacterStream(int parameterIndex, java.io.Reader r, int length);
void setObject(int parameterIndex, Object x);
void setObject(int parameterIndex, Object x, int targetSqlType);
void setObject(int parameterIndex, Object x, int targetSqlType, int scale);
void setRef(int parameterIndex, Ref r);
void setBlob(int parameterIndex, Blob b);
void setClob(int parameterIndex, Clob c);
void setArray(int parameterIndex, Array a);
void setNull(int parameterIndex, int sqlType, String typeName);
void setURL(int parameterIndex, java.net.URL url);
void clearParameters();
void setObject(...);

Note that the setObject() and clearParameters() methods have the same meaning as for callable statements.

OUT parameters aren’t supported by prepared statements.

Executing the query and retrieving results

After all IN parameters are set, the execution of a prepared statement is performed as for normal statements. A prepared statement may return a count value as well as a ResultSet. Listing 8-2 shows the setting of parameters and the call to the executeUpdate() method.

Listing 8-2: Dealing with Prepared Statement Parameters
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
        "javauser", "hotjava");
PreparedStatement myStmt = myConnection.prepareStatement(
        "UPDATE employees SET floor = ? WHERE department = ?");
myStmt.setInt(1, 1);
myStmt.setString(2, "Operations");
int res = myStmt.executeUpdate();
myStmt.setInt(1, 2);
myStmt.setString(2, "Engineering");
res = myStmt.executeUpdate();
myStmt.setInt(1, 3);
myStmt.setString(2, "Management");
res = myStmt.executeUpdate();
myStmt.close();
myConnection.close();
...
...
End example

Sending BLOBs

With JDBC 1, there was no way to send binary large objects (BLOBs) to a database using normal SQL statements. This feature was simply not supported within normal SQL statements. Because prepared statements support the setAsciiStream(), setUnicode-Stream(), and setBinaryStream() methods of setting IN parameters, it was however possible to send multikilobyte and multimegabyte values to the database.

JDBC 2 introduced the setBlob() and getBlob() methods. These can be used to set and get BLOB content to table’s columns; however, I recommend using the techniques described in this chapter for accessing large BLOB values of several megabytes. Building several Blob objects and garbage-collecting them may be inefficient, and actually not needed if those objects are never used as such in the code. This applies to the CLOB types as well.

Very large binary data is sent using input/output (I/O) streams and setBinaryStream(). It is unnecessary to send the data in small chunks as is required for receiving BLOBs because the JDBC driver makes repeated calls on the I/O stream to read the stream’s content and send the content (that is, bytes) to the database as the actual parameter data. Listing 8-3 illustrates an insertion of BLOBs using input streams.

Listing 8-3: Sending Very Large Parameters to the Database
Start example
...
...
Connection myConnection = DriverManager.getConnection(url,
        "javauser", "hotjava");
java.io.File pictFile = new java.io.File("jones.jpeg");
java.io.File audioFile = new java.io.File("jones.au");
int pictFileLen = (int) pictFile.length();
int audioFileLen = (int) audioFile.length();
java.io.InputStream fPict =
        new java.io.FileInputStream(pictFile);
java.io.InputStream fAudio =
        new java.io.FileInputStream(audioFile);
PreparedStatement myStmt = myConnection.prepareStatement(
        "UPDATE employees SET emp_pict = ?, emp_welcome = ?
        WHERE id = ?");
myStmt.setBinaryStream(1, fPict, pictFileLen);
myStmt.setBinaryStream(2, fAudio, audioFileLen);
myStmt.setInt(3, 1);
int res = myStmt.executeUpdate();
myStmt.close();
myConnection.close();
...
...
End example


Using RowSets

RowSets are part of the javax.sql package. They extend java.sql.ResultSet and add support for JavaBeans to enable developers to use RowSets in visual JavaBean development editors. A company can therefore define several data views as JavaBeans, and developers can manipulate the data views in a visual way. RowSets contain a number of properties that can be set at design time, such as a SQL query. Other parameters can be set at runtime, when the RowSet is actually used within a program. RowSets support JavaBean type of events. Using such an event model allows RowSets to be notified whenever a cursor moves or a row is updated, for example.

Using RowSet methods

The following are the main methods provided in the RowSet interface. Only the methods that a developer will typically use are listed.

RowSet’s Methods

void addRowSetListener(RowSetListener listener)
void clearParameters()
void execute()
void removeRowSetListener(RowSetListener listener)
void setCommand(java.lang.String cmd)
void setConcurrency(int concurrency)
void setDataSourceName(java.lang.String name)
void setEscapeProcessing(boolean enable)
void setMaxFieldSize(int max)
void setMaxRows(int max)
void setPassword(java.lang.String password)
void setQueryTimeout(int seconds)
void setReadOnly(boolean value)
void setTransactionIsolation(int level)
void setType(int type)
void setTypeMap(java.util.Map map)
void setUsername(java.lang.String name)
void setXXX(int parameterIndex, ...)

When creating a RowSet, you use the void setCommand(java.lang.String cmd) method to set the SQL text associated to the RowSet. This is typically a query that returns rows of data. You can pass parameters to SQL queries to the RowSet object at runtime, in the same way parameters are set for callable statements and prepared statements. (A question mark indicates the place of a parameter.) The void setXXX(int parameterIndex, ...) methods are used to pass values to these parameters, where XXX can be one of String, Int, Long, Blob, Clob, Object, and so on.

addRowSetListener(RowSetListener listener) and removeRowSetListener (RowSetListener listener) are used to register and detach an object that implements the RowSetListener interface.

void setDataSourceName(java.lang.String name) is used to set the JNDI name of a data source that the RowSet must use to connect to the database, and void setUsername(java.lang.String name) and void setPassword(java.lang. String password) are used to pass login and password information. Finally, void execute() causes the SQL statement to be sent to the database and processed. The returned rows are then available using the standard getXXX() methods of the ResultSet interface.

Designing and using RowSets

Designing and using a RowSet is very simple. The example in Listing 8-4 illustrates the different steps. Note that because the JDBC API doesn’t provide an implementation of RowSets, you must refer to the documentation of particular JDBC drivers, for example, for details on how to instantiate the rowset.

You can set the initial parameters at the design time of a rowset. In this example, the SQL query contains one parameter that will be set at runtime. After executing the rowset, individual rows can be fetched one by one, just as rows are accessed in a usual result set. Note that all ResultSet methods are applicable to the RowSet object, as RowSet inherits from ResultSet.

Listing 8-4: Using RowSets
Start example
...
// setting initial parameters
rowset.setDataSourceName("jdbc/MyDataSource");
rowset.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
rowset.setUserName("dba");
rowset.setPassword("hotjava");
rowset.setMaxRows(1000);
rowset.setCommand("SELECT emp_no, firstname, name, dept WHERE location = ?");
...

// setting runtime parameters
rowset.setString(1, "MOUNTAIN VIEW");
...

// executing rowset
rowset.execute();
...

// accessing the rowset content
rowset.beforeFirst();
while (rowset.next()) {
        System.out.println("Employee Number: " +
                   rowset.getInt(1));
        System.out.println("Firstname: " +
                   rowset.getString(2));
        System.out.println("Name: " +
                   rowset.getString(3));
        System.out.println("Department: " +
                   rowset.getString(4));
}
rowset.close();
End example


Using Auto-Generated Keys

Most database products support automatic counters or auto-generated keys. Such a feature is used to maintain an ordered sequence of numbers or string values used as a record key when inserting new data in a table. When a key is defined as an auto-generated value, the application code doesn’t provide a value for the key when inserting rows. Instead, the database auto-increments the key and then performs the insertion of the data for the non-automatic fields. Note that in some cases, more than a single field is defined as an auto-generated key. In this case, the database generates independent values for each key. It maintains independent sequences for such keys.

JDBC provides a way to retrieve the values generated by the database for automatic keys. Statement.RETURN_GENERATED_KEYS must be passed as an argument to the execute(), executeUpdate(), and prepareStatement() methods in order to be able to retrieve auto-generated keys.

You retrieve the key values by using a ResultSet returned by the getGeneratedKeys() method. This method must be called just after an execute() or executeUpdate() call, as illustrated in Listing 8-5. In this example, I assume that one key is a generated key. The remaining record field values are explicitly passed by the program.

Listing 8-5: Using Auto-generated Keys
Start example
...
...

Connection myConnection = DriverManager.getConnection(url,
        "javauser", "hotjava");

PreparedStatement myStmt = myConnection.prepareStatement(
        "INSERT INTO employees (firstname, name, dept, phone) " +
        "VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATE_KEYS);

myStmt.setString(1, "John");
myStmt.setString(2, "Doe");
myStmt.setString(3, "Engineering");
myStmt.setString(4, "x48888");

int res = myStmt.executeUpdate();
ResultSet rs = myStmt.getGeneratedKeys();

boolean isKeyAvailable = rs.next();
if (isKeyAvailable) {
         String key = rs.getString(1);
         System.out.println("The auto-generated key is: " + key);
}
rs.close();

myStmt.close();
myConnection.close();
...
...
End example

Note that the metadata object associated with this result set provides information such as the name(s) of the column(s) for which a key has been auto-generated, as well as the associated type.


Summary

This chapter discussed advanced techniques of SQL and JDBC that add a professional touch to applications, including using connection pooling to build very scalable applications and using stored procedures and prepared statements to get performance improvements. Rowsets and auto-generated keys were covered as well in this chapter.

The next chapter explains what database metadata is, how to use it to discover properties of a database and the objects that it contains, and how to work with metadata belonging to result sets.


Chapter 9: Accessing Database Metadata

This chapter introduces the database metadata APIs. Such APIs are used to discover database objects and their properties at runtime: They provide key mechanisms to build highly dynamic applications. An important aspect of dynamic programs is their genericness. In addition to using metadata interfaces, dynamically typed data access is a strategy to achieve such genericness. This is covered as well in this chapter.

Metadata Interfaces

Metadata interfaces are useful to query a database or a ResultSet for meta information. Meta information about database objects may not be known at development time; therefore developers must either write very generic programs or make use of techniques to discover database objects and their properties at runtime. This chapter covers three types of metadata interfaces: DatabaseMetaData, ResultSetMetaData, and ParameterMetaData. The DatabaseMetaData interface provides many interesting methods for discovering database behaviors, default values, supported functions, and so on. Programmers can use this interface when a program needs to find out at runtime what is allowed and what is not with a particular database, for exam- ple. The ResultSetMetaData interface is probably used more often because it provides information on ResultSets that are, indeed, results of user queries. The ParameterMetaData interface provides information about parameters used with dynamic SQL and stored procedures.

The scope of database metadata is very broad. One of its most interesting uses is to obtain information on the database objects themselves.

A DatabaseMetaData object is obtained from the Connection object created for a given database, as shown in the following:

Connection

DatabaseMetaData getMetaData();

A database can provide information on its objects, such as tables, stored procedures, SQL grammar, and various properties. All this information is obtain- able through methods that apply to a DatabaseMetaData object. The call to getMetaData() returns such an object. Listing 9-1, later in this chapter, provides an example of a call to this method.


The DatabaseMetaData Interface

The DatabaseMetaData interface provides a number of methods to access database metadata. The methods fit into different categories, such as information on the database itself, information on what kind of features it supports, on its limitations, and on all the database objects it contains. Most of these methods return string, Boolean, or integer values, but a number of them return ResultSets. How to deal with ResultSets is discussed later in this chapter, in the section "The ResultSetMetaData Interface."

Database information

The DatabaseMetaData interface is a rich interface. It provides many methods useful for discovering various properties of the database engine, as listed in the following. This information might prove useful in building dynamic programs, when the target database isn’t known at design time. In fact, it is a good practice to use the DatabaseMetaData interface even in static programs to verify the capabilities or availability of database features.

DatabaseMetaData Methods for Database Information

boolean allProceduresAreCallable();
boolean allTablesAreSelectable();
String getURL();
String getUserName();
boolean isReadOnly();
boolean nullsAreSortedHigh();
boolean nullsAreSortedLow();
boolean nullsAreSortedAtStart();
boolean nullsAreSortedAtEnd();
String getDatabaseProductName();
String getDatabaseProductVersion();
String getDriverName();
String getDriverVersion();
int getDriverMajorVersion();
int getDriverMinorVersion();
boolean usesLocalFiles();
boolean usesLocalFilePerTable();
boolean supportsMixedCaseIdentifiers();
boolean storesUpperCaseIdentifiers();
boolean storesLowerCaseIdentifiers();
boolean storesMixedCaseIdentifiers();
boolean supportsMixedCaseQuotedIdentifiers();
boolean storesUpperCaseQuotedIdentifiers();
boolean storesLowerCaseQuotedIdentifiers();
boolean storesMixedCaseQuotedIdentifiers();
String getIdentifierQuoteString();
String getSQLKeywords();
String getNumericFunctions();
String getStringFunctions();
String getSystemFunctions();
String getTimeDateFunctions();
String getSearchStringEscape();
String getExtraNameCharacters();

Listing 9-1 illustrates how to get various kinds of information using some of the DatabaseMetaData object methods. Most of the properties relate to the current connection; others reflect the database engine version and the SQL keywords supported by the database. Note the getSQLKeywords() method call; it provides interesting information about the SQL keywords that the database recognizes and supports. After opening a connection to the database, this code will display this type of information.

Listing 9-1: Obtaining Information with DatabaseMetaData Methods
Start example
// databasemetadata
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                      "javauser", "hotjava");
                                          DatabaseMetaData mtdt =
                                  myConnection.getMetaData();
                          System.out.println("URL in use: " +
                                  mtdt.getURL());
                          System.out.println("User name: " +
                                  mtdt.getUserName());
                          System.out.println("DBMS name: " +
                                  mtdt.getDatabaseProductName());
                          System.out.println("DBMS version: " +
                                  mtdt.getDatabaseProductVersion());
                          System.out.println("Driver name: " +
                                  mtdt.getDriverName());
                          System.out.println("Driver version: " +
                                  mtdt.getDriverVersion());
                          System.out.println("supp. SQL Keywords: " +
                                  mtdt.getSQLKeywords());
                          myConnection.close();
                 }
                  catch(java.lang.Exception ex)
                 {
                          ex.printStackTrace();
                 }
         }
}
End example

Listing 9-1’s output may be similar to the following, which is particular to Sybase System 11. This simple program is a good start when trying a new JDBC driver or a very first connection to a database server, as it will provide you with all the available SQL keywords.

URL in use: jdbc:odbc:mysource
User name: javauser
DBMS name: SQL Server
DBMS version: SQL Server/11.0/P/Sun_svr4/OS 5.4/1/OPT/Thu Dec 7 23:58:01 PST 1995
Driver name: JDBC-ODBC Bridge (SYSYB95.DLL)
Driver version: 1.0101 (02.12.0000)
supp. SQL Keywords: arith_overflow,break,browse,bulk,char_convert,checkpoint,
clustered,commit,compute,confirm,controlrow,data_pgs,database,dbcc,disk,dummy,
dump,endtran,errlvl,errorexit,exit,fillfactor,holdlock,identity_insert,if,kill,
lineno,load,mirror,mirrorexit,noholdlock,nonclustered,numeric_truncation,offsets,
once,over,perm,permanent,plan,print,proc,processexit,raiserror,read,readtext,
reconfigure,replace,reserved_pgs,return,role,rowcnt,rowcount,rule,save,setuser,
shared,shutdown,some,statistics,stripe,syb_identity,syb_restree,syb_terminate,
temp,textsize,tran,trigger,truncate,tsequal,used_pgs,user_option,waitfor,while,
writetext

Supported features

The DatabaseMetaData interface also provides a large number of methods to query about the supported features of a database, as listed in the following. Not all database server implementations support all features, so again, it is good advice to check the availability of these functions prior to attempting to use them in a program.

DatabaseMetaData Methods for Information on the Database’s Supported Features

boolean supportsAlterTableWithAddColumn();
boolean supportsAlterTableWithDropColumn();
boolean supportsColumnAliasing();
boolean nullPlusNonNullIsNull();
boolean supportsConvert();
boolean supportsConvert(int fromType, int toType);
boolean supportsTableCorrelationNames();
boolean supportsDifferentTableCorrelationNames();
boolean supportsExpressionsInOrderBy();
boolean supportsOrderByUnrelated();
boolean supportsGroupBy();
boolean supportsGroupByUnrelated();
boolean supportsGroupByBeyondSelect();
boolean supportsLikeEscapeClause();
boolean supportsMultipleResultSets();
boolean supportsMultipleTransactions();
boolean supportsNonNullableColumns();
boolean supportsMinimumSQLGrammar();
boolean supportsCoreSQLGrammar();
boolean supportsExtendedSQLGrammar();
boolean supportsANSI92EntryLevelSQL();
boolean supportsANSI92IntermediateSQL();
boolean supportsANSI92FullSQL();
boolean supportsIntegrityEnhancementFacility();
boolean supportsOuterJoins();
boolean supportsFullOuterJoins();
boolean supportsLimitedOuterJoins();
String getSchemaTerm();
String getProcedureTerm();
String getCatalogTerm();
boolean isCatalogAtStart();
String getCatalogSeparator();
boolean supportsSchemasInDataManipulation();
boolean supportsSchemasInProcedureCalls();
boolean supportsSchemasInTableDefinitions();
boolean supportsSchemasInIndexDefinitions();
boolean supportsSchemaInPrivilegeDefinitions();
boolean supportsCatalogsInDataManipulation();
boolean supportsCatalogsInProcedureCalls();
boolean supportsCatalogsInTableDefinitions();
boolean supportsCatalogsInIndexDefinitions();
boolean supportsCatalogsInPrivilegeDefinitions();
boolean supportsPositionedDelete();
boolean supportsPositionedUpdate();
boolean supportsSelectForUpdate();
boolean supportsStoredProcedures();
boolean supportsSubqueriesInComparisons();
boolean supportsSubqueriesInExists();
boolean supportsSubqueriesInIns();
boolean supportsSubqueriesInQuantifieds();
boolean supportsCorrelatedSubqueries();
boolean supportsUnion();
boolean supportsUnionAll();
boolean supportsOpenCursorAcrossCommit();
boolean supportsOpenCursorAcrossRollback();
boolean supportsOpenStatementAcrossCommit();
boolean supportsOpenStatementAcrossRollback();

These methods can be used in the same way the getSQLKeywords() method is used in Listing 9-1.

Database limitations

The DatabaseMetaData interface also provides methods for discovering the database’s limitations such as the maximum size for a row (expressed in bytes), the maximum length of a column name, the maximum allowed number of simultaneous connections, and so on, as listed in the following.

DatabaseMetaData Methods for Information on the Database’s Limitations

int getMaxBinaryLiteralLength();
int getMaxCharLiteralLength();
int getMaxColumnNameLength();
int getMaxColumnsInGroupBy();
int getMaxColumnsInIndex();
int getMaxColumnsInOrderBy();
int getMaxColumnsInSelect();
int getMaxColumnsInTable();
int getMaxConnections();
int getMaxCursorNameLength();
int getMaxIndexLength();
int getMaxSchemaNameLength();
int getMaxProcedureNameLength();
int getMaxCatalogNameLength();
int getMaxRowSize();
boolean doesMaxRowSizeIncludeBlobs();
int getMaxStatementLength();
int getMaxStatements();
int getMaxTableNameLength();
int getMaxTablesInSelect();
int getMaxUserNameLength();
int getDefaultTransactionIsolation();
boolean supportsTransactions();
boolean supportsTransactionIsolationLevel(int level);
boolean supportsDataDefinitionAndDataManipulationTransactions();
boolean supportsDataManipulationTransactionsOnly();
boolean dataDefinitionCausesTransactionCommit();
boolean dataDefinitionIgnoredInTransactions();

Listing 9-2 illustrates a metadata method for discovering the database’s ANSI compliance level, such as Entry, Intermediate, Full, and so on. The code displays a selected subset of what the database supports.

Listing 9-2: A Metadata Method for Discovering the ANSI Compliance Level
Start example
// discovering ANSI compliance
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                {
                          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                          Connection myConnection =
                                  DriverManager.getConnection(url,
                                  "javauser", "hotjava");
                          DatabaseMetaData mtdt =
                                  myConnection.getMetaData();
                          System.out.println("ANSI92 Entry Level: " +
                                  mtdt.supportsANSI92EntryLevelSQL());
                          System.out.println("ANSI92 Intermediate: " +
                                  mtdt.supportsANSI92IntermediateSQL());
                          System.out.println("ANSI92 Full SQL: " +
                                  mtdt.supportsANSI92FullSQL());
                          System.out.println("Minimum SQL Grammar: " +
                                  mtdt.supportsMinimumSQLGrammar());
                          System.out.println("Core SQL Grammar: " +
                                  mtdt.supportsCoreSQLGrammar());
                          System.out.println("Extended SQL Grammar: "
                                  + mtdt.supportsExtendedSQLGrammar());
                          myConnection.close();
                 }
                 catch(java.lang.Exception ex)
                 {
                         ex.printStackTrace ();
                 }
        }
}
End example

Database objects

The DatabaseMetaData interface also provides several methods for discovering the database’s objects, as listed in the following. This is quite useful for programs that must discover the content of a database at runtime, such as a database browser, a CASE tool, and so on.

DatabaseMetaData Methods for Information on the Database’s Contents

ResultSet getProcedures(String catalog, String schemaPattern,
String procedureNamePattern);
ResultSet getProcedureColumns(String catalog, String schemaPattern,
String procedureNamePattern, String columnNamePattern);
ResultSet getTables(String catalog, String schemaPattern,
String tableNamePattern, String types[]);
ResultSet getschemas();
ResultSet getCatalogs();
ResultSet getTableTypes();
ResultSet getColumns(String catalog, String schemaPattern,
String tableNamePattern, String columnNamePattern);
ResultSet getColumnPrivileges(String catalog, String schema, String table,
String columnNamePattern);
ResultSet getTablePrivileges(String catalog, String schemaPattern,
String tableNamePattern);
ResultSet getBestRowIdentifier(String catalog, String schema, String table,
int scope, boolean nullable);
ResultSet getVersionColumns(String catalog, String schema, String table);
ResultSet getPrimaryKeys(String catalog, String schema, String table);
ResultSet getImportedKeys(String catalog, String schema, String table);
ResultSet getExportedKeys(String catalog, String schema, String table);
ResultSet getCrossReference(String primaryCatalog, String primarySchema,
String primaryTable, String foreignCatalog, String foreignSchema,
String foreignTable);
ResultSet getTypeInfo();
ResultSet getIndexInfo(String catalog, String schema, String table,
boolean unique, boolean approximate);
Note

Certain DBMSs may not support some features. An empty ResultSet may be returned by the driver in such circumstances. Note that the exact definition of catalog and schema varies from database to database. A catalog is usually a database subspace, as if a database server would contain several logical databases in it. The catalog name refers to the name of such subspaces. Database schemas usually refer to a group of database objects such as tables and stored procedures belonging to a particular database user. The schema name can be a user’s login identifier. I recommend that you refer to the administration guide of your particular database if you need to specify individual catalog and schema names when using these methods.

Most of these methods need arguments, such as catalog name, schema name, procedure, table, and column name. All the parameters named xxxPattern don’t have to match a particular database object name. If necessary, they may be composed of the % and _ matching characters. The % matches zero or more characters, while _ matches any one character.

All these methods return ResultSets. Indeed, they usually return multiple values, which means providing results through ResultSets is very convenient. As Figure 9-1 shows, the usual method is used to scan those result sets. The different values are retrieved exactly as when dealing with SELECT statements that return several rows of data. Individual rows are accessed using the ResultSet object.

Click To expand
Figure 9-1: Processing methods that return a ResultSet.

Listing 9-3 includes some database metadata calls that show how to query metadata information using the preceding methods. This code opens a database connection and displays the catalog names as well as table and stored procedures names for all schemas belonging to the default catalog. The default catalog is the “home” catalog of the user who opened the connection, as defined by the DBA.

Listing 9-3: Metadata about Database Objects
Start example
// retrieving results
import java.sql.*;
class SimpleExample
{
         public static void main(String args[])
         {
                 String url = "jdbc:odbc:mysource";
                 try
                 {
                         Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                         Connection myConnection =
                                 DriverManager.getConnection(url,
                                  "javauser", "hotjava");

                         DatabaseMetaData dmtd = myConnection.getMetaData();

                         // list catalogs managed by this dbms
                         scanRS("Info on " + dmtd.getCatalogTerm() + "(s):",
                                 dmtd.getCatalogs());

                         // list all tables in current catalog, belonging
                         // to all schemas, of all types
                         scanRS("Info on tables:",
                                 dmtd.getTables(myConnection.getCatalog(), "%",
                                  "%", null));

                         // list all procedures in current catalog,
                         // belonging to all schemas
                         scanRS("Info on " + dmtd.getProcedureTerm() + "(s):",
                                 dmtd.getProcedures(myConnection.getCatalog(),
                                  "%", "%"));

                         myConnection.close();
                }
                catch(java.lang.Exception ex)
                {
                         ex.printStackTrace();
                }
        }

        private static void scanRS(String info, ResultSet rs) throws SQLException
        {
                System.out.println(info);
                System.out.println();
                if (rs != null)
                {
                         int i;

                         // we have a ResultSet

                         ResultSetMetaData rsmd = rs.getMetaData();
                         int numCols = rsmd.getColumnCount();
                          // display column headers
                          for (i = 1; i <= numCols; i++)
                          {
                                   if (i > 1) System.out.print(", ");
                                   System.out.print(rsmd.getColumnLabel(i));
                          }
                          System.out.println("");

                          // step through the rows
                          while (rs.next())
                          {
                                   // process the columns
                                   for (i = 1; i <= numCols; i++)
                                   {
                                           if (i > 1) System.out.print(", ");
                                           System.out.print(rs.getString(i));
                                   }
                                   System.out.println("");
                          }
                 }
                 else
                 {
                          System.out.println("no data returned...");
                 }
                 System.out.println ();
        }
}
End example

Listing 9-3 prints information similar to the following output. The data returned here came from a Sybase System 11 server. The user’s current catalog is the default sample database provided by Sybase.

Note

Note that a SQLException message appearing on the stack trace indicates the nature of the problem, usually showing that an unimplemented feature has been called.

Info on database(s)
TABLE_QUALIFIER
master
model
pubs2
sybsecurity
sybsyntax
sybsystemprocs
tempdb
test
testdb2
userdb
Info on tables
TABLE_QUALIFIER, TABLE_OWNER, TABLE_NAME, TABLE_TYPE, REMARKS
pubs2, dbo, sysalternates, SYSTEM TABLE, null
pubs2, dbo, syscolumns, SYSTEM TABLE, null
pubs2, dbo, syscomments, SYSTEM TABLE, null
pubs2, dbo, sysconstraints, SYSTEM TABLE, null
pubs2, dbo, sysdepends, SYSTEM TABLE, null
pubs2, dbo, sysindexes, SYSTEM TABLE, null
pubs2, dbo, syskeys, SYSTEM TABLE, null
pubs2, dbo, syslogs, SYSTEM TABLE, null
pubs2, dbo, sysobjects, SYSTEM TABLE, null
pubs2, dbo, sysprocedures, SYSTEM TABLE, null
pubs2, dbo, sysprotects, SYSTEM TABLE, null
pubs2, dbo, sysreferences, SYSTEM TABLE, null
pubs2, dbo, syssegments, SYSTEM TABLE, null
pubs2, dbo, systypes, SYSTEM TABLE, null
pubs2, dbo, sysusermessages, SYSTEM TABLE, null
pubs2, dbo, sysusers, SYSTEM TABLE, null
pubs2, dbo, au_pix, TABLE, null
pubs2, dbo, authors, TABLE, null
pubs2, dbo, blurbs, TABLE, null
pubs2, dbo, discounts, TABLE, null
pubs2, dbo, publishers, TABLE, null
pubs2, dbo, roysched, TABLE, null
pubs2, dbo, sales, TABLE, null
pubs2, dbo, salesdetail, TABLE, null
pubs2, dbo, stores, TABLE, null
pubs2, dbo, titleauthor, TABLE, null
pubs2, dbo, titles, TABLE, null
Info on Stored Procedure(s)
PROCEDURE_QUALIFIER, PROCEDURE_OWNER, PROCEDURE_NAME, NUM_INPUT_PARAMS,
NUM_OUTPUT_PARAMS, NUM_RESULT_SETS, REMARKS, PROCEDURE_TYPE
pubs2, dbo, byroyalty, null, null, null, null, 1
pubs2, dbo, discount_proc, null, null, null, null, 1
pubs2, dbo, history_proc, null, null, null, null, 1
pubs2, dbo, insert_sales_proc, null, null, null, null, 1
pubs2, dbo, insert_salesdetail_proc, null, null, null, null, 1
pubs2, dbo, storeid_proc, null, null, null, null, 1
pubs2, dbo, storename_proc, null, null, null, null, 1
pubs2, dbo, title_proc, null, null, null, null, 1
pubs2, dbo, titleid_proc, null, null, null, null, 1
pubs2, guest, testproc, null, null, null, null, 1


The ResultSetMetaData Interface

After a ResultSet has been returned by the database, it’s possible to get all kinds of information concerning the ResultSet, such as the names and types of the columns that it contains. The ResultSetMetaData interface offers the following methods for finding out about a result set’s metadata. These methods also work on ResultSets returned by some of the DatabaseMetaData class because those ResultSets are still just ResultSets.

ResultSet columns

In dynamic programs, SQL queries are built at runtime. This means that the properties of the results of such queries aren’t known at design time. The ResultSetMetaData interface is a rich interface providing many methods for obtaining information about the columns of a result set, as listed in the following. This information can be leveraged at runtime to build a dynamic result screen, format a GUI table widget, and so on.

ResultSetMetaData Methods for Information about a Result Set’s Columns

int getColumnCount();
int getColumnDisplaySize(int column);
String getColumnLabel(int column);
String getColumnName(int column);
String getSchemaName(int column);
int getPrecision(int column);
int getScale(int column);
String getTableName(int column);
String getCatalogName(int column);
int getColumnType(int column);
String getColumnTypeName(int column);

Column properties

Individual columns of a result set may be analyzed as well. The ResultSetMetaData interface provides a few methods for obtaining information about the properties of the columns of a result set, as listed in the following.

ResultSetMetaData Methods for Property Information about a Result Set’s Columns

boolean isAutoIncrement(int column);
boolean isCaseSensitive(int column);
boolean isSearchable(int column);
boolean isCurrency(int column);
int isNullable(int column);
boolean isSigned(int column);
boolean isReadOnly(int column);
boolean isWritable(int column);
boolean isDefinitelyWritable(int column);

Note that there is no way to get information on rows of data. Such information is only available on columns. The method in Listing 9-4 gets the number and label of each column and displays all metadata available for the columns in a tabular form.

Listing 9-4: ResultSetMetaData: Getting Column Characteristics
Start example
...
...
int i;
// we have a ResultSet and want to display a table detailing
// every column’s metadata

ResultSetMetaData rsmd = rs.getMetaData();

int numCols = rsmd.getColumnCount();

// display column headers
System.out.print("\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.getColumnLabel(i));
}
System.out.println("");

// now we will print the column characteristics
System.out.print("\nAuto Increment\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isAutoIncrement(i));
}
System.out.print("\nCase Sensitive\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isCaseSensitive(i));
}
System.out.print("\nSearchable\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isSearchable(i));
}
System.out.print("\nCurrency\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isCurrency(i));
}
System.out.print("\nAllows nulls\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isNullable(i));
}
System.out.print("\nSigned\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isSigned(i));
}
System.out.print("\nRead only\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isReadOnly(i));
}
System.out.print("\nWritable\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isWritable(i));
}
System.out.print("\nDefinitely Writable\t");
for (i = 1; i <= numCols; i++)
{
         if (i > 1) System.out.print("\t ");
         System.out.print(rsmd.isDefinitelyWritable(i));
}
System.out.println();
...
...
End example


The ParameterMetaData Interface

Metadata information can be obtained for the parameters passed to a PreparedStatement or CallableStatement. This information concerns individual parameters defined as ? in the SQL statement and can provide various information such as the SQL type for a parameter, the scale, the associated class, and so on, as listed in the following. PreparedStatement.getParameterMetaData() returns a ParameterMetaData object. This interface was introduced in JDBC version 3.0.

ParameterMetaData Methods for Property Information about Query Parameters

int getParameterCount()
java.lang.String getParameterClassName(int param)
int getParameterType(int param)
java.lang.String getParameterTypeName(int param)
int getPrecision(int param)
int getScale(int param)
int isNullable(int param)
boolean isSigned(int param)

The only argument of these methods, except for getParameterCount(), is an integer that identifies the parameter to be analyzed. Values start from 1.

Listing 9-5 provides a short example illustrating the use of these methods.

Listing 9-5: ParameterMetaData: Getting Column Labels
Start example
...
...
PreparedStatement stmt = conn.prepareStatement("SELECT *
FROM EMPLOYEES WHERE NAME LIKE ?");
ParameterMetaData mtdt = stmt.getParameterMetaData();

System.out.println("The type of the first parameter is: " +
mtdt.getParameterTypeName(1));
if (mtdt.isNullable(1)) {
    System.out.println("It allows null values");
} else {
    System.out.println("It does not allow null values");
}
...
...
End example


Dynamic Data Access

While the DatabaseMetaData and ResultSetMetaData interfaces provide numerous methods to access a database without knowing its schema, other methods exist to support generic data access. These methods allow data to be accessed dynamically through generic Java objects. They are of the form getObject() and setObject() to retrieve and to set data, respectively, in a table or result set’s columns.

The usual methods to send and retrieve data allow you to map one or more SQL data types to specific Java types. The methods explained here allow you to use Java objects, regardless of what type SQL data is accessed. Precise mapping rules are used. Indeed, specific SQL data types must correspond to specific Java types, and specific Java types must correspond to specific SQL types.

Retrieving dynamically typed data

Dynamically typed data retrieval is performed using ResultSet.getObject() to access columns or CallableStatement.getObject() to access OUT parameters of stored procedures. Table 9-1 shows the default mapping from SQL types to Java types that are subtypes of Object. No mapping to Java streams is provided.

Table 9-1: DEFAULT MAPPING FROM SQL TYPES TO JAVA OBJECT TYPES
SQL Type | Java Object Type
CHAR | String
VARCHAR | String
LONGVARCHAR | String
NUMERIC | java.math.BigDecimal
DECIMAL | java.math.BigDecimal
BIT | Boolean
TINYINT | Integer
SQL Type | Java Object Type
SMALLINT | Integer
INTEGER | Integer
BIGINT | Long
REAL | Float
FLOAT | Double
DOUBLE | Double
BINARY | byte[ ]
VARBINARY | byte[ ]
LONGVARBINARY | byte[ ]
DATE | java.sql.Date
TIME | java.sql.Time
TIMESTAMP | java.sql.Timestamp
CLOB | Clob
BLOB | Blob
ARRAY | Array
DISTINCT | mapping of underlying type
STRUCT | Struct
REF | Ref
DATALINK | java.net.URL

The following methods apply to the ResultSet interface to retrieve dynamically typed data:

ResultSet Methods to Access Column Values as Objects

Object getObject(int columnIndex);
Object getObject(String columnName);

The getObject() method is used like other getXXX() methods but returns a Java object whose type may be discovered using Table 9-1. This object corresponds to the SQL data type of the accessed result set column.

The following methods apply to the CallableStatement interface:

CallableStatement Methods to Access Parameters

void registerOutParameter(int parameterIndex, int sqlType);
void registerOutParameter(int parameterIndex, int sqlType, int scale);
Object getObject(int parameterIndex);

As shown earlier with callable statements, it is necessary to register OUT parameters before executing the call and accessing them. A Java object type corresponding to the SQL data type passed as parameter is returned.

Listing 9-6 provides a short example illustrating the use of the registerOutParameter() method when calling a stored procedure.

Listing 9-6: Accessing Parameters of CallableStatements
Start example
...
...
// assume that this stored procedure provides one OUT parameter
CallableStatement stmt = conn.prepareCall("{CALL getCurrentQuarterRevenue(?)}");
stmt.registerOutParameter(1, java.sql.Types.FLOAT);

stmt.execute();

float revenue = stmt.getFloat(1);
System.out.println("The revenue to date for the current quarter is: " + revenue);
...
...
End example

Inserting or updating dynamically typed data

Dynamically typed data insertion or update may be performed only through IN parameters of stored procedures or prepared statements. Specific SQL data types may be explicitly targeted in accordance with Table 9-2.

Table 9-2: CONVERSIONS BETWEEN JAVA OBJECT TYPES AND TARGET SQL TYPES
 | TINYINT | SMALLINT | INTEGER | BIGINT | REAL | FLOAT
 | LONGVARCHAR | BINARY | VARBINARY | LONGVARBINARY |  |
 | DATE | TIME | TIMESTAMP |  |  |
String | J | J | J | J | J | J
BigDecimal | J | J | J | J | J | J
 | TINYINT | SMALLINT | INTEGER | BIGINT | REAL | FLOAT
Boolean | J | J | J | J | J | J
Integer | J | J | J | J | J | J
Long | J | J | J | J | J | J
Float | J | J | J | J | J | J
Double | J | J | J | J | J | J
byte[ ] | - | - | - | - | - | -
java.sql. DateTime | - | - | - | - | - | -
java.sql. Time | - | - | - | - | - | -
java.sql. Timestamp | - | - | - | - | - | -
String | J | J | J | J | J | J
BigDecimal | J | J | J | J | J | J
Boolean | J | J | J | J | J | J
Integer | J | J | J | J | J | J
Long | J | J | J | J | J | J
Float | J | J | J | J | J | J
Double | J | J | J | J | J | J
byte[ ] | - | - | - | - | - | -
java.sql.Date | - | - | - | - | J | J
java.sql.Time | - | - | - | - | J | J
java.sql.Timestamp | - | - | - | - | J | J
String | J | J | J | J |  |
BigDecimal | J | - | - | - |  |
Boolean | J | - | - | - |  |
Integer | J | - | - | - |  |
Long | J | - | - | - |  |
Float | J | - | - | - |  |
Double | J | - | - | - |  |
byte[ ] | - | J | J | J |  |
java.sql.Date | J | - | - | - |  |
java.sql.Time | J | - | - | - |  |
java.sql.Timestamp | J | - | - | - |  |
String | J | J | J |  |  |
BigDecimal | - | - | - |  |  |
Boolean | - | - | - |  |  |
Integer | - | - | - |  |  |
Long | - | - | - |  |  |
Float | - | - | - |  |  |
Double | - | - | - |  |  |
byte[ ] | - | - | - |  |  |
java.sql.Date | J | J | - |  |  |
java.sql.Time | - | J | - |  |  |
java.sql.Timestamp | J | J | J |  |  |

J means that the conversion can be done. No support for Java streams is provided.

The following methods apply to the PreparedStatement interface in order to set values for parameters:

CallableStatement or PreparedStatement: Setting Parameter Values

void setObject(int parameterIndex, Object x);
void setObject(int parameterIndex, Object x, int targetSqlType);
void setObject(int parameterIndex, Object x, int targetSqlType, int scale);

When no target SQL type is specified to the setObject() method, the Java object is directly converted according to the default mapping as shown in Table 9-3. If a target SQL type is provided, the Java object is first mapped to its default corresponding type and then converted to the specified SQL type (see Table 9-2).

Table 9-3: DEFAULT MAPPING FROM JAVA OBJECT TYPES TO SQL TYPES
Java Object Type | SQL Type
String | VARCHAR or LONGVARCHAR
java.math.BigDecimal | NUMERIC
Boolean | BIT
Integer | INTEGER
Long | BIGINT
Float | REAL
Double | DOUBLE
byte[ ] | VARBINARY or LONGVARBINARY
java.sql.Date | DATE
java.sql.Time | TIME
java.sql.Timestamp | TIMESTAMP


Summary

This chapter discussed methods to analyze metadata information about database objects. Several interfaces were provided to get database properties such as what it supports, what are its limitations, what objects it contains, and so on. Other methods enable you to discover and handle ResultSets and parameters at runtime. This chapter also discussed a technique for accessing data in a dynamic way: the so-called dynamically typed data access.

The next chapter discusses the use of JDBC in the context of Enterprise JavaBeans.


Chapter 10: Accessing Databases with Enterprise JavaBeans

In This Chapter

  • Types of beans: session and entity

  • Container-managed persistence versus bean-managed persistence

This chapter introduces the use of Enterprise JavaBeans (EJBs) to access databases. It presents the various ways that JDBC can be used with EJBs and includes an overview of their respective advantages and disadvantages.


Types of Beans

Enterprise JavaBeans are distributed components that are deployed in application servers. Examples of commercial application servers are iPlanet Application Server, BEA Weblogic, IBM WebSphere, Oracle Application Server, and Sybase Jaguar. EJBs are distributed because they can run on separate virtual machines and application server nodes and communicate via RMI, Java’s Remote Method Invocation (which in most application server products is implemented by a CORBA IIOP stack). EJBs address two main tasks: providing business logic and representing data in an object- oriented view. In this chapter, you find out how these tasks are intimately linked to database access, and how the database access is actually done in practice.

There are two types of beans: session beans and entity beans. Session beans incorporate business logic for distributed applications. They behave as services, where methods can be invoked remotely from other beans, from servlets, or from client applications. A session bean normally doesn’t represent data; entity beans are used for this purpose. Both types have a well-defined life cycle managed by application servers, but explaining the details about creation, activation (moving a bean’s state from passivated to activated), passivation (moving a bean’s state from activated to passivated), and destruction of beans is beyond the scope of this book. This chapter focuses on the relevance of database access for both types of beans.

Note that both types of beans can use DataSource objects and connection pools provided by application servers, as well as transaction management on bean methods and underlying data sources.


Session Beans

Session beans are used to hold business logic and make it available in a distributed way. In fact, a session bean doesn’t do any processing on its own. Its method must be triggered by external programs or other beans. You can think of session beans as RPC services. Invoking a method on a bean starts some kind of processing and returns results. Session beans are short-lived; they are created by a client application or client bean for the duration of an application session. As soon as the application terminates, its session beans are no longer necessary.

As many applications involve accessing data, session beans may have to connect to a database and perform queries and updates and return results to the caller. In general, entity beans are used for all database access because that’s what they are made for. However, when only a few tables are accessed or whenever using entity beans doesn’t prove useful, session beans may access a database in much the same way as a standalone Java program does. The EJB framework doesn’t provide an API or technique to map session beans to database tables because that isn’t what they were created for: They don’t represent data from a database.

Stateless session beans

Session beans can be either stateless or stateful. Stateless beans don’t contain member attributes (class variables), only methods. A stateless bean doesn’t maintain data (that is, state) outside of method invocations. Session beans are stateless services where methods can be triggered from the outside world. Their methods perform processing of data (which can be mapped to a database if needed) and then return results to the caller when the method reaches its end.

An example of a stateless session bean that necessitates database access is a phonebook service. Such an object provides directory-based functions such as looking up phone numbers. It isn’t necessary to hold any kind of state outside the boundaries of the bean’s service methods. Consider a simple PhoneBook session bean that contains a single method called lookup(String namePattern) and returns an array of name-phone number pairs. Listing 10-1 illustrates the bean implementation for this example. Querying the database table containing all phone numbers is done at the time lookup is called, and for the simplicity of this example, no caching of results is performed.

Listing 10-1: A Stateless Session Bean
Start example
// a stateless session bean
import java.sql.*;
import java.util.Hashtable;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.EJBException;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class PhoneBookBean implements SessionBean {

  public void ejbActivate() {
  }

  public void ejbRemove() {
  }

  public void ejbPassivate() {
  }

  public void ejbCreate () throws CreateException {
  }

  public Hashtable lookup(String namePattern) {

    String query = "SELECT name, firstname, phone FROM phonebook" +
        "ORDER BY name, firstname WHERE name LIKE ‘" + namePattern + "‘";

    Hashtable results = new Hashtable();

    try {
      Connection conn = getConnection();
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery(query);

      while (rs.next()) {
        results.put(rs.getString("name") + ", " + rs.getString("firstname"),
          rs.getString("phone"));
      }

      stmt.close();
      conn.close();
    } catch (SQLException e) {
      throw new EJBException(e);
    }
    return results;
  }

  private Connection getConnection() throws SQLException
  {
    InitialContext initCtx = null;
    try {
      initCtx = new InitialContext();
      DataSource ds = (javax.sql.DataSource)
        initCtx.lookup("java:comp/env/jdbc/databasePool");
      return ds.getConnection();
    } catch(NamingException ne) {
      throw new EJBException(ne);
    } finally {
      try {
        if(initCtx != null) initCtx.close();
      } catch(NamingException ne) {
        throw new EJBException(ne);
      }
    }
  }
}
End example

Listing 10-2 provides a simple client application that accesses the PhoneBook bean. Notice that there are no JDBC method calls made in the client: Accessing the database is the entire responsibility of the bean. After looking up a reference of a factory for the bean (PhoneBookHome), this client asks for the creation of the bean in the application server (home.create()) and then invokes its lookup method, passing a search string as a parameter. The intention is to retrieve all matching names, first names, and phone numbers for the provided name pattern and print them on the console. Next, the bean is destructed by calling the remove() method. Note that ejbCreate(), ejbRemove(), ejbActivate(), and ejbPassivate() of the bean itself are never called from within the client. They are reserved for use from the container.

Note

It is beyond the scope of this book to explain the life cycle of beans and how a client can interfere in this cycle. If you want to obtain more information, please refer to the J2EE Reference Implementation documentation, available at http://java.sun.com/j2ee.

Listing 10-2: A Stateless Session Bean Client
Start example
// a stateless session bean client
import java.util.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

public class Client {

   public static void main(String[] args) {
       try {
           Context initial = new InitialContext();
           Object objref = initial.lookup("MyPhoneBook");

           PhoneBookHome home =
               (PhoneBookHome)PortableRemoteObject.narrow(objref,
                                            PhoneBookHome.class);

           PhoneBook phonebook = home.create();

           Hashtable h = phonebook.lookup("Van H%cke");
           for (Enumeration keys = h.keys() ; keys.hasMoreElements() ;) {
               String fullname = (String) keys.nextElement();
               System.out.println("Name: " + fullname);
               System.out.println("Phone: " + (String) h.get(fullname));
           }

           phonebook.remove();

       } catch (Exception ex) {
           System.err.println("Caught an unexpected exception!");
           ex.printStackTrace();
       }
   }
}
End example

Stateful session beans

Stateful session beans differ from stateless session beans in that they maintain state across method invocations. They can hold information on behalf of a client and make this information available during method invocations. State is preserved across method calls. Note that maintaining an open database connection as a bean attribute isn’t a good idea; maintaining open connections during the whole life of a bean may not prove efficient. A more scalable approach is to get a connection from the pool whenever needed and return it to the pool when it is no longer required.

As an example, consider a shopping cart for an e-commerce application. Unlike items for sale, orders, and prices, a shopping cart isn’t typically a database object; there won’t be a database table for shopping carts. In fact there is no need to maintain persistent information for a shopping cart for a very long time. Listing 10-3 shows how a very simple shopping cart may be implemented with a stateful session bean. In this example, a bean client can add items to its shopping cart after creating it and then pass the order. Adding items to the shopping cart will actually modify its state, or member attribute, but won’t affect the database. However, ordering the items will imply some interaction with a database, as the order details must be available for processing the order asynchronously.

Listing 10-3: A Stateful Session Bean
Start example
// a stateful session bean
import java.sql.*;
import java.util.Date;
import java.util.Vector;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.EJBException;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ShoppingCartBean implements SessionBean {

  private Vector items = new Vector();

  public void ejbActivate() {
  }

  public void ejbRemove() {
  }

  public void ejbPassivate() {
  }

  public void ejbCreate () throws CreateException {
  }

  public void addItem(String item, int quantity) {

    Object[] orderedItem = new Object[2];
    orderedItem[0] = item;
    orderedItem[1] = new Integer(quantity);
    items.addElement(orderedItem);
  }

  public void order(String client) {

    Date today = new Date();
    String query = "INSERT INTO orders VALUES (?, ?, ?, ?)";

    try {
      Connection conn = getConnection();
      PreparedStatement stmt = conn.prepareStatement(query);

      for (int j=0; j<items.size(); j++) {

        stmt.setDate(1, today);
        stmt.setString(2, client);
        stmt.setString(3, (String)((Object[])items.elementAt(j))[0]);
        stmt.setInt(4, ((Integer)((Object[])items.elementAt(j))[1]).intValue());

        stmt.executeUpdate();
      }

      stmt.close();
      conn.close();
    } catch (SQLException e) {
      throw new EJBException(e);
    }
  }

  private Connection getConnection() throws SQLException
  {
    InitialContext initCtx = null;
    try {
      initCtx = new InitialContext();
      DataSource ds = (javax.sql.DataSource)
        initCtx.lookup("java:comp/env/jdbc/databasePool");
      return ds.getConnection();
    } catch(NamingException ne) {
      throw new EJBException(ne);
    } finally {
      try {
        if(initCtx != null) initCtx.close();
      } catch(NamingException ne) {
        throw new EJBException(ne);
      }
    }
  }
}
End example


Entity Beans

Unlike session beans, entity beans are long-lived components. They represent data in an object-oriented way, while the data typically resides in a relational database. The API provides methods to create, look up, update, and delete entity beans without necessitating client beans or client applications to handle SQL statements. Entity beans will survive after normal (or abnormal) termination of their clients.

An entity bean instance basically represents a row in a database table. It is therefore totally stateful because it contains member attributes that correspond to a table’s columns. The EJB framework provides techniques to map database tables to entity beans.

Two options are available to provide persistence to entity beans: The container can either provide the mechanism for the database mapping (container-managed persistence) or delegate it to the bean developer (bean-managed persistence). For example, the iPlanet Application Server provides such a container.

Container-managed persistence

When using container-managed persistence, a programmer doesn’t need to provide the code to insert, update, delete, and select data from a database. She actually doesn’t need to use JDBC at all. The container generates the mapping code at deployment time or uses the features of an object-relational bridge for this purpose. Although this option leaves little room for developers to control all interactions with databases, it is a quite powerful and fast technique to implement distributed business components.

As shown in Listing 10-4, the code for an entity bean using container-managed persistence is fairly simple. It basically contains only member attributes for the bean.

Listing 10-4: Entity Bean with Container-Managed Persistence
Start example
import javax.ejb.EntityBean;
import javax.ejb.CreateException;
import javax.ejb.RemoveException;

public class AccountBean implements EntityBean {

  public String accountId; // also the primary Key
  public double balance;

  public void ejbActivate() {
  }

  public void ejbPassivate() {
  }

  public void ejbLoad() {
  }

  public void ejbStore() {
  }

  public void ejbRemove() throws RemoveException
  {
  }

  public String ejbCreate(String accountId, double initialBalance) throws
CreateException
  {
    this.accountId = accountId;
    this.balance   = initialBalance;
    return null;
  }

  public void ejbPostCreate(String accountId, double initialBalance)
  {
  }

  public double deposit(double amount)
  {
    balance += amount;
    return balance;
  }

  public double withdraw(double amount)
  {
    balance -= amount;
    return balance;
  }

  public double balance()
  {
    return balance;
  }
}
End example
Note

Application server tools are used to generate database-mapping code for this type of entity bean. The developer, or more often the deployer of the application, can specify which bean attributes map to which database table columns in so-called deployment descriptors. There is a one-to-one relationship between attributes and columns in such descriptors. It is unnecessary to recompile the whole set of beans when mapping information is updated: The deployment tools of the application server take care of this mapping.

Bean-managed persistence

In the second case, bean-managed persistence, a developer must provide the necessary methods to make the data represented by the entity bean stay in sync with data residing in a database table. The methods that have to be implemented are as follows:

  • public void ejbLoad(): Synchronizes the bean’s attributes with the corresponding data residing in the database.

  • public void ejbStore(): Synchronizes the data residing in the database with the bean’s attributes.

  • public String ejbCreate(params...): Creates a new instance of a bean and inserts the corresponding data in a database table.

  • public void ejbRemove(): Deletes persistent data for this bean in the database.

  • public String ejbFindByPrimaryKey(String pk): Loads this bean’s attributes with the corresponding data from a table, using the primary key to locate the row.

  • public Enumeration ejbFindByXXX(params...): Returns an enumeration of all primary keys of rows matching certain criteria (similar to a SQL WHERE clause).

Using bean-managed persistence is much more complex than using container-managed persistence. The following example illustrates the AccountBean again, but this time using bean-managed persistence. The important life cycle methods that make the synchronization with the database are implemented in Listing 10-5. Note that a programmer never actually calls these methods. They are implicitly called by the container.

Listing 10-5: Entity Bean with Bean-Managed Persistence
Start example
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.CreateException;
import javax.ejb.RemoveException;

public class AccountBean implements EntityBean {

  private EntityContext ctx;
  private String accountId; // also the primary Key
  private double balance;

  public void setEntityContext(EntityContext ctx) {
    this.ctx = ctx;
  }

  public void unsetEntityContext() {
    this.ctx = null;
  }

  public void ejbActivate() {
  }

  public void ejbPassivate() {
  }

  public void ejbLoad() {

    Connection conn = null;
    PreparedStatement ps = null;
    accountId = (String) ctx.getPrimaryKey();

    try {
      conn = getConnection();
      ps  = conn.prepareStatement("SELECT balance FROM accounts WHERE id = ?");
      ps.setString(1, accountId);
      ps.executeQuery();
      ResultSet rs = ps.getResultSet();
      if (rs.next()) {
        balance = rs.getDouble(1);
      } else {
        throw new NoSuchEntityException (accountId + " not found");
       }
    } catch (SQLException e) {
      throw new EJBException(e);
    } finally {
      try {
        if (ps != null) ps.close();
        if (conn != null) conn.close();
      } catch (Exception e) {
          throw new EJBException(e);
      }
    }
  }

  public void ejbStore() {

    Connection conn = null;
    PreparedStatement ps = null;

    try {
      conn = getConnection();
      ps = conn.prepareStatement("UPDATE accounts SET balance = ? WHERE id = ?");
      ps.setDouble(1, balance);
      ps.setString(2, accountId);
      if (!(ps.executeUpdate() > 0)) {
        throw new NoSuchEntityException (accountId + " not found");
      }
    } catch(SQLException e) {
      throw new EJBException (e);
    } finally {
      try {
        if (ps != null) ps.close();
        if (conn != null) conn.close();
      } catch (Exception e) {
          throw new EJBException(e);
      }
    }
  }

  public void ejbRemove() throws RemoveException
  {

    Connection conn = null;
    PreparedStatement ps = null;

    try {
      conn = getConnection();
      accountId = (String) ctx.getPrimaryKey();
      ps = conn.prepareStatement("DELETE FROM accounts WHERE id = ?");
      ps.setString(1, accountId);
      if (!(ps.executeUpdate() > 0)) {
        throw new NoSuchEntityException (accountId + " not found");
      }
    } catch (SQLException e) {
      throw new EJBException (e);
    } finally {
      try {
        if (ps != null) ps.close();
        if (conn != null) conn.close();
      } catch (Exception e) {
          throw new EJBException(e);
      }
    }
  }

  public String ejbCreate(String accountId, double initialBalance) throws
CreateException
  {
    this.accountId = accountId;
    this.balance   = initialBalance;

    Connection conn = null;
    PreparedStatement ps = null;

    try {
      conn = getConnection();
      ps = conn.prepareStatement("INSERT INTO accounts (id, balance)
 VALUES (?, ?)");
      ps.setString(1, accountId);
      ps.setDouble(2, balance);
      if (ps.executeUpdate() != 1) {
        throw new CreateException ("not created");
      }
      return accountId;

    } catch (SQLException e) {
      try {
        ejbFindByPrimaryKey(accountId);
      } catch(ObjectNotFoundException onfe) {
        throw new CreateException (e);
      }
      throw new DuplicateKeyException(accountId);
    } finally {
      try {
        if (ps != null) ps.close();
        if (conn != null) conn.close();
      } catch (Exception e) {
          throw new EJBException(e);
      }
    }
    return null;
  }

  public void ejbPostCreate(String accountId, double initialBalance)
  {
  }

  public String ejbFindByPrimaryKey(String pk) throws ObjectNotFoundException
  {
    Connection conn = null;
    PreparedStatement ps = null;

    try {
      conn = getConnection();
      ps  = conn.prepareStatement("SELECT balance FROM accounts WHERE id = ?");
      ps.setString(1, pk);
      ps.executeQuery();
      ResultSet rs = ps.getResultSet();
      if (rs.next()) {
        balance = rs.getDouble(1);
      } else {
        throw new ObjectNotFoundException (pk + " not found");
       }
    } catch (SQLException e) {
      throw new EJBException (e);
    } finally {
      try {
        if (ps != null) ps.close();
        if (conn != null) conn.close();
      } catch (Exception e) {
          throw new EJBException(e);
      }
    }
    return pk;
  }

  public double deposit(double amount)
  {
    balance += amount;
    return balance;
  }

  public double withdraw(double amount)
  {
    balance -= amount;
    return balance;
  }

  public double balance()
  {
    return balance;
  }
}
End example

Container-managed persistence versus bean-managed persistence

Using container-managed persistence has several advantages over using bean-managed persistence. However, the second technique allows more complex queries involving joins, for example, or queries involving stored procedures to be executed. Table 10-1 summarizes the advantages and disadvantages of both approaches.

Table 10-1: CONTAINER-MANAGED PERSISTENCE (CMP) VERSUS BEAN-MANAGED PERSISTENCE (BMP)
Advantage | CMP | BMP
Portability | Very portable with respect to the application server and database | Table names and SQL queries are hard-coded in the beans, which makes them less portable
Performance | Application servers may provide an enhanced object-relational bridge and caching technology | Developers are responsible for achieving the performance level that they require
JDBC code must be provided by the developer | No | Yes
Finer control on database mapping | No | Yes
Self-contained components (components that don’t need external code to integrate with databases) | Yes | Yes
Deployment tool facilities for database mapping at deployment time | Available | Not available
Maintenance of code | Easier because the code is database independent | More complex if several databases must be used or table names and queries have to be changed


Summary

This chapter discussed the way JDBC is used in the context of Enterprise JavaBeans. An overview of the different bean types and database access available in the EJB framework showed that developers face several choices when choosing to develop with J2EE application servers. Of course, usual JDBC code can be used in J2EE components, but what you were introduced to in this chapter shows that a great deal of the complexity of accessing databases from Java objects has been addressed by the designers of J2EE. It is therefore possible to hide such complexity in both container-managed entity beans and bean-managed entity beans.

The next chapter provides examples that illustrate several techniques discussed in previous chapters.


Part III: Learning from Examples

Chapter List

Chapter 11: Examples of Java Applications
Chapter 12: Complex Examples of Java Applications


Chapter 11: Examples of Java Applications

This chapter provides many examples of Java applets or standalone applications. Each example covers a particular topic discussed in this book.

Handling Simple Database Statements

Almost all database applications written in Java handle normal rows of data. SQL (Structured Query Language) only provides ways of inserting and extracting data in a tabular format, while permitting complex queries to be issued.

A simple Interactive SQL client application

My first example is a simple ISQL client application that shows how to handle normal rows of data in a simple way. ISQL stands for Interactive SQL, which means that this client can be used to send queries to a database and then retrieve the results in a text-based interface. This ISQL client is a standalone Java application.

As shown in Figure 11-1, after this application is launched, a number of questions appear on the screen. The questions prompt you for a Java Database Connectivity (JDBC) uniform resource locator (URL), a database login, and a database password. You then enter SQL queries from the keyboard, and the results immediately appear on-screen. This application is really a primitive ISQL client. However, it does support SQL selects, updates, and multiline queries.

Click To expand
Figure 11-1: The ISQL standalone application.

As Figure 11-1 shows, this simple ISQL standalone application runs in a terminal window. Its input is taken from the standard input, and its output is directed to the standard output. Default values are provided for connection parameters just for ease of use.

Listing 11-1 gives you an example of an ISQL session. It uses a database with only three tables: clients, accounts, and transaction history. These tables are used in another example later in the Bank of Java applet.

Listing 11-1: Simple Java ISQL
Start example
Enter the url or [ENTER] for jdbc:odbc:netbank :
Enter the login or [ENTER] for dba :
Enter the passwd or [ENTER] for default :
Type ‘quit’ on a blank line to exit, or ‘go’ to execute the query.
1> select * from clients
2> go
ownerno, name, address
1, Bernard Van Haecke, Brussels, 1000
2, John Doe, Imola Circuit, KM83
3, Jane Doe, Imola Circuit, KM83
4, Santa Klaus, North Pole, 1
5, Little Duke, Java Island, 1
6, The Bank, Downtown LA
1> select name, acctno, balance
2> from clients, accounts
3> where clients.ownerno = accounts.ownerno
4> order by balance
5> go
name, acctno, balance
Little Duke, 5, -840
Jane Doe, 3, 320600
Bernard Van Haecke, 1, 991900
John Doe, 2, 1256050
Santa Klaus, 4, 8892750
The Bank, 6, 999999995904
1> select distinct typetransaction
2> from history
3> go
typetransaction
Received
Transferred
Withdraw
1> select sum(balance)
2> from accounts
3> go
sum(balance)
1000011464704
1> update accounts
2> set balance = balance + (balance * 0.05)
3> go
6 row(s) affected.
1> quit
End example

There is only one class for this example: The class isql handles everything. The class constructor initializes the database connection and then calls a method that handles the user’s input in a loop to enable entry of multiple queries. The keywords go and quit are caught to process a query or quit the application. The database connection is closed when a quit is issued or a fatal error occurs.

Listing 11-2 shows the source code for this ISQL client.

Listing 11-2: An Interactive SQL Client
Start example
import java.sql.*;
import java.io.*;
import java.util.*;

/**
 * Title:        isql
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
*/

public class isql {

  static DataInputStream kbd = new DataInputStream(System.in);
  static String url = "jdbc:odbc:netbank";
  static String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
  static String login = "dba";
  static String passwd = "javabank";
  static Connection curConn = null;

  public static void main(String argv[]) throws IOException
  {
    String temp = "";
    System.out.println("Simple Java Isql, by Bernard Van Haecke,   1996.\n");
    System.out.print("Enter the url or [ENTER] for " + url + " : ");
    System.out.flush();
    temp = kbd.readLine();
    if (!temp.equals("")) url = temp;
    System.out.print("Enter the login or [ENTER] for " + login +  " : ");
    System.out.flush();
    temp = kbd.readLine();
    if (!temp.equals("")) login = temp;
    System.out.print("Enter the passwd or [ENTER] for default :  ");
    System.out.flush();
    temp = kbd.readLine();
    if (!temp.equals("")) passwd = temp;
    isql session = new isql();
  }

  public isql() throws IOException
  {
    try {
      Class.forName(driver);
      curConn = DriverManager.getConnection(url, login,  passwd);
      checkForWarnings(curConn.getWarnings ());
    }
    catch(java.lang.Exception ex) {
      System.out.println("url : " + url);
      System.out.println("login : " + login);
      System.out.println("passwd : " + passwd);
      ex.printStackTrace();
      return;
    }
    processQueries();
    finalize();
  }

  protected void finalize()
  {
    try {
      curConn.close();
    }
    catch (SQLException ex) { }
  }

  private void processQueries() throws IOException
  {
    int i = 1;
    String temp = "";
    String query = "";
    String results = "";
    System.out.println("Type ‘quit’ on a blank line to exit, or ‘go’ to execute
    the query.");
    do {
      System.out.print(i + "> ");
      System.out.flush();
      temp = kbd.readLine();
      if (temp.equals("quit"))
      break;
      if (temp.equals("go")) {
        executeThisQuery(query);
        i = 1;
        query = "";
      }
      else {
        query = query + " " + temp;
        i++;
      }
    } while (true);
  }

  private void executeThisQuery(String sqlText)
  {
    boolean resultSetIsAvailable;
    boolean moreResultsAvailable;
    int i = 0;
    int res=0;
    try {
      Statement curStmt = curConn.createStatement();
      resultSetIsAvailable = curStmt.execute(sqlText);
      ResultSet rs = null;
      for (moreResultsAvailable = true;  moreResultsAvailable;)
      {
        checkForWarnings(curConn.getWarnings());
        if (resultSetIsAvailable)
        {
          if ((rs = curStmt.getResultSet()) !=  null)
          {
            // we have a resultset
            checkForWarnings(curStmt.getWarnings());
            ResultSetMetaData rsmd = rs.getMetaData();
            int numCols = rsmd.getColumnCount();
            // display column headers
            for (i = 1; i <= numCols; i++)
            {
              if (i > 1) System.out.print(", ");
              System.out.print(rsmd.
              getColumnLabel(i));
            }
            System.out.println("");
            // step through the rows
            while (rs.next())
            {
              // process the columns
              for (i = 1; i <= numCols;  i++)
              {
                if (i > 1) System.out.print(", ");
                System.out.print(rs.getString(i));
              }
              System.out.println("");
            }
          }
        }
        else
        {
          if ((res = curStmt.getUpdateCount()) != -1)
          {
            // we have an updatecount
            System.out.println(res + "  row(s) affected.");
          }
          // else no more results
          else
          {
            moreResultsAvailable = false;
          }
        }
        if (moreResultsAvailable)
        {
          resultSetIsAvailable =  curStmt.getMoreResults();
        }
      }
      if (rs != null) rs.close();
      curStmt.close();
    }
    catch (SQLException ex) {
      // Unexpected SQL exception.
      ex.printStackTrace ();
    }
    catch (java.lang.Exception ex) {
      // Got some other type of exception. Dump it.
      ex.printStackTrace ();
    }
  }

  private static void checkForWarnings (SQLWarning warn) throws SQLException
  {
    while (warn != null) {
      System.out.println(warn);
      warn = warn.getNextWarning();
    }
  }
}
End example

A simple ISQL client applet

My second example is another ISQL client. It is different from the previous example because it runs as an applet. Anyone with a Java-enabled World Wide Web (WWW) browser can load the Hypertext Markup Language (HTML) file containing the applet tag that calls this applet. The logic to execute the SQL statements is similar to the logic of the command-line ISQL example.

A 100 percent Java JDBC driver must be supplied with such an applet. The JDBC-ODBC Bridge, for example, wouldn’t work because it calls native methods to talk to ODBC. “All-Java” drivers are becoming available as more and more developers implement the JDBC Driver Application Programming Interface (API).

It is remarkably simple to provide the 100 percent Java JDBC driver classes to the calling browser: The classes — the JDBC driver package — must be available in the directory where the applet resides. As soon as the Java applet is loaded in the virtual machine running in the WWW browser, the class loader notices that it needs additional classes, and a call to Class.forName() dynamically loads the appropriate driver class. The Hypertext Transfer Protocol (HTTP) server then sends the requested classes.

As shown in Figure 11-2, the applet lets you enter a SQL query in a floating window.

Click To expand
Figure 11-2: The ISQL applet.

Clicking the Go! button sends the query to the database and retrieves the results. Figure 11-3 shows the resulting rows of data displayed in another floating window.

Click To expand
Figure 11-3: Executing SQL statements.

The graphical user interface (GUI) part of this applet was created using Marimba Bongo, which generates a 100 percent portable .gui file containing the persisted GUI objects. This file contains a persistent form of the widgets used in this example. The unzipped Marimba classes must be in the CLASSPATH or available in the applet’s home directory on the WWW server to run this example.

On the Web

The .gui file uses several Marimba Bongo classes, which are available in demo version on this book’s companion Web site at www.hungryminds.com/extras/. Please see the Preface for details on accessing files on the Web site.

The following is the HTML file that calls the applet. The connection parameters are passed as arguments to the applet for greater convenience. These parameters specify which JDBC driver to load and which database URL to use. Note that the JDBC URL is dependent of the data source and driver. Its format varies a lot between products. In this case, you can notice that the database host is database. eng and its TCP/IP port is 8192.

<applet
name="jsql"
code="jsql.class"
width="430"
height="390"
align="Top"
alt="If you had a java-enabled browser, you would see an applet here."
>
<param name="driver" value="com.sybase.jdbc.SybDriver">
<param name="url" value="jdbc:sybase:Tds:database.eng:8192">
<param name="login" value="guest">
<param name="password" value="javabank">
<param name="catalog" value="javabank">
<hr>If your browser recognized the applet tag,
you would see an applet here.<hr>
</applet>

Listing 11-3 contains the source code for this ISQL applet example. Remember that the Marimba classes must be in the CLASSPATH or in the applet’s home directory on the WWW server to run.

Listing 11-3: An Interactive SQL Applet
Start example
import java.awt.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
import java.net.*;
import marimba.gui.*;

/**
 * Title:        jsql
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class jsql extends java.applet.Applet {

  Presentation presentation;
  PlayerPanel player;
  PlayerUtil util;
  Connection conn = null;
  DatabaseMetaData mtdt = null;
  ResultSet rs = null;

  /**
  * initialize the applet
  */
  public void init() {
    try {
    presentation =
    Presentation.getPresentation(new URL(getDocumentBase(), "jsql.gui"));
    }
    catch (MalformedURLException ex) {
      ex.printStackTrace();
    }
    // create a player panel
    setLayout(new BorderLayout());
    add("Center", player = new PlayerPanel());
    // set the presentation
    player.setPresentation(presentation);
    // create a player utility object
    util = new PlayerUtil(player);
    // load applet parameters
     ((ChoiceWidget) util.getWidget("dataURL")).addChoice(getParameter("url"));
     ((ChoiceWidget)
     util.getWidget("dataDriver") ).addChoice(getParameter("driver"));
    util.setText("dataLogin", getParameter("login"));
    util.setText("dataPasswd", getParameter("password"));
    util.setText("dataCatalog", getParameter("catalog"));
    // add some jdbc connection choices
    // jdbc-odbc bridge
    addDriverInfo("jdbc:odbc:data-source-name",
     "sun.jdbc.odbc.JdbcOdbcDriver");
    // sybase’s driver
    addDriverInfo("jdbc:sybase:Tds:host.domain.com:8192",
     "com.sybase.jdbc.SybDriver");
    // connect software’s sybase driver
    addDriverInfo("jdbc:sybase://host.domain.com:8192",
     "connect.sybase.SybaseDriver");
    // funny driver
    addDriverInfo("foo:bar:database", "foo.bar.Driver");
  }

  /**
  * add a new entry in the url and driver listboxes
  */
  public void addDriverInfo(String url, String driver)
  {
    // add entry for this driver provider
     ((ChoiceWidget) util.getWidget("dataURL")).addChoice(url);
     ((ChoiceWidget) util.getWidget("dataDriver")).addChoice(driver);
  }

  /**
  * we handle all gui events here
  */
  public boolean handleEvent(Event evt)
  {
    try {
      if ((evt.id == Event.ACTION_EVENT) && (evt.target instanceof Widget)) {
        Widget w = (Widget)evt.target;
        String nm = w.getName();
        if (nm != null) System.out.println("Event: " + nm);
        // The user has logged in.
        if (nm.equals("dataLoginButton")) {
          String url = util.getText("dataURL").trim();
          String uid = util.getText("dataLogin").trim();
          String pwd = util.getText("dataPasswd").trim();
          String catalog = util.getText("dataCatalog").trim();
          String driver = util.getText("dataDriver").trim();
          try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, uid, pwd);
            if (conn != null) {
              mtdt = conn.getMetaData();
              conn.setCatalog(catalog);
            }
          }
          catch (SQLException ex) {
            System.out.println(ex);
          }
          catch (java.lang.Exception ex) {
            System.out.println(ex);
          }
        }
        // The user has clicked logout
        if (nm.equals("dataLogoutButton")) {
          if (conn != null) {
            conn.close();
          }
        }
        // execute the sql query
        if (nm.equals("isqlGoButton")) {
          String query = util.getText("isqlQueryText");
          if (true)
          {
            TableWidget tbl = (TableWidget)  util.getWidget("isqlResultTable");
            tbl.removeAllRows();
            tbl.removeAllColumns();
            util.show("isqlResultWindow", true);
            ResultSet rs = getSingleRS(query);
            Vector headers = getRSColumnHeadersAsVector(rs);
            int i;
            for (i=0; i<headers.size(); i++)
            tbl.addColumn((String) headers.elementAt(i));
            Vector rows = getRSRowsAsVector(rs);
            for (i=0; i<rows.size(); i++)
              tbl.addRow((Vector) rows.elementAt(i));
            rs.close();
          }
        }
        // close the isql result window
        if (nm.equals("resultCloseButton")) {
          util.show("isqlResultWindow", false);
        }
      }
    }
    catch(java.lang.Exception ex) {
      ex.printStackTrace();
    }
    return super.handleEvent(evt);
  }

  /**
  * return the resultset of a simple query
  */
  public ResultSet getSingleRS(String sqlText)
  {
    ResultSet rs = null;
    int res;
    try {
      Statement st = conn.createStatement();
      if (st.execute(sqlText)) {
        // okay it’s not an update count
        rs = st.getResultSet();
      }
      else if ((res = st.getUpdateCount()) != -1) {
        // it’s an update count
        // we could display it
      }
    } catch (SQLException ex) { ex.printStackTrace(); }
    return rs;
  }

  /**
  * return the column headers of a resultset as vector
  */
  public Vector getRSColumnHeadersAsVector(ResultSet rs) {
    int i;
    Vector v = new Vector();
    try {
      ResultSetMetaData rsmd = rs.getMetaData();
      int numCols = rsmd.getColumnCount();
      // fetch column headers
      for (i = 1; i <= numCols; i++)
      {
        v.addElement(rsmd.getColumnLabel(i));
      }
    }
    catch (SQLException ex)
    {
    }
    return v;
  }

  /**
  * return a resultset as vector
  */
  public Vector getRSRowsAsVector(ResultSet rs) {
    ProgressIndicatorWidget bar = (ProgressIndicatorWidget)
    util.getWidget( "sqlProgressBar");
    int barValue = 0;
    Vector v = new Vector();
    Vector r = null;
    int i;
    try {
      ResultSetMetaData rsmd = rs.getMetaData();
      int numCols = rsmd.getColumnCount();
      bar.setValue(0);
      // step through the rows
      while (rs.next())
      {
        // process the columns
        r = new Vector();
        for (i = 1; i <= numCols; i++)
        {
          r.addElement(rs.getString(i));
        }
        v.addElement(r);
        if (barValue < 100) {
          barValue = barValue + 10;
        }
        else {
          barValue = 0;
        }
        bar.setValue(barValue);
        bar.repaint();
      }
    }
    catch (SQLException ex)
    {
    }
    return v;
  }
}
End example


Handling Multimedia Content

SQL doesn’t provide mechanisms that are powerful enough to handle binary large objects, known as BLOBs. Fortunately, JDBC contains the necessary methods to insert and extract BLOBs.

Sending BLOBS

My next example is a simple command-line tool used to insert binary large objects in a table. You can use any kind of BLOB, including pictures, audio files, binary data, and texts. This program is quite simple to use. The tool prompts you for a database URL, a login, a password, the name of the table to be updated, the BLOB column name (which is the column that holds a BLOB), and the BLOB filename.

A row must exist in the table before trying to insert a BLOB. For example, a table of employees must contain a row for Jones before a picture can be inserted for this employee. To locate this row, the program also prompts for a column name and value, which represent search criteria. In the case of employee Jones, simply use name as the column name and Jones as the column value.

You can pass all parameters but the database URL, login, and password on the command line. In this case, the program uses the default URL, login, and password. Passing parameters on the command line is extremely convenient for inserting multiple BLOBs at once from a shell script.

Consider the following script, which contains batched commands. The script calls the BLOB program example several times in order to populate a database table with pictures:

java txblob -c employees pict name Jones /tmp/pictures/jones.jpg
java txblob -c employees pict name Dupont /tmp/pictures/dupont.jpg
java txblob -c employees pict name Duke /tmp/pictures/duke.jpg
java txblob -c employees pict name Jack /tmp/pictures/jack.jpg
...
...

The preceding batch command inserts the pictures of Jones, Dupont, Duke, and Jack in the table of employees. Note that the field that is updated with picture bytes should be of the SQL type LONGVARBINARY.

Listing 11-4 contains the source code for this example.

Listing 11-4: txblob.java
Start example
import java.sql.*;
import java.io.*;
import java.util.*;

/**
 * Title:        txblob
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class txblob {

  static DataInputStream kbd = new DataInputStream(System.in);
  static String url = "jdbc:odbc:netbank";
  static String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
  static String login = "dba";
  static String passwd = "javabank";
  static String filename = "";
  static String tablename = "";
  static String blobcolumnname = "";
  static String selectcolumnname = "";
  static String selectcolumnvalue = "";
  static Connection curConn = null;

  public static void main(String argv[]) throws IOException
  {
    String temp = "";
    if (argv[0].equals("-c")) {
      tablename = argv[1];
      blobcolumnname = argv[2];
      selectcolumnname = argv[3];
      selectcolumnvalue = argv[4];
      filename = argv[5];
    } else {
      System.out.println("Simple tool to insert BLOBS, by Bernard Van Haecke,
      1996.\n");
      System.out.print("Enter the url or [ENTER] for " + url  + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) url = temp;
      System.out.print("Enter the login or [ENTER] for " +  login + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) login = temp;
      System.out.print("Enter the passwd or [ENTER] for " +  passwd + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) passwd = temp;
      System.out.print("\nEnter the table name : ");
      System.out.flush();
      tablename = kbd.readLine();
      System.out.print("Enter the blob column name : ");
      System.out.flush();
      blobcolumnname = kbd.readLine();
      System.out.print("Enter the row selection criteria  column name : ");
      System.out.flush();
      selectcolumnname = kbd.readLine();
      System.out.print("Enter the row selection criteria  value : ");
      System.out.flush();
      selectcolumnvalue = kbd.readLine();
      System.out.print("Enter the file name : ");
      System.out.flush();
      filename = kbd.readLine();
    }
    txblob session = new txblob();
  }

  public txblob() throws IOException
  {
    try {
      Class.forName(driver);
      curConn = DriverManager.getConnection(url, login,  passwd);
    }
    catch(java.lang.Exception ex) {
      System.out.println("url : " + url);
      System.out.println("login : " + login);
      System.out.println("passwd : " + passwd);
      ex.printStackTrace();
      return;
    }
    processBlob();
    finalize();
  }

  protected void finalize()
  {
    try {
      curConn.close();
    }
    catch (SQLException ex) { }
  }

  private void processBlob() throws IOException
  {
    try {
      java.io.File blobFile = new java.io.File(filename);
      int blobFileLen = (int) blobFile.length();
      java.io.InputStream fblob = new  java.io.FileInputStream(blobFile);
      PreparedStatement myStmt = curConn.prepareStatement(
       "UPDATE " + tablename + " SET " + blobcolumnname + " = ? WHERE " +
       selectcolumnname + " = ?");
      myStmt.setBinaryStream(1, fblob, blobFileLen);
      myStmt.setString(2, selectcolumnvalue);
      int res = myStmt.executeUpdate();
      myStmt.close();
    }
    catch (SQLException ex) {
      // Unexpected SQL exception.
      System.out.println(ex);
    }
    catch (java.lang.Exception ex) {
      // Got some other type of exception. Dump it.
      ex.printStackTrace ();
    }
  }
}
End example

Retrieving BLOBS

My next example is very similar to the previous one. It is a simple command-line tool to retrieve binary large objects from a table. It prompts for a database URL, a login, a password, the name of the table to be updated, the BLOB column name (which is the column that holds a BLOB), and the BLOB filename where this BLOB must be stored.

For example, if a table of employees contains a row for Jones and if a picture is available for this employee, it is possible to retrieve it. To locate this row, the program prompts for a column name and value, which represent search criteria. In the case of employee Jones, you can simply use name as the column name and Jones as the column value.

All parameters but the database URL, login, and password pass on the command line. In this case, the program uses the default URL, login, and password. This is extremely convenient for retrieving many BLOBs at once from a shell script.

Consider the script in Listing 11-5. Several batched calls to the program example are made in order to retrieve pictures from a database table.

Listing 11-5: Batch Command
Start example
java rxblob -c employees pict name Jones /tmp/pictures/jones.jpg
java rxblob -c employees pict name Dupont /tmp/pictures/dupont.jpg
java rxblob -c employees pict name Duke /tmp/pictures/duke.jpg
java rxblob -c employees pict name Jack /tmp/pictures/jack.jpg
...
...
End example

The batch command in Listing 11-5 retrieves the pictures of Jones, Dupont, Duke, and Jack from the table of employees and stores these pictures in different files. The filename and file type aren’t stored in the table. You could have stored the file type in the table by simply adding a file type record. In case the client application isn’t aware of the BLOB format, it is mandatory to store this type of information somewhere. It is possible to do so, but, in this case, special fields must be added to the table structure because it is considered extra information regarding BLOBs. Indeed, BLOBs are nothing more than untyped binary data.

It may be a good idea to hold the data type along with BLOBs, particularly when the information is to be extracted and sent to a Web browser. In this case, it is appropriate to store the BLOB’s Multimedia Internet Mail Extension (MIME) type in a specific field of the table so that the browser knows how to interpret the data (for example, should the browser display the data as a JPEG [Joint Photographic Experts Group] picture or MPEG [Motion Pictures Experts Group] movie file or play it as an .au [common audio file on UNIX machines] sound file).

Listing 11-6 contains the source code for this example.

Listing 11-6: rxblob.java
Start example
import java.sql.*;
import java.io.*;
import java.util.*;

/**
 * Title:        rxblob
 * Description:
* Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class rxblob {

  static DataInputStream kbd = new DataInputStream(System.in);
  static String url = "jdbc:odbc:netbank";
  static String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
  static String login = "dba";
  static String passwd = "javabank";
  static String filename = "";
  static String tablename = "";
  static String blobcolumnname = "";
  static String selectcolumnname = "";
  static String selectcolumnvalue = "";
  static Connection curConn = null;

  public static void main(String argv[]) throws IOException
  {
    String temp = "";
    if ((argv[0] != null) && (argv[0].equals("-c")))
    {
      tablename = argv[1];
      blobcolumnname = argv[2];
      selectcolumnname = argv[3];
      selectcolumnvalue = argv[4];
      filename = argv[5];
    } else {
      System.out.println("Simple tool to retrieve BLOBS, by Bernard Van Haecke,
      1996.\n");
      System.out.print("Enter the url or [ENTER] for " + url  + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) url = temp;
      System.out.print("Enter the login or [ENTER] for " +  login + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) login = temp;
      System.out.print("Enter the passwd or [ENTER] for " +  passwd + " : ");
      System.out.flush();
      temp = kbd.readLine();
      if (!temp.equals("")) passwd = temp;
      System.out.print("\nEnter the table name : ");
      System.out.flush();
      tablename = kbd.readLine();
      System.out.print("Enter the blob column name : ");
      System.out.flush();
      blobcolumnname = kbd.readLine();
      System.out.print("Enter the row selection criteria  column name : ");
      System.out.flush();
      selectcolumnname = kbd.readLine();
      System.out.print("Enter the row selection criteria  value : ");
      System.out.flush();
      selectcolumnvalue = kbd.readLine();
      System.out.print("Enter the file name : ");
      System.out.flush();
      filename = kbd.readLine();
    }
    rxblob session = new rxblob();
  }

  public rxblob() throws IOException
  {
    try {
      Class.forName(driver);
      curConn = DriverManager.getConnection(url, login, passwd);
    }
    catch(java.lang.Exception ex) {
      System.out.println("url : " + url);
      System.out.println("login : " + login);
      System.out.println("passwd : " + passwd);
      ex.printStackTrace();
      return;
    }
    processBlob();
    finalize();
  }

  protected void finalize()
  {
    try {
      curConn.close();
    }
    catch (SQLException ex) { }
  }

  private void processBlob() throws IOException
  private void processBlob() throws IOException
  {
    try {
      java.io.File blobFile = new java.io.File(filename);
      java.io.OutputStream fblob = new java.io.FileOutputStream(blobFile);
      java.sql.Statement myStatement = curConn.createStatement();
      ResultSet rs = myStatement.executeQuery("SELECT " + blobcolumnname +
      " FROM " + tablename + " WHERE " + selectcolumnname + " = " +
      selectcolumnvalue);
      // we retrieve in 4K chunks
      byte[] buffer = new byte[4096];
      int size;
      if (rs.next()) {
        // fetch blob
        java.io.InputStream strin =  rs.getBinaryStream(blobcolumnname);
        for (;;)
        {
          size = strin.read(buffer);
          if (size == 0)
          {
            break;
          }
          // Send the buffer to some output stream
          fblob.write(buffer, 0, size);
        }
      }
      else System.out.println("Row not found.");
      myStatement.close();
      rs.close();
    }
    catch (SQLException ex) {
      // Unexpected SQL exception.
      System.out.println(ex);
    }
    catch (java.lang.Exception ex) {
      // Got some other type of exception. Dump it.
      ex.printStackTrace ();
    }
  }
}
End example


Accessing a Database Remotely with a Browser

Looking for cheap tickets? Choose JDBC Airlines! The JDBC Airlines applet illustrates remote access to a database through a browser user interface. This example runs as an applet within World Wide Web browsers that support Java. It uses JDBC to connect and retrieve flight schedules from a database. No other middleware is involved. The JDBC driver used for this example is a 100 percent Java driver that directly connects to the database server.

Figure 11-4 shows the JDBC Airlines applet, which is from Connect Software, Inc.

Click To expand
Figure 11-4: Connect Software’s JDBC Airlines applet.

Thanks to its 100 percent Java drivers, this applet is able to run within any Java-compatible WWW browser. Again, no specific classes must be preinstalled on the client machine. The JDBC driver downloads from the Web server along with the applet classes.

The HTML file

The following is the HTML file for this example; it contains the tag to load the applet as well as parameters that provide connection information to the applet. Such connection information includes the driver to use to connect to the database and the database’s URL.

<html>
<head>
<title>
Airplet, the Airline Applet by Connect Software
</title>
</head>
<body bgcolor="#FFFFFF">
<center>
<img src="images/banner.gif">
<p>
<applet code=airplet.Airplet width=500 height=600>
<param name=driver value=connect.sybase.SybaseDriver>
<param name=connection value=’jdbc:sybase://db.mydomain.com:8192/airline;user=guest;password=guest’>
</center>
</applet>
</html>

A Type 4 driver for Sybase was used in this example. If a Type 4 driver is available for your database, refer to its documentation for the format of the URL and possible restrictions when using it over the Internet. If the driver and database listener doesn’t support HTTP-tuneling, firewalls and Web proxies won’t be supported.

Airplet.java

Airplet.java is the main applet class. Initialization establishes a connection with the database server. As soon as the connection is established, various panels are prepared and displayed. These panels include a panel with name and preset choices for departure and arrival airports, a panel with search and roundtrip buttons, and a panel with maps and routes between airports.

User events are handled when selecting airport choices and clicking search or roundtrip buttons. A search for flights from the origin to the destination is performed. A method is also provided to load map images from the server.

On the Web

The structure of the database tables plus some sample data is available on this book’s companion Web site at www.hungryminds.com/extras/. Please see the Preface for details on accessing files on the Web site.

Listing 11-7 shows the source code for the main part of the applet, Airplet. java.

Listing 11-7: Airplet.java
Start example
//
// Airplet.java - Connect Software’s Airline Applet, a.k.a. jdbc airlines
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//
// Connect Software, Inc.
// 81 Lansing Street, Suite #411
// San Francisco, CA 94105
// (415) 710-1544 (phone) - (415) 543-6695 (fax)
//
// email: info@connectsw.com - www: http://www.connectsw.com

package airplet; // airplet’s package
import java.applet.*; // import a number of java libraries
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.sql.*; // import modified jdbc libraries

public class Airplet extends java.applet.Applet // main applet class
{

    private TextField nameTo = null; // names of departure and arrival airports
    private TextField nameFrom = null;
    private AirportChoice choiceTo = null;
    // preset lists of departure and arrival airports
    private AirportChoice choiceFrom = null;
    private FlightsPanel panelFlights = null;
    // panel containing maps and flight listings

    /** Initialize the applet, opens the connection with the database and
        add user interface items in the applet. */

    synchronized public void init()
    {
         airplet = this; // static reference to this airplet
         setBackground(Color.white); // white background for this applet
        LayoutManager columnLayout = new ColumnLayout(5,5);
        // all panels go in a single column
        setLayout(columnLayout);
        showStatus("Connecting...");
        // let user know we’re connecting to the database
        try
            {
                String driver = getParameter("driver");
                // use sql driver specified in ‘driver’ parameter
                if(driver != null) Class.forName(driver).newInstance();
                // register driver with DriverManager
                String url = getParameter("connection"); // get connection’s url
                connection = DriverManager.getConnection(url);
                // establish connection with server
            }
        catch(Exception sqlEx)
            {
                System.out.println("Connection failed because " + sqlEx + "\n");
            }
        showStatus("Preparing...");
        try
            {
                // create panel with name and preset choices
                // for departure’s airport
                Panel panelFrom = new Panel();
                ImageCanvas imageFrom = new
                    ImageCanvas("images/airFrom.gif"); panelFrom.add(imageFrom);
                nameFrom = new TextField(25); panelFrom.add(nameFrom);
                choiceFrom = new AirportChoice(); panelFrom.add(choiceFrom);
                // create panel with name and preset choices
                // for arrival’s airport
                Panel panelTo = new Panel();
                ImageCanvas imageTo = new ImageCanvas("images/airTo.gif");
                panelTo.add(imageTo);
                nameTo = new TextField(25); panelTo.add(nameTo);
                choiceTo = new AirportChoice(); panelTo.add(choiceTo);
                Panel panelButtons = new Panel();
                // panel with search and roundtrip buttons
                Button button1 = new Button("Search"); panelButtons.add(button1);
                Button button2 = new Button("Roundtrip");
                panelButtons.add(button2);
                panelFlights = new FlightsPanel(); // panel with maps and routes
                add(panelFrom); // add all panels to the applet
                add(panelTo);
                add(panelButtons);
                add(panelFlights);
                showStatus("Connect Software, 1996."); // here we are!
            }
        catch(SQLException sqlEx) {
            showStatus("Sorry, could not initialize, e-mail
            support@connectsw.com");
        }
   }

   /** Responds to user selecting an airport in the choice menus or clicking
       search or roundtrip. */
   public boolean action(Event iEvent,Object iArgument)
   {
        if(iEvent.target == choiceFrom) // user picked an origin from the choices
            {
                Airport air = choiceFrom.getSelectedAirport();
                nameFrom.setText(air.getName());
                // copy origin’s name to origin’s text field
                return true;
            }
        if(iEvent.target == choiceTo)
        // user picked a destination from the choices
            {
                Airport air = choiceTo.getSelectedAirport();
                nameTo.setText(air.getName());
                // copy destination’s name to destination’s text field
            }
        // search for flights from origin to destination
        if(iArgument.equals("Search") || iArgument.equals("Roundtrip"))
            {
                String airFrom = nameFrom.getText();
                if(airFrom.length() < 1) airFrom = choiceFrom.getSelectedItem();
                String airTo = nameTo.getText();
                if(airTo.length() < 1) airTo = choiceTo.getSelectedItem();
                searchFlights(airFrom,airTo,iArgument.equals("Roundtrip"));
                return true;
             }
         return super.action(iEvent,iArgument); // event was handled
    }

    private void searchFlights(String departingFrom,String arrivingTo,
    boolean roundTrip)
    {
         try
             {
                 Airport airFrom = Airport.getAirport(departingFrom);
                 // find out more about departing airport
                 Airport airTo = Airport.getAirport(arrivingTo);
                 // find out more about arriving airport
                 // if both airports were found (and they are different)
                 if(airFrom != null && airTo != null)
                     {
                          // show complete name and code for departure airport
                          nameFrom.setText(airFrom.getName());
                          choiceFrom.select(airFrom.getCode());
                          // show complete name and code for arrival airport
                          nameTo.setText(airTo.getName());
                          choiceTo.select(airTo.getCode());
                          if(roundTrip) // if user requested return trip
                              {
                                  // show inverse route
                                  panelFlights.setAirports(airTo,airFrom);
                              }
                          // show normal route
                          else panelFlights.setAirports(airFrom, airTo);
                          layout();
                     }
             }
         catch(SQLException sqlEx) { panelFlights.setText(sqlEx.toString());
         }
    }
    static Statement createStatement() throws SQLException
    {
         return connection.createStatement();
    }

    private static Connection connection = null;
    // connection to the airline database

    /** Loads given image from the network, or file system, and returns it. */
    static Image loadImage(String iName)
    {
         if(images == null) // if there’s no hash table for images yet
             {
                 images = new Hashtable(); // create an empty hash table
             }
         // try to get image from the hash table (hash is image’s name)
         Image image = (Image) images.get(iName);
         if(image == null) // if this image hasn’t been loaded yet
             {
                 try // catch all loading problems
                     {
                          // create url of image on Web server or
                          // local file system
                          URL url = new URL(airplet.getDocumentBase(), iName);
                          image = airplet.getImage(url); // try to load image
                          airplet.prepareImage(image,airplet);
                     }
                 catch(Exception e) { }
                 if(image != null) // if image was loaded
                     {
                          // add it to the hash table so next time
                          // we don’t have to load it
                          images.put(iName,image);
                     }
             }
         return image; // return the image
    }

    static private Hashtable images = null; // a hash table of loaded images
    // a static reference to this applet
    // (there’s only one instance of it running at any time)
    static private Airplet airplet = null;
}
End example

Airport.java

Airport.java holds the information regarding an airport. The constructor executes a query returning airport details such as its code, its name, its description, and its geographical coordinates in terms of x and y positions on different maps.

A hash table of airports is also created in Listing 11-8, which shows the source code of Airport.java.

Listing 11-8: Airport.java
Start example
//
// Airport.java - this object holds information regarding an airport
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.sql.*; // import sql server access classes
import java.awt.*; // java’s windowing toolkit and other ui classes
import java.util.*; // utility classes

/** Information regarding an airport. */
class Airport
{

    public Airport(String iAirport) throws SQLException
    {
         iAirport = iAirport.trim(); // remove leading and trailing spaces
         // use normal statement to query the Airports table
         ResultSet r = null; Statement s = Airplet.createStatement();
         if(iAirport.length() == 3) // if this is likely to be an airport code
             {
                 r = s.executeQuery("select * from airports where code =
                 ‘" + iAirport + "‘");
                 // move over to the first (and only) row in the result set
                 if(r.next() == false)
                     {
                          r = null;
                          // there are no entries with given airport code
                     }
             }
         // search for airports whose name contain given airport
         // string (like %string%)
         if(r == null)
             {
                 r = s.executeQuery("select * from airports where name like ‘%" +
                 iAirport + "%’");
                 // move to first (and probably only) row in result set
                 if(r.next() == false)
                     {
                          // case insensitive name, eg. [mM][iI][lL][aA][nN]
                          // instead of Milan
                          String nocase = "";
                          // scan all characters in the string
                          for(int i = 0 ; i < iAirport.length() ; i++)
                              {
                                  // extract character then convert to
                                  // lowercase and uppercase
                                  String single = iAirport.substring(i,i+1);
                                  String lower = single.toLowerCase(), upper =
                                  single.toUpperCase();
                                  // if lowercase is different from uppercase
                                  // (that is, if this character is alpha)
                                  if(lower.equals(upper) == false)
                                      {
                                           // regular expression for both lower
                                           // or uppercase
                                           // (for example, [aA])
                                           nocase += "[" + lower + upper + "]";
                                      }
                                  else nocase += single;
                              }
                          r = s.executeQuery("select * from airports where name
                          like ‘%" +
                          nocase + "%’");
                          // if this one didn’t work either, there’s
                          // no such airport
                          if(r.next() == false) r = null;
                     }
             }
         if(r != null)
             {
                 code = r.getString("code"); // airport code, eg. ‘SFO’
                 name = r.getString("name"); // airport name,
                                             // eg. ‘San Francisco, CA’
                 description = r.getString("description"); // description
                                                           // of this airport
                 StringTokenizer sTokenizer = new StringTokenizer
                 (r.getString("maps"),";");
                 // scan each token, maps entry looks something like
                 // "california(45,60);usa(123,3);world(56,78)"
                 while(sTokenizer.hasMoreTokens())
                     {
                          // create an object containing information regarding
                          // this airport on a single map
                          MapInfo info = new MapInfo(sTokenizer.nextToken());
                          if(maps != null) // if there are other maps already
                              {
                                  // add this map to the linked list of maps
                                  maps.append(info);
                              }
                          else maps = info; // this is the first map in the list
                          // System.out.println(code + " map " + info);
                     }
             }
         else throw new SQLException("Can’t find ‘" + iAirport +
         "‘ in the airports database.");
    }

    // airport code, name and description, eg. ‘SFO’,
    // ‘San Francisco, CA’, ‘International Airport, ...’
    private String code, name, description;

    // linked list of maps available for this airport (and coordinates
    // on each map) in preferred order (eg. ‘california’, ‘usa’, ‘world’)
    private MapInfo maps;

    public String getCode()
    {
         return code; // return airport code
    }

    public String getName()
    {
         return name;
    }

    public MapInfo getMaps()
    {
         return maps;
    }

    /** Returns airport with the given name or code. */
    static public Airport getAirport(String iName)
    {
         try
             {
                 if(airports = null) // if there’s no hash table for airports
                     {
                          // create an empty hash table
                          airports = new Hashtable();
                     }
                 // try getting the airport from the hash table
                 Airport airport = (Airport) airports.get(iName);
                 if(airport = null) // if airport was not found
                     {
                          // create a new airport from that name
                          // (will query the database)
                          airport = new Airport(iName);
                          // add airport to the hash table (by name)
                          airports.put(airport.getName(),airport);
                          // add also by code
                          airports.put(airport.getCode(),airport); //
                     }
                 return airport; // return the airport
             }
         catch(SQLException sqlException) { return null; } // airport could
                                                           // not be found
    }

    // hash table of airports (used to minimize database access)
    static private Hashtable airports = null;

    public String toString()
    {
         return "Airport[" + code + "," + name + "]"; // convert object to string
    }
}
End example

AirportChoice.java

The AirportChoice.java class queries the database to build a list of airport codes such as SFO, LAX, and JFK. The list is used within the user interface to enable the user to choose the departure and arrival airports. Listing 11-9 shows the source code for AirPortChoice.java.

Listing 11-9: AirportChoice.java
Start example
//
// AirportChoice.java - user interface widget showing a choice of airports
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.sql.*; // import jdbc and other sql libraries
import java.awt.*; // java windowing toolkit

/** A choice user interface widget showing a list of available airport codes. */
class AirportChoice extends Choice
{

    /**
     * Initialize the choice user interface widget with a list of airports
     * available in the database. The method will query the airports table
     * of the database, listing all available airports by code.
     */
    public AirportChoice() throws SQLException
    {
         // use sql to select all airport codes from the
         // airports table then add them to the widget
         // scan all the airports in the table
         Statement s = Airplet.createStatement();
         for(ResultSet r = s.executeQuery("select code from airports
         order by code") ; r.next() ; )
             {
                 String name = r.getString(1); // name of this airport
                 addItem(name); // add airport to the choices
             }
         s.close(); // close statement
    }
    /** Returns the Airport corresponding to the entry with the given index. */
    public Airport getAirport(int index)
    {
         return Airport.getAirport(getItem(index)); // return Airport object
    }
    /** Returns the currently selected Airport. */

    public Airport getSelectedAirport()
    {
         return getAirport(getSelectedIndex());
    }

}
End example

ColumnLayout.java

The ColumnLayout.java class arranges a set of components in a single column. The source code for this class is in Listing 11-10.

Listing 11-10: ColumnLayout.java
Start example
//
// ColumnLayout.java - layout that arranges all components in a column
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo.
//

package airplet;
import java.awt.*; // import java windowing classes
/** A layout that arranges all components in a single column. */

public class ColumnLayout implements LayoutManager // just another layout manager
{

    public ColumnLayout()
    {
         hgap = vgap = 0; // no gap between components
    }

    public ColumnLayout(int hgap,int vgap)
    {
         this.hgap = hgap; this.vgap = vgap; // use this spacing
                                             // between components
    }

    private int hgap, vgap; // horizontal and vertical spacing between components
    /** Arrange components contained in iParent in a single column using their
        preferred size. */

    public void layoutContainer(Container iParent)
    {
         Insets insets = iParent.insets(); // insets (borders around
                                           // the container)
         Dimension dimension = iParent.size(); // size of parent container
         dimension.width -= insets.left + insets.right; // net width of container
         for(int i = 0, v = vgap ; i < iParent.countComponents() ; i++)
             {
                 // scan each component in the container
                 Component component = iParent.getComponent(i);
                 // get component’s preferred size and then reshape it
                 Dimension size = component.preferredSize();
                 component.reshape(insets.left,v,dimension.width - insets.left -
                 insets.right,size.height);
                 component.repaint(); // redraw the component
                 // update vertical origin for next component
                 v += size.height + vgap;
             }
    }

    /** Returns the minimum layout size calculated using each component’s
        preferred size. */
    public Dimension minimumLayoutSize(Container iParent)
    {
         Dimension dimension = new Dimension(0,0);
         for(int i = 0 ; i < iParent.countComponents() ; i++) // scan components
             {
                 Component component = iParent.getComponent(i);
                 // get i-th component’s size
                 Dimension size = component.preferredSize();
                 dimension.width = Math.max(dimension.width,size.width);
                 // update height including this component
                 dimension.height += size.height + vgap;
             }
         Insets insets = iParent.insets(); // add insets (border)
         dimension.width += insets.left + insets.right + 2 * hgap;
         dimension.height += insets.top + insets.bottom + vgap;
         return dimension;
    }

    /** Preferred size is just like minimum size but can be as wide as the parent
        component. */
    public Dimension preferredLayoutSize(Container iParent)
    {
         Dimension dimension = minimumLayoutSize(iParent);
         dimension.width = Math.max(iParent.size().width,dimension. width);
         return dimension;
    }

    public void addLayoutComponent(String iName,Component iComponent)
    {
    }

    public void removeLayoutComponent(Component iComponent)
    {
    }
}
End example

Flight.java

Flight.java contains a constructor that initializes the class members (attributes) using flight information. Flight.java extracts the flight number, departure and arrival, flight frequency, and plane identification. Listing 11-11 shows the source code for this class.

Listing 11-11: Flight.java
Start example
//
// Flight.java - holds information regarding a flight
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.sql.*;         // import jdbc and other sql libraries

class Flight
{

    /**
     * Initialize flight from the information contained in the current
     * row of this result set. The result set is a subset of rows from
     * the flights table in the airline database. This method will read
     * information on current row (it will not call next).
     *
     * @param iFlight is a result set whose current row is a flight
     */

    public Flight(ResultSet iFlight) throws SQLException
    {
        code = iFlight.getString("code"); // get flight number
        from = iFlight.getString("from_city"); to = iFlight.getString("to_city");
        departure = iFlight.getTime("departure"); arrival =
        iFlight.getTime("arrival");
        // flight frequency (eg. which days this flight operates)
        frequency = iFlight.getString("frequency");
        plane = iFlight.getString("plane"); // airplane used
   }
   String code, from, to; // the flight code/number and city of
                          // departure/arrival, e.g., ‘TWA800’
   Time departure, arrival; // departure and arrival time
   String frequency; // days when the flight is available,
                     // e.g., 123 for Mon, Tue, Wed
   String plane; // airplane used, e.g., "Boeing 767"

   public String toString()
   {
        return "Flight[" + code + "," + from + " " + departure + "," + to + " " +
        arrival +
        "," + frequency + "," + plane + "]";
   }
}
End example

FlightsPanel.java

The FlightsPanel.java class is a panel containing a graphical map. Which map is displayed depends on the departure and destination airport locations. This panel also displays the routes. Listing 11-12 contains the source code for this class.

Listing 11-12: FlightsPanel.java
Start example
//
// FlightsPanel.java - a panel showing flight information and routes
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet; // airplet package
import java.sql.*; // import connect’s jdbc libraries
import java.awt.*; // import java windowing library

class FlightsPanel extends Panel
{

    public FlightsPanel()
    {
         // column layout with 10 pixels between components
         LayoutManager layout = new ColumnLayout(0,10);
         setLayout(layout); // use this layout for the panel
         map = new MapCanvas(); add(map); // add a map to the panel
         // label that can display multiple lines of text (draw with subtle
         // good looking shadow)
         label = new MultilineLabel(Label.CENTER);
         setText("Welcome to jdbc airlines!\n \nPlease pick an origin and a
         destination\n" +
         "then click Search or RoundTrip.");
         add(label); // add label to panel
    }

    /** Converts a time object into a string in the form hh:mm am/pm */
    String time2string(Time time)
    {
         int hour = time.getHours(); // get hours (0..23) and minutes (0..59)
         // format the string as hh:mm then append am or pm
         int minute = time.getMinutes();
         return (hour % 12 < 10 ? "0" : "") + Integer.toString(hour % 12) + ":" +
         (minute < 10 ? "0" : "") + Integer.toString(minute) +
         (hour < 12 ? " AM" : " PM");
    }

    void setAirports(Airport iFrom,Airport iTo) throws SQLException
    {
         String str = null;
         try
             {
                 // show best map for these two airports
                 // (and a route between them)
                 map.setAirports(iFrom,iTo);
                 // if the two airports are not the same
                 if(iFrom.getCode().equals(iTo.getCode()) = false)
                     {
                          // create a vector containing all the
                          // flights between the two airports
                          FlightsVector flights = new FlightsVector(iFrom,iTo);
                          int numFlights = flights.size(); // number of flights
                                                           // found
                          if(numFlights > 0) // if there are flights
                              {
                                  str = "Flights from " + iFrom.getName() +
                                  " to " + iTo.getName() + "\n \n";
                                  // scan flights between these two airports
                                  for(int i = 0 ; i < numFlights ; i++)
                                      {
                                           // retrieve i-th flight
                                           Flight flight = (Flight)
                                           flights.elementAt(i);
                                           str += flight.code + " leaves at " +
                                           time2string(flight.departure) + "
                                           arrives at " +
                                           time2string(flight.arrival) + "
                                           (frequency " +
                                           flight.frequency + ").\n";
                                      }
                              }
                          else str = "There are no flights between " +
                               iFrom.getName() +
                               " and " + iTo.getName() + ".";
                     }
                 // if there are no flights or airports are the same,
                 // show an error message
                 else str = "Please pick two different airports, then retry.";
             }
         // some sql exception was raised, notify the user
         catch(SQLException sqlEx)
             {
                 str = "Sorry, your request didn’t go through,\n" +
                 "the server is probably down or busy,\nplease try again later.\n
                 \n" + sqlEx;
             }
         setText(str); // show the string with the flights or the warning
         // we may need to redo this panel’s layout
         // (the label may have changed its size)
         layout();
    }

    public void setText(String text)
    {
         label.setText(text);
    }

    private MapCanvas map = null; // map and route canvas
    private MultilineLabel label = null; // label with flights or error message
}
End example

FlightsVector.java

FlightsVector.java is a vector containing all flights between the departure and arrival airports. A query is sent to the database server to get information about flights with the given airport codes for departure and arrival. Listing 11-13 shows the source code for this class.

Listing 11-13: FlightsVector.java
Start example
//
// FlightsVector.java - a vector containing a bunch of flights
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.sql.*; // import jdbc and other sql libraries
import java.util.*; // java utility classes

class FlightsVector extends Vector // this is just a vector of Flight objects
{

    /**
     * Initialize this vector with all flights between two given airports.
     * The method will select all rows in the flights table having the given
     * airport codes in the from_city and to_city fields. An entry in the vector
     * will then be created for each flight and each entry will be added to the
     * vector.
     *
     * @param iConnection connection to the database
     * @param iFrom the airport we’re leaving from
     * @param iTo the airport we’re arriving to
     */
    public FlightsVector(Airport iFrom,Airport iTo) throws SQLException
    {

         // executes something like: select * from flights where
         // from_city = ‘SFO’ and to_city = ‘JFK’
         String sql = "select * from flights where from_city = ‘" +
          iFrom.getCode() +
          "‘ and to_city = ‘" + iTo.getCode() + "‘ order by departure";
         Statement s = Airplet.createStatement(); // create normal sql statement
         // scan all flights between given airports
         for(ResultSet r = s.executeQuery(sql) ; r.next() ; )
             {
                 // create a new flight from current row
                 Flight flight = new Flight(r);
                 addElement(flight); // add this flight to the vector
             }
         s.close(); // we don’t have to do this
                    // (but it could help jdbc optimize access)
    }
}
End example

ImageCanvas.java

The ImageCanvas.java class is a canvas containing an image. An update method is provided to draw the image using double buffering, if possible. Listing 11-14 shows the source code for this class.

Listing 11-14: ImageCanvas.java
Start example
//
// ImageCanvas.java - a canvas that shows an image
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.applet.*;
import java.awt.*; // java windowing classes

/** A canvas used to display an image. */
public class ImageCanvas extends Canvas // shows a canvas containing an image
{

    /** Initialize canvas showing the image with the given name. */
    public ImageCanvas(String name)
   {
        if(name != null && name.length() > 0) // if a name was specified
            {
                setImage(name); // load image
            }
   }

   protected Image image = null; // image shown by this canvas

   /** Display image with given name in the canvas. */
   public void setImage(String iName)
   {
        Image newimage = Airplet.loadImage(iName); // load new image
        if(image != newimage) // if image changed
            {
                image = newimage; repaint(); // refresh the canvas
            }
   }

   /** Update the canvas using double buffering (if enough memory’s
       available). */
   synchronized public void update(Graphics iGraphics)
   {
        Dimension d = size();
        if(d.width < 1 || d.height < 1) return; // don’t update if empty
        Image buf = null;
        try // catch memory full and other problem
            {
                buf = createImage(d.width,d.height); // create temporary buffer
            }
        catch(Exception e) { }
        if(buf != null) // if buffer was created
            {
                // get buffer’s graphic context
                Graphics bufGr = buf.getGraphics();
                bufGr.clearRect(0,0,d.width,d.height); // erase content of buffer
                paint(bufGr); // paint into the offscreen buffer
                // copy the offscreen buffer to the panel
                iGraphics.drawImage(buf,0,0,this);
                buf.flush(); // dispose buffer’s resources
            }
        // if there’s not enough memory for double buffering,
        // let the superclass update as usual
        else super.update(iGraphics);
    }

    /** Draw the image centered in the canvas. */
    public void paint(Graphics iGraphics)
    {
         if(image != null) // if there is an image
             {
                 Dimension d = size(); // calculate image’s origin
                 d.width -= image.getWidth(this);
                 // then draw the image centered in the canvas
                 d.height -= image.getHeight(this);
                 iGraphics.drawImage(image,d.width,d.height,this);
             }
    }

    /** Preferred size for this canvas is the size of the image that it is
        showing, if any. */
    public Dimension preferredSize()
    {
         if(image != null) // if an image was selected, return its size
             {
                 return new Dimension(image.getWidth(this),image.
                 getHeight(this));
             }
         // otherwise 1 pixel will do (0 would be too little,
         // ‘cause paint would never be called)
         return new Dimension(1,1);
    }
}
End example

MapCanvas.java

MapCanvas.java contains the methods used to display the most appropriate map for the departure and arrival selections. A route is drawn between the two airports. Listing 11-15 shows the source code for this class.

Listing 11-15: MapCanvas.java
Start example
//
// MapCanvas.java - a view that shows a map with airports and a route
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.awt.*; // import java windowing toolkit
import java.io.*; // I/O streams, exceptions, etc.
import java.applet.*; // applet class

/** A canvas that shows a map and a flight’s route. */
class MapCanvas extends ImageCanvas // map class extends canvas (drawable view)
{

    public MapCanvas()
    {
         // display world map until airports are selected
         super("images/world.gif");
         // load origin and destination icons
         iconFrom = Airplet.loadImage("images/iconFrom.gif");
         iconTo = Airplet.loadImage("images/iconTo.gif");
    }

    private Airport airFrom = null; // arrival and departure airports
    private Airport airTo = null;
    private MapInfo mapFrom = null;
    // information regarding the airports on the map
    private MapInfo mapTo = null;
    private Image iconFrom = null;
    // icons for arrival and departure points on the map
    private Image iconTo = null;

    /** Draw a route going from x1,y1 to x2,y2 */
    private void drawRoute(Graphics iGraphics,int x1,int y1,int x2,int y2)
    {
         int xp = x1;
         int yp = y1;
         double arc = Math.min(Math.abs(x1 - x2) * .20 +
         Math.abs(y1 - y2) * .20,30.0);
         // draw a slanted arc as 20 connected lines
         for(double p = .1 ; p <= 1.0 ; p += .1)
             {
                 // calculate parametric position in the line
                 // connecting origin with arrival
                 int xc = (int) (x1 + (double) (x2 - x1) * p);
                 int yc = (int) (y1 + (double) (y2 - y1) * p);
                 double pslanted = p; // (p < .75) ? (p * .50 / .75) : (.50 +
                 (p - .75) * .50 / .25);
                 // add variable y value to form an arc
                 yc -= (int) (Math.sin(Math.PI * pslanted) * arc);
                 iGraphics.drawLine(xp,yp,xc,yc); // draw current segment
                 xp = xc; // current position becomes previous position
                 yp = yc;
             }
    }

    /** Draw the map of the region containing both airports and a route. */
    public void paint(Graphics iGraphics)
    {
         super.paint(iGraphics); // draws the map
         if(mapFrom != null && mapTo != null)
             {
                 Dimension d = size(); // size of this canvas
                 // origin of the map in the canvas
                 int w = image.getWidth(this), hofs = (d.width - w) / 2;
                 int h = image.getHeight(this), vofs = (d.height - h) / 2;
                 iGraphics.setColor(Color.lightGray);
                 drawRoute(iGraphics,hofs + mapFrom.x + 1,vofs + mapFrom.y +
                  1,hofs +
                  mapTo.x + 1,vofs + mapTo.y + 1);
                 iGraphics.setColor(Color.black);
                 drawRoute(iGraphics,hofs + mapFrom.x,vofs + mapFrom.y,hofs +
                 mapTo.x,vofs + mapTo.y);
                 int xFrom = hofs + mapFrom.x - iconFrom.getWidth(this) / 2;
                 int yFrom = vofs + mapFrom.y - iconFrom.getHeight(this) / 2;
                 // calculate origin and destination icon’s position
                 int xTo = hofs + mapTo.x - iconTo.getWidth(this) / 2;
                 int yTo = vofs + mapTo.y - iconTo.getHeight(this) / 2;
                 // draw origin and destination icons
                 iGraphics.drawImage(iconFrom,xFrom,yFrom,this);
                 iGraphics.drawImage(iconTo,xTo,yTo,this);
             }
    }

    /** Sets departure and arrival airports, selecting and displaying the most
        appropriate map. */
    void setAirports(Airport iFrom,Airport iTo)
    {
         String name = null;
         airFrom = iFrom; airTo = iTo; // set departure and arrival airports
         if(airFrom != null && airTo != null)
         // if departure and arrival airports were specified
             {
                 for(mapFrom = airFrom.getMaps() ; name == null && mapFrom !=
                 null ; )
                     {
                          for(mapTo = airTo.getMaps() ; name == null && mapTo !=
                          null ; )
                              {
                                  if(mapFrom.name.equals(mapTo.name))
                                      {
                                           name = mapFrom.name;
                                      }
                                  else mapTo = mapTo.next;
                              }
                          if(name == null) mapFrom = mapFrom.next;
                     }
             }
         // use world’s map if there’s no better one
         name = "images/" + (name != null ? name : "world") + ".gif";
         setImage(name); // display new image
    }

    public Dimension preferredSize()
    {
         return new Dimension(500,300); // size of the maps is fixed
    }
}
End example

MapInfo.java

The MapInfo.java class extracts the x,y coordinates from the flight’s string for a particular graphic map. Listing 11-16 shows its source code.

Listing 11-16: MapInfo.java
Start example
//
// MapInfo.java - informations regarding airport’s position on a map
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet; // airplet’s package
import java.util.*; // utility classes
/** Information about an airport’s position on a map. */

class MapInfo
{

    /** Initialize from a ‘map(x,y)’ string. */
    MapInfo(String map)
    {
         // name is encoded as name(x,y) so use ( and comma as separators
         StringTokenizer sTokenizer = new StringTokenizer(map,"(,)");
         // name of this map (eg. ‘usa’, ‘europe’, ‘world’)
         name = sTokenizer.nextToken().toLowerCase();
         // coordinate of the airport in this map
         x = Integer.parseInt(sTokenizer.nextToken());
         y = Integer.parseInt(sTokenizer.nextToken());
    }
    String name; // name of the map
    int x,y; // coordinates of the airport on this map
    MapInfo next = null; // next map (this is a linked list)

    void append(MapInfo item)
    {
         // appends item at the end of the linked list
         if(next != null) next.append(item); else next = item;
    }

    public String toString()
    {
         return "MapInfo[" + name + "," + x + "," + y + "]";
         // returns MapInfo[name,x,y]
    }
}
End example

MultilineLabel.java

MultilineLabel.java is simply a label that can display multiple lines of text. It also provides text shadow for the drawn string. Listing 11-17 shows the source code for this class.

Listing 11-17: MultilineLabel.java
Start example
//
// MultilineLabel.java - a label that can draw several lines of text
//
// Copyright (C) 1996 by Connect Software. All rights reserved.
//
// Written by Gionata Mettifogo, Peter Ham.
//

package airplet;
import java.awt.*;
import java.util.*;

public class MultilineLabel extends java.awt.Canvas
{

    public MultilineLabel(int alignment)
    {
         align = alignment;
    }

    private String text; private int align;
    // text and alignment (see constants in Label)

    public void setText(String text)
    {
         this.text = text;
    }

    /** Draw the multiline label aligned as specified during object’s
        construction. */
    public void paint(Graphics iGraphics)
    {
         // get information on the font’s sizes
         FontMetrics fm = iGraphics.getFontMetrics();
         // separate different lines
         StringTokenizer tokens = new StringTokenizer(text,"\n");
         // line height and label’s width
         int w = size().width, h = fm.getHeight();
         // scan all lines in the label
         for(int y = h ; tokens.hasMoreTokens() ; y += h)
             {
                 String line = tokens.nextToken(); // retrieve line
                 int x = 0;
                 // if line is centered or right aligned
                 if(align == Label.CENTER || align == Label.RIGHT)
                     {
                          // calculate spacing on left side
                          x = w - fm.stringWidth(line);
                         if(align == Label.CENTER) x /= 2;
                    }
                shadowString(iGraphics,line,x,y); // draw the line
            }
   }

   public Dimension preferredSize()
   {
        // get information on the font’s sizes
        FontMetrics fm = getGraphics().getFontMetrics();
        // separate different lines
        StringTokenizer tokens = new StringTokenizer(text,"\n");
        Dimension dimension = new Dimension(0,fm.getHeight() *
         tokens.countTokens() +
         fm.getMaxDescent() + 1);
        while(tokens.hasMoreTokens()) // scan lines
            {
                String line = tokens.nextToken(); // retrieve line
                // width is the length of the longest line
                dimension.width = Math.max(fm.stringWidth(line),dimension.width);
            }
        return dimension;
   }

   /**
    * Draws the given string at the given position using a
    * subtle 1 pixel gray shadow. Light comes from the upper
    * left corner (where the Apple used to be).
    */
   public void shadowString(Graphics iGraphics,String iString,int x,int y)
   {
        Color color = iGraphics.getColor();
        iGraphics.setColor(Color.lightGray);
        iGraphics.drawString(iString,x+1,y+1);
        iGraphics.setColor(color);
        iGraphics.drawString(iString,x,y);
   }
}
End example


Dealing with Database Transactions

As shown in Chapter 7, transactions group the execution of a number of SQL statements to maintain consistency in multiuser environments. In the following example, I group multiple SQL INSERT statements to ensure consistent money transfers by using database transactions.

The Bank of Java applet is similar to the software provided by banks to their customers to perform operations on their accounts from their home computers with telephones and modems. It was quite simplified to illustrate database transactions with JDBC.

The main operations are these:

  1. Welcome a client and prompt for the client’s ID and PIN code.

  2. Look up the client’s balance and transaction history in the database.

  3. Perform money transfers to other accounts.

  4. For fun, withdraw virtual $20 banknotes.

The information about clients and their accounts is, of course, stored in a database. The data structure was kept simple to allow a quick understanding of the whole application and the transaction mechanism. Database transactions are performed in the main thread, and a second thread serves as a clock. Each time an update is made to the database, the SQL queries that perform the update are grouped in a single transaction unit. By doing so, no inconsistent update can bring the database to an incoherent state.

If the client/server link is broken in the middle of a transaction, the transaction will be canceled; otherwise, it is committed. Canceling a transaction is called transaction rollback. Rolling back the transaction prevents unlogged transfers or unlogged withdrawals. Indeed, transfers and withdrawals are SQL INSERTs in database tables such as accounts and history log.

The GUI part of this applet was written using Marimba Bongo, which generates a 100 percent portable .gui file. This file contains a persistent form of the widgets used in this example. The unzipped Marimba classes must be in the CLASSPATH or present on the WWW server to run this example. The GUI part of the application uses the Marimba Bongo classes that are persisted to a portable file, which is the main reason why almost no GUI code is present in the source code. Each GUI control is a Marimba widget, which has a name and various properties that are also persisted in the permanent GUI file.

On the Web

The .gui file uses several Marimba Bongo classes, which are available in demo version on this book’s companion Web site at www.hungryminds.com/extras/. Please see the Preface for details on accessing files on the Web site.

Figure 11-5 shows the welcome screen of the Bank of Java applet. This screen prompts for an account number and a PIN code. There is a status bar below the validate button. If the PIN code is incorrect, this status bar displays an error message.

Click To expand
Figure 11-5: The JavaBank applet login screen.

The names of the main controls on the welcome screen are as follows:

  • welcomeAccountNo: A text field to get the account number

  • welcomePinCode: A text field to get the personal identification number

  • welcomeOkButton: A button to log in to the database

  • welcomeEndButton: A button to close the database connection and quit the application

  • statusBar: A noneditable text field to display various messages

The values associated with these controls are checked and set within the program; the control names refer to them as instances of the Marimba GUI widgets.

After the client has logged in, a lookup is performed in the database, and the customer’s account balance and transaction history are displayed, as shown in Figure 11-6.

Click To expand
Figure 11-6: The JavaBank applet account balance.

After the client has logged in, the available controls are the following:

  • balanceHistory: A scrollable text list to display the transaction history for the current account

  • balanceBalance: A noneditable text field to display the balance of the account

  • balanceRefreshButton: A button to refresh the history log

  • balanceEndButton: A button to exit the session

  • statusBar: A noneditable text field to display various messages

The client’s account balance and transaction history display each time the refresh button is pressed.

The next screen panel enables transfers to other accounts. The name and address of the recipient is looked up in the database and displayed in the status bar. Then the amount of money is transferred, as shown in Figure 11-7.

Click To expand
Figure 11-7: The JavaBank applet transfer screen.

The control names for the transfer screen include the following:

  • transferAccountNo: A text field for the recipient’s account number

  • transferAmount: A text field for the amount of money to transfer

  • transferYesButton: A button to commit the transfer

  • transferEndButton: A button to exit the session

  • statusBar: A noneditable text field to display various messages

This is the automatic teller machine (ATM) panel. After choosing an amount to withdraw and after pressing the withdraw button, a Java banknote appears and scrolls on the screen. Figure 11-8 shows this panel.

Click To expand
Figure 11-8: The JavaBank applet cash withdrawal.

The withdrawal screen controls include the following:

  • withdrawXX (where XX is one of 20, 100, 200, or 1,000): Radio buttons used to select the amount of money to withdraw

  • withdrawImage: A picture of a banknote that displays and scrolls when the withdrawal is committed

  • withdrawWithdrawButton: A button to commit the withdrawal

  • withdrawEndButton: A button to exit the session

  • statusBar: A noneditable text field to display various messages

The applet contains two important classes: Account and NetBank. NetBank is the main class, which handles user input, and Account has specific methods to perform normal bank operations on an account. The most essential part of this example, the JDBC and SQL code, is in the Account class.

The HTML file

This is the HTML page that calls the applet:

<html>
<title>JavaBank Applet</title>
<head>
<h1>Welcome to JavaBank!</h1>
</head>
<body>
<applet code=NetBank.class width=480 height=380>
</applet>
</body>
</html>

Account.java

Listing 11-18 contains the source code for the Account.java class.

Listing 11-18: Account.java
Start example
import java.sql.*;
import java.io.*;
import java.util.*;
import java.net.*;

/**
 * Title:        Account
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class Account {

  long acctNo = 0;
  Connection curConn;

  public Account(String url, String uid, String pwd) {
    try {
      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
      curConn = DriverManager.getConnection(url, uid, pwd);
    }
    catch(java.lang.Exception ex) {
      ex.printStackTrace();
    }
  }

  protected void finalize()
  {
    try {
      curConn.close();
    } catch (SQLException ex) { }
  }

  public boolean verifyPinCode(long checkAcctNo, String checkPinCode)
  {
    boolean rc = (0 == 1);
    String acctPinCode = "";
    String curQueryString = "SELECT pincode FROM accounts WHERE acctno = " +
    checkAcctNo;
    try {
      Statement curSt = curConn.createStatement();
      curSt.setQueryTimeout(60);
      ResultSet curRs = curSt.executeQuery(curQueryString);
      while (curRs.next()) {
        acctPinCode = curRs.getString("pincode");
      }
      curRs.close();
      curSt.close();
      rc = (checkPinCode.compareTo(acctPinCode) == 0);
    } catch (SQLException ex) { }
    if (rc) {
      acctNo = checkAcctNo;
    }
    return rc;
  }

  public float checkAcctBalance()
  {
    float acctBalance = 0;
    String curQueryString = "SELECT balance FROM accounts WHERE acctno = " +
    acctNo;
    try {
      Statement curSt = curConn.createStatement();
      curSt.setQueryTimeout(60);
      ResultSet curRs = curSt.executeQuery(curQueryString);
      while (curRs.next()) {
        acctBalance = curRs.getFloat("balance");
      }
      curRs.close();
      curSt.close();
    } catch (SQLException ex) { }
    return (acctBalance);
  }

  public Vector checkHistory()
  {
    Vector acctTransactionHistory = new Vector();
    String curQueryString = "SELECT tdate, typetransaction, otheracct, amount,
    ipaddress "
    + "FROM history WHERE acctno = " + acctNo;
    try {
      Statement curSt = curConn.createStatement();
      curSt.setQueryTimeout(60);
      ResultSet curRs = curSt.executeQuery(curQueryString);
      while (curRs.next()) {
        acctTransactionHistory.addElement(curRs.getString(1) + " "
          + curRs.getString(2) + " "
          + curRs.getString(3) + " "
          + curRs.getString(4) + " "
          + curRs.getString(5));
      }
      curRs.close();
      curSt.close();
    } catch (SQLException ex) { }
    return (acctTransactionHistory);
  }

  public Vector checkAcctOwnerName(long checkAcctNo)
  {
    Vector acctOwner = new Vector();
    String curQueryString = "SELECT name, address FROM clients WHERE ownerno = " +
     "(SELECT ownerno FROM accounts WHERE acctno = " + checkAcctNo + ")";
    try {
      Statement curSt = curConn.createStatement();
      curSt.setQueryTimeout(60);
      ResultSet curRs = curSt.executeQuery(curQueryString);
      while (curRs.next()) {
        acctOwner.addElement(curRs.getString("name"));
        acctOwner.addElement(curRs.getString("address"));
      }
      curRs.close();
      curSt.close();
    } catch (SQLException ex) { }
    return (acctOwner);
  }

  public void makeTransfer(long toAcctNo, float amount)
  {
    String curUpdateString = "UPDATE accounts SET balance =  balance + ?
    WHERE acctno = ?";
    String logInsertString = "INSERT INTO history (tdate, acctno, typetransaction,
     otheracct, " +
     "amount, ipaddress) VALUES (?, ?, ?, ?, ?, ?)";
    try {
      curConn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE   );
      curConn.setAutoCommit(false);
      PreparedStatement curSt =  curConn.prepareStatement(curUpdateString);
      curSt.setQueryTimeout(60);
      curSt.setFloat(1, -amount);
      curSt.setLong(2, acctNo);
      curSt.executeUpdate();
      curSt.setFloat(1, amount);
      curSt.setLong(2, toAcctNo);
      curSt.executeUpdate();
      java.util.Date toDay = new java.util.Date();
      String localHost = "";
      try {
        localHost =  InetAddress.getLocalHost().toString();
      }
      catch (UnknownHostException ex) {
        localHost = "localhost/127.0.0.1";
      }
      PreparedStatement logSt =  curConn.prepareStatement(logInsertString);
      logSt.setQueryTimeout(60);
      logSt.setString(1, toDay.toGMTString());
      logSt.setLong(2, acctNo);
      logSt.setString(3, "Transfert");
      logSt.setLong(4, toAcctNo);
      logSt.setFloat(5, -amount);
      logSt.setString(6, localHost);
      logSt.executeUpdate();
      logSt.setString(1, toDay.toGMTString());
      logSt.setLong(2, toAcctNo);
      logSt.setString(3, "Received");
      logSt.setLong(4, acctNo);
      logSt.setFloat(5, amount);
      logSt.setString(6, localHost);
      logSt.executeUpdate();
      curConn.commit();
      curConn.setTransactionIsolation(Connection.TRANSACTION_NONE);
      curSt.close();
      logSt.close();
    } catch (SQLException ex) { }
  }

  public void cashWithdraw(float amount)
  {
    String curUpdateString = "UPDATE accounts SET balance = balance + ?
    WHERE acctno = ?";
    String logInsertString = "INSERT INTO history (tdate, acctno,      typetransaction, otheracct, " +
     " amount, ipaddress) VALUES (?, ?, ?, ?, ?, ?)";
    try {
      curConn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
      curConn.setAutoCommit(false);
      PreparedStatement curSt = curConn.prepareStatement(curUpdateString);
      curSt.setQueryTimeout(60);
      curSt.setFloat(1, -amount);
      curSt.setLong(2, acctNo);
      curSt.executeUpdate();
      java.util.Date toDay = new java.util.Date();
      String localHost = "";
      try {
        localHost =  InetAddress.getLocalHost().toString();
      }
      catch (UnknownHostException ex) {
        localHost = "localhost/127.0.0.1";
      }
      PreparedStatement logSt = curConn.prepareStatement(logInsertString);
      logSt.setQueryTimeout(60);
      logSt.setString(1, toDay.toGMTString());
      logSt.setLong(2, acctNo);
      logSt.setString(3, "Withdraw");
      logSt.setLong(4, 0);
      logSt.setFloat(5, -amount);
      logSt.setString(6, localHost);
      logSt.executeUpdate();
      curConn.commit();
      curConn.setTransactionIsolation(Connection.TRANSACTION_NONE);
      curSt.close();
      logSt.close();
    } catch (SQLException ex) { }
  }
}
End example

NetBank.java

Listing 11-19 contains the source code for NetBank.java.

Listing 11-19: NetBank.java
Start example
import java.awt.*;
import java.sql.*;
import java.lang.*;
import java.util.*;
import java.net.*;
import marimba.gui.*;

/**
 * Title:        NetBank
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class NetBank extends java.applet.Applet {

  Presentation presentation;
  PlayerPanel player;
  PlayerUtil util;
  Account curAcct = null;
  float curWithdrawAmount = 0;

  public void init()
  {
    try {
      presentation = Presentation.getPresentation(new
      URL(getDocumentBase(), "netbank.gui"));
    } catch (MalformedURLException ex) {
       ex.printStackTrace();
    }
    // Create a Player Panel
    setLayout(new BorderLayout());
    add("Center", player = new PlayerPanel());
    // Set the presentation
    player.setPresentation(presentation);
    // Create a Player utility object
    util = new PlayerUtil(player);
     ((FolderWidget)util.getWidget("netbankFolder")).setTabMode(0);

    // Initialize the clock thread
    TimeT t;
    t = new TimeT((TextBoxWidget)util.getWidget("clockLabel"));
    t.start();
  }

  public void logoutRequest()
  {
    util.setText("welcomeAccountNo", "");
    util.setText("welcomePinCode", "");
    util.setText("balanceBalance", "");
    util.setText("balanceHistory", "");
    util.setText("transferAccountNo", "");
    util.setText("transferAmount", "");
    util.setText("statusBar", "");
    curAcct.finalize();
    util.gotoPage("welcomePage");
  }

  public void displayBalance()
  {
    String bal = (new Float(curAcct.checkAcctBalance())).toString();
    util.setText("balanceBalance", bal);
    Vector v = curAcct.checkHistory();
    String s = "";
    for (int i=0; i < v.size(); i++)
      s = s + v.elementAt(i) + "\n";
    util.setText("balanceHistory", s);
    util.setText("statusBar", "");
  }

  public boolean handleEvent(Event evt)
  {
    if ((evt.id == Event.ACTION_EVENT) && (evt.target instanceof Widget)) {
      Widget w = (Widget)evt.target;
      String nm = w.getName();
      System.out.println("Event: " + nm);
      // The user has switched pages.
      if (nm.equals("netbankFolder")) {
        util.setText("statusBar", "");
      }
      if (nm.equals("loginPanelButton")) {
        util.gotoPage("welcomePage");
      }
      if (nm.equals("balancePanelButton")) {
        util.gotoPage("balancePage");
      }
      if (nm.equals("transferPanelButton")) {
        util.gotoPage("transferPage");
      }
      if (nm.equals("cashPanelButton")) {
        util.gotoPage("withdrawPage");
      }
      // The user has logged in.
      if (nm.equals("welcomeOkButton")) {
        Long acct = new Long(util.getText("welcomeAccountNo").trim());
        String pin = util.getText("welcomePinCode").trim();
        util.setText("statusBar", "Please wait...");
        if ((acct.longValue() > 0) && (pin.length() > 0))
        {
          curAcct = new Account("jdbc:odbc:netbank", "dba", "javabank");
          if (curAcct.verifyPinCode(acct.longValue(), pin))
          {
            Vector v = curAcct.checkAcctOwnerName(acct.longValue());
            util.setText("statusBar", "Welcome " + v.elementAt(0) + ", " +
            v.elementAt(1));
            util.gotoPage("balancePage");
            displayBalance();
          }
          else
          {
            // wrong info
            util.setText("statusBar", "Account number or PIN invalid!");
            logoutRequest();
          }
        }
        else
          util.setText("statusBar", "Please enter your account number first!");
      }
      // The user has clicked refresh
      if (nm.equals("balanceRefreshButton")) {
        util.setText("statusBar", "Please wait...");
        displayBalance();
      }
      // The user has clicked OK to transfer money
      if (nm.equals("transferYesButton")) {
        Long acct = new Long(util.getText("transferAccountNo").trim());
        Float amnt = new Float(util.getText("transferAmount").trim());
        util.setText("statusBar", "Please wait...");
        if ((acct.longValue() > 0) && (amnt.floatValue() > 0))
        {
          if (0 == 0) // should verify the transferAcctNo
          {
            curAcct.makeTransfer(acct.longValue(), amnt.floatValue());
            Vector v = curAcct.checkAcctOwnerName(acct.longValue());
            util.setText("statusBar", "Transfered to " + v.elementAt(0) + ", " +
            v.elementAt(1));
            util.setText("transferAccountNo", "");
            util.setText("transferAmount", "");
          }
else
          {
            // acct does not exist in database
            util.setText("statusBar", "INVALID ACCT NO OR PIN CODE!!!");
          }
        }
        else
          util.setText("statusBar", "Please enter the account number first!");
      }
      // Check the selection for cash
      if (nm.equals("withdraw20")) {
        curWithdrawAmount = 20;
      } else if (nm.equals("withdraw100")) {
        curWithdrawAmount = 100;
      } else if (nm.equals("withdraw200")) {
        curWithdrawAmount = 200;
      } else if (nm.equals("withdraw1000")) {
        curWithdrawAmount = 1000;
      }
      // The user has clicked withdraw
      if (nm.equals("withdrawWithdrawButton")) {
        util.setText("statusBar", "Please wait.");
        curAcct.cashWithdraw(curWithdrawAmount);
        util.setText("statusBar", "Please wait...");
        ImageWidget img = (ImageWidget) util.getWidget("bankNote");
        img.show();
        for (int i = 0; i < 3050; i++)
        {
          img.reshape(60, 120 - (i / 10), 100, 10 + (i / 10));
          img.repaint();
        }
        //img.hide();
      }
      // The user has clicked EndPage to log out
      if (nm.equals("welcomeEndButton")) {
        logoutRequest();
        System.out.println("Ended");
        return true;
      }
    }
    return super.handleEvent(evt);
  }
}
End example

TimeT.java

Listing 11-20 contains the source code for TimeT.java. This class is a simple thread that runs on its own. It updates the clock time on-screen every second. It doesn’t play any role related to JDBC.

Listing 11-20: TimeT.java
Start example
import java.io.*;
import java.lang.*;
import java.util.*;
import marimba.gui.*;

/**
 * Title:        TimeT
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 1.0
 */

public class TimeT extends Thread {

  private Thread GetTime;
  private boolean bRun;
  TextBoxWidget tbw;

  public TimeT(TextBoxWidget t) {
    tbw = t;
  }

  public void start() {
    bRun = true;
    GetTime = new Thread(this);
    GetTime.start();
  }

  public void run() {
    while(bRun)
    {
      try {GetTime.sleep(1000);}
      catch (InterruptedException e) { }
      String today = (new Date()).toString();
      tbw.setText(today);
    }
  }
}
End example

The Data Definition Language for the Bank of Java applet

Some keywords for this example are Transact-SQL. You may want to modify the DDL (Data Definition Language) and DML (Data Manipulation Language) for your DBMS. Listing 11-21 shows how to create the tables for this example.

Listing 11-21: DDL to Create the Tables for the Bank of Java Applet
Start example
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create tables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

CREATE TABLE "accounts"
(
"acctno"                        integer NULL,
"pincode"                       varchar(50) NULL,
"ownerno"                       integer NULL,
"datecreated"                   varchar(50) NULL,
"balance"                       float NULL,
);
CREATE TABLE "clients"
(
"ownerno"                       integer NULL,
"name"                          varchar(50) NULL,
"address"                       varchar(50) NULL,
);
CREATE TABLE "history"
(
"tdate"                         varchar(50) NULL,
"acctno"                        integer NULL,
"typetransaction"               varchar(20) NULL,
"otheracct"                     integer NULL,
"amount"                        float NULL,"                     varchar(50) NULL,);"/>

INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘1’,’1111’,’1’,’’,’992800’);
INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘2’,’2222’,’2’,’’,’1257450’);
INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘3’,’3333’,’3’,’’,’320700’);
INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘4’,’4444’,’4’,’’,’8900750’);
INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘5’,’5555’,’5’,’’,’-840’);
INSERT INTO "accounts" ("acctno","pincode","ownerno","datecreated","balance")
VALUES (‘6’,’6666’,’6’,’’,’999999995904’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘1’,’Bernard Van Haecke’,’Brussels, 1000’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘2’,’John Doe’,’Imola Circuit, KM83’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘3’,’Jane Doe’,’Imola Circuit, KM83’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘4’,’Santa Claus’,’North Pole, 1’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘5’,’Little Duke’,’Java Island, 1’);
INSERT INTO "clients" ("ownerno", "name", "address")
VALUES (‘6’,’The Bank’,’Downtown LA’);
INSERT INTO "history"
 ("tdate","acctno","typetransaction","otheracct","amount","ipaddress")
VALUES (‘23 Oct 1996 20:30:15 GMT’,’1’,’Transfert’,’4’,
 ‘-1000’,’localhost/127.0.0.1’);
INSERT INTO "history"
 ("tdate","acctno","typetransaction","otheracct","amount","ipaddress")
VALUES (‘23 Oct 1996 20:30:15 GMT’,’4’,’Received’,’1’,
 ‘1000’,’localhost/127.0.0.1’);
INSERT INTO "history"
 ("tdate","acctno","typetransaction","otheracct","amount","ipaddress")
VALUES (‘24 Oct 1996 21:18:43 GMT’,’5’,’Withdraw’,’0’,
 ‘-20’,’localhost/127.0.0.1’);
End example


Summary

This chapter provided examples of JDBC in the form of Java applets or standalone applications. Each example covered a specific topic discussed in earlier chapters. The simple ISQL application is an interactive SQL tool that can be used to connect and create tables in your databases or execute SQL queries and updates. Other examples included BLOB storage and retrieval, applets, and transactions.

The next chapter provides more complex examples of Java applications.


Chapter 12: Complex Examples of Java Applications

This chapter provides advanced examples of Java applications using database metadata and Remote Method Invocation (RMI).

Dynamic Database Access: A Java Database Explorer

My first example illustrates how to use JDBC’s DatabaseMetaData and ResultSetMetaData methods. This example is a Java database explorer, and it runs as a standalone application. It can dynamically discover database content thanks to a very intuitive, SWING-based graphical user interface (GUI). Numerous JDBC database metadata methods are exploited in this example to enable the exploration of virtually any relational database management system (RDBMS), provided that a compliant JDBC driver is available for it.

The main features of this example are the following:

  • Displays DBMS information such as specifications, supported features, and inherent limitations of the engine. These features and limitations are normally not driver-dependent: Different drivers connecting to the same database will report identical information. Although JDBC is portable, databases have different capabilities and limitations that a developer may want to verify first. The tool in this example provides a simple way to fetch this kind of information from the database.

  • Explores most database objects, including database catalogs, tables, and stored procedures. For tables, metadata as well as data contained in the table can be displayed within the tool.

  • Gives relational information — that is, primary, imported, and exported keys for all tables. The tool reports the key columns and other characteristics of all types of keys.

  • Provides an Interactive SQL query and update tool. This handy tool enables you to quickly execute SQL statements and display the results in a tabular format. The SQL statement is directly passed to the driver and database. You can issue Data Definition Language (DDL) statements as well as Data Manipulation Language (DML) statements: DDL statements are used to create or modify tables and indexes, for example, whereas DML consists of the usual SELECT, UPDATE, INSERT, and DELETE statements. The tool supports statements that return a result set as well as statements that return a number, such as an update count.

  • Displays ResultSet content as formatted tabular output.

The graphical user interface part of this example was written using the SWING part of the Java Foundation Classes, part of Java 2 Standard Edition. It is currently using the SWING Metal look and feel, which can easily be changed to the Windows, Motif, or Macintosh look and feel.

The main database explorer window is divided into two areas:

  • The main database navigation widget — the left-sided tree control, from which nearly all database metadata method invocations are performed

  • The result window, showing a table widget to represent either database metadata information or table data (up to 200 rows in this example)

Figure 12-1 depicts the main window of this example.

The following subsections explain how the user interacts with this standalone Java application, discovers the database properties using the DatabaseMetaData interface, and executes SQL statements.

Logging in to the database

As shown in Figure 12-2, logging in to the database engine requires a correct database URL, JDBC driver, user login, and user password. The syntax of the URL is driver-dependant. The login and password are the identification and authorization strings for a particular user in the database management system (DBMS). Note that sample URL strings and driver class names are provided and accessible via the bottom-left drop-down list box. These samples are located in the connections. properties file provided in the jdbcexplorer package directory of the jar file. Adding or changing entries is simply done by editing this property file. An example is provided in Listing 12-1 (later in this chapter). An entry looks like the following:

Hypersonic: jdbc:HypersonicSQL:hsql://localhost|org.hsql.jdbcDriver
Click To expand
Figure 12-1: The JDBCExplorer main window.
Click To expand
Figure 12-2: Supplying login data.

Three fields are specified per entry:

  • The connection name, which cannot contain spaces.

  • The JDBC URL used to connect to a given database; its format is driver-dependent.

  • The JDBC driver class name, including the package name; this driver will be dynamically loaded and must be present in the CLASSPATH.

Click Connect to log in to the DBMS. Use Disconnect to disconnect from the database engine without quitting the application. You can enter another JDBC URL, and you can click the Connect button again. Disconnect can be used as a temporary logout if you intend to reboot the database server or before logging in as another user. This sample program tries to load the JDBC driver at the connect time, which will throw an exception if the required driver isn’t in the CLASSPATH.

The navigation graphical control

The tree widget on the left side, which controls the whole application and navigates within the database, is a SWING JTree component. The Session, Engine, and Objects nodes intensively use database metadata methods to get information from the database. Double-clicking these tree nodes performs all actions. The resulting data displays in the right window, a SWING JTable.

The tree widget shown in Figure 12-3 controls the whole program.

Click To expand
Figure 12-3: The main navigation control widget.

Database engine specifications and limitations

Database information is divided into four categories. Figure 12-4 illustrates one of the four categories, Specs, or the database specifications. Figure 12-4 shows a small part of the features supported by the database engine. Each topic has its corresponding JDBC database metadata method, which, in general, returns true or false, an integer value, or a list of string values.

Click To expand
Figure 12-4: Database specifications.

Browsing database catalogs and their content

The database-browsing features are the most interesting. The main navigation widget enables you to browse through many database objects by expanding and collapsing its nodes. Each activation of a node issues database metadata method invocations to dynamically discover the database objects. Figure 12-5 shows the database catalog nodes. All metadata available about any particular database object is shown in the table on the right side.

Click To expand
Figure 12-5: Database catalog nodes.

When you click the Objects Catalogs node, the program fetches information about database objects, such as system tables, user tables, and stored procedures. Catalogs are simply database subspaces. In a DBMS managing multiple databases, a catalog is one database. Each catalog can contain system and user tables as well as stored procedures. Both types of database objects can be discovered using the JDBC MetaData interface. Figure 12-6 shows the effect of selecting a table object.

Click To expand
Figure 12-6: Table objects.

As shown in Figure 12-7, metadata about the table columns is available. The metadata that is available is database and driver dependent. It may provide column details such as the following:

Click To expand
Figure 12-7: Columns.

  • The catalog of the table

  • The schema of the table

  • The SQL data type integer

  • The SQL type name

  • The column size

  • The buffer length

  • The number of decimal digits

  • Whether or not the column is nullable

Primary key columns, as well as details for imported keys and exported keys, are available, too, for user and system tables. This is shown in Figure 12-8.

The procedure node lists all database-stored procedures in the current catalog and displays the results of the DatabaseMetaData.getProcedureColumns() method.

Click To expand
Figure 12-8: Primary keys.

An Interactive SQL tool

Figure 12-9 depicts the Interactive SQL tool that enables you to type and execute SQL statements, such as queries and updates. The results, which can be composed of rows or an update counter, are displayed in the JTable.

Click To expand
Figure 12-9: An Interactive SQL tool.

SQLException messages aren’t standardized: They are database and driver dependent. Comparing exception messages thrown by different drivers for the same query is a good exercise.

Click To expand
Figure 12-10: A SQLException message window.

As shown in Figure 12-11, a help screen is available. Help is provided as an HTML file loaded in a SWING JEditorPane. It is fairly simple to use hyperlinks within the help files as well as to provide contextual help; however, in this example, help isn’t context-sensitive.

Click To expand
Figure 12-11: JDBCExplorer help.

Finally, a simple About box provides version information, as shown in Figure 12-12.

Click To expand
Figure 12-12: The JDBCExplorer About box.

The source code for the JDBCExplorer example

Listing 12-1 shows the connections.properties file used by JDBCExplorer. It defines several database URLs and drivers that can be used within the tool. Listings 12-2 through 12-10 contain the whole source code for the Java database explorer.

Listing 12-1: connections.properties
Start example
DB2: jdbc:db2://localhost:4100/mydb;|com.ibm.DB2.JdbcDriver
Cloudscape: jdbc:cloudscape:HelloWorldDB;create=true| \
  COM.cloudscape.core.JDBCDriver
Connect_SW: jdbc:sybase://localhost:8192|connect.sybase.SybaseDriver
Hypersonic: jdbc:HypersonicSQL:hsql://localhost|org.hsql.jdbcDriver
Informix: jdbc:informix-sqli://localhost:1526/mydb:INFORMIXSERVER=prod01_ol;| \
  com.informix.jdbc.IfxDriver
MiniSQL: jdbc:msql://localhost:4333/Testdb|COM.imaginary.sql.msql.MsqlDriver
ODBC_Bridge: jdbc:odbc:data-source-name|sun.jdbc.odbc.JdbcOdbcDriver
Oracle: jdbc:oracle://localhost:1521/ORACLE_SID;|com.oracle.jdbc.OracleDriver
Oracle_Lite: jdbc:polite:data_sourcename|oracle.pol.poljdbc.POLJDBCDriver
Sybase: jdbc:sybase:Tds:localhost:8192|com.sybase.jdbc.SybDriver
Other: add it in the connections.properties file!|...
End example

Each entry of this file contains both a key and connection information. The key is an arbitrary name for your database. The connection information is structured: It contains a JDBC URL, followed by a pipe character (|), followed by the class name of the JDBC driver that understands the preceding URL format. You are free to add as many lines as you want or to adapt these lines to your database.

Listing 12-2: AboutBox.java
Start example
package jdbcexplorer;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * Title:        AboutBox
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class AboutBox extends JDialog implements ActionListener {

  JPanel panel1 = new JPanel();
  JPanel panel2 = new JPanel();
  JPanel insetsPanel1 = new JPanel();
  JPanel insetsPanel2 = new JPanel();
  JPanel insetsPanel3 = new JPanel();
  JButton button1 = new JButton();
  JLabel imageLabel = new JLabel();
  JLabel label1 = new JLabel();
  JLabel label2 = new JLabel();
  JLabel label3 = new JLabel();
  JLabel label4 = new JLabel();
  BorderLayout borderLayout1 = new BorderLayout();
  BorderLayout borderLayout2 = new BorderLayout();
  FlowLayout flowLayout1 = new FlowLayout();
  GridLayout gridLayout1 = new GridLayout();
  String product = "JDBCExplorer";
  String version = "2.0";
  String copyright = "Copyright (c) 1996, 2000, 2001";
  String comments = "Bernard.Vanhaecke@Belgium.Sun.COM";

  public AboutBox(Frame parent) {

    super(parent);
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    pack();
  }
  /**Component initialization*/
  private void jbInit() throws Exception  {

    //imageLabel.setIcon(new ImageIcon(
      Mainframe_AboutBox.class.getResource("[Your Image]")));
    this.setTitle("About");
    setResizable(false);
    panel1.setLayout(borderLayout1);
    panel2.setLayout(borderLayout2);
    insetsPanel1.setLayout(flowLayout1);
    insetsPanel2.setLayout(flowLayout1);
    insetsPanel2.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    gridLayout1.setRows(4);
    gridLayout1.setColumns(1);
    label1.setText(product);
    label2.setText(version);
    label3.setText(copyright);
    label4.setText(comments);
    insetsPanel3.setLayout(gridLayout1);
    insetsPanel3.setBorder(BorderFactory.createEmptyBorder(10, 60, 10, 10));
    button1.setText("Ok");
    button1.addActionListener(this);
    imageLabel.setIcon(new ImageIcon(AboutBox.class.getResource("logo.gif")));
    insetsPanel2.add(imageLabel, null);
    panel2.add(insetsPanel2, BorderLayout.WEST);
    this.getContentPane().add(panel1, null);
    insetsPanel3.add(label1, null);
    insetsPanel3.add(label2, null);
    insetsPanel3.add(label3, null);
    insetsPanel3.add(label4, null);
    panel2.add(insetsPanel3, BorderLayout.CENTER);
    insetsPanel1.add(button1, null);
    panel1.add(insetsPanel1, BorderLayout.SOUTH);
    panel1.add(panel2, BorderLayout.NORTH);
  }

  /**Overridden so we can exit when window is closed*/
  protected void processWindowEvent(WindowEvent e) {

    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      cancel();
    }
    super.processWindowEvent(e);
  }

  /**Close the dialog*/
  void cancel() {

    dispose();
  }

  /**Close the dialog on a button event*/
  public void actionPerformed(ActionEvent e) {

    if (e.getSource() == button1) {
      cancel();
    }
  }
}
End example
Listing 12-3: ConnectionBox.java
Start example
package jdbcexplorer;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * Title:        ConnectionBox
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class ConnectionBox extends JDialog {

  BorderLayout borderLayout1 = new BorderLayout();
  JPanel jPanel1 = new JPanel();
  FlowLayout flowLayout1 = new FlowLayout();
  JButton jButton1 = new JButton();
  JButton jButton2 = new JButton();
  JPanel jPanel2 = new JPanel();
  JTextField jTextField3 = new JTextField();
  JTextField jTextField2 = new JTextField();
  JTextField jTextField1 = new JTextField();
  JPasswordField jPasswordField1 = new JPasswordField();
  GridBagLayout gridBagLayout1 = new GridBagLayout();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel1 = new JLabel();
  JPanel jPanel3 = new JPanel();
  FlowLayout flowLayout2 = new FlowLayout();
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel5 = new JLabel();
  String databases[][] = new String[20][2];
  Mainframe mf;

  public ConnectionBox(Mainframe parent) {

    super((Frame) parent);
    mf = parent;
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    pack();
  }

  private void jbInit() throws Exception {

    this.getContentPane().setLayout(borderLayout1);
    jPanel1.setLayout(flowLayout1);
    jButton1.setText("Connect");
    if (DatabaseConnection.getInstance() != null) {
      if (DatabaseConnection.getInstance().isActive()) {
         jButton1.setText("Disconnect");
      }
    }
    jButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);
      }
    });
    jButton2.setText("Close");
    jButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton2_actionPerformed(e);
      }
    });
    this.setTitle("JDBC Connection Parameters");
    jPanel2.setLayout(flowLayout2);
    jTextField3.setSelectionEnd(15);
    jLabel4.setText("Password:");
    jLabel3.setText("Login:");
    jLabel2.setText("Driver:");
    jLabel1.setText("URL:");
    jPanel3.setLayout(gridBagLayout1);
    jLabel5.setText("Bookmarks:");
    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
    this.getContentPane().add(jPanel1, BorderLayout.SOUTH);
    jPanel1.add(jLabel5, null);
    jPanel1.add(jComboBox1, null);
    jPanel1.add(jButton1, null);
    jPanel1.add(jButton2, null);
    this.getContentPane().add(jPanel2, BorderLayout.CENTER);
    jPanel2.add(jPanel3, null);
    jPanel3.add(jLabel1, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
            GridBagConstraints.WEST, GridBagConstraints.NONE,
            new Insets(0, 10, 0, 0), 10, 0));
    jPanel3.add(jTextField1, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
            GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL,
            new Insets(10, 0, 10, 10), 233, 0));
    jPanel3.add(jLabel2, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
            GridBagConstraints.WEST, GridBagConstraints.NONE,
            new Insets(0, 10, 0, 0), 10, 0));
    jPanel3.add(jTextField2, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0,
            GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL,
            new Insets(10, 0, 10, 10), 164, 0));
    jPanel3.add(jLabel3, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
            GridBagConstraints.WEST, GridBagConstraints.NONE,
            new Insets(0, 10, 0, 0), 10, 0));
    jPanel3.add(jTextField3, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0,
            GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL,
            new Insets(10, 0, 10, 10), 163, 0));
    jPanel3.add(jLabel4, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
            GridBagConstraints.WEST, GridBagConstraints.NONE,
            new Insets(0, 10, 0, 0), 10, 0));
    jPanel3.add(jPasswordField1, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0,
            GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL,
            new Insets(10, 0, 10, 10), 131, 0));

    Properties p = new Properties();
    p.load(ConnectionBox.class.getResourceAsStream("connections.properties"));
    int i=0;
    for (Enumeration e = p.propertyNames(); e.hasMoreElements();) {
        String name = (String) e.nextElement();
        String entry = p.getProperty(name);
        databases[i][0] = entry.substring(0, entry.indexOf(‘|’));
        databases[i][1] = entry.substring(entry.indexOf(‘|’) + 1);
        jComboBox1.addItem(name);
        i++;
    }
  }

  public void showError(Exception e) {

    mf.showError(e);
  }

  void jButton1_actionPerformed(ActionEvent e) {

    DatabaseConnection conn = DatabaseConnection.getInstance();
    try {
      if (conn == null) {
        conn = new DatabaseConnection(jTextField1.getText(),
          jTextField2.getText(), jTextField3.getText(),
          new String(jPasswordField1.getPassword()));
        jButton1.setText("Disconnect");
        this.dispose();
      } else if (conn.isActive()) {
        conn.disconnect();
        conn = null;
        jButton1.setText("Connect");
      } else {
        conn.connect(jTextField1.getText(), jTextField2.getText(),
           jTextField3.getText(), new String(jPasswordField1.getPassword()));
        jButton1.setText("Disconnect");
        this.dispose();
      }
    } catch (Exception ex) {
      showError(ex);
      conn = null;
      jButton1.setText("Connect");
    }
  }

  void jButton2_actionPerformed(ActionEvent e) {

    this.dispose();
  }

  void jComboBox1_actionPerformed(ActionEvent e) {

    int i = jComboBox1.getSelectedIndex();
    jTextField1.setText(databases[i][0]);
    jTextField2.setText(databases[i][1]);
  }

}
End example
Listing 12-4: DatabaseConnection.java
Start example
package jdbcexplorer;

import java.sql.*;
import java.util.*;

/**
 * Title:        DatabaseConnection
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class DatabaseConnection {

  private boolean connected = false;
  private Connection conn = null;
  private DatabaseMetaData mtdt = null;
  private static DatabaseConnection instance;

  public DatabaseConnection() {

    instance = this;
  }

  public DatabaseConnection(String url, String driver, String login,
                            String password) throws Exception {

    instance = this;
    connect(url, driver, login, password);
  }

  public static void main(String[] args) throws Exception {

    DatabaseConnection databaseConnection1 = new DatabaseConnection(args[0],
       args[1], args[2], args[3]);
    databaseConnection1.test();
  }

  public void connect(String url, String driver, String login,
                      String password) throws Exception {

    Class.forName(driver);
    conn = DriverManager.getConnection(url, login, password);

    if (conn != null) {
      connected = true;
    }
  }

  public void disconnect() {

    try {
      conn.close();
      connected = false;
      mtdt = null;
      conn = null;
    } catch (Exception e) {
    }
  }

  public static DatabaseConnection getInstance() {

    return instance;
  }

  public boolean isActive() {

    return connected;
  }

  public String[][] getSession() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = new String[3][2];
    s[0] = setString2("Property", "Value");
    s[1] = setString2("URL in use", mtdt.getURL());
    s[2] = setString2("Username", mtdt.getUserName());
    mtdt = null;
    return s;
  }

  public String[][] getEngineInfo() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = new String[5][2];
    s[0] = setString2("Property", "Value");
    s[1] = setString2("Database name", mtdt.getDatabaseProductName());
    s[2] = setString2("Database version", mtdt.getDatabaseProductVersion());
    s[3] = setString2("Driver name", mtdt.getDriverName());
    s[4] = setString2("Driver version", mtdt.getDriverVersion());
    mtdt = null;
    return s;
  }

  public String[][] getEngineSpecs() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = new String[13][2];
    s[0] = setString2("Property", "Value");
    s[1] = setString2("Uses local files", mtdt.usesLocalFiles());
    s[2] = setString2(" Uses local file per table", mtdt.usesLocalFilePerTable());
    s[3] = setString2("Nulls are sorted high", mtdt.nullsAreSortedHigh());
    s[4] = setString2("Nulls are sorted at end", mtdt.nullsAreSortedAtEnd());
    s[5] = setString2("Supports mixed case identifiers",
                       mtdt.supportsMixedCaseIdentifiers());
    s[6] = setString2("Stores mixed case identifiers",
                       mtdt.storesMixedCaseIdentifiers());
    s[7] = setString2(" Identifier quote string", mtdt.getIdentifierQuoteString());
    s[8] = setString2("Supported SQL keywords", mtdt.getSQLKeywords());
    s[9] = setString2("Numeric functions", mtdt.getNumericFunctions());
    s[10] = setString2("String functions", mtdt.getStringFunctions());
    s[11] = setString2("System functions", mtdt.getSystemFunctions());
    s[12] = setString2("Time and date functions", mtdt.getTimeDateFunctions());
    mtdt = null;
    return s;
  }

  public String[][] getEngineFeatures() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = new String[27][2];
    s[0] = setString2("Property", "Value");
    s[1] = setString2("Minimun SQL grammar", mtdt.supportsMinimumSQLGrammar());
    s[2] = setString2("Core SQL grammar", mtdt.supportsCoreSQLGrammar());
    s[3] = setString2(" Extended SQL grammar", mtdt.supportsExtendedSQLGrammar());
    s[4] = setString2("ANSI-92 Entry Level SQL",
                       mtdt.supportsANSI92EntryLevelSQL());
    s[5] = setString2("ANSI-92 Intermediate SQL",
                       mtdt.supportsANSI92IntermediateSQL());
    s[6] = setString2("ANSI-92 Full SQL grammar", mtdt.supportsANSI92FullSQL());
    s[7] = setString2("Integrity enhancement facility",
                       mtdt.supportsIntegrityEnhancementFacility());
    s[8] = setString2("Outer joins", mtdt.supportsOuterJoins());
    s[9] = setString2("Full outer joins", mtdt.supportsFullOuterJoins());
    s[10] = setString2("Limited outer joins", mtdt.supportsLimitedOuterJoins());
    s[11] = setString2("Alter table with add column",
                        mtdt.supportsAlterTableWithAddColumn());
    s[12] = setString2("Alter table with drop column",
                        mtdt.supportsAlterTableWithDropColumn());
    s[13] = setString2("Column aliasing", mtdt.supportsColumnAliasing());
    s[14] = setString2("Table correlation names",
                        mtdt.supportsTableCorrelationNames());
    s[15] = setString2("Expressions in order by",
                        mtdt.supportsExpressionsInOrderBy());
    s[16] = setString2("Unrelated order by", mtdt.supportsOrderByUnrelated());
    s[17] = setString2("Group by", mtdt.supportsGroupBy());
    s[18] = setString2("Unrelated group by", mtdt.supportsGroupByUnrelated());
    s[19] = setString2("Group by beyond select",
                        mtdt.supportsGroupByBeyondSelect());
    s[20] = setString2("Like escape clause", mtdt.supportsLikeEscapeClause());
    s[21] = setString2(" Multiple result sets", mtdt.supportsMultipleResultSets());
    s[22] = setString2("Multiple transactions",
                        mtdt.supportsMultipleTransactions());
    s[23] = setString2(" Non nullable columns",  mtdt.supportsNonNullableColumns());
    s[24] = setString2("Term for schemas", mtdt.getSchemaTerm());
    s[25] = setString2("Term for procedures", mtdt.getProcedureTerm());
    s[26] = setString2("Term for catalogs", mtdt.getCatalogTerm());
    mtdt = null;
    return s;
  }

  public String[][] getEngineLimitations() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = new String[10][2];
    s[0] = setString2("Property", "Value");
    s[1] = setString2(" Binary literal length", mtdt.getMaxBinaryLiteralLength());
    s[2] = setString2(" Character literal length", mtdt.getMaxCharLiteralLength());
    s[3] = setString2("Column name length", mtdt.getMaxColumnNameLength());
    s[4] = setString2("Columns in group by", mtdt.getMaxColumnsInGroupBy());
    s[5] = setString2("Columns in index", mtdt.getMaxColumnsInIndex());
    s[6] = setString2("Columns in order by", mtdt.getMaxColumnsInOrderBy());
    s[7] = setString2("Columns in select", mtdt.getMaxColumnsInSelect());
    s[8] = setString2("Columns in table", mtdt.getMaxColumnsInTable());
    s[9] = setString2("Number of connections", mtdt.getMaxConnections());
    mtdt = null;
    return s;
  }

  public String[] getCatalogs() throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[] s = getResultSetColumn(mtdt.getCatalogs(), 1);
    if (s.length == 0) {
      s = new String[1];
      s[0] = ""; // anonymous catalog
    }
    mtdt = null;
    return s;
  }

  public String[] getTables(String catalog, String type) throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[] types = new String[1];
    types[0] = type;
    String[] s = getResultSetColumn(mtdt.getTables(catalog, null, "%", types),
                                    "TABLE_NAME");
    mtdt = null;
    return s;
  }

  public String[][] getTableColumns(String catalog, String table)
                    throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = getAllResultSetColumns(mtdt.getColumns(catalog, null, table,
                                          "%"));
    mtdt = null;
    return s;
  }

  public String[][] getTablePrimaryKeys(String catalog, String table)
                    throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = getAllResultSetColumns(mtdt.getPrimaryKeys(catalog, null,
                                          table));
    mtdt = null;
    return s;
  }

  public String[][] getTableImportedKeys(String catalog, String table)
                    throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = getAllResultSetColumns(mtdt.getImportedKeys(catalog, null,
                                          table));
    mtdt = null;
    return s;
  }

  public String[][] getTableExportedKeys(String catalog, String table)
                    throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = getAllResultSetColumns(mtdt.getExportedKeys(catalog, null,
                                          table));
    mtdt = null;
    return s;
  }

  public String[] getProcedures(String catalog) throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[] s = getResultSetColumn(mtdt.getProcedures(catalog, null, "%"),
                                    "PROCEDURE_NAME");
    mtdt = null;
    return s;
  }

  public String[][] getProcedureColumns(String catalog, String procedure)
                    throws Exception {

    if (mtdt == null) { mtdt = conn.getMetaData(); }
    String[][] s = getAllResultSetColumns(mtdt.getProcedureColumns(catalog, null,
                                          procedure, "%"));
    mtdt = null;
    return s;
  }

  public void test() throws Exception {

    String text =        toString2(getSession()) +
                         toString2(getEngineInfo()) +
                         toString2(getEngineSpecs()) +
                         toString2(getEngineFeatures()) +
                         toString2(getEngineLimitations());

    System.out.println("-> METADATAS\n" + text);

    String[] catalogs = getCatalogs();
    System.out.println("-> CATALOGS\n" + toString1(catalogs));
    for (int i = 0; i<catalogs.length; i++) {
      System.out.println("-> USER TABLES IN " + catalogs[i]);
      System.out.println(toString1(getTables(catalogs[i], "TABLE")));
    }
    for (int i = 0; i<catalogs.length; i++) {
      System.out.println("-> SYSTEM TABLES IN " + catalogs[i]);
      System.out.println(toString1(getTables(catalogs[i], "SYSTEM TABLE")));
    }
    System.out.println(toString2(getAllResultSetColumns(
                                    getResultSet("SELECT * FROM TEST"))));
    System.out.println("OK");
  }

  // ************************************************************************

  public String[] getResultSetColumn(ResultSet rs, String column)
                  throws Exception {

    Vector v = new Vector();
    while (rs.next()) {
      v.addElement(rs.getString(column));
    }
    String s[] = new String[v.size()];
    s = v2a(v);
    return s;
  }

  public String[] getResultSetColumn(ResultSet rs, int i) throws Exception {

    Vector v = new Vector();
    while (rs.next()) {
      v.addElement(rs.getString(i));
    }
    String s[] = new String[v.size()];
    s = v2a(v);
    return s;
  }

  public ResultSet getResultSet(String sql) throws Exception {

    Statement st = conn.createStatement();
    st.setMaxRows(200);
    System.out.println(sql);
    return st.executeQuery(sql);
  }

  public String[][] executeComplexQuery(String sql) throws Exception {

    boolean resultSetIsAvailable;
    boolean moreResultsAvailable;
    int i = 0;
    int res=0;
    String[][] bigresult = null;
    String[][] result = null;

    Statement curStmt = conn.createStatement();
    resultSetIsAvailable = curStmt.execute(sql);
    ResultSet rs = null;
    for (moreResultsAvailable = true; moreResultsAvailable; ) {
      if (resultSetIsAvailable) {
        if ((rs = curStmt.getResultSet()) != null) {
          // we have a resultset
          result = getAllResultSetColumns(rs);
        }
      } else {
        if ((res = curStmt.getUpdateCount()) != -1) {
          // we have an updatecount
          result = new String[2][2];
          result[0] = setString2("UPDATE", "");
          result[1] = setString2("Update count", res);
        } else {
          // else no more results
          moreResultsAvailable = false;
        }
      }
      if (moreResultsAvailable) {
          resultSetIsAvailable = curStmt.getMoreResults();
      }
      bigresult = concat(bigresult, result);
    }
    if (rs != null) rs.close();
    curStmt.close();
    return bigresult;
  }

  public String[][] getAllResultSetColumns(ResultSet rs) throws Exception {

    String[] headers = getResultSetColumnHeaders(rs);
    String[][] rows = getResultSetRows(rs);
    String[][] t = new String[rows.length+1][headers.length];
    t[0] = headers;
    for (int i=0; i<rows.length; i++) {
      t[i+1] = rows[i];
    }
    return t;
  }

  public String[] getResultSetColumnHeaders(ResultSet rs) throws Exception {

    ResultSetMetaData rsmd = rs.getMetaData();
    String[] headers = new String[rsmd.getColumnCount()];
    for (int i=0; i<headers.length; i++) {
      headers[i] = rsmd.getColumnLabel(i+1);
    }
    return headers;
  }

  public String[][] getResultSetRows(ResultSet rs) throws Exception {

    ResultSetMetaData rsmd = rs.getMetaData();
    Vector v = new Vector();
    while (rs.next()) {
      String[] columns = new String[rsmd.getColumnCount()];
      for (int i=0; i<columns.length; i++) {
          columns[i] = rs.getString(i+1);
      }
      v.addElement(columns);
    }
    String[][] t = new String[v.size()][rsmd.getColumnCount()];
    for (int i=0; i<v.size(); i++) {
      t[i] = (String[]) v.elementAt(i);
    }
    rs.close();
    return t;
  }

  public String[] setString2(String s, String t) {

    String[] r = new String[2];
    r[0] = new String(s);
    r[1] = new String(t);
    return r;
  }

  public String[] setString2(String s, boolean b) {

    String[] r = new String[2];
    r[0] = new String(s);
    r[1] = new String(b?"yes":"no");
    return r;
  }

  public String[] setString2(String s, int i) {

    String[] r = new String[2];
    r[0] = new String(s);
    r[1] = "" + i;
    return r;
  }

  public String toString1(String[] s1) {

    String s = "\n";
    for (int i=0; i<s1.length; i++) {
      s += s1[i] + "\n";
    }
    return s;
  }

  public String toString2(String[][] s2) {

    String s = "\n";
    for (int i=0; i<s2.length; i++) {
      for (int j=0; j<s2[0].length; j++) {
        s += s2[i][j] + "\t";
      }
      s += "\n";
    }
    return s;
  }

  public String[] v2a(Vector v) {

    String[] s = new String[v.size()];
    for (int i=0; i<v.size(); i++) {
      s[i] = (String) v.elementAt(i);
    }
    return s;
  }

  public String[][] concat(String[][] a, String[][] b) {

    if (a == null) return b;
    if (b == null) return a;

    String[][] out =
       new String[a.length + b.length][Math.max(a[0].length, b[0].length)];
    for (int i=0; i<a.length; i++) {
      out[i] = a[i];
    }
    for (int j=0; j<b.length; j++) {
      out[a.length + j] = b[j];
    }
    return out;
  }
}
End example
Listing 12-5: ErrorBox.java
Start example
package jdbcexplorer;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * Title:        ErrorBox
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0  */

public class ErrorBox extends JDialog {

  JPanel panel1 = new JPanel();
  JPanel insetsPanel1 = new JPanel();
  JButton button1 = new JButton();
  BorderLayout borderLayout1 = new BorderLayout();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextPane jTextPane1 = new JTextPane();

  static Exception lastException = new Exception("No Exception");

  public ErrorBox(Frame parent, Exception ex) {

    super(parent);
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
      String text = "";
      if (ex != null) {
         lastException = ex;
      }
      java.io.StringWriter s = new java.io.StringWriter();
      lastException.printStackTrace(new java.io.PrintWriter(s));
      text = s.toString();
      jTextPane1.setText(text);
      this.setTitle(lastException.getMessage());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    pack();
  }

  /**Component initialization*/
  private void jbInit() throws Exception  {

    //imageLabel.setIcon(
         new ImageIcon( Mainframe_AboutBox.class.getResource("[Your Image]")));
    panel1.setLayout(borderLayout1);
    button1.setText("Close");
    button1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);
      }
    });
    jScrollPane1.setHorizontalScrollBarPolicy(
           JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setVerticalScrollBarPolicy(
           JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setPreferredSize(new Dimension(400, 150));
    jTextPane1.setForeground(Color.red);
    jTextPane1.setPreferredSize(new Dimension(400, 150));
    jTextPane1.setEditable(false);
    this.getContentPane().add(panel1, null);
    insetsPanel1.add(button1, null);
    panel1.add(jScrollPane1, BorderLayout.CENTER);
    jScrollPane1.getViewport().add(jTextPane1, null);
    panel1.add(insetsPanel1, BorderLayout.SOUTH);
  }

  /**Overridden so we can exit when window is closed*/
  protected void processWindowEvent(WindowEvent e) {

    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      cancel();
    }
    super.processWindowEvent(e);
  }

  /**Close the dialog*/
  void cancel() {

    dispose();
  }

  void jButton1_actionPerformed(ActionEvent e) {

    cancel();
  }

  /**Close the dialog on a button event*/
  public void actionPerformed(ActionEvent e) {

    if (e.getSource() == button1) {
      cancel();
    }
  }
}
End example
Listing 12-6: HelpBox.java
Start example
package jdbcexplorer;

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.html.*;

/**
 * Title:        HelpBox
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class HelpBox extends JDialog {

  JPanel panel1 = new JPanel();
  JPanel insetsPanel1 = new JPanel();
  JButton button1 = new JButton();
  BorderLayout borderLayout1 = new BorderLayout();
  JScrollPane jScrollPane1 = new JScrollPane();
  JEditorPane jEditorPane = new JEditorPane();

  public HelpBox(Frame parent) {

    super(parent);
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    jbInit();
    this.setTitle("Help");
    pack();
  }

  /**Component initialization*/
  private void jbInit() {

    //imageLabel.setIcon(new ImageIcon(
            Mainframe_AboutBox.class.getResource("[Your Image]")));
    panel1.setLayout(borderLayout1);
    button1.setText("Close");
    button1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);
      }
    });
    jScrollPane1.setHorizontalScrollBarPolicy(
           JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setVerticalScrollBarPolicy(
           JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setPreferredSize(new Dimension(400, 300));

    jEditorPane.setPreferredSize(new Dimension(400, 300));
    jEditorPane.setEditable(false);

    URL url = jdbcexplorer.Mainframe.class.getResource("help.html");
    try {
      jEditorPane.setPage(url);
    } catch (IOException e) {
      System.err.println("Attempted to read a bad URL: " + url);
    }

    HyperlinkListener h = new HyperlinkListener() {

      public void hyperlinkUpdate(HyperlinkEvent e) {

        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
          JEditorPane pane = (JEditorPane) e.getSource();
            if (e instanceof HTMLFrameHyperlinkEvent) {
              HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;
              HTMLDocument doc = (HTMLDocument)pane.getDocument();
              doc.processHTMLFrameHyperlinkEvent(evt);
            } else {
              try {
                  pane.setPage(e.getURL());
              } catch (Throwable t) {
                  t.printStackTrace();
              }
            }
        }
      }
    };

    jEditorPane.addHyperlinkListener(h);

    this.getContentPane().add(panel1, null);
    insetsPanel1.add(button1, null);
    panel1.add(jScrollPane1, BorderLayout.CENTER);
    jScrollPane1.getViewport().add(jEditorPane, null);
    panel1.add(insetsPanel1, BorderLayout.SOUTH);
  }

  /**Overridden so we can exit when window is closed*/
  protected void processWindowEvent(WindowEvent e) {

    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      cancel();
    }
    super.processWindowEvent(e);
  }

  /**Close the dialog*/
  void cancel() {

    dispose();
  }

  void jButton1_actionPerformed(ActionEvent e) {

    cancel();
  }

  /**Close the dialog on a button event*/
  public void actionPerformed(ActionEvent e) {

    if (e.getSource() == button1) {
      cancel();
    }
  }
}
End example
Listing 12-7: JDBCExplorer.java
Start example
package jdbcexplorer;

import javax.swing.UIManager;
import java.awt.*;

/**
* Title:        JDBCExplorer
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class JDBCExplorer {

  boolean packFrame = false;

  /**Construct the application*/
  public JDBCExplorer() {

    Mainframe frame = new Mainframe();
    //Validate frames that have preset sizes
    //Pack frames that have useful preferred size info, e.g. from their layout
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Center the window
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2,
                      (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }

  /**Main method*/
  public static void main(String[] args) {

    try {
      UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new JDBCExplorer();
  }
}
End example
Listing 12-8: Mainframe.java
Start example
package jdbcexplorer;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

/**
 * Title:        Mainframe
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class Mainframe extends JFrame {

  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenuFile = new JMenu();
  JMenuItem jMenuFileConnect = new JMenuItem();
  JMenuItem jMenuFileSQL = new JMenuItem();
  JMenuItem jMenuFileError = new JMenuItem();
  JMenuItem jMenuFileExit = new JMenuItem();
  JMenu jMenuHelp = new JMenu();
  JMenuItem jMenuHelpHelp = new JMenuItem();
  JMenuItem jMenuHelpAbout = new JMenuItem();
  JToolBar jToolBar = new JToolBar();
  JButton jButton1 = new JButton();
  JButton jButton2 = new JButton();
  JButton jButton3 = new JButton();
  JButton jButton4 = new JButton();
  ImageIcon image1;
  ImageIcon image2;
  ImageIcon image3;
  ImageIcon image4;
  JLabel statusBar = new JLabel();
  BorderLayout borderLayout1 = new BorderLayout();
  JLabel status = new JLabel();
  TitledBorder titledBorder1;
  JSplitPane jSplitPane1 = new JSplitPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JTable jTable;
  Navigator navigator;

  public void showTable(String[][] data) {

    if (data != null) {
      String[] headers = data[0];
      String[][] rows = new String[data.length-1][data[0].length];
      for (int i=1; i<data.length; i++) {
        rows[i-1] = data[i];
      }
      jTable = new JTable(rows, headers);
      jScrollPane2 = new JScrollPane(jTable);
      jScrollPane2.setHorizontalScrollBarPolicy(
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
      jScrollPane2.setVerticalScrollBarPolicy(
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      //jTable.setPreferredScrollableViewportSize(new Dimension(800, 600));
      jSplitPane1.add(jScrollPane2, JSplitPane.RIGHT);
      jTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
      TableColumn column = null;
      int max = 600;
      int growf = 20;
      if (headers.length > 2) {
        growf = 12;
      }
      for (int i = 0; i < headers.length; i++) {
        column = jTable.getColumnModel().getColumn(i);
        //column.sizeWidthToFit();
        if (i == (headers.length-1)) {
          if (max < (headers[i].length() * growf)) {
            max = (headers[i].length() * growf);
          }
          column.setPreferredWidth(max);
        } else {
          column.setPreferredWidth(headers[i].length() * growf);
          max = max - (headers[i].length() * growf);
        }
      }
    }
  }

  /**Construct the frame*/
  public Mainframe() {

    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**Component initialization*/
  private void jbInit() throws Exception  {

    navigator = new Navigator(this);
    image1 = new ImageIcon(jdbcexplorer.Mainframe.class.getResource(
                                                               "connect.gif"));
    image2 = new ImageIcon(jdbcexplorer.Mainframe.class.getResource("isql.gif"));
    image3 = new ImageIcon(jdbcexplorer.Mainframe.class.getResource("error.gif"));
    image4 = new ImageIcon(jdbcexplorer.Mainframe.class.getResource("help.gif"));
    //setIconImage(Toolkit.getDefaultToolkit().createImage(
          Mainframe.class.getResource("[Your Icon]")));
    contentPane = (JPanel) this.getContentPane();
    titledBorder1 = new TitledBorder("");
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(800, 600));
    this.setTitle("JDBCExplorer");
    statusBar.setText(" ");
    jMenuFile.setText("File");
    jMenuFileConnect.setText("Connect");
    jMenuFileConnect.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileConnect_actionPerformed(e);
      }
    });
    jMenuFileSQL.setText("SQL Command");
    jMenuFileSQL.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileSQL_actionPerformed(e);
      }
    });
    jMenuFileError.setText("Show Last Error");
    jMenuFileError.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileError_actionPerformed(e);
      }
    });
    jMenuFileExit.setText("Exit");
    jMenuFileExit.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileExit_actionPerformed(e);
      }
    });
    jMenuHelp.setText("Help");
    jMenuHelpHelp.setText("Quick Tips");
    jMenuHelpHelp.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuHelpHelp_actionPerformed(e);
      }
    });
    jMenuHelpAbout.setText("About");
    jMenuHelpAbout.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuHelpAbout_actionPerformed(e);
      }
    });
    jButton1.setIcon(image1);
    jButton1.setToolTipText("Open Connection");
    jButton1.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileConnect_actionPerformed(e);
      }
    });
    jButton2.setIcon(image2);
    jButton2.setToolTipText("SQL Command");
    jButton2.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileSQL_actionPerformed(e);
      }
    });
    jButton3.setIcon(image3);
    jButton3.setToolTipText("Error Log");
    jButton3.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuFileError_actionPerformed(e);
      }
    });
    jButton4.setIcon(image4);
    jButton4.setToolTipText("Help");
    jButton4.addActionListener(new ActionListener()  {
      public void actionPerformed(ActionEvent e) {
        jMenuHelpHelp_actionPerformed(e);
      }
    });
    status.setBorder(BorderFactory.createLoweredBevelBorder());
    status.setText("JDBCExplorer");
    jSplitPane1.setContinuousLayout(true);
    jSplitPane1.setOneTouchExpandable(true);
    jToolBar.add(jButton1);
    jToolBar.add(jButton2);
    jToolBar.add(jButton3);
    jToolBar.add(jButton4);
    jMenuFile.add(jMenuFileConnect);
    jMenuFile.add(jMenuFileSQL);
    jMenuFile.add(jMenuFileError);
    jMenuFile.add(jMenuFileExit);
    jMenuHelp.add(jMenuHelpHelp);
    jMenuHelp.add(jMenuHelpAbout);
    jMenuBar1.add(jMenuFile);
    jMenuBar1.add(jMenuHelp);
    this.setJMenuBar(jMenuBar1);
    contentPane.add(statusBar, BorderLayout.WEST);
    contentPane.add(status, BorderLayout.SOUTH);
    contentPane.add(jSplitPane1, BorderLayout.CENTER);
    jSplitPane1.add(navigator, JSplitPane.LEFT);
    jSplitPane1.add(jScrollPane2, JSplitPane.RIGHT);
    contentPane.add(jToolBar, BorderLayout.NORTH);
  }
  /**File | Exit action performed*/
  public void jMenuFileExit_actionPerformed(ActionEvent e) {
    System.exit(0);
  }

  /**File | Connect action performed*/
  public void jMenuFileConnect_actionPerformed(ActionEvent e) {
    ConnectionBox dlg = new ConnectionBox(this);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
        (frmSize.height - dlgSize.height) / 2 + loc.y);
    dlg.setModal(true);
    dlg.show();
  }

  /**File | SQL action performed*/
  public void jMenuFileSQL_actionPerformed(ActionEvent e) {

    SQLCommandBox dlg = new SQLCommandBox(this);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
        (frmSize.height - dlgSize.height) / 2 + loc.y);
    dlg.setModal(false);
    dlg.show();
  }

  /**File | Error action performed*/
  public void jMenuFileError_actionPerformed(ActionEvent e) {

    showError(null);
  }

  public void showError(Exception e) {

    ErrorBox dlg = new ErrorBox(this, e);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
        (frmSize.height - dlgSize.height) / 2 + loc.y);
    dlg.setModal(true);
    dlg.show();
  }

  /**Help | Help action performed*/
  public void jMenuHelpHelp_actionPerformed(ActionEvent e) {

    HelpBox dlg = new HelpBox(this);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
        (frmSize.height - dlgSize.height) / 2 + loc.y);
    dlg.setModal(false);
    dlg.show();
  }

  /**Help | About action performed*/
  public void jMenuHelpAbout_actionPerformed(ActionEvent e) {

    AboutBox dlg = new AboutBox(this);
    Dimension dlgSize = dlg.getPreferredSize();
    Dimension frmSize = getSize();
    Point loc = getLocation();
    dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
        (frmSize.height - dlgSize.height) / 2 + loc.y);
    dlg.setModal(true);
    dlg.show();
  }

  /**Overridden so we can exit when window is closed*/
  protected void processWindowEvent(WindowEvent e) {

    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      jMenuFileExit_actionPerformed(null);
    }
  }
}
End example
Listing 12-9: Navigator.java
Start example
package jdbcexplorer;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;

/**
 * Title:        Navigator
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
 */

public class Navigator extends JPanel {

  public JTree tree;
  public Mainframe mf;

  public DefaultMutableTreeNode root;
  public DefaultMutableTreeNode session;
  public DefaultMutableTreeNode engine;
  public DefaultMutableTreeNode engine_info;
  public DefaultMutableTreeNode engine_specs;
  public DefaultMutableTreeNode engine_features;
  public DefaultMutableTreeNode engine_limitations;
  public DefaultMutableTreeNode objects;
  public DefaultMutableTreeNode objects_catalogs;
  public DefaultMutableTreeNode objects_catalogs_default;
  public DefaultMutableTreeNode objects_catalogs_default_tables;
  public DefaultMutableTreeNode objects_catalogs_default_tables_system;
  public DefaultMutableTreeNode objects_catalogs_default_tables_user;
  public DefaultMutableTreeNode objects_catalogs_default_tables_x_table;
  public DefaultMutableTreeNode objects_catalogs_default_procedures;
  public DefaultMutableTreeNode objects_catalogs_default_procedures_x_procedure;
  public DefaultMutableTreeNode tools;
  public DefaultMutableTreeNode tools_isql;

  public Navigator(Mainframe mf) {

    this.mf = mf;
    setLayout(new BorderLayout());
    root = new DefaultMutableTreeNode("Database");
    addTopNodes(root);
    tree = new JTree(root);
    JScrollPane pane = new JScrollPane();
    pane.getViewport().add(tree);
    add(pane, BorderLayout.CENTER);
    tree.setCellRenderer(new MyRenderer());
    tree.putClientProperty("JTree.lineStyle", "Angled");

    MouseListener ml = new MouseAdapter() {

      public void mouseClicked(MouseEvent e) {

         int selRow = tree.getRowForLocation(e.getX(), e.getY());
         TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
         if(selRow != -1) {
           System.out.println(selPath.toString());
           Object[] nodes = selPath.getPath();
           String[] path = new String[nodes.length];
           for (int i=0; i<nodes.length; i++) {
             path[i] = ((DefaultMutableTreeNode) nodes[i]).toString();
           }

           DatabaseConnection conn = DatabaseConnection.getInstance();
           try {
             if (conn == null || !conn.getInstance().isActive() ||
                 path.length == 1) { return; }
             if (path[1].equals("Session")) {
               showTable(conn.getSession());

             } else if ((path.length == 3) && (path[1].equals("Engine"))) {
               if (path[2].equals("Info")) {
                 showTable(conn.getEngineInfo());

               } else if (path[2].equals("Specs")) {
                 showTable(conn.getEngineSpecs());

               } else if (path[2].equals("Features")) {
                 showTable(conn.getEngineFeatures());

               } else if (path[2].equals("Limitations")) {
                 showTable(conn.getEngineLimitations());

               }
             } else if ((path.length == 3) && (path[2].equals("Catalogs"))) {
               // refresh catalog nodes
               addCatalogs(conn.getCatalogs());

             } else if ((path.length == 6) && (path[4].equals("Tables"))) {
               // refresh tables in catalog
               addTables((DefaultMutableTreeNode) selPath.getLastPathComponent(),
                         conn.getTables(path[3],
                         path[5].equals("User")?"TABLE":"SYSTEM TABLE"));
               tree.treeDidChange();

             } else if ((path.length == 7) && (path[4].equals("Tables"))) {
               // display table content
               String cat = !path[3].equals("")? path[3] + "..":"";
               showTable(conn.getAllResultSetColumns(
                   conn.getResultSet("SELECT * FROM " + cat + path[6])));

             } else if ((path.length == 8) && (path[4].equals("Tables")) &&
                        (path[7].equals("Columns"))) {
               // display table columns
               showTable(conn.getTableColumns(path[3], path[6]));

             } else if ((path.length == 8) && (path[4].equals("Tables")) &&
                        (path[7].equals("Primary Keys"))) {
               // display primary key
               showTable(conn.getTablePrimaryKeys(path[3], path[6]));

             } else if ((path.length == 8) && (path[4].equals("Tables")) &&
                        (path[7].equals("Imported Keys"))) {
               // display imported keys
               showTable(conn.getTableImportedKeys(path[3], path[6]));

             } else if ((path.length == 8) && (path[4].equals("Tables")) &&
                        (path[7].equals("Exported Keys"))) {
               // display exported keys
               showTable(conn.getTableExportedKeys(path[3], path[6]));

             } else if ((path.length == 5) && (path[4].equals("Procedures"))) {
               // refresh procedures in catalog
               addProcedures((DefaultMutableTreeNode)
                              selPath.getLastPathComponent(),
                              conn.getProcedures(path[3]));
               tree.treeDidChange();

             } else if ((path.length == 6) && (path[4].equals("Procedures"))) {
               // display procedure content
               showTable(conn.getProcedureColumns(path[3], path[5]));

             } else if ((path.length == 3) && (path[2].equals("ISQL"))) {
               showISQL();
             }
           } catch (Exception ex) {
             ex.printStackTrace();
             showError(ex);
           }
         }
      }
    };
    tree.addMouseListener(ml);
  }

  public void showTable(String[][] data) {

    mf.showTable(data);
  }

  public void showError(Exception e) {

    mf.showError(e);
  }

  public void showISQL() {

    mf.jMenuFileSQL_actionPerformed(null);
  }

  public void addCatalogs(String[] catalogs) {

    objects_catalogs.removeAllChildren();
    for (int i=0; i<catalogs.length; i++) {
      objects_catalogs_default = new DefaultMutableTreeNode(catalogs[i]);
      objects_catalogs.add(objects_catalogs_default);
      objects_catalogs_default_tables = new DefaultMutableTreeNode("Tables");
      objects_catalogs_default.add(objects_catalogs_default_tables);
      objects_catalogs_default_tables_system =
          new DefaultMutableTreeNode("System");
      objects_catalogs_default_tables.add(objects_catalogs_default_tables_system);
      objects_catalogs_default_tables_user = new DefaultMutableTreeNode("User");
      objects_catalogs_default_tables.add(objects_catalogs_default_tables_user);
      objects_catalogs_default_procedures =
          new DefaultMutableTreeNode("Procedures");
      objects_catalogs_default.add(objects_catalogs_default_procedures);
    }
  }

  public void addTables(DefaultMutableTreeNode hook, String[] tables) {

    hook.removeAllChildren();
    for (int i=0; i<tables.length; i++) {
      objects_catalogs_default_tables_x_table =
          new DefaultMutableTreeNode(tables[i]);
      objects_catalogs_default_tables_x_table.add(
          new DefaultMutableTreeNode("Columns"));
      objects_catalogs_default_tables_x_table.add(
          new DefaultMutableTreeNode("Primary Keys"));
      objects_catalogs_default_tables_x_table.add(
          new DefaultMutableTreeNode("Imported Keys"));
      objects_catalogs_default_tables_x_table.add(
          new DefaultMutableTreeNode("Exported Keys"));
      hook.add(objects_catalogs_default_tables_x_table);
    }
  }

  public void addProcedures(DefaultMutableTreeNode hook, String[] procedures) {

    hook.removeAllChildren();
    for (int i=0; i<procedures.length; i++) {
      objects_catalogs_default_procedures_x_procedure =
          new DefaultMutableTreeNode(procedures[i]);
      hook.add(objects_catalogs_default_procedures_x_procedure);
    }
  }

  public void addTopNodes(DefaultMutableTreeNode root) {

    session = new DefaultMutableTreeNode("Session");
    engine = new DefaultMutableTreeNode("Engine");
    engine_info = new DefaultMutableTreeNode("Info");
    engine.add(engine_info);
    engine_specs = new DefaultMutableTreeNode("Specs");
    engine.add(engine_specs);
    engine_features = new DefaultMutableTreeNode("Features");
    engine.add(engine_features);
    engine_limitations = new DefaultMutableTreeNode("Limitations");
    engine.add(engine_limitations);
    objects = new DefaultMutableTreeNode("Objects");
    objects_catalogs = new DefaultMutableTreeNode("Catalogs");
    objects.add(objects_catalogs);
    String[] def = { "" };
    addCatalogs(def);
    addCatalogs(def);
    addCatalogs(def);
    tools = new DefaultMutableTreeNode("Tools");
    tools_isql = new DefaultMutableTreeNode("ISQL");
    tools.add(tools_isql);
    root.add(session);
    root.add(engine);
    root.add(objects);
    root.add(tools);
  }

    class MyRenderer extends DefaultTreeCellRenderer {

      ImageIcon rootIcon;
      ImageIcon tableIcon;
      ImageIcon sessionIcon;
      ImageIcon docIcon;
      ImageIcon dbIcon;
      ImageIcon isqlIcon;
      ImageIcon keyIcon;
      ImageIcon pkIcon;
      ImageIcon objectIcon;
      ImageIcon blueIcon;
      ImageIcon redIcon;
      ImageIcon greenIcon;
      ImageIcon magentaIcon;

      public MyRenderer() {

         rootIcon =
           new ImageIcon(jdbcexplorer.Mainframe.class.getResource("db.gif"));
        tableIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("table.gif"));
        sessionIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("session.gif"));
        docIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("archivs.gif"));
        dbIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("db.gif"));
        isqlIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("isql.gif"));
        keyIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("key.gif"));
        pkIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("pk.gif"));
        objectIcon =
         new ImageIcon(jdbcexplorer.Mainframe.class.getResource("object.gif"));
        blueIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("blue.gif"));
        redIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("red.gif"));
        greenIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("green.gif"));
        magentaIcon =
          new ImageIcon(jdbcexplorer.Mainframe.class.getResource("magenta.gif"));
     }

     public Component getTreeCellRendererComponent(JTree tree, Object value,
       boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {

       super.getTreeCellRendererComponent(tree, value, sel, expanded,
                                          leaf, row, hasFocus);
       if (((DefaultMutableTreeNode) value).toString().equals("Database")) {
          setIcon(rootIcon);
       } else if (((DefaultMutableTreeNode) value).toString().equals("Session")) {
          setIcon(sessionIcon);
       } else if (((DefaultMutableTreeNode) value).toString().equals("Engine")) {
          setIcon(docIcon);        } else if (((DefaultMutableTreeNode) value).toString().equals("Info")) {
          setIcon(redIcon);
       } else if (((DefaultMutableTreeNode) value).toString().equals("Specs")) {
          setIcon(blueIcon);

       } else if (((DefaultMutableTreeNode) value).toString().equals("Features")) {
          setIcon(greenIcon);
       } else if (
          ((DefaultMutableTreeNode) value).toString().equals("Limitations")) {
          setIcon(magentaIcon);
       } else if (
          ((DefaultMutableTreeNode) value).toString().equals("Catalogs")) {
          setIcon(dbIcon);
       } else if (((DefaultMutableTreeNode) value).getLevel() == 4) {
          setIcon(objectIcon);
        } else if (
           ((DefaultMutableTreeNode) value).toString().equals("Primary Keys")) {
          setIcon(pkIcon);
        } else if (
           ((DefaultMutableTreeNode) value).toString().endsWith("Keys")) {
          setIcon(keyIcon);
       } else if (((DefaultMutableTreeNode) value).toString().equals("ISQL")) {
          setIcon(isqlIcon);
       } else if (((DefaultMutableTreeNode) value).getLevel() == 6) {
          setIcon(tableIcon);
       }
       return this;
     }
   }
}
End example
Listing 12-10: SQLCommandBox.java
Start example
package jdbcexplorer;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * Title:        SQLCommandBox
 * Description:
 * Company:
 * @author Bernard Van Haecke
 * @version 2.0
*/

public class SQLCommandBox extends JDialog {

  BorderLayout borderLayout2 = new BorderLayout();
  JPanel jPanel1 = new JPanel();
  JButton jButton1 = new JButton();
  JButton jButton2 = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextPane jTextPane1 = new JTextPane();
  static String sql = "SELECT * FROM TEST";
  Mainframe mf;

  public SQLCommandBox(Mainframe parent) {

    super((Frame) parent);
    mf = parent;
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    pack();
  }

  private void jbInit() throws Exception {

    this.getContentPane().setLayout(borderLayout2);
    jButton1.setText("Execute");
    jButton1.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {

        jButton1_actionPerformed(e);
      }
    });
    jButton2.setText("Close");
    jButton2.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {

        jButton2_actionPerformed(e);
      }
    });
    this.setTitle("SQL Command");
    jScrollPane1.setHorizontalScrollBarPolicy(
          JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setVerticalScrollBarPolicy(
          JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    jScrollPane1.setPreferredSize(new Dimension(400, 150));
    jTextPane1.setBackground(Color.black);
    jTextPane1.setFont(new java.awt.Font("Monospaced", 0, 12));
    jTextPane1.setForeground(Color.green);
    jTextPane1.setPreferredSize(new Dimension(400, 200));
    jTextPane1.setCaretColor(Color.white);
    jTextPane1.setText(sql);
    this.getContentPane().add(jPanel1, BorderLayout.SOUTH);
    jPanel1.add(jButton1, null);
    jPanel1.add(jButton2, null);
    this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
    jScrollPane1.getViewport().add(jTextPane1, null);
  }

  public void showTable(String[][] data) {

    mf.showTable(data);
  }

  public void showError(Exception e) {

    mf.showError(e);
  }

  void jButton1_actionPerformed(ActionEvent e) {

    try {
      sql = jTextPane1.getText();
      DatabaseConnection conn = DatabaseConnection.getInstance();
      if (conn == null || !conn.getInstance().isActive()) { return; }
      //showTable(conn.getAllResultSetColumns(conn.getResultSet(sql)));
      showTable(conn.executeComplexQuery(sql));
    } catch (Exception ex) {
      showError(ex);
    }
  }

  void jButton2_actionPerformed(ActionEvent e) {
    this.dispose();
  }

}
End example


Multitier Applications: Remote Method Invocation and JDBC

I discuss different approaches to software partitioning in Chapter 1, which discusses N-tiered approaches, RMI allows Java objects to be distributed and shared across computers and networks. This example uses RMI between the client and the middleware and JDBC between the middleware and the database server.

RMI combined with JDBC for database access is a simple but efficient enabler for software partitioning. In this example, the client performs presentation (GUI) tasks only, the middleware stores the application’s logic, and the database provides a persistent and coherent storage for the data.

This example deals with cars. In this example, all the cars are built in hypothetical car factories, and there is one factory for each different car brand. Clients can invoke various methods on the cars and factories, although these objects aren’t local client objects to them; they are remote objects. This means that all methods called on these objects are executed where these objects reside — that is, on the RMI server. If parameters must be passed to such methods, they are serialized by RMI and passed to the server object that will deserialize them.

The example uses these classes:

  • Car.java is an interface for objects that represent cars. It extends java.rmi.remote.

  • CarImpl.java implements Car.

  • CarFactory.java is an interface that extends java.rmi.remote. It is used for objects that are factories of car objects. Factory is used in the OO sense here, not the industrial sense.

  • CarFactoryImpl.java implements CarFactory.

  • CarSupplierServer.java is a server. It brings car factories to life and makes them reachable through the RMI mechanism.

  • CarSales.java is a client that deals with objects such as Car and CarFactories.

The client has access only to the Car and CarFactory interfaces. All methods invoked on these objects are actually implemented within the RMI server, which, in turn, performs the calls to the database through JDBC. Figure 12-13 illustrates the whole architecture for this example.

Click To expand
Figure 12-13: The three-tiered architecture of the car factory example.

Instead of providing object persistency at the Car level, a simpler option was chosen: The CarFactory level provides persistent storage. Practically, this means that information about the car factories is saved in a database table and loaded by the CarFactoryImpl constructor. The database immediately reflects all updates of the car factories. Another option is to save the different instances of CarFactory in their finalize() methods whenever the RMI server program terminates.

The database side

The data structure is quite simple. The following is the SQL to create the table used for this example. The primary key is composed of two fields: serialno and brand.

CREATE TABLE cars
(serialno INT NULL,
brand VARCHAR(12) NULL,
model VARCHAR(12) NULL,
color VARCHAR(12) NULL,
price INT NULL,
owner VARCHAR(12) NULL)
GO
INSERT INTO cars VALUES
(1000000, ‘Volkswagen’, ‘Golf GL’, ‘black’, NULL, ‘’)
GO

The following SQL statement queries the content of the table after a few executions of the RMI client and RMI server:

1> SELECT * FROM cars
2> ORDER BY brand, serialno
3> GO
serialno brand model color price owner
------ ------ ------ ------ ------ ------
1000001 Audi A6 black NULL
1000002 Audi A8 yellow NULL
1000003 Audi A6 black NULL
1000004 Audi A8 yellow NULL
1000005 Audi A6 black NULL
1000006 Audi A8 yellow NULL
1000007 Audi A6 black NULL
1000008 Audi A8 yellow NULL
1000001 BMW 528i fjordgreen NULL
1000002 BMW 750Li arcticsilver NULL
1000003 BMW 528i fjordgreen NULL
1000004 BMW 750Li arcticsilver NULL
1000005 BMW 528i fjordgreen NULL
1000006 BMW 750Li arcticsilver NULL
1000007 BMW 528i fjordgreen NULL
1000008 BMW 750Li arcticsilver NULL
1000000 Volkswagen Golf GL black NULL
1000001 Volkswagen Golf CL darkred NULL
1000002 Volkswagen Golf CL darkred NULL
1000003 Volkswagen Golf CL darkred NULL
1000004 Volkswagen Golf CL darkred NULL
(21 rows affected)

The RMI server side

A script file starts the server and an RMI service called the RMI Registry. As soon as the RMI server launches, the CarSupplierServer object re-creates car factories and cars from the data in the database. CarFactory objects are thus created and bound to a name. Client lookups use this name to obtain references to these remote objects. Here is the output of the CarSupplierServer when launched on UNIX (Windows users: the RMI registry command must be executed in a separate DOS shell):

csh: start
starting registry
[1] 7852
starting CarSupplierServer
press CTRL-C to interrupt server
type: java CarSales to start client
Creating Car Factories
CarFactory: Loaded new Car:Car: model=Audi model=A6 color=black serial=1 owner=
CarFactory: Loaded new Car:Car: model=Audi model=A8 color=yellow serial=2 owner=
CarFactory: Loaded new Car:Car: model=Audi model=A8 color=yellow serial=3 owner=
CarFactory: Loaded new Car:Car: model=Audi model=A8 color=pink serial=4 owner=
CarFactory: Loaded new Car:Car: model=BMW model=528i color=fjordgreen
serial=1 owner=
CarFactory: Loaded new Car:Car: model=BMW model=750Li color=arcticsilver
serial=2 owner=
CarFactory: Loaded new Car:Car: model=BMW model=528i color=applegreen
serial=3 owner=
CarFactory: Loaded new Car:Car: model=BMW model=528i color=sunblue  serial=5 owner=
CarFactory: Loaded new Car:Car: model=Volkswagen model=Golf TDI
color=black serial=1000000 owner=
CarFactory: Loaded new Car:Car: model=Volkswagen model=Golf CL
color=darkred serial=1000001 owner=
CarFactory: Loaded new Car:Car: model=Volkswagen model=Golf TDI
color=deep space b serial=1000002 owner=
Registering Car Factories

The client side

The client programs are started by simply running CarSales as shown in this command line:

% java CarSales

CarSales calls a lookup method to obtain references to remote objects. Once obtained, these references are used to invoke various methods defined in CarFactory and implemented in CarFactoryImpl.

The window shown in Figure 12-14 appears on-screen, displaying a trace of the different actions the client performs.

Click To expand
Figure 12-14: The RMI client window.

As soon as the client launches, the RMI server logs all the actions that it performs on behalf of the client, such as the following:

CarFactory Audi: request for all cars. 4 returned.
CarFactory BMW: request for all cars. 4 returned.
CarFactory Volkswagen: request for all cars. 3 returned.
CarFactory Audi: request for all cars. 4 returned.
CarFactory: Created new Car:Car: model=Audi model=A8 color=orange
serial=5 owner=None
CarFactory Audi: request for all cars. 5 returned.
CarFactory: Deleted Car:CarImpl_Stub[RemoteStub [ref:
[endpoint:[guadalajara:37065](remote),objID:[14]]]]
CarFactory Audi: request for all cars. 4 returned.

Car.java

Car.java is the interface for cars. It extends java.rmi.Remote and is implemented by the CarImpl class. All methods invoked on Car instances trigger respective methods implemented by CarImpl instances. Listing 12-11 shows the source code for Car.java.

Listing 12-11: Car.java
Start example
//
// Car.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
// Interface describing stub Car functionality
// the actual implementation will be the responsibility of
// CarImpl; Car’s will be created by a remote factory object:
// CarFactory and CarFactoryImplementation.
//
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Car extends Remote {

  public int getPrice () throws RemoteException;

  public int getTopSpeed() throws RemoteException;
  public long getSerialNr() throws RemoteException;
  public void sellTo ( String owner ) throws RemoteException;
  public String getOwner ( ) throws RemoteException;

  public String getColor ( ) throws RemoteException;
  public String getModel ( ) throws RemoteException;

  public String getObjectString ( ) throws RemoteException;
}
End example

CarImpl.java

The CarImpl.java class implements Car. It contains various methods to perform miscellaneous actions on Cars. Listing 12-12 is the source code for CarImpl.java.

Listing 12-12: CarImpl.java
Start example
//
// CarImpl.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class CarImpl extends UnicastRemoteObject implements Car {

  private int price;
  private long serialNr;
  private String brand;
  private String model;
  private String color;
  private String owner = null;

  public CarImpl ( String brand, String model, String color, long serialNr )
    throws RemoteException {

    this.brand = brand;
    this.model = model;
    this.color = color;
    this.serialNr = serialNr;
  }

  public CarImpl ( String brand, String model, String color, long serialNr,
                   String owner ) throws RemoteException {

    this.brand = brand;
    this.model = model;
    this.color = color;
    this.serialNr = serialNr;
    this.owner = owner;
  }

  public int getPrice () throws RemoteException {

    return 0; // Catalog.getPrice( brand, model );
  }

  public int getTopSpeed() throws RemoteException {

    return 0; // Catalog.getTopSpeed( brand, model );
  }

  public long getSerialNr() throws RemoteException {

    return serialNr;
  }

  public void sellTo ( String owner ) throws RemoteException {

    this.owner = owner;
  }

  public String getOwner ( ) throws RemoteException {

    return owner;
  }

  public String getColor ( ) throws RemoteException {

    return color;
  }

  public String getBrand ( ) throws RemoteException {

    return brand;
  }

  public String getModel ( ) throws RemoteException {

    return model;
  }

  public String toString ( ) {

    return "Car: model=" + brand + " model=" + model + " color=" + color +
    " serial=" + serialNr + " owner=" + ((owner == null)? "None" : owner);
  }

  public String getObjectString ( ) throws RemoteException {

    return this.toString();
  }
}
End example

CarFactory.java

The CarFactory class is an interface implemented by CarFactoryImpl. Like the Car interface, CarFactory inherits from java.rmi.Remote. Listing 12-13 is the source code for CarFactory.java.

Listing 12-13: CarFactory.java
Start example
//
// CarFactory.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
// interface describing stub CarFactory functionality
// the actual implementation will be the responsibility of
// CarFactoryImpl.
//
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.sql.*;

public interface CarFactory extends Remote {

  public Car createCar ( String model, String color ) throws RemoteException,
                                                             SQLException;
  public Car getCar ( long serialNr ) throws RemoteException;
  public Car[] getAll () throws RemoteException;
  public boolean deleteCar ( Car car ) throws RemoteException, SQLException;
  public String getObjectString () throws RemoteException;
}
End example

CarFactoryImpl.java

CarFactoryImpl implements CarFactory and provides connectivity to the database through JDBC. It manipulates objects whose lifetime is longer than the application’s lifetime. These objects are persisted, stored in a database table, and loaded by the CarFactoryImpl constructor upon initialization.

The methods that perform updates of data call JDBC and execute SQL statements to synchronize the data in the database.

Listing 12-14 shows the source code for CarFactoryImpl.java.

Listing 12-14: CarFactoryImpl.java
Start example
//
// CarFactoryImpl.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
// interface describing stub CarFactory functionality
// the actual implementation will be the responsibility of
// CarFactoryImpl.
//
import java.util.Hashtable;
import java.util.Enumeration;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.*;

public class CarFactoryImpl extends UnicastRemoteObject implements CarFactory {

  private String brand;
  private long lastSerialNr = 1000000;
  private Hashtable cars = new Hashtable();
  // local variables for connection state
  private Connection conn;
  private String uid = "guest";
  private String pwd = "sybase";
  private String table = "cars";
  // url for sybase’s driver
  private String url = "jdbc:sybase:Tds:guadalajara:8192";
  private String driver = "com.sybase.jdbc.SybDriver";

  public CarFactoryImpl ( String brand ) throws RemoteException,
                                                SQLException, Exception {

    Class.forName(driver);
    conn = DriverManager.getConnection(url, uid, pwd);
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM " + table
    + " WHERE brand = ‘" + brand + "‘");

    while (rs.next()) {
      wakeupCar(rs.getInt("serialno"),
      rs.getString("brand"),
      rs.getString("model"),
      rs.getString("color"),
      rs.getString("owner"));
    }
    rs = stmt.executeQuery("SELECT MAX(serialno) FROM " + table
    + " WHERE brand = ‘" + brand + "‘");
    rs.next();
    lastSerialNr = rs.getLong(1);
    rs.close();
    stmt.close();
    this.brand = brand;
  }

  protected void finalize() throws SQLException {

    conn.close();
  }

  public void wakeupCar ( int sn, String brand, String model, String color,
                          String owner ) throws RemoteException {

    CarImpl car = new CarImpl ( brand, model, color, sn, owner );
    cars.put("SN"+car.getSerialNr(), car);
    System.out.println("CarFactory: Loaded new Car:" + car);
  }

  public Car createCar ( String model, String color ) throws RemoteException,
                                                             SQLException {

    CarImpl car = new CarImpl ( brand, model, color, ++lastSerialNr );
    Statement stmt = conn.createStatement();
    int res = stmt.executeUpdate("INSERT INTO " + table
      + "(serialno, brand, model, color, owner) VALUES ("
      + car.getSerialNr() + ", ‘" + brand + "‘, ‘" + model
      + "‘, ‘" + color + "‘, ‘’)");
    stmt.close();
    cars.put ( "SN" + car.getSerialNr(), car );
    System.out.println("CarFactory: Created new Car:" + car);
    return car;
  }

  public Car getCar ( long serialNr ) throws RemoteException {

    return (Car)cars.get("SN"+serialNr);
  }

  /**
  * get all cars without worrying about synchronization
  */
  public Car[] getAll () throws RemoteException {

    Car [] allcars = new Car[cars.size()];
    int i = 0;
    Enumeration e = cars.elements();
    while (e.hasMoreElements()) {
      allcars[i++] = (Car)e.nextElement();
    }
    System.out.println("CarFactory " + brand + ": request for all cars. "
                       + i + " returned.");
    return allcars;
  }

  public boolean deleteCar ( Car car ) throws RemoteException, SQLException {

    long sn = car.getSerialNr();
    if ( cars.remove("SN"+ sn) != null ) {
      Statement stmt = conn.createStatement();
      int res = stmt.executeUpdate("DELETE " + table
        + " WHERE brand = ‘" + brand + "‘ AND serialno = " + sn + "");
      stmt.close();
      System.out.println("CarFactory: Deleted Car:" + car);
      return true;
    }
    else {
      return false;
    }
  }

  public String toString () {

    return "CarFactory: " + brand + " lastNr=" + lastSerialNr;
  }

  public String getObjectString () throws RemoteException {

    return this.toString();
  }
}
End example

CarSales.java

CarSales.java is the client class. CarSales is a standalone application that looks up CarFactories in the RMI server to get references to these remote CarFactories instances.

The application tries to obtain references to three remote CarFactories. After it obtains the references, actions such as selecting, ordering, selling, and destroying cars can be performed. This RMI client refers only to the CarFactory and Car interfaces, not their actual implementation, which is the main objective of this exercise. The implementation class instances run elsewhere on the network and are seamlessly accessed through RMI.

Listing 12-15 shows the source code for CarSales.java.

Listing 12-15: CarSales.java
Start example
//
// CarSales.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
// This code is not to be distributed without
// explicit confirmation by the author.
//
import java.awt.*;
import java.rmi.Naming;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.net.UnknownHostException;

/**
* CarSales-class connecting to a Remote Object
* registry.
* The Carsales instance allows simple order and selling
* of cars.
*/

public class CarSales extends Frame {

  TextArea ta = new TextArea("Application started");
  Button quitB = new Button ( "Quit" ), orderB = new Button ( "Order Car" );
  Button sellB = new Button ( "Sell" );
  Button wreckB = new Button ( "Wreck" );
  Choice brandCH = new Choice (), allCarsCH = new Choice();
  TextField modelTF = new TextField(10), colorTF = new TextField(10);
  TextField buyerTF = new TextField(10);
  CarFactory carFactory[];
  Car cars[] = null;

  /**
  * Construct the CarSales GUI
  */
  public CarSales ( ) {

    super ("BEST CARS IN THE WORLD");
    // Setup the User Interface
    Panel northPan = new Panel ( );
    northPan.setLayout ( new BorderLayout () );
    northPan.add ( "North",
    new Label ("Car Ordering: Select brand and model", Label.LEFT) );
    northPan.setLayout ( new BorderLayout() );
    Panel orderPanel = new Panel ();
    //orderPanel.setLayout ( new FlowLayout ( FlowLayout.LEFT ) );
    orderPanel.setLayout ( new GridLayout ( 1,7) );
    orderPanel.add ( new Label ("Brand:", Label.RIGHT ) );
    orderPanel.add ( brandCH );
    orderPanel.add ( new Label ("Model:", Label.RIGHT ) );
    orderPanel.add ( modelTF );
    orderPanel.add ( new Label ("Color:", Label.RIGHT ) );
    orderPanel.add ( colorTF );
    orderPanel.add ( orderB );
    Panel sellPanel = new Panel ();
    //sellPanel.setLayout ( new FlowLayout ( FlowLayout.LEFT ) );
    sellPanel.setLayout ( new GridLayout ( 1,7) );
    sellPanel.add ( new Label ("All Cars:", Label.RIGHT ) );
    sellPanel.add ( allCarsCH );
    sellPanel.add ( new Label ("Buyer:", Label.RIGHT ) );
    sellPanel.add ( buyerTF );
    sellPanel.add ( new Label ( "" ) );
    sellPanel.add ( new Label( "Actions:", Label.RIGHT ) );
    Panel buttonPan = new Panel ( );
    buttonPan.setLayout ( new GridLayout ( 1, 2) );
    buttonPan.add ( sellB );
    buttonPan.add ( wreckB );
    sellPanel.add ( buttonPan );
    Panel northCenterPanel = new Panel ();
    northCenterPanel.setLayout ( new GridLayout ( 2, 1 ) );
    northCenterPanel.add ( orderPanel );
    northCenterPanel.add ( sellPanel );
    northPan.add ( "Center", northCenterPanel );
    northPan.add ( "South", new Label ( "RMI/SQL log:", Label.CENTER ) );
    add("North", northPan );
    add("Center", ta);
    add("South", quitB );
    // In a real application there would be a remote object
    // giving us an array or enumeration with all brands.
    // In this example we do it hard coded.
    String carBrands[] = { "audi", "bmw", "vw" };
    carFactory = new CarFactory [ carBrands.length ];
    for (int ndx=0; ndx< carBrands.length; ndx ++ ) {
      try {
        brandCH.addItem ( carBrands[ndx] );
        carFactory[ndx] = (CarFactory) (java.rmi.Naming.lookup (
                           "rmi://serverhost/CarFactory." + carBrands[ndx] ) );
        appendTA( carBrands[ndx] + ": " + carFactory[ndx]);
      }
      catch ( java.rmi.RemoteException ex) {
        appendTA( "Constructor() RemoteException: " + ex.getMessage() );
      }
      catch ( java.rmi.NotBoundException ex) {
        appendTA( "Constructor() NotBoundException: " + ex.getMessage() );}
      catch ( java.net.MalformedURLException ex) {
        appendTA ( "Constructor() MalformedURLException: "+ ex.getMessage() );
      }
    } // end for carBrands[ndx]
    try {
      appendTA("");
      appendTA("Creating Cars:");
      updateAllCarsChoice ( ) ;
      //Car nr1 = audiFact.createCar("A6", "black");
    }
    catch ( Exception ex) {
      appendTA( "Constructor() Exception: " + ex.getMessage() );
      ex.printStackTrace();
    }
    pack();
    setVisible ( true );    // JDK1.1 replaced deprecated show()
  }

  private void updateAllCarsChoice ( ) {

    int ndx = brandCH.getSelectedIndex();
    int count = 0;
    allCarsCH.removeAll();
    try {
      cars = carFactory[ndx].getAll();
      for ( int i=0 ; i < cars.length; i++ ) {
        allCarsCH.addItem ( "" + cars[i].getSerialNr() + " " +
          cars[i].getModel() + "," + cars[i].getColor() );
        count++;
      }
    }
    catch ( Exception ex ) {
      appendTA ( "updateAllCarChoice() Exception: " + ex.getMessage() );
    }
    if ( count > 0 ) {
      allCarsCH.setEnabled ( true );
      allCarsCH.select( 0 );
      try {
        buyerTF.setText ( cars[0].getOwner() );
        colorTF.setText ( cars[0].getColor() );
        modelTF.setText ( cars[0].getModel() );
      }
      catch ( Exception ex ) {
        appendTA ( "updateAllCarChoice() Exception: " + ex.getMessage() );
      }
    }
    else {
      allCarsCH.setEnabled ( false );
      allCarsCH.addItem ( "No Cars Available" );
    }
    appendTA ( "Added " + count + " cars to allCarsCH for " +
               brandCH.getSelectedItem() );
  }

  private void appendTA ( String text ) {

    ta.setText( ta.getText() + "\n" + text.toString() );
  }

  private void appendTA ( Car car ) {

    try {
      ta.setText( ta.getText() + "\n" + car.getObjectString() );
    }
    catch ( java.rmi.RemoteException ex ) {
      ta.setText ( "RemoteException: " + ex.getMessage() );
      ex.printStackTrace();
    }
  }

  // JDK1.02 event-model
  public boolean action ( Event evt, Object arg ) {

    try {
      if ( evt.target == quitB ) {
        setVisible ( false ); // JDK1.1’s setVisible() replaced deprecated hide()
        dispose();
        System.exit(0);
        return true;
      }
      else if ( evt.target == orderB ) {
        int factIndex = brandCH.getSelectedIndex();
        carFactory[factIndex].createCar ( modelTF.getText(), colorTF.getText() );
        updateAllCarsChoice ( ) ;
      }
      else if ( evt.target == sellB ) {
        int carIndex = allCarsCH.getSelectedIndex();
        cars[carIndex].sellTo ( buyerTF.getText() );
        appendTA ( "sold car: " + cars[carIndex].getSerialNr() + " to "
                   + buyerTF.getText() );
      }
      else if ( evt.target == wreckB ) {
        int carIndex = allCarsCH.getSelectedIndex();
        int factIndex = brandCH.getSelectedIndex();
        appendTA ( "wrecked car: " + cars[carIndex].getSerialNr() );
        carFactory[factIndex].deleteCar ( cars[carIndex] );
        updateAllCarsChoice ( ) ;
      }
      else if ( evt.target == brandCH ) {
        colorTF.setText ( "" );
        modelTF.setText ( "" );
        updateAllCarsChoice ( ) ;
      }
      else if ( evt.target == allCarsCH ) {
        int carIndex = allCarsCH.getSelectedIndex();
        colorTF.setText ( cars[carIndex].getColor() );
        modelTF.setText ( cars[carIndex].getModel() );
        buyerTF.setText ( cars[carIndex].getOwner() );
      }
    }
    catch ( java.rmi.RemoteException ex) {
      appendTA ( "action() RemoteException: " + ex.getMessage() );
    }
    catch ( java.sql.SQLException ex) {
      appendTA ( "action() SQLException: " + ex.getMessage() );
    }
    return true;
  }

  public boolean handleEvent ( Event evt ) { // deprecated by processEvent( )

    if ( evt.id == Event.WINDOW_DESTROY ) {
      setVisible ( false); // JDK1.1’s setVisible() replaced deprecated hide( )
      dispose();
      System.exit(0);
      return true;
    }
    else {
      return super.handleEvent ( evt );
    }
  }

  public static void main ( String args[] ) {

    // Create GUI-object
    CarSales cs = new CarSales();
  }
}
End example

CarSupplierServer.java

The CarSupplierServer class is the RMI server class. It creates three instances of CarFactory and binds them to the RMI Registry. A simple string names the bindings to enable clients to perform lookups in the Registry. Listing 12-16 shows the source code for CarSupplierServer.java.

Listing 12-16: CarSupplierServer.java
Start example
//
// CarSupplierServer.java
//
// (C) 1996 Wim De Munck mailto: wimdm@dm-mediaware.be
//
import java.rmi.Naming;

class CarSupplierServer {

  public static void main ( String args[] ) {

    // Install a SecurityManager for this server
    System.setSecurityManager( new java.rmi.RMISecurityManager() );
    // create and register all CarFactories
    System.out.println ( "Creating Car Factories" );
    CarFactoryImpl audi, bmw, vw ;
    try {
      audi = new CarFactoryImpl("Audi");
      bmw = new CarFactoryImpl("BMW");
      vw = new CarFactoryImpl("Volkswagen");
    } catch ( Exception ex ) {
      ex.printStackTrace();
      return;
    }
    System.out.println ( "Registering Car Factories" );
    try {
      Naming.bind("CarFactory.audi", audi);
      Naming.bind("CarFactory.bmw", bmw);
      Naming.bind("CarFactory.vw", vw);
    } catch ( java.net.MalformedURLException ex ) {
      ex.printStackTrace();
    } catch ( java.rmi.AlreadyBoundException ex ) {
      ex.printStackTrace();
    } catch ( java.rmi.RemoteException ex) {
      ex.printStackTrace();
    }
  }
}
End example

RMI, as defined and implemented by JavaSoft, Inc., is HTTP-proxy aware. The networking layer of RMI provides server- and client-side transparent support for HTTP tunneling that allows applets to communicate with remote methods and remote objects through WWW proxy servers.


Summary

This chapter provided complex examples using database metadata and RMI. The graphical database explorer provided a fun and convenient example of using metadata. A small multitiered application, the Car example, illustrated how JDBC can be used very simply in such cases.

The next chapter is a JDBC 3 API reference.


Part IV: JDBC API Quick Reference

Chapter List

JDBC Extension Reference


JDBC API Reference

This reference provides information about the JDBC 3 API. All JDBC 3–compliant drivers are required to support this API.

Note

The interfaces and classes in this reference are sorted alphabetically, as are the attributes and methods that they provide. Repeated method names indicate that several method signatures are available for the same purpose, each one supporting a different set of parameters. Those parameters and the return values are described as well in this reference.

Interface Array

public interface Array

The Array object is valid only during the transaction where it is used. It is a pointer to the data in the SQL ARRAY field; it doesn’t actually contain the array elements. There are methods available to access the elements of the array as either an array or a JDBC ResultSet object. By default, the elements are mapped using the standard mapping for data types, but you can provide a custom map to the methods getArray() and getResultSet().

Methods

getArray

public Object getArray() throws SQLException

This returns a Java array containing the values of the elements of the SQL ARRAY using the type map associated with the connection.

Returns: The array of values contained in the SQL ARRAY. A SQLException is thrown if the values cannot be accessed.

getArray

public Object getArray(java.util.Map map) throws SQLException

This returns a Java array containing the values of the elements of the SQL ARRAY using the type map passed as a parameter. If no user-defined type is defined for the array’s base type, the standard mapping is used.

Parameters:

map:

A java.util.Map object containing mappings of SQL type names to Java classes

Returns: A Java array containing the ordered elements of the SQL array designated by this object. A SQLException is thrown if the values cannot be accessed.

getArray

public Object getArray(long index, int count) throws SQLException

This returns a Java array containing the values of the subset of elements of the SQL ARRAY determined by the index and element count parameters using the type map associated with the connection.

Parameters:

index: | The index of the first element to return begins at 1.
count: | The number of elements of the SQL array elements to return.

Returns: An array containing count elements of the SQL array, starting at element index. A SQLException is thrown if the values cannot be accessed.

getArray

public Object getArray(long index, int count,
java.util.Map map) throws SQLException

This returns a Java array containing the values of the subset of elements of the SQL ARRAY determined by the index and element count parameters using the type map passed as a parameter. If no user-defined type is defined for the array’s base type, the standard mapping is used.

Parameters:

index: | The index of the first element to return begins at 1.
count: | The number of elements of the SQL array elements to return.
map: | A java.util.Map object containing mappings of SQL type names to Java classes.

Returns: An array containing count elements of the SQL array, starting at element index. A SQLException is thrown if the values cannot be accessed.

getBaseType

public int getBaseType() throws SQLException

This gets the JDBC type of the elements in the array.

Returns: A java.sql.Types constant. A SQLException is thrown if the type name cannot be returned.

getBaseTypeName

public String getBaseTypeName() throws SQLException

This gets the type name of the elements in the array. These elements can be of a specific database type or a user-defined type. When a user-defined type is used, the method returns the SQL type name for the elements in the array.

Returns: The database-specific name for a built-in base type or the fully qualified SQL type name for a user-defined type. A SQLException is thrown if the type name cannot be returned.

getResultSet

public ResultSet getResultSet() throws SQLException

This returns a ResultSet object containing the values of the elements of the SQL ARRAY using the type map associated with the connection. Each row of the ResultSet contains the index of the array element as the first column and the value of the element as the second column.

Returns: A ResultSet object containing a row for each element in the array. A SQLException is thrown if the values cannot be accessed.

getResultSet

public ResultSet getResultSet(java.util.Map map) throws SQLException

This returns a ResultSet object containing the values of the elements of the SQL ARRAY using the type map passed as a parameter. If no user-defined type is defined for the array’s base type, the standard mapping is used. Each row of the ResultSet contains the index of the array element as the first column and the value of the element as the second column.

Parameters:

map:

A java.util.Map object containing mappings of SQL type names to Java classes

Returns: A ResultSet object containing a row for each element in the array. A SQLException is thrown if the values cannot be accessed.

getResultSet

public ResultSet getResultSet(long index, int count) throws SQLException

This returns a ResultSet object containing the values of the subset of elements of the SQL ARRAY determined by the index and element count parameters using the type map associated with the connection. Each row of the ResultSet contains the index of the array element as the first column and the value of the element as the second column.

Parameters:

index: | The index of the first element to return begins at 1.
count: | The number of elements of the SQL array elements to return.

Returns: A ResultSet containing count elements of the SQL array, starting at element index. A SQLException is thrown if the values cannot be accessed.

getResultSet

public ResultSet getResultSet(long index, int count,
java.util.Map map) throws SQLException

This returns a ResultSet object containing the values of the subset of elements of the SQL ARRAY determined by the index and element count parameters using the type map passed as a parameter. If no user-defined type is defined for the array’s base type, the standard mapping is used. Each row of the ResultSet contains the index of the array element as the first column and the value of the element as the second column.

Parameters:

index: | The index of the first element to return begins at 1.
count: | The number of elements of the SQL array elements to return.
map: | A java.util.Map object containing mappings of SQL type names to Java classes.

Returns: A ResultSet containing count elements of the SQL array, starting at element index. A SQLException is thrown if the values cannot be accessed.


Class BatchUpdateException

public class BatchUpdateException
extends SQLException

A BatchUpdateException is a SQLException that is thrown when an error occurs during a batch update. An update count that represents the number of successful updates per batch element is provided. You can set the update count to EXECUTE_FAILED in case the update failed; the driver may or may not continue to process the batch update elements. Updates are performed in the same order that they were added to the batch update.

Constructors

BatchUpdateException

public BatchUpdateException(String reason, String SQLState,
int vendorCode, int[] updateCounts)

This builds a BatchUpdateException object.

Parameters:

reason: | The exception message
SQLState: | The X/OPEN code identifying the error
vendorCode: | The database vendor specific exception
updateCounts: | An array of update counts for each element of this batch

BatchUpdateException

public BatchUpdateException(String reason, String SQLState,
int[] updateCounts)

This builds a BatchUpdateException object with a 0 vendor error code.

Parameters:

reason: | The exception message
SQLState: | The X/OPEN code identifying the error
updateCounts: | An array of update counts for each element of this batch

BatchUpdateException

public BatchUpdateException(String reason, int[] updateCounts)

This builds a BatchUpdateException object with a 0 vendor error code and SQLState.

Parameters:

reason: | The exception message
updateCounts: | An array of update counts for each element of this batch

BatchUpdateException

public BatchUpdateException(int[] updateCounts)

This builds a BatchUpdateException object with a 0 vendor error code and SQLState and a null exception reason message.

Parameters:

updateCounts:

An array of update counts for each element of this batch

BatchUpdateException

public BatchUpdateException()

This builds a BatchUpdateException object with a 0 vendor error code and SQLState and a null exception reason message and update count array.

Methods

getUpdateCounts

public int[] getUpdateCounts()

The array returned by this method contains the update counts for this batch. When this exception is thrown, a failure occurs, and the current count is set to EXECUTE_FAILED. The driver may or may not continue processing the other update statements in the batch.

Returns: An array of int containing the update counts for the updates that were executed successfully before this exception was thrown. The elements of the array can be as follows:

  • The update count

  • SUCESS_NO_INFO if the number of rows affected by the update isn’t known and no error occurred

  • EXECUTE_FAILED if an error occurred


Interface Blob

public interface Blob

A Blob object is a pointer to a binary large object (BLOB) value in a table column. It is valid only during the transaction in which it was created. The corresponding SQL type is SQL BLOB.

Methods

getBinaryStream

public java.io.InputStream getBinaryStream() throws SQLException

This gets the BLOB’S content as an input stream.

Returns: A stream containing the BLOB data. A SQLException is thrown if an error occurs while accessing this data.

getBytes

public byte[] getBytes(long pos, int length) throws SQLException

This gets a part of the BLOB’S content as an array of bytes. A starting point and length are provided as parameters.

Parameters:

pos: | The first byte in the BLOB value to be returned begins at 1.
length: | The number of bytes to be returned in the array.

Returns: A byte array containing up to length bytes from the BLOB, starting at position pos. A SQLException is thrown if an error occurs while accessing this value.

length

public long length() throws SQLException

This gets the number of bytes in the BLOB value referenced by the Blob object.

Returns: The length of the BLOB in bytes. A SQLException is thrown if an error occurs while accessing this value.

position

public long position(byte[] pattern, long start) throws SQLException

This searches for a position within the BLOB’S bytes using an array of bytes as a pattern. A starting point is provided. No wildcards bytes are available.

Parameters:

pattern: | The byte array containing the bytes to search in the BLOB.
start: | The start position; the first byte is at position 1.

Returns: The position at which the pattern appears or -1 if the pattern isn’t found. A SQLException is thrown if an error occurs while accessing this value.

position

public long position(Blob pattern, long start) throws SQLException

This searches for a position within the BLOB’S bytes using another BLOB as a pattern. A starting point is provided. No wildcards are available.

Parameters:

pattern: | The BLOB containing the bytes to search in the current BLOB.
start: | The start position; the first byte is at position 1.

Returns: The position at which the pattern appears or -1 if the pattern isn’t found. A SQLException is thrown if an error occurs while accessing this value.

setBinaryStream

public java.io.OutputStream setBinaryStream(long pos) throws SQLException

This returns an output stream that can be used to write any number of bytes to the BLOB at position pos.

Parameters:

pos:

The position in the BLOB object at which to start writing

Returns: The output stream to which data can be written. A SQLException is thrown if an error occurs while accessing this value.

setBytes

public int setBytes(long pos, byte[] bytes) throws SQLException

This writes an array of bytes to the BLOB starting at position pos.

Parameters:

pos: | The position in the BLOB object at which to start writing
bytes: | The array of bytes to be written to the BLOB object

Returns: The number of bytes written to the BLOB object. A SQLException is thrown if an error occurs while accessing this value.

setBytes

public int setBytes(long pos, byte[] bytes, int offset, int len)
throws SQLException

This writes a subarray of bytes to the BLOB starting at position pos. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

pos: | The position in the BLOB object at which to start writing
bytes: | The array of bytes to be written to the BLOB object
offset: | The offset into the array bytes to start reading the bytes to be set
len: | The number of bytes to be written to the BLOB object

Returns: The number of bytes written to the BLOB object. A SQLException is thrown if an error occurs while accessing this value.

truncate

public void truncate(long len) throws SQLException

This method is used to truncate the current BLOB to length len. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

len:

The length, in bytes, to which the current BLOB must be truncated


Interface CallableStatement

public interface CallableStatement
extends Object
extends PreparedStatement

Callable statements are used to call SQL stored procedures in a standard way for all DBMSs. Escape syntax is used for procedures that return a result parameter and those that don’t return a parameter. If the procedure returns a result, the result parameter must be registered as an OUT parameter.

The set methods inherited from PreparedStatement are used to set IN parameter values. The type of all OUT parameters must be registered prior to executing the stored procedure. Their values are retrieved via the get methods provided in this section.

A Callable statement can return a ResultSet or multiple ResultSets. Multiple ResultSets are handled using methods inherited from Statement. The OUT param-eters must always be retrieved after processing ResultSets and update counts, if any.

The following shows the JDBC format of SQL queries that call a stored procedure:

{?= call <PROCEDURE-NAME>[<ARG1>,<ARG2> , ...]}
{call <PROCEDURE-NAME>[<ARG1>,<ARG2> , ...]}

See also: prepareCall, ResultSet

Methods

getArray

public Array getArray(int parameterIndex) throws SQLException

This gets the value of a JDBC ARRAY parameter as an Array object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The parameter value as an Array object

getBigDecimal

public BigDecimal getBigDecimal(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL NUMERIC as a java.math.BigDecimal object, with as many decimal digits as the parameter value contains.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if its value is SQL NULL

getBigDecimal

public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException

This gets the value of an OUT parameter of type SQL NUMERIC as a java.math.BigDecimal object.

Parameters:

parameterIndex: | The parameter index begins at 1.
scale: | A positive value representing the decimal precision.

Returns: The OUT parameter value; null if its value is SQL NULL

getBlob

public Blob getBlob(int parameterIndex) throws SQLException

This gets the value of a JDBC BLOB parameter as a Blob object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The parameter value as a Blob object

getBoolean

public boolean getBoolean(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL BIT as a Java boolean.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; false if the value is SQL NULL

getByte

public byte getByte(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL TINYINT as a Java byte.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getBytes

public byte[] getBytes(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL BINARY or VARBINARY as a Java byte[].

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if the value is SQL NULL

getClob

public Clob getClob(int parameterIndex) throws SQLException

This gets the value of a JDBC CLOB parameter as a Clob object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The parameter value as a Clob object

getDate

public Date getDate(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL DATE as a java.sql.Date object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if the value is SQL NULL

getDouble

public double getDouble(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL DOUBLE as a Java double.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getFloat

public float getFloat(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL FLOAT as a Java float.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getInt

public int getInt(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL INTEGER as a Java int.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getLong

public long getLong(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL BIGINT as a Java long.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getObject

public Object getObject(int parameterIndex) throws SQLException

This gets the value of an OUT parameter as a Java object.

The object type corresponds to the SQL type that was registered for this param-eter using registerOutParameter().

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: An Object containing the OUT parameter value

See also: Types

getObject

public Object getObject(int parameterIndex, java.util.Map map) throws SQLException

This gets the value of an OUT parameter as a Java object using a map for custom mapping.

The object type corresponds to the SQL type that was registered for this param-eter using registerOutParameter().

Parameters:

parameterIndex: | The parameter index begins at 1.
map: | The mapping from SQL type names to Java classes.

Returns: An Object containing the OUT parameter value

See also: Types

getRef

public Ref getRef(int parameterIndex) throws SQLException

This gets the value of a JDBC REF parameter as a Ref object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The parameter value as a Ref object or null if the value is SQL NULL

getShort

public short getShort(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL SMALLINT as a Java short.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; 0 if the value is SQL NULL

getString

public String getString(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL CHAR, VARCHAR, or LONGVARCHAR as a Java String.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if the value is SQL NULL

getTime

public Time getTime(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL TIME as a java.sql.Time object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if the value is SQL NULL

getTimestamp

public Timestamp getTimestamp(int parameterIndex) throws SQLException

This gets the value of an OUT parameter of type SQL TIMESTAMP as a java.sql. Timestamp object.

Parameters:

parameterIndex:

The parameter index begins at 1.

Returns: The OUT parameter value; null if the value is SQL NULL

getURL

public java.net.URL getURL(int parameterIndex) throws SQLException,
java.net.MalformedURLException

This gets the value of a DATALINK parameter as a java.net.URL object.

Parameters:

parameterIndex:

The parameter index begins at 1.

registerOutParameter

public void registerOutParameter(int parameterIndex,
int sqlType) throws SQLException

The registerOutParameter() method must be called before executing a stored procedure to register the java.sql.Type of each OUT parameter. This type is used to retrieve the OUT parameter value with the appropriate getXXX() method.

Parameters:

parameterIndex: | The parameter index begins at 1.
sqlType: | The SQL type code defined by java.sql.Types.

See also: Type

registerOutParameter

public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException

This registerOutParameter() method is used for registering Numeric or Decimal OUT parameters.

Parameters:

parameterIndex: | The parameter index begins at 1.
sqlType: | java.sql.Type.NUMERIC or java.sql.Type. DECIMAL.
scale: | A positive value representing the desired number of decimal digits.

See also: Numeric, Type

registerOutParameter

public void registerOutParameter(int parameterIndex, int sqlType,
String typeName) throws SQLException

This registerOutParameter() method is used for registering REF parameters.

Parameters:

parameterIndex: | The parameter index begins at 1.
sqlType: | A value from Types.
typeName: | The fully qualified name of a SQL structured type.

setArray

public void setArray(String parameterName, Array x) throws SQLException

This sets the parameter to the given Array object.

Parameters:

parameterName: | The name of the parameter
x: | The Array object that maps a SQL ARRAY value

setAsciiStream

public void setAsciiStream(String parameterName, InputStream x, int length)
throws SQLException

setAsciiStream() is used to set very large LONGVARCHAR parameters. You can send the ASCII data using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file). ASCII characters are converted to the database CHAR format.

Parameters:

parameterName: | The name of the parameter
x: | The ASCII data stream
length: | The data length in bytes

setBigDecimal

public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException

This supplies a java.math.BigDecimal value that will be converted to a SQL NUMERIC value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setBinaryStream

public void setBinaryStream(String parameterName, InputStream x, int length)
throws SQLException

setBinaryStream() is used to set very large LONGVARBINARY parameters. You can send the binary data using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file).

Parameters:

parameterName: | The name of the parameter
x: | The binary data stream
length: | The data length in bytes

setBlob

public void setBlob(String parameterName, Blob x) throws SQLException

This sets the parameter to the given Blob object.

Parameters:

parameterName: | The name of the parameter
x: | A Blob object that maps a SQL BLOB value

setBoolean

public void setBoolean(String parameterName, boolean x) throws SQLException

This supplies a Java boolean value that is converted to a SQL BIT value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setByte

public void setByte(String parameterName, byte x) throws SQLException

This supplies a Java byte value that is converted to a SQL TINYINT value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setBytes

public void setBytes(String parameterName, byte x[]) throws SQLException

This supplies a Java array of bytes that is converted to a SQL VARBINARY or LONGVARBINARY when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setCharacterStream

public void setCharacterStream(String parameterName, java.io.Reader reader,
int length) throws SQLException

This sets a Unicode character stream to the designated parameter.

Parameters:

parameterName: | The name of the parameter
reader: | The java.io.Reader object containing the Unicode data
length: | The number of characters in the stream

setClob

public void setClob(String parameterName, Clob x) throws SQLException

This sets the parameter to the given Clob object.

Parameters:

parameterName: | The name of the parameter
x: | The Clob object that maps a SQL CLOB value

setDate

public void setDate(String parameterName, Date x) throws SQLException

This supplies a java.sql.Date value that is converted to a SQL DATE value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setDate

public void setDate(String parameterName, Date x, java.util.Calendar cal)
throws SQLException

This supplies a java.sql.Date value that is converted to a SQL DATE value when sent to the database using the calendar provided as parameter.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value
cal: | The Calendar object that the driver will use to construct the date

setDouble

public void setDouble(String parameterName, double x) throws SQLException

This supplies a Java double value that is converted to a SQL DOUBLE value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setFloat

public void setFloat(String parameterName, float x) throws SQLException

This supplies a Java float value that is converted to a SQL FLOAT value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setInt

public void setInt(String parameterName, int x) throws SQLException

This supplies a Java int value that is converted to a SQL INTEGER value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setLong

public void setLong(String parameterName, long x) throws SQLException

This supplies a Java long value that is converted to a SQL BIGINT value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setNull

public void setNull(String parameterName, int sqlType) throws SQLException

This supplies a SQL NULL value. The parameter’s SQL type must be supplied.

Parameters:

parameterName: | The name of the parameter
sqlType: | A SQL type code (see java.sql.Types)

setNull

public void setNull(int paramIndex, int sqlType, String typeName)
throws SQLException

This supplies a SQL NULL value. The parameter’s SQL type must be supplied as well as the fully qualified SQL Type name for greater portability.

Parameters:

paramIndex: | The parameter index begins at 1.
sqlType: | A value from java.sql.Types.
typeName: | The fully qualified name of a SQL user-defined type. It is ignored if the parameter isn’t a user-defined type or REF type.

setObject

public void setObject(String parameterName, Object x,int targetSqlType,  int scale) throws SQLException

This supplies a parameter value using an object that is converted to the targetSqlType when sent to the database. Data types may be passed using a driver-specific Java type and using java.sql.types.OTHER as targetSqlType.

Parameters:

parameterName: | The name of the parameter.
x: | The object containing the input parameter value.
targetSqlType: | A SQL type code (see java.sql.Types).
scale: | The number of digits after the decimal for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types. This is ignored for other types.

See also: Types

setObject

public void setObject(String parameterName, Object x, int targetSqlType)
throws SQLException

This enables you to use an object as a parameter value and to specify a target SQL type.

Parameters:

parameterName: | The name of the parameter
x: | The object containing the input parameter value
targetSqlType: | The SQL type to which this object must be converted

setObject

public void setObject(String parameterName, Object x) throws SQLException

This enables you to use an object as a parameter value but uses the standard mapping from Java object types to SQL types.

Parameters:

parameterName: | The name of the parameter
x: | The object containing the input parameter value

setRef

public void setRef(String parameterName, Ref x) throws SQLException

This sets the parameter to the given REF value.

Parameters:

parameterName: | The name of the parameter
x: | A SQL REF value

setShort

public void setShort(String parameterName, short x) throws SQLException

This supplies a Java short value that is converted to a SQL SMALLINT value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setString

public void setString(String parameterName, String x) throws SQLException

This supplies a Java String value that is converted to a SQL VARCHAR or LONGVARCHAR value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setTime

public void setTime(String parameterName, Time x) throws SQLException

This supplies a java.sql.Time value that is converted to a SQL TIME value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setTime

public void setTime(String parameterName, Time x, java.util.Calendar cal)
throws SQLException

This supplies a java.sql.Time value that is converted to a SQL TIME value when sent to the database using the Calendar object provided as a parameter.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value
cal: | The Calendar object that the driver will use to construct the time

setTimestamp

public void setTimestamp(String parameterName, Timestamp x) throws SQLException

This supplies a java.sql.Timestamp value that is converted to a SQL TIMESTAMP value when sent to the database.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value

setTimestamp

public void setTimestamp(String parameterName, Timestamp x,
java.util.Calendar cal) throws SQLException

This supplies a java.sql.Timestamp value that is converted to a SQL TIMESTAMP value when sent to the database using the Calendar object provided as a parameter.

Parameters:

parameterName: | The name of the parameter
x: | The parameter value
cal: | The Calendar object that the driver will use to construct the timestamp

setUnicodeStream

public void setUnicodeStream(String parameterName, InputStream x,int length)
throws SQLException

setUnicodeStream() is used to set very large LONGVARCHAR parameters. The Unicode data may be sent using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file). Unicode characters are converted to the database CHAR format.

Parameters:

parameterName: | The name of the parameter
x: | The Unicode data stream
length: | The data length in bytes

setURL

public void setURL(String parameterName, java.net.URL x) throws SQLException

This sets the parameter to a java.net.URL value. This value is converted to a SQL DATALINK when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

wasNull

public boolean wasNull() throws SQLException

This method reports whether the last value read was a SQL NULL. A getXXX() must be invoked first.

Returns: true if the last parameter read was SQL NULL


Interface Clob

public interface Clob

A Clob object is a pointer to a character large object (CLOB) value in a table column. It is valid only during the transaction in which it was created. The corresponding SQL type is SQL CLOB.

Methods

getAsciiStream

public java.io.InputStream getAsciiStream() throws SQLException

This gets the CLOB’s content as a stream of ASCII bytes.

Returns: A stream containing the CLOB data. A SQLException is thrown if an error occurs while accessing this value.

getCharacterStream

public java.io.Reader getCharacterStream() throws SQLException

This gets the CLOB’s content as a Unicode character stream.

Returns: A Unicode character stream containing the CLOB data. A SQLException is thrown if an error occurs while accessing this value.

getSubString

public String getSubString(long pos, int length) throws SQLException

This gets a string of characters beginning at pos, containing length characters, from the original CLOB characters.

Parameters:

pos: | The index of the first character to return. The first character of the Clob object is at position 1.
length: | The number of characters to be copied from the Clob object.

Returns: A String that is the substring delimited by pos and length. A SQLException is thrown if an error occurs while accessing this value.

length

public long length() throws SQLException

This gets the number of characters in the CLOB value referenced by this Clob object.

Returns: The length of the CLOB in characters. A SQLException is thrown if an error occurs while accessing this value.

position

public long position(String searchstr, long start) throws SQLException

This searches for a position within the CLOB’s characters using a String as pattern. A starting point is provided. No wildcards are available.

Parameters:

searchstr: | The string to search in the CLOB.
start: | The start position; the first character is at position 1.

Returns: The position at which the pattern appears or -1 if the pattern isn’t found. A SQLException is thrown if an error occurs while accessing this value.

position

public long position(Clob searchstr, long start) throws SQLException

This searches for a position within the CLOB’s characters using another CLOB as a pattern. A starting point is provided. No wildcards are available.

Parameters:

searchstr: | The CLOB containing the characters to search in the current CLOB.
start: | The start position; the first byte is at position 1.

Returns: The position at which the pattern appears or -1 if the pattern isn’t found. A SQLException is thrown if an error occurs while accessing this value.

setAsciiStream

public java.io.OutputStream setAsciiStream(long pos) throws SQLException

This returns an output stream that can be used to write any number of ASCII characters to this CLOB at position pos.

Parameters:

pos:

The position in this CLOB object at which to start writing

Returns: The output stream to which data can be written. A SQLException is thrown if an error occurs while accessing this value.

setCharacterStream

public java.io.Writer setCharacterStream(long pos) throws SQLException

This returns an output stream that can be used to write a stream of Unicode characters to this CLOB at position pos.

Parameters:

pos:

The position in this CLOB object at which to start writing

Returns: The output stream to which data can be written. A SQLException is thrown if an error occurs while accessing this value.

setString

public int setString(long pos, String str) throws SQLException

This updates the CLOB’s characters using the string provided as a parameter. The characters are updated beginning at pos in the CLOB.

Parameters:

pos: | The position in the Clob object at which to start writing
str: | The string to be written to this Clob object

Returns: The number of bytes written to the clob object. A SQLException is thrown if an error occurs while accessing this value.

setString

public int setString(long pos, String str, int offset, int len)
throws SQLException

This writes len characters of str, starting at position pos. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

pos: | The position in the BLOB object at which to start writing
str: | The string to be written to the CLOB object
offset: | The offset into str to start reading the characters to be set
len: | The number of characters to be written to this CLOB object

Returns: The number of bytes written to the CLOB object. A SQLException is thrown if an error occurs while accessing this value.

truncate

public void truncate(long len) throws SQLException

This method is used to truncate the current CLOB to length len. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

len:

The length, in bytes, to which the current BLOB must be truncated


Interface Connection

public interface Connection
extends Object

A Connection is a session in a specific database engine. SQL statements and their results are executed within the context of such a Connection.

You can obtain information such as database tables, stored procedures, and other database objects from a Connection with the getMetaData methods.

All changes are committed after the execution of a statement. This is the default behavior. If autocommit has been disabled, an explicit commit must be done, or database changes won’t be effective.

See also: getConnection, Statement, ResultSet, DatabaseMetaData

Fields

TRANSACTION_NONE

public static final int TRANSACTION_NONE

This constant value specifies that transactions aren’t supported.

TRANSACTION_READ_COMMITTED

public static final int TRANSACTION_READ_COMMITTED

This constant value specifies that only reads on the current row are repeatable. Dirty reads aren’t allowed, but nonrepeatable and phantom reads can occur.

TRANSACTION_READ_UNCOMMITTED

public static final int TRANSACTION_READ_UNCOMMITTED

This constant value specifies that dirty reads, nonrepeatable reads, and phantom reads can occur.

TRANSACTION_REPEATABLE_READ

public static final int TRANSACTION_REPEATABLE_READ

This constant value specifies that only phantom reads can occur.

TRANSACTION_SERIALIZABLE

public static final int TRANSACTION_SERIALIZABLE

This constant value specifies that dirty reads, nonrepeatable reads, and phantom reads cannot occur.

Methods

clearWarnings

public void clearWarnings() throws SQLException

This clears the chained warnings of a Connection. getWarnings() returns null until a new warning is reported.

close

public void close() throws SQLException

The close method provides an immediate release for a Connection. All its resources are released upon invocation, including resources maintained by the DBMS and the JDBC driver. Note that a Connection is automatically closed when it is garbage-collected.

commit

public void commit() throws SQLException

This method is used to commit transactions. All changes made since the previous commit() or rollback() are made permanent, and any database locks currently held by the Connection are released. Note that all PreparedStatements, CallableStatements, and ResultSets are implicitly closed when a Connection is committed.

See also: setAutoClose, setAutoCommit

createStatement

public Statement createStatement() throws SQLException

This method creates a Statement object used to execute SQL statements without parameters. Unlike PreparedStatement, this method is used for Statements that are executed only once.

Returns: A new Statement object

createStatement

public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException

This method creates a Statement object that generates ResultSet objects with the given type and concurrency.

Parameters:

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

Returns: The newly created Statement object

createStatement

public Statement createStatement(int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException

This method creates a Statement object that generates ResultSet objects with the given type and concurrency.

Parameters:

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

resultSetHoldability:

One of the following cursor holdabilities:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

Returns: The newly created Statement object

getAutoClose

public boolean getAutoClose() throws SQLException

This checks whether the Connection’s state is autoclose.

Returns: The current state of autoclose mode

See also: setAutoClose

getAutoCommit

public boolean getAutoCommit() throws SQLException

This checks whether the Connection’s state is autocommit.

Returns: The current state of autocommit mode

See also: setAutoCommit

getCatalog

public String getCatalog() throws SQLException

If catalogs are supported, this method returns the Connection’s current catalog name.

Returns: The current catalog name or null

getHoldability

public int getHoldability() throws SQLException

This gets the current holdability of ResultSet objects for this connection.

Returns: The holdability, which is one of the following:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

getMetaData

public DatabaseMetaData getMetaData() throws SQLException

You can use the DatabaseMetaData object returned by this method to get information from the database engine. Such information includes a description of tables, stored procedures, keys and indexes, the supported SQL grammar, and so on. Refer to the DatabaseMetaData interface for more detail.

Returns: A DatabaseMetaData object

getTransactionIsolation

public int getTransactionIsolation() throws SQLException

This returns the current transaction isolation mode. The different values are those listed as TRANSACTION_XXX static variables.

Returns: The current transaction mode value

getTypeMap

public java.util.Map getTypeMap() throws SQLException

This gets the type map object for this connection.

Returns: The java.util.Map object associated with this connection

getWarnings

public SQLWarning getWarnings() throws SQLException

Warnings issued by calls on a Connection are chained together. This method returns the first warning that is reported as a SQLWarning.

Returns: The first SQLWarning or null

isClosed

public boolean isClosed() throws SQLException

This checks whether a connection has been closed.

Returns: true if the connection is closed or false if it’s still open

isReadOnly

public boolean isReadOnly() throws SQLException

This checks whether the Connection is in read-only mode.

Returns: true if Connection is read-only

nativeSQL

public String nativeSQL(String sql) throws SQLException

Under some circumstances, specific JDBC drivers may translate the SQL statements into a database’s native SQL grammar prior to sending them. This method is useful to obtain the native form of the statement that the driver would have sent.

Parameters:

sql:

A SQL statement. Note that it may contain ? parameter placeholders.

Returns: The native form of the statement

prepareCall

public CallableStatement prepareCall(String sql) throws SQLException

CallableStatements are used for stored procedure call statements. This method creates such an object that can be used later with appropriate methods to provide IN and OUT parameters to the stored procedure.

Parameters:

sql:

A SQL statement. Note that it may contain ? parameter placeholders.

Returns: A new CallableStatement object containing the precompiled SQL statement

prepareCall

public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException

CallableStatements are used for stored procedure call statements. This method creates such an object that can be used later with appropriate methods to provide IN and OUT parameters to the stored procedure.

Parameters:

sql:

The SQL string containing parameter marks

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

Returns: The newly created CallableStatement

prepareCall

public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException

CallableStatements are used for stored procedure call statements. This method creates such an object that can be used later with appropriate methods to provide IN and OUT parameters to the stored procedure.

Parameters:

sql:

The SQL string containing parameter marks

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

resultSetHoldability:

One of the following cursor holdabilities:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

Returns: The newly created CallableStatement

prepareStatement

public PreparedStatement prepareStatement(String sql) throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql:

A SQL statement. Note that it is normally used with ? IN parameter placeholders.

Returns: The newly created PreparedStatement object

prepareStatement

public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql: | A SQL statement. Note that it is normally used with ? IN parameter placeholders.
columnIndexes: | An array containing the column numbers returned by the statement in case of an update.

Returns: The newly created PreparedStatement object

prepareStatement

public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql: | A SQL statement. Note that it is normally used with ? IN parameter placeholders.
columnNames: | An array containing the column names returned by the

statement in case of an update.

Returns: The newly created PreparedStatement object

prepareStatement

public PreparedStatement prepareStatement(String sql, int flag)
throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql:

A SQL statement. Note that it is normally used with ‘?’ IN parameter placeholders.

flag:

One of the following flags, which indicate whether auto-generated keys should be returned:

  • Statement.RETURN_GENERATED_KEYS

  • Statement.NO_GENERATED_KEYS

Returns: The newly created PreparedStatement object

prepareStatement

public PreparedStatement prepareStatement(String sql,
int resultSetType, int resultSetConcurrency) throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql:

The SQL string containing IN parameters represented by ?

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

Returns: The newly created PreparedStatement

prepareStatement

public PreparedStatement prepareStatement(String sql,
int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException

This method returns a PreparedStatement object. Such objects are useful when a SQL statement must be executed multiple times. The SQL statement is precompiled before it actually receives parameters and is executed. If supported by the driver and by the DBMS, parsing and optimizations are performed only once during precompilation.

Parameters:

sql:

The SQL string containing IN parameters represented by ?

resultSetType:

One of the following result set types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

resultSetConcurrency:

One of the following concurrency types:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

resultSetHoldability:

One of the following cursor holdabilities:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

Returns: The newly created PreparedStatement

releaseSavepoint

public void releaseSavepoint(Savepoint savepoint) throws SQLException

This deletes a savepoint from the current transaction.Parameters:

Parameters:

savepoint:

The savepoint to be removed

rollback

public void rollback() throws SQLException

Unlike commit(), rollback() cancels all changes made since the previous commit() or rollback() invocation and releases any database locks currently held by the Connection. This method is used to abort transactions. Note that a Connection’s PreparedStatements, CallableStatements, and ResultSets are implicitly closed when it is rolled back.

See also: setAutoClose, setAutoCommit

rollback

public void rollback(Savepoint savepoint) throws SQLException

This cancels all the changes that were made after the savepoint was set.

Parameters:

savepoint:

The savepoint to roll back to

setAutoClose

public void setAutoClose(boolean autoClose) throws SQLException

When autoclose is disabled, JDBC attempts to keep all Statements and ResultSets open across commits and rollbacks.

Parameters:

autoClose:

true enables autoclose; false disables autoclose.

See also: supportsOpenCursorsAcrossCommit, supportsOpenCursorsAcrossRollback, supportsOpenStatementsAcrossCommit, supportsOpenStatementsAcrossRollback

setAutoCommit

public void setAutoCommit(boolean autoCommit) throws SQLException

SQL statements are executed and committed as individual transactions if a Connection is in autocommit mode. If not in autocommit mode, the SQL statements are grouped into transactions that are terminated by either commit() or rollback(). By default, new connections are in autocommit mode. In autocommit mode, a commit always occurs after all results and output parameter values for a specific statement have been retrieved.

Parameters:

autoCommit:

true enables autocommit; false disables it.

setCatalog

public void setCatalog(String catalog) throws SQLException

If the database supports catalogs, this method selects a specific catalog. The method has no effect if catalogs aren’t supported.

setHoldability

public void setHoldability(int holdability) throws SQLException

This changes the holdability of ResultSet objects for the connection.

Parameters:

holdability:

One of the following values:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

setReadOnly

public void setReadOnly(boolean readOnly) throws SQLException

This sets connections in read-only mode. In this case, no database updates are allowed, and performance is often improved. Note that this method cannot be called while in the middle of a transaction.

Parameters:

readOnly:

true enables read-only mode; false disables read-only mode.

setSavepoint

public Savepoint setSavepoint() throws SQLException

This sets an unnamed savepoint. The savepoint will be automatically numbered.

Returns: The savepoint

setSavepoint

public Savepoint setSavepoint(String name) throws SQLException

This sets a named savepoint.

Parameters:

name:

The name of the savepoint

Returns: The savepoint

setTransactionIsolation

public void setTransactionIsolation(int level) throws SQLException

This method is used to change the transaction isolation level using the TRANSACTION_ XXX static variables defined in the beginning of this section. Note that it cannot be called while in the middle of a transaction.

Parameters:

level:

A TRANSACTION_XXX isolation value with the exception of TRANSACTION_NONE

See also: supportsTransactionIsolationLevel

setTypeMap

public void setTypeMap(java.util.Map map) throws SQLException

This sets the type map as the type map for the connection for the custom mapping of SQL structured types and distinct types.

Parameters:

map:

The java.util.Map object to install for the connection


Class DataTruncation

public class DataTruncation
extends SQLWarning

If JDBC unexpectedly truncates a data value during a write, a DataTruncation exception is thrown. If this occurs during a read, a DataTruncation warning is created. The SQLstate value is set to 01004 for a DataTruncation.

Constructors

DataTruncation

public DataTruncation(int index, boolean parameter, boolean read, int dataSize,
int transferSize)

This constructs a DataTruncation object with 01004 as SQLState and Data truncation as reason.

Parameters:

index: | The index of the parameter or column value for which a truncation occurred
parameter: | true if the truncation occurred when accessing a parameter
read: | true if the truncation occurred during a database read
dataSize: | The size of the data before being truncated
transferSize: | The size after truncation

Methods

getDataSize

public int getDataSize()

This gets the original data length in bytes.

Returns: The DataTruncation’s dataSize value or -1 if unknown

getIndex

public int getIndex()

This gets the index of the column or the parameter that was truncated.

Returns: The DataTruncation’s index value or -1 if unknown

getParameter

public boolean getParameter()

This checks whether the truncation occurred when reading or writing a parameter’s value.

Returns: true if the truncated value was a parameter or false if it was a column

getRead

public boolean getRead()

This checks whether the truncation occurred when reading a parameter or a column.

Returns: true if the value was truncated during a database read or false if the truncation occurred during a database write

getTransferSize

public int getTransferSize()

This gets the number of bytes of data transferred.

Returns: The number of bytes of data transferred or -1 if unknown


Interface DatabaseMetaData

public interface DatabaseMetaData
extends Object

The DatabaseMetaData interface provides methods that return information about the database.

A part of its methods returns ResultSets. Normal ResultSet methods such as getString() and getInt() must be used to retrieve the data from these ResultSets. A SQLException is thrown if a given form of metadata isn’t available.

The methods that take String pattern arguments return information using these patterns. Within a pattern String, % means match any substring of 0 or more characters, and _ means match any one character. The various methods that use patterns return only metadata entries matching the search pattern. A search criterion is suppressed if its pattern is set to null.

If a driver doesn’t support a metadata method, an exception is thrown. If such a method normally returns a ResultSet, a ResultSet (which may be empty) is returned or a SQLException is thrown.

Fields

The following fields are static integer values provided by the DatabaseMetaData interface. They are used by several database metadata methods that return result sets, under the columns named in uppercase in the following descriptions.

bestRowNotPseudo

public static final int bestRowNotPseudo

BEST ROW PSEUDO_COLUMN:

If bestRowNotPseudo is in this column, it indicates that the best row identifier isn’t a pseudocolumn.

bestRowPseudo

public static final int bestRowPseudo

BEST ROW PSEUDO_COLUMN:

If bestRowPseudo is in this column, it is a pseudocolumn.

bestRowSession

public static final int bestRowSession

BEST ROW SCOPE:

It is valid for the remainder of the current session.

bestRowTemporary

public static final int bestRowTemporary

BEST ROW SCOPE:

Very temporary, while using row

bestRowTransaction

public static final int bestRowTransaction

BEST ROW SCOPE:

It is valid for the remainder of the current transaction.

bestRowUnknown

public static final int bestRowUnknown

BEST ROW PSEUDO_COLUMN:

The driver is unable to indicate whether or not this is a pseudocolumn.

columnNoNulls

public static final int columnNoNulls

COLUMN NULLABLE:

It may not allow NULL values.

columnNullable

public static final int columnNullable

COLUMN NULLABLE:

It definitely allows NULL values.

columnNullableUnknown

public static final int columnNullableUnknown

COLUMN NULLABLE:

Its nullability is unknown.

importedKeyCascade

public static final int importedKeyCascade
IMPORT KEY UPDATE | For update, change the imported key to agree
_RULE and DELETE_RULE: | with the primary key update. For delete, delete rows that import a deleted key.

importedKeyInitiallyDeferred

public static final int importedKeyInitiallyDeferred

IMPORT KEY DEFERRABILITY:

See SQL92 for more information.

importedKeyInitiallyImmediate

public static final int importedKeyInitiallyImmediate

IMPORT KEY DEFERRABILITY:

See SQL92 for more information.

importedKeyNoAction

public static final int importedKeyNoAction

IMPORT KEY UPDATE
_RULE and DELETE_RULE:

Don’t allow the primary key to be updated or deleted if it has been imported.

importedKeyNotDeferrable

public static final int importedKeyNotDeferrable

IMPORT KEY DEFERRABILITY:

See SQL92 for more information.

importedKeyRestrict

public static final int importedKeyRestrict

IMPORT KEY UPDATE
_RULE and DELETE_RULE:

Don’t allow the primary key to be updated or deleted if it has been imported.

importedKeySetDefault

public static final int importedKeySetDefault

IMPORT KEY UPDATE
 _RULE and DELETE_RULE

Change imported key to default values if its primary key has been updated or deleted.

importedKeySetNull

public static final int importedKeySetNull

IMPORT KEY UPDATE
_RULE and DELETE_RULE:

Change imported key to NULL if its primary key has been updated or deleted.

procedureColumnUnknown

public static final int procedureColumnUnknown

COLUMN_TYPE:

Unknown type for a procedure’s parameter

procedureColumnIn

public static final int procedureColumnIn

COLUMN_TYPE:

It is an IN parameter.

procedureColumnInOut

public static final int procedureColumnInOut

COLUMN_TYPE:

It is an INOUT parameter.

procedureColumnOut

public static final int procedureColumnOut

COLUMN_TYPE:

It is an OUT parameter.

procedureColumnResult

public static final int procedureColumnResult

COLUMN_TYPE:

The result column is a ResultSet.

procedureColumnReturn

public static final int procedureColumnReturn

COLUMN_TYPE:

The procedure returns a value.

procedureNoNulls

public static final int procedureNoNulls

TYPE NULLABLE:

The procedure doesn’t allow NULL values.

procedureNoResult

public static final int procedureNoResult

PROCEDURE_TYPE:

The procedure doesn’t return a result.

procedureNullable

public static final int procedureNullable

TYPE NULLABLE:

It allows NULL values.

procedureNullableUnknown

public static final int procedureNullableUnknown

TYPE NULLABLE:

Its nullability is unknown.

procedureResultUnknown

public static final int procedureResultUnknown

PROCEDURE_TYPE:

It may return a result.

procedureReturnsResult

public static final int procedureReturnsResult

PROCEDURE_TYPE:

It returns a result.

sqlStateSQL99

public static final int sqlStateSQL99

A constant indicating that SQLException.getSQLState returns a SQL99 SQLSTATE.

sqlStateXOpen

public static final int sqlStateXOpen

A constant indicating that SQLException.getSQLState returns an X/Open SQL CLI SQLSTATE.

tableIndexClustered

public static final short tableIndexClustered

INDEX INFO TYPE:

This identifies a clustered index.

tableIndexHashed

public static final short tableIndexHashed

INDEX INFO TYPE:

This identifies a hashed index.

tableIndexOther

public static final short tableIndexOther

INDEX INFO TYPE:

This identifies some form of index other than an index using clusters, a hashed index, or an index using statistics.

tableIndexStatistic

public static final short tableIndexStatistic

INDEX INFO TYPE:

This identifies table statistics that are returned in conjunction with a table’s index descriptions.

typeNoNulls

public static final int typeNoNulls

TYPE NULLABLE:

It doesn’t allow NULL values.

typeNullable

public static final int typeNullable

TYPE NULLABLE:

It allows NULL values.

typeNullableUnknown

public static final int typeNullableUnknown

TYPE NULLABLE:

Its nullability is unknown.

typePredBasic

public static final int typePredBasic

TYPE INFO SEARCHABLE:

Supported except for WHERE . . . LIKE

typePredChar

public static final int typePredChar

TYPE INFO SEARCHABLE:

Only supported with WHERE . . . LIKE

typePredNone

public static final int typePredNone

TYPE INFO SEARCHABLE:

No support

typeSearchable

public static final int typeSearchable

TYPE INFO SEARCHABLE:

Supported for all WHERE clauses

versionColumnNotPseudo

public static final int versionColumnNotPseudo

VERSION COLUMNS PSEUDO_COLUMN:

?It isn’t a pseudocolumn.

versionColumnPseudo

public static final int versionColumnPseudo

VERSION COLUMNS PSEUDO_COLUMN:

?It is a pseudocolumn.

versionColumnUnknown

public static final int versionColumnUnknown

VERSION COLUMNS PSEUDO_COLUMN:

It may or may not be a pseudocolumn.

Methods

allProceduresAreCallable

public boolean allProceduresAreCallable() throws SQLException

This checks whether the current user can call all the procedures returned by getProcedures.

Returns: true if the procedures are callable

allTablesAreSelectable

public boolean allTablesAreSelectable() throws SQLException

This checks whether all the tables returned by getTable can be selected by the current user.

Returns: true if the tables are selectable

dataDefinitionCausesTransactionCommit

public boolean dataDefinitionCausesTransactionCommit() throws SQLException

This checks whether a data definition statement within a transaction forces the transaction to commit.

Returns: true if the data definition forces the transaction to commit

dataDefinitionIgnoredInTransactions

public boolean dataDefinitionIgnoredInTransactions() throws SQLException

This checks whether a data definition statement within a transaction will be ignored.

Returns: true if the data definition will be ignored

deletesAreDetected

public boolean deletesAreDetected(int type) throws SQLException

This checks whether a visible row delete can be detected by calling the method ResultSet.rowDeleted().

Parameters:

type:

One of the following the ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if a row delete can be detected

doesMaxRowSizeIncludeBlobs

public boolean doesMaxRowSizeIncludeBlobs() throws SQLException

This checks whether getMaxRowSize() includes LONGVARCHAR and LONGVARBINARY BLOBs.

Returns: true if these BLOBs are included

getAttributes

public ResultSet getAttributes(String catalog,
String schemaPattern, String typeNamePattern,
String attributeNamePattern) throws SQLException

This gets a description of type attributes available in the specified catalog. The result set contains the following columns:

TYPE_CAT String:

The type catalog (may be null)

TYPE_SCHEM String:

The type schema (may be null)

TYPE_NAME String:

The type name

ATTR_NAME String:

The attribute name

DATA_TYPE short:

The attribute type SQL type from java.sql.Types

ATTR_TYPE_NAME String:

The data source–dependent type name

ATTR_SIZE int:

The column size

DECIMAL_DIGITS int:

The number of fractional digits

NUM_PREC_RADIX int:

The radix

NULLABLE int:

Whether or not NULL is allowed, according to the following values:

  • attributeNoNulls: May not allow NULL values

  • attributeNullable: Definitely allows NULL values

  • attributeNullableUnknown: Nullability unknown

REMARKS String:

A comment describing the column (may be null)

ATTR_DEF String:

The default value (may be null)

SQL_DATA_TYPE int:

Unused

SQL_DATETIME_SUB int:

Unused

CHAR_OCTET_LENGTH int:

The maximum number of bytes in the column

ORDINAL_POSITION int:

The index of column in the table

IS_NULLABLE String:

The column nullability

SCOPE_CATALOG String:

The catalog of the table that is the scope of a reference attribute (null if DATA_TYPE isn’t REF)

SCOPE_SCHEMA String:

The schema of the table that is the scope of a reference attribute

SCOPE_TABLE String:

The table name that is the scope of a reference attribute

SOURCE_DATA_TYPE short:

The source type of a distinct type

Parameters:

catalog: | A catalog name, "" for no catalog, or null for any catalog
schemaPattern: | A schema name pattern, "" for no schema, or null for any schema
typeNamePattern: | A table name pattern
attributeNamePattern: | A column name pattern

Returns: A result set containing the attribute descriptions

getBestRowIdentifier

public ResultSet getBestRowIdentifier(String catalog, String schema,
String table, int scope, boolean nullable) throws SQLException

This returns a set of column descriptions that uniquely identifies a row of a table. They are ordered by SCOPE.

The result set has the following columns:

SCOPE short:

The actual scope of the result is one of the following:

  • bestRowTemporary: Very temporary, while using row

  • bestRowTransaction: Valid for the remainder of the current transaction

  • bestRowSession: Valid for the remainder of the current session

COLUMN_NAME String:

The column name

DATA_TYPE short:

The SQL data type from java.sql.Types

TYPE_NAME String:

The data-source–dependent type name

COLUMN_SIZE int:

The precision for the data type, such as the number of decimal digits if the type is float, for example

BUFFER_LENGTH int:

Not used

DECIMAL_DIGITS short:

The scale

PSEUDO_COLUMN short:

A pseudocolumn that can have one of these values:

  • bestRowUnknown: May or may not be pseudocolumn

  • bestRowNotPseudo: Isn’t a pseudocolumn

  • bestRowPseudo: Is a pseudocolumn

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; null means don’t use catalogs for the selection criteria.
schema: | A schema name; "" retrieves those without a schema.
table: | A table name.
scope: | The scope of interest; the values are the same as SCOPE.
nullable: | Include columns that are nullable.

Returns: A ResultSet; each row is a column description.

getCatalogs

public ResultSet getCatalogs() throws SQLException

This gets a table of catalog names available in the database. The results are ordered by catalog name. The catalog column is

TABLE_CAT String:

Catalog name

Returns: A ResultSet containing one row per catalog name

getCatalogSeparator

public String getCatalogSeparator() throws SQLException

This gets the separator between the catalog and table name.

Returns: The catalog separator string

getCatalogTerm

public String getCatalogTerm() throws SQLException

This gets the term used for catalogs.

Returns: The vendor term for catalog

getColumnPrivileges

public ResultSet getColumnPrivileges(String catalog, String schema,
String table, String columnNamePattern) throws SQLException

This returns a description of the access rights for the columns of a table. COLUMN_NAME and PRIVILEGE order the privileges.

The ResultSet contains rows of privileges and has the following columns:

TABLE_CAT String: | The table catalog (may be null).
TABLE_SCHEM String: | The table schema (may be null).
TABLE_NAME String: | The table name.
COLUMN_NAME String: | The column name.
GRANTOR: | The grantor of access (may be null).
GRANTEE String: | The grantee of access.
PRIVILEGE String: | The name of access (such as SELECT, INSERT, UPDATE, and REFERENCES).
IS_GRANTABLE String: | If the grantee is permitted to grant to others, the column contains YES, NO if it isn’t permitted, or null if unknown.

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; null means don’t use catalogs for the selection criteria.
schema: | A schema name; "" retrieves those without a schema.
table: | A table name.
columnNamePattern: | A column name pattern.

Returns: A ResultSet; each row is a description of a column privilege.

See also: getSearchStringEscape

getColumns

public ResultSet getColumns(String catalog, String schemaPattern,
String tableNamePattern, String columnNamePattern) throws SQLException

This returns a ResultSet containing a description of table columns matching the criteria available in a catalog. The ResultSet is ordered TABLE_SCHEM, TABLE_ NAME, and ORDINAL_POSITION.

The ResultSet has the following columns:

TABLE_CAT String:

The table catalog (may be null)

TABLE_SCHEM String:

The table schema (may be null)

TABLE_NAME String:

The table name

COLUMN_NAME String:

The column name

DATA_TYPE short:

The SQL type from java.sql.Types

TYPE_NAME String:

The data source–dependent type name

COLUMN_SIZE int:

The column size (the maximum number of characters for the CHAR or DATE type or decimal precision for NUMERIC or DECIMAL types)

BUFFER_LENGTH:

Isn’t used

DECIMAL_DIGITS int:

The number of fractional digits

NUM_PREC_RADIX int:

The radix (typically either 10 or 2)

NULLABLE int:

Contains one of these values:

  • columnNoNulls: May not allow NULL values

  • columnNullable: Definitely allows NULL values

  • columnNullableUnknown: Nullability unknown

REMARKS String:

A comment describing the column (may be null)

COLUMN_DEF String:

The default value (may be null)

SQL_DATA_TYPE int:

Unused

SQL_DATETIME_SUB int:

Unused

CHAR_OCTET_LENGTH int:

The length of the column in bytes

ORDINAL_POSITION int:

The index of the column in the table (starting at 1)

IS_NULLABLE String:

NO if NULL values aren’t allowed, YES if the column may allow NULL values, or an empty string if this attribute is unknown

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; null means don’t use catalogs for the selection criteria.
schemaPattern: | A schema name pattern; "" retrieves those without a schema.
tableNamePattern: | A table name pattern.
columnNamePattern: | A column name pattern.

Returns: a ResultSet; each row is a column description.

See also: getSearchStringEscape

getConnection

public Connection getConnection() throws SQLException

This gets the connection used to obtain the metadata object.

Returns: The connection

getCrossReference

public ResultSet getCrossReference(String primaryCatalog, String primarySchema,
String primaryTable, String foreignCatalog, String foreignSchema,
String foreignTable) throws SQLException

This describes the foreign keys of a table and the primary keys of another table that they refer to. They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

The ResultSet contains foreign key column descriptions. It contains the following columns:

PKTABLE_CAT String:

The primary key table catalog (may be null)

PKTABLE_SCHEM String:

The primary key table schema (may be null)

PKTABLE_NAME String:

The primary key table name

PKCOLUMN_NAME String:

The primary key column name

FKTABLE_CAT String:

The foreign key table catalog being exported (may be null)

FKTABLE_SCHEM String:

The foreign key table schema being exported (may be null)

FKTABLE_NAME String:

The foreign key table name being exported

FKCOLUMN_NAME String:

The foreign key column name being exported

KEY_SEQ short:

The sequence number within the foreign key

UPDATE_RULE short:

What happens to the foreign key when the primary key is updated, according to the following values:

  • importedKeyNoAction: Don’t allow the update of the primary key if it has been imported.

  • importedKeyCascade: Change the imported key to agree with the primary key update.

  • importedKeyRestrict: Don’t allow the update of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been updated.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been updated.

DELETE_RULE short:

What happens to the foreign key when the primary key is deleted, according to the following values:

  • importedKeyNoAction: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeyCascade: Delete rows that import a deleted key.

  • importedKeyRestrict: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been deleted.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been deleted.

FK_NAME String:

The foreign key identifier (may be null)

PK_NAME String:

The primary key identifier (may be null)

DEFERRABILITY short:

Specifies whether the evaluation of foreign key constraints can be deferred until commit, based on the following values:

  • importedKeyInitiallyDeferred: See SQL92 for definition.

  • importedKeyInitiallyImmediate: See SQL92 for definition.

  • importedKeyNotDeferrable: See SQL92 for definition.

Parameters:

primaryCatalog: | A catalog name; "" retrieves those without a catalog; the catalog name criteria is suppressed if null.
primarySchema: | A schema name pattern; "" retrieves those without a schema.
primaryTable: | The table name that exports the key.
foreignCatalog: | A catalog name; "" retrieves those without a catalog; the catalog name criteria is suppressed if null.
foreignSchema: | A schema name pattern; "" retrieves those without a schema.
foreignTable: | The table name that imports the key.

Returns: A ResultSet; each row is a foreign key column description.

See also: getImportedKeys

getDatabaseMajorVersion

public int getdatabaseMajorVersion() throws SQLException

This returns the database major version number_—_for example, the 2 in 2.0.

Returns: The database major version

getDatabaseMinorVersion

public int getdatabaseMinorVersion() throws SQLException

This returns the database minor version number_—_for example, the 3 in 1.3.

Returns: The database minor version

getDatabaseProductName

public String getDatabaseProductName() throws SQLException

This gets the name of the database product in use.

Returns: The database product name

getDatabaseProductVersion

public String getDatabaseProductVersion() throws SQLException

This gets the version of the database product in use.

Returns: The database version

getDefaultTransactionIsolation

public int getDefaultTransactionIsolation() throws SQLException

This gets the database’s default transaction isolation level. See the possible values in java.sql.Connection.

Returns: The default isolation level

See also: Connection

getDriverMajorVersion

public int getDriverMajorVersion()

This gets the JDBC driver’s major version number.

Returns: The JDBC driver major version

getDriverMinorVersion

public int getDriverMinorVersion()

This gets the JDBC driver’s minor version number.

Returns: The JDBC driver minor version number

getDriverName

public String getDriverName() throws SQLException

This gets the name of the JDBC driver in use.

Returns: The JDBC driver name

getDriverVersion

public String getDriverVersion() throws SQLException

This gets the version of the JDBC driver in use.

Returns: The JDBC driver version

getExportedKeys

public ResultSet getExportedKeys(String catalog, String schema, String table)
throws SQLException

This gets a description of foreign key columns that reference a table’s primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

The ResultSet contains foreign key column descriptions. Each row has these columns:

PKTABLE_CAT String:

The primary key table catalog (may be null)

PKTABLE_SCHEM String:

The primary key table schema (may be null)

PKTABLE_NAME String:

The primary key table name

PKCOLUMN_NAME String:

The primary key column name

FKTABLE_CAT String:

The foreign key table catalog being exported (may be null)

FKTABLE_SCHEM String:

The foreign key table schema being exported (may be null)

FKTABLE_NAME String:

The foreign key table name being exported

FKCOLUMN_NAME String:

The foreign key column name being exported

KEY_SEQ short:

The sequence number within the foreign key

UPDATE_RULE short:

What happens to the foreign key when the primary key is updated, according to the following values:

  • importedKeyNoAction: Don’t allow the update of the primary key if it has been imported.

  • importedKeyCascade: Change the imported key to agree with the primary key update.

  • importedKeyRestrict: Don’t allow the update of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been updated.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been updated.

DELETE_RULE short:

What happens to the foreign key when the primary key is deleted, according to the following values:

  • importedKeyNoAction: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeyCascade: Delete rows that import a deleted key.

  • importedKeyRestrict: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been deleted.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been deleted.

FK_NAME String:

The foreign key identifier (may be null)

PK_NAME String:

The primary key identifier (may be null)

DEFERRABILITY short:

Specifies whether the evaluation of foreign key constraints can be deferred until commit, based on the following values:

  • importedKeyInitiallyDeferred: See SQL92 for definition.

  • importedKeyInitiallyImmediate: See SQL92 for definition.

  • importedKeyNotDeferrable: See SQL92 for definition.

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schema: | A schema name pattern; "" retrieves those without a schema.
table: | A table name.

Returns: A ResultSet; each row is a foreign key column description.

See also: getImportedKeys

getExtraNameCharacters

public String getExtraNameCharacters() throws SQLException

The database may allow special characters to be used in unquoted identifiers. This method returns a String containing such characters.

Returns: The string containing the extra characters

getIdentifierQuoteString

public String getIdentifierQuoteString() throws SQLException

This gets the string used to quote SQL identifiers.

Returns: The quoting string or a space character if the database doesn’t support identifier quoting

getImportedKeys

public ResultSet getImportedKeys(String catalog, String schema, String table)
throws SQLException

This gets a description of the primary key columns referenced by a table’s foreign key columns. They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

The ResultSet contains primary key column descriptions. It has these columns:

PKTABLE_CAT String: The primary key table catalog being imported (may be null)

PKTABLE_SCHEM String: The primary key table schema being imported (may be null)

PKTABLE_NAME String: The primary key table name being imported

PKCOLUMN_NAME String: The primary key column name being imported

FKTABLE_CAT String: The foreign key table catalog (may be null)

FKTABLE_SCHEM String: The foreign key table schema (may be null)

FKTABLE_NAME String: The foreign key table name

FKCOLUMN_NAME String: The foreign key column name

KEY_SEQ short: The sequence number within the foreign key

UPDATE_RULE short: What happens to the foreign key when the primary key is updated, according to the following values:

  • importedKeyNoAction: Don’t allow the update of the primary key if it has been imported.

  • importedKeyCascade: Change the imported key to agree with the primary key update.

  • importedKeyRestrict: Don’t allow the update of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been updated.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been updated.

DELETE_RULE short: What happens to the foreign key when the primary key is deleted, according to the following values:

  • importedKeyNoAction: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeyCascade: Delete rows that import a deleted key.

  • importedKeyRestrict: Don’t allow the deletion of the primary key if it has been imported.

  • importedKeySetDefault: Change the imported key to the default value if its primary key has been deleted.

  • importedKeySetNull: Change the imported key to NULL if its primary key has been deleted.

FK_NAME String: The foreign key name (may be null)

PK_NAME String: The primary key name (may be null)

DEFERRABILITY short: Specifies whether the evaluation of foreign key constraints can be deferred until commit, based on the following values:

  • importedKeyInitiallyDeferred: See SQL92 for definition.

  • importedKeyInitiallyImmediate: See SQL92 for definition.

  • importedKeyNotDeferrable: See SQL92 for definition.

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schema: | A schema name pattern; "" retrieves those without a schema.
table: | A table name.

Returns: A ResultSet; each row is a primary key column description.

See also: getExportedKeys

getIndexInfo

public ResultSet getIndexInfo(String catalog, String schema, String table,
boolean unique, boolean approximate) throws SQLException

This gets a description of a table’s indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION. The ResultSet contains index column descriptions. It has the following columns:

TABLE_CAT String:

The table catalog (may be null).

TABLE_SCHEM String:

The table schema (may be null).

TABLE_NAME String:

The table name.

NON_UNIQUE boolean:

Specifies whether index values can be nonunique; false when TYPE is tableIndexStatistic.

INDEX_QUALIFIER String:

The index catalog (may be null); null when TYPE is tableIndexStatistic.

INDEX_NAME String:

The index name; null when TYPE is tableIndexStatistic.

TYPE short:

The index type; the possible values are

  • tableIndexStatistic: This identifies table statistics that are returned in conjunction with a table’s index descriptions.

  • tableIndexClustered: This is a clustered index.

  • tableIndexHashed: This is a hashed index.

  • tableIndexOther: This index is not a hashed, clustered, or statistic-based index.

ORDINAL_POSITION short:

The column sequence number within the index; zero if TYPE is tableIndexStatistic.

COLUMN_NAME String:

The column name; null if TYPE is tableIndexStatistic.

ASC_OR_DESC String:

The column sort sequence: A for ascending and D for descending; may be null if sort sequence isn’t supported; null if TYPE is tableIndexStatistic.

CARDINALITY int:

If TYPE is tableIndexStatisic, this is the number of rows in the table; otherwise, it is the number of unique values in the index.

PAGES int:

If TYPE is tableIndexStatisic, this is the number of pages used for the table; otherwise, it is the number of pages used for the current index.

FILTER_CONDITION String:

The filter condition, if any (may be null).

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schema: | A schema name pattern; "" retrieves those without a schema.
table: | A table name.
unique: | If true, returns only indices for unique values; if false, returns all indices.
approximate: | If true, results are allowed to reflect approximate or out of data values; if false, results must be accurate.

Returns: A ResultSet; each row is an index column description.

getMaxBinaryLiteralLength

public int getMaxBinaryLiteralLength() throws SQLException

This gets the maximum number of hex characters allowed in an inline binary literal.

Returns: The maximum literal length

getMaxCatalogNameLength

public int getMaxCatalogNameLength() throws SQLException

This gets the maximum length of a catalog name.

Returns: The maximum name length in bytes

getMaxCharLiteralLength

public int getMaxCharLiteralLength() throws SQLException

This gets the maximum length for a character literal.

Returns: The maximum literal length

getMaxColumnNameLength

public int getMaxColumnNameLength() throws SQLException

This gets the maximum length allowed for a column name.

Returns: The maximum literal length

getMaxColumnsInGroupBy

public int getMaxColumnsInGroupBy() throws SQLException

This gets the maximum number of columns allowed in a GROUP BY clause.

Returns: The maximum number of columns

getMaxColumnsInIndex

public int getMaxColumnsInIndex() throws SQLException

This gets the maximum number of columns allowed in an index.

Returns: The maximum number of columns

getMaxColumnsInOrderBy

public int getMaxColumnsInOrderBy() throws SQLException

This gets the maximum number of columns allowed in an ORDER BY clause.

Returns: The maximum number of columns

getMaxColumnsInSelect

public int getMaxColumnsInSelect() throws SQLException

This gets the maximum number of columns allowed in a SELECT list.

Returns: The maximum number of columns

getMaxColumnsInTable

public int getMaxColumnsInTable() throws SQLException

This gets the maximum number of columns allowed in a table.

Returns: The maximum number of columns

getMaxConnections

public int getMaxConnections() throws SQLException

This gets the maximum number of simultaneous active connections for this database.

Returns: The maximum number of connections

getMaxCursorNameLength

public int getMaxCursorNameLength() throws SQLException

This gets the maximum cursor name length.

Returns: The maximum cursor name length in bytes

getMaxIndexLength

public int getMaxIndexLength() throws SQLException

This gets the maximum length of an index.

Returns: The maximum index length in bytes

getMaxProcedureNameLength

public int getMaxProcedureNameLength() throws SQLException

This gets the maximum length of a procedure name.

Returns: The maximum name length in bytes

getMaxRowSize

public int getMaxRowSize() throws SQLException

This gets the maximum length of a single row.

Returns: The maximum row size in bytes

getMaxSchemaNameLength

public int getMaxSchemaNameLength() throws SQLException

This gets the maximum length of a schema name.

Returns: The maximum name length in bytes

getMaxStatementLength

public int getMaxStatementLength() throws SQLException

This gets the maximum length of a SQL statement.

Returns: The maximum length in bytes

getMaxStatements

public int getMaxStatements() throws SQLException

This gets the maximum number of simultaneous active statements for this database.

Returns: The maximum number of statements

getMaxTableNameLength

public int getMaxTableNameLength() throws SQLException

This gets the maximum length of a table name.

Returns: The maximum name length in bytes

getMaxTablesInSelect

public int getMaxTablesInSelect() throws SQLException

This gets the maximum number of tables in a SELECT clause.

Returns: The maximum number of tables

getMaxUserNameLength

public int getMaxUserNameLength() throws SQLException

This gets the maximum length of a username.

Returns: The maximum name length in bytes

getNumericFunctions

public String getNumericFunctions() throws SQLException

This gets a list of supported math functions.

Returns: The list with a comma as a separator

getPrimaryKeys

public ResultSet getPrimaryKeys(String catalog, String schema, String table)
throws SQLException

This gets a description of a table’s primary key columns. They are ordered by COLUMN_NAME.

The ResultSet contains column descriptions. It has these columns:

TABLE_CAT String: | The table catalog (may be null)
TABLE_SCHEM String: | The table schema (may be null)
TABLE_NAME String: | The table name
COLUMN_NAME String: | The column name
KEY_SEQ short: | The sequence number within the primary key
PK_NAME String: | The primary key name (may be null)

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schema: | A schema name pattern; "" retrieves those without a schema.
table: | A table name.

Returns: A ResultSet; each row is a primary key column description.

getProcedureColumns

public ResultSet getProcedureColumns(String catalog, String schemaPattern,
String procedureNamePattern, String columnNamePattern) throws SQLException

This gets a description of a catalog’s stored procedure parameters and result columns. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME.

If the procedure has a return value, its description is given first. The remaining descriptions refer to the procedure’s parameters.

Each row in the ResultSet is a parameter description or column description with the following fields:

PROCEDURE_CAT String:

The procedure catalog (may be null)

PROCEDURE_SCHEM String:

The procedure schema (may be null)

PROCEDURE_NAME String:

The procedure name

COLUMN_NAME String:

The column/parameter name

COLUMN_TYPE Short:

The kind of column/parameter, according to the following values:

  • procedureColumnUnknown: The driver is unable to tell if this is an IN or OUT parameter or a return value.

  • procedureColumnIn: The IN parameter.

  • procedureColumnInOut: The INOUT parameter.

  • procedureColumnOut: The OUT parameter.

  • procedureColumnReturn: The procedure return value.

  • procedureColumnResult: The result column in ResultSet.

DATA_TYPE short:

The SQL type from java.sql.Types

TYPE_NAME String:

The SQL type name

PRECISION int:

The decimal precision (for float numbers, for example)

LENGTH int:

The length in bytes of data

SCALE short:

The scale

RADIX short:

The radix

NULLABLE short:

Specifies whether the parameter or return value can contain NULL, according to the following values:

  • procedureNoNulls: Doesn’t allow NULL values

  • procedureNullable: Allows NULL values

  • procedureNullableUnknown: Nullability unknown

REMARKS String:

A comment describing the parameter/column

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schemaPattern: | A schema name pattern; "" retrieves those without a schema.
procedureNamePattern: | A procedure name pattern.
columnNamePattern: | A column name pattern.

Returns: A ResultSet; each row is a stored procedure parameter or column description.

See also: getSearchStringEscape

getProcedures

public ResultSet getProcedures(String catalog, String schemaPattern,
String procedureNamePattern) throws SQLException

This gets a description of stored procedures. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME.

The ResultSet contains procedure descriptions. It has these columns:

PROCEDURE_CAT String:

The procedure catalog (may be null)

PROCEDURE_SCHEM String:

The procedure schema (may be null)

PROCEDURE_NAME String:

The procedure name

REMARKS String:

An explanatory comment on the procedure

PROCEDURE_TYPE short:

The kind of procedure, according to the following values:

  • procedureResultUnknown: May return a result

  • procedureNoResult: Doesn’t return a result

  • procedureReturnsResult: Returns a result

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schemaPattern: | A schema name pattern; "" retrieves those without a schema.
procedureNamePattern: | A procedure name pattern.

Returns: A ResultSet; each row is a procedure description.

See also: getSearchStringEscape

getProcedureTerm

public String getProcedureTerm() throws SQLException

This gets the database vendor’s preferred term for procedure.

Returns: The vendor term

getSchemas

public ResultSet getSchemas() throws SQLException

This gets the schema names available in the database in use. The results are ordered by TABLE_SCHEM. The ResultSet contains one column, which is

TABLE_SCHEM String: The schema name

Returns: A ResultSet; each row has a single String column that is a schema name.

getSchemaTerm

public String getSchemaTerm() throws SQLException

This gets the database vendor’s preferred term for schema.

Returns: The vendor term

getSearchStringEscape

public String getSearchStringEscape() throws SQLException

This gets the string that can be used to escape wildcard characters such as _ or % in the string pattern style catalog search parameters. The _ character represents any single character. The % character represents any sequence of zero or more characters.

Returns: The string used to escape wildcard characters

getSQLKeywords

public String getSQLKeywords() throws SQLException

This gets a list of all SQL keywords that aren’t also SQL92 keywords supported by the database in use.

Returns: The list, comma separated

getSQLStateType

public int getSQLStateType() throws SQLException

This returns the type of SQLSTATE values for this database.

Returns: The SQLSTATE type, which is one of the following:

  • sqlStateXOpen

  • sqlStateSQL99

getStringFunctions

public String getStringFunctions() throws SQLException

This gets the list of string functions supported by the database in use.

Returns: The list, which is comma separated

getSuperTables

public ResultSet getSuperTables(String catalog,
String schemaPattern, String tableNamePattern) throws SQLException

This gets a description of the table hierarchies defined in a particular schema in the database.

Parameters:

catalog: | A catalog name, "" for no catalog, or null for any catalog
schemaPattern: | A schema name pattern or "" for no schema
typeNamePattern: | A type name pattern

Returns: A result set containing the description of the table hierarchies.

getSuperTypes

public ResultSet getSuperTypes(String catalog,
String schemaPattern, String typeNamePattern) throws SQLException

This gets the description of the user-defined type hierarchies defined in a particular schema in the database. Only the immediate supertype/subtype relationship is modeled.

Parameters:

catalog: | A catalog name, "" for no catalog, or null for any catalog
schemaPattern: | A schema name pattern or "" for no schema
typeNamePattern: | A type name pattern

Returns: A result set containing type descriptions

getSystemFunctions

public String getSystemFunctions() throws SQLException

This gets the list of system functions supported by the database in use.

Returns: The list, comma separated

getTablePrivileges

public ResultSet getTablePrivileges(String catalog, String schemaPattern,
String tableNamePattern) throws SQLException

This returns a description of table privileges. Note that privileges may not apply to all columns of the table. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

The ResultSet has these columns:

TABLE_CAT String: | The table catalog (may be null).
TABLE_SCHEM String: | The table schema (may be null).
TABLE_NAME String: | The table name.
GRANTOR: | The grantor of access (may be null).
GRANTEE String: | The grantee of access.
PRIVILEGE String: | The name of access (such as SELECT, INSERT, UPDATE, and REFERENCES).
IS_GRANTABLE String: | If YES, the grantee is permitted to grant to others; if NO, no grant is allowed; if null, the granting status is unknown.

Parameters:

catalog: | A catalog name; “” retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schemaPattern: | A schema name pattern; “” retrieves those without a schema.
tableNamePattern: | A table name pattern.

Returns: A ResultSet; each row is a description of a table privilege.

See also: getSearchStringEscape

getTables

public ResultSet getTables(String catalog, String schemaPattern,
String tableNamePattern, String types[]) throws SQLException

This returns a list of user or system tables or views available in a catalog. The search criteria are catalog, schema, table name, and table type. The results are ordered by TABLE_TYPE, TABLE_SCHEM, and TABLE_NAME.

The ResultSet has these columns:

TABLE_CAT String: | The table catalog (may be null).
TABLE_SCHEM String: | The table schema (may be null).
TABLE_NAME String: | The table name.
TABLE_TYPE String: | The table type; possible types are TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, and SYNONYM.
REMARKS String: | An explanatory comment on the table.

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schemaPattern: | A schema name pattern; "" retrieves those without a schema.
tableNamePattern: | A table name pattern.
types: | A list of table types to include or null to return all types.

Returns: A ResultSet; each row is a table description.

See also: getSearchStringEscape, getTableTypes

getTableTypes

public ResultSet getTableTypes() throws SQLException

This gets all the table types available in the current database. The results are ordered by table type. The table type is

TABLE_TYPE String: The table type; possible types are TABLE, VIEW, SYSTEM TABLE, GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, and SYNONYM.

Returns: A ResultSet; each row contains a table type.

getTimeDateFunctions

public String getTimeDateFunctions() throws SQLException

This gets a list of time and date functions.

Returns: A comma-separated list of time and date functions

getTypeInfo

public ResultSet getTypeInfo() throws SQLException

This gets information about all the standard SQL types supported by the database. The results are ordered by DATA_TYPE. Type definitions that are closer to their corresponding java.sql.Types are listed first. The ResultSet contains these columns:

TYPE_NAME String:

The type name

DATA_TYPE short:

The SQL data type from java.sql.Types

PRECISION int:

The maximum precision

LITERAL_PREFIX String:

The prefix used to quote a literal (may be null)

LITERAL_SUFFIX String:

The suffix used to quote a literal (may be null)

CREATE_PARAMS String:

The parameters used to create the type (may be null)

NULLABLE short:

One of these values:

  • typeNoNulls: Doesn’t allow NULL values

  • typeNullable: Allows NULL values

  • typeNullableUnknown: Nullability unknown

CASE_SENSITIVE boolean:

Specifies whether the type is case sensitive

SEARCHABLE short:

Specifies the level of support in WHERE clauses, according to the following values:

  • typePredNone: No support

  • typePredChar: Only supported with WHERE . . . LIKE

  • typePredBasic: Supported except for WHERE . . . LIKE

  • typeSearchable: Supported for all WHERE clauses

UNSIGNED_ATTRIBUTE

?

boolean:

true if unsigned

FIXED_PREC_SCALE

?

boolean:

true if the precision is fixed

AUTO_INCREMENT boolean:

true if it can be used for an auto-increment value

LOCAL_TYPE_NAME String:

The localized version of the type name (may be null)

MINIMUM_SCALE short:

The minimum scale supported

MAXIMUM_SCALE short:

The maximum scale supported

SQL_DATA_TYPE int:

Unused

SQL_DATETIME_SUB int:

Unused

NUM_PREC_RADIX int:

The radix, which is usually 2 or 10

Returns: A ResultSet; each row is a description of a SQL type supported by the database.

getUDTs

public ResultSet getUDTs(String catalog, String schemaPattern,
String typeNamePattern, int[] types) throws SQLException

This gets a description of the user-defined types defined in a particular schema. Each type description has the following columns:

TYPE_CAT String: | The type’s catalog (may be null)
TYPE_SCHEM String: | The type’s schema (may be null)
TYPE_NAME String: | The type name
CLASS_NAME String: | The Java class name
DATA_TYPE String: | JAVA_OBJECT, STRUCT, or DISTINCT
REMARKS String: | A comment on the type
BASE_TYPE short: | The type code of the source type

Parameters:

catalog: | A catalog name, "" for no catalog, or null for any catalog
schemaPattern: | A schema pattern name, "" for no schema, or null for any schema
typeNamePattern: | A type name pattern
types: | A list of user-named types to include

Returns: A result set containing type descriptions

getURL

public String getURL() throws SQLException

This gets the URL for the current database.

Returns: The URL or null if it isn’t possible to find it

getUserName

public String getUserName() throws SQLException

This gets the database username for the current session.

Returns: The current session’s username

getVersionColumns

public ResultSet getVersionColumns(String catalog, String schema, String table)
throws SQLException

This returns information about the columns of a table that are automatically updated when any field in a row is updated.

The ResultSet contains these columns:

SCOPE short:

Unused

COLUMN_NAME String:

The column name

DATA_TYPE short:

The SQL data type from java.sql.Types

TYPE_NAME String:

The database type name

COLUMN_SIZE int:

The precision, such as the number of decimal digits

BUFFER_LENGTH int:

The length of the column value in bytes

DECIMAL_DIGITS short:

The scale

PSEUDO_COLUMN short:

The state of a column, according to the following values:

  • versionColumnUnknown: May or may not be a pseudocolumn

  • versionColumnNotPseudo: Isn’t a pseudocolumn

  • versionColumnPseudo: Is a pseudocolumn

Parameters:

catalog: | A catalog name; "" retrieves those without a catalog; a null means that the catalog name must be suppressed from the selection criteria.
schema: | A schema name; "" retrieves those without a schema.
table: | A table name.

Returns: A ResultSet; each row is a column description.

insertsAreDetected

public boolean insertsAreDetected(int type) throws SQLException

This checks whether a visible row insert can be detected by calling the method ResultSet.rowInserted().

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if a row insert can be detected

isCatalogAtStart

public boolean isCatalogAtStart() throws SQLException

This checks whether a catalog appears at the start of a qualified table name or at the end of a qualified table name.

Returns: true if it appears at the start

isReadOnly

public boolean isReadOnly() throws SQLException

This checks whether the database is in read-only mode.

Returns: true if the database is in read-only mode

nullPlusNonNullIsNull

public boolean nullPlusNonNullIsNull() throws SQLException

This checks whether a concatenation of NULL values is a NULL value.

Returns: true if a concatenation of NULLs is NULL

nullsAreSortedAtEnd

public boolean nullsAreSortedAtEnd() throws SQLException

This checks whether NULL values are sorted at the end regardless of sort order.

Returns: true if NULLs are sorted at the end

nullsAreSortedAtStart

public boolean nullsAreSortedAtStart() throws SQLException

This checks whether NULL values are sorted at the start regardless of sort order.

Returns: true if NULLs are sorted at the start

nullsAreSortedHigh

public boolean nullsAreSortedHigh() throws SQLException

This checks whether NULL values appear first in the sorted results.

Returns: true if NULLs are sorted high

nullsAreSortedLow

public boolean nullsAreSortedLow() throws SQLException

This checks whether NULL values appear last in the sorted results.

Returns: true if NULLs are sorted low

othersDeletesAreVisible

public boolean othersDeletesAreVisible(int type) throws SQLException

This indicates whether deletes made by others are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if deletes made by others are visible

othersInsertsAreVisible

public boolean othersInsertsAreVisible(int type) throws SQLException

This indicates whether inserts made by others are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if inserts made by others are visible

othersUpdatesAreVisible

public boolean othersUpdatesAreVisible(int type) throws SQLException

This indicates whether updates made by others are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if updates made by others are visible

ownDeletesAreVisible

public boolean ownDeletesAreVisible(int type) throws SQLException

This checks whether a result set’s own deletes are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if a result set’s own deletes are visible

ownInsertsAreVisible

public boolean ownInsertsAreVisible(int type) throws SQLException

This checks whether a result set’s own inserts are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if a result set’s own inserts are visible

ownUpdatesAreVisible

public boolean ownUpdatesAreVisible(int type) throws SQLException

This checks whether a result set’s own updates are visible.

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if a result set’s own updates are visible

storesLowerCaseIdentifiers

public boolean storesLowerCaseIdentifiers() throws SQLException

This checks whether the database automatically converts unquoted SQL identifiers to lowercase.

Returns: true if the database stores lowercase identifiers

storesLowerCaseQuotedIdentifiers

public boolean storesLowerCaseQuotedIdentifiers() throws SQLException

This checks whether the database automatically converts quoted SQL identifiers to lowercase.

Returns: true if the database stores lowercase quoted identifiers

storesMixedCaseIdentifiers

public boolean storesMixedCaseIdentifiers() throws SQLException

This checks whether the database stores mixed-case unquoted identifiers.

Returns: true if the database stores mixed-case identifiers

storesMixedCaseQuotedIdentifiers

public boolean storesMixedCaseQuotedIdentifiers() throws SQLException

This checks whether the database stores mixed-case quoted identifiers.

Returns: true if the database stores mixed-case quoted identifiers

storesUpperCaseIdentifiers

public boolean storesUpperCaseIdentifiers() throws SQLException

This checks whether the database automatically converts unquoted SQL identifiers to uppercase.

Returns: true if the database stores uppercase identifiers

storesUpperCaseQuotedIdentifiers

public boolean storesUpperCaseQuotedIdentifiers() throws SQLException

This checks whether the database automatically converts quoted SQL identifiers to uppercase.

Returns: true if the database stores uppercase quoted identifiers

supportsAlterTableWithAddColumn

public boolean supportsAlterTableWithAddColumn() throws SQLException

This checks whether an ALTER TABLE clause can be used to add a column.

Returns: true if ALTER TABLE can be used

supportsAlterTableWithDropColumn

public boolean supportsAlterTableWithDropColumn() throws SQLException

This checks whether an ALTER TABLE clause can be used to drop a column.

Returns: true if ALTER TABLE can be used

supportsANSI92EntryLevelSQL

public boolean supportsANSI92EntryLevelSQL() throws SQLException

This checks whether the ANSI92 Entry Level SQL grammar is supported. Must be true for all JDBC-compliant drivers.

Returns: true if ANSI92 Entry Level SQL is supported

supportsANSI92FullSQL

public boolean supportsANSI92FullSQL() throws SQLException

This checks whether the ANSI92 Full SQL grammar is supported.

Returns: true if ANSI92 Full SQL is supported

supportsANSI92IntermediateSQL

public boolean supportsANSI92IntermediateSQL() throws SQLException

This checks whether the ANSI92 Intermediate SQL grammar is supported.

Returns: true if ANSI92 Intermediate SQL is supported

supportsBatchUpdates

public boolean supportsBatchUpdates() throws SQLException

This checks whether the driver supports batch updates.

Returns: true if batch updates are supported

supportsCatalogsInDataManipulation

public boolean supportsCatalogsInDataManipulation() throws SQLException

This checks whether a catalog name can be used in a DML statement.

Returns: true if catalog names can be used

supportsCatalogsInProcedureCalls

public boolean supportsCatalogsInProcedureCalls() throws SQLException

This checks whether a catalog name can be used in a procedure call statement.

Returns: true if catalog names can be used

supportsCatalogsInTableDefinitions

public boolean supportsCatalogsInTableDefinitions() throws SQLException

This checks whether a catalog name can be used in a table definition (DDL) statement.

Returns: true if catalog names can be used

supportsCatalogsInIndexDefinitions

public boolean supportsCatalogsInIndexDefinitions() throws SQLException

This checks whether a catalog name can be used in an index definition (DDL) statement.

Returns: true if catalog names can be used

supportsCatalogsInPrivilegeDefinitions

public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException

This checks whether a catalog name can be used in a privilege definition statement.

Returns: true if catalog names can be used

supportsColumnAliasing

public boolean supportsColumnAliasing() throws SQLException

This checks whether column aliasing is supported to provide names to computed columns with the AS SQL keyword.

Returns: true if column aliasing is supported

supportsConvert

public boolean supportsConvert() throws SQLException

This checks whether the CONVERT function is supported between SQL types.

Returns: true if CONVERT is supported

supportsConvert

public boolean supportsConvert(int fromType, int toType) throws SQLException

This checks whether the CONVERT function is supported between the given SQL types.

Parameters:

fromType:

The type to convert from

toType:

The type to convert to

Returns: true if CONVERT is supported

supportsCorrelatedSubqueries

public boolean supportsCorrelatedSubqueries() throws SQLException

This checks whether correlated subqueries are supported.

Returns: true if correlated subqueries are supported

supportsCoreSQLGrammar

public boolean supportsCoreSQLGrammar() throws SQLException

This checks whether the ODBC Core SQL grammar is supported.

Returns: true if ODBC Core SQL is supported

supportsDataDefinitionAndDataManipulationTransactions

public boolean supportsDataDefinitionAndDataManipulation Transactions()
throws SQLException

This checks whether both data definition (DDL) and data manipulation (DML) statements are supported within a transaction.

Returns: true if DDL and DML are supported

supportsDataManipulationTransactionsOnly

public boolean supportsDataManipulationTransactionsOnly() throws SQLException

This checks whether only data manipulation statements are supported within a transaction.

Returns: true if only DML is supported

supportsDifferentTableCorrelationNames

public boolean supportsDifferentTableCorrelationNames() throws SQLException

This checks whether table correlation names are supported and if they must be different from the table names.

Returns: true if so

supportsExpressionsInOrderBy

public boolean supportsExpressionsInOrderBy() throws SQLException

This checks whether expressions are supported in ORDER BY lists.

Returns: true if expressions are supported

supportsExtendedSQLGrammar

public boolean supportsExtendedSQLGrammar() throws SQLException

This checks whether the ODBC Extended SQL grammar is supported.

Returns: true if ODBC Extended SQL is supported

supportsFullOuterJoins

public boolean supportsFullOuterJoins() throws SQLException

This checks whether full nested outer joins are supported.

Returns: true if full outer joins are supported

supportsGetGeneratedKeys

public boolean supportsGetGeneratedKeys() throws SQLException

This checks whether auto-generated keys can be retrieved after a statement is executed.

Returns: true if auto-generated keys can be retrieved

supportsGroupBy

public boolean supportsGroupBy() throws SQLException

This checks whether the SQL GROUP BY clause is supported.

Returns: true if GROUP BY is supported

supportsGroupByUnrelated

public boolean supportsGroupByUnrelated() throws SQLException

This checks whether a GROUP BY clause can use columns that aren’t in the SELECT statement.

Returns: true if GROUP BY can use unrelated columns

supportsGroupByBeyondSelect

public boolean supportsGroupByBeyondSelect() throws SQLException

This checks whether a GROUP BY clause can add columns that aren’t in the SELECT statement, provided it specifies all the columns in the SELECT clause.

Returns: true if so

supportsIntegrityEnhancementFacility

public boolean supportsIntegrityEnhancementFacility() throws SQLException

This checks whether the SQL Integrity Enhancement Facility is supported.

Returns: true if the SQL Integrity Enhancement Facility is supported

supportsLikeEscapeClause

public boolean supportsLikeEscapeClause() throws SQLException

This checks whether the escape character is supported in LIKE clauses.

Returns: true if LIKE supports the escape character

supportsLimitedOuterJoins

public boolean supportsLimitedOuterJoins() throws SQLException

This checks whether there is limited support for outer joins.

Returns: true if limited outer joins are supported

supportsMinimumSQLGrammar

public boolean supportsMinimumSQLGrammar() throws SQLException

This checks whether the ODBC Minimum SQL grammar is supported. Must be true for all JDBC-compliant drivers.

Returns: true if ODBC Minimum SQL is supported

supportsMixedCaseIdentifiers

public boolean supportsMixedCaseIdentifiers() throws SQLException

This checks whether the database supports unquoted mixed-case identifiers.

Returns: true if the database supports mixed-case identifiers

supportsMixedCaseQuotedIdentifiers

public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException

This checks whether the database supports mixed-case quoted identifiers.

Returns: true if the database supports mixed-case quoted identifiers

supportsMultipleOpenResults

public boolean supportsMultipleOpenResults() throws SQLException

This checks whether multiple ResultSet objects can be returned from a CallableStatement simultaneously.

Returns: true if multiple ResultSets can be returned

supportsMultipleResultSets

public boolean supportsMultipleResultSets() throws SQLException

This checks whether multiple ResultSets returned after a single execute are supported.

Returns: true if multiple ResultSets are supported

supportsMultipleTransactions

public boolean supportsMultipleTransactions() throws SQLException

This checks whether multiple transactions are supported simultaneously on different connections.

Returns: true if multiple transactions are supported

supportsNamedParameters

public boolean supportsNamedParameters() throws SQLException

This checks whether named parameters to callable statements are supported.

Returns: true if named parameters are supported

supportsNonNullableColumns

public boolean supportsNonNullableColumns() throws SQLException

This checks whether columns can be defined as non-nullable.

Returns: true if non-nullable columns are supported

supportsOpenCursorsAcrossCommit

public boolean supportsOpenCursorsAcrossCommit() throws SQLException

This checks whether cursors can remain open across commits.

Returns: true if open cursors across commits are supported

See also: disableAutoClose

supportsOpenCursorsAcrossRollback

public boolean supportsOpenCursorsAcrossRollback() throws SQLException

This checks whether cursors can remain open across rollbacks.

Returns: true if open cursors across rollbacks are supported

See also: disableAutoClose

supportsOpenStatementsAcrossCommit

public boolean supportsOpenStatementsAcrossCommit() throws SQLException

This checks whether statements can remain open across commits.

Returns: true if open statements across commits are supported

See also: disableAutoClose

supportsOpenStatementsAcrossRollback

public boolean supportsOpenStatementsAcrossRollback() throws SQLException

This checks whether statements can remain open across rollbacks.

Returns: true if open statements across rollbacks are supported

See also: disableAutoClose

supportsOrderByUnrelated

public boolean supportsOrderByUnrelated() throws SQLException

This checks whether an ORDER BY clause can use columns that aren’t in the SELECT statement.

Returns: true if ORDER BY can use unrelated columns

supportsOuterJoins

public boolean supportsOuterJoins() throws SQLException

This checks whether the database supports outer joins.

Returns: true if outer joins are supported

supportsPositionedDelete

public boolean supportsPositionedDelete() throws SQLException

This checks whether the database supports positioned DELETE.

Returns: true if positioned DELETE is supported

supportsPositionedUpdate

public boolean supportsPositionedUpdate() throws SQLException

This checks whether the database supports positioned UPDATE.

Returns: true if positioned UPDATE is supported

supportsResultSetConcurrency

public boolean supportsResultSetConcurrency(int type, int concurrency)
throws SQLException

This checks whether the database supports the concurrency type with the given result set type.

Parameters:

type: | Defined in java.sql.ResultSet
concurrency: | The type defined in java.sql.ResultSet

Returns: true if the concurrency type is supported

supportResultSetHoldability

public boolean supportResultSetHoldability(int holdability) throws SQLException

This checks whether the database supports the given result set holdability.

Parameters:

holdability:

Defined in java.sql.ResultSet

Returns: true if the holdability is supported

supportsResultSetType

public boolean supportsResultSetType(int type) throws SQLException

This checks whether the database supports the given result set type.

Parameters:

type:

Defined in java.sql.ResultSet

Returns: true if the result set type is supported

supportsSavepoints

public boolean supportsSavepoints() throws SQLException

This checks whether savepoints are supported in transactions.

Returns: true if savepoints are supported

supportsSchemasInDataManipulation

public boolean supportsSchemasInDataManipulation() throws SQLException

This checks whether a schema name can be used in a data manipulation (DML) statement.

Returns: true if schemas are supported

supportsSchemasInIndexDefinitions

public boolean supportsSchemasInIndexDefinitions() throws SQLException

This checks whether a schema name can be used in an index definition (DDL) statement.

Returns: true if schemas are supported

supportsSchemasInPrivilegeDefinitions

public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException

This checks whether a schema name can be used in a privilege definition statement.

Returns: true if schemas are supported

supportsSchemasInProcedureCalls

public boolean supportsSchemasInProcedureCalls() throws SQLException

This checks whether a schema name can be used in a procedure call statement.

Returns: true if schemas are supported

supportsSchemasInTableDefinitions

public boolean supportsSchemasInTableDefinitions() throws SQLException

This checks whether a schema name can be used in a table definition (DDL) statement.

Returns: true if schemas are supported

supportsSelectForUpdate

public boolean supportsSelectForUpdate() throws SQLException

This checks whether the database supports SELECT for UPDATE clauses.

Returns: true if SELECT for UPDATE is supported

supportsStoredProcedures

public boolean supportsStoredProcedures() throws SQLException

This checks whether the stored procedure escape syntax can be used to call stored procedures.

Returns: true if the stored procedure escape syntax is supported

supportsSubqueriesInComparisons

public boolean supportsSubqueriesInComparisons() throws SQLException

This checks whether subqueries are supported in comparison expressions.

Returns: true if subqueries in comparisons are supported

supportsSubqueriesInExists

public boolean supportsSubqueriesInExists() throws SQLException

This checks whether subqueries are supported in exists expressions.

Returns: true if subqueries in exists expressions are supported

supportsSubqueriesInIns

public boolean supportsSubqueriesInIns() throws SQLException

This checks whether subqueries are supported in IN statements.

Returns: true if subqueries in INs are supported

supportsSubqueriesInQuantifieds

public boolean supportsSubqueriesInQuantifieds() throws SQLException

This checks whether subqueries are supported in quantified expressions.

Returns: true if subqueries in quantified expressions are supported

supportsTableCorrelationNames

public boolean supportsTableCorrelationNames() throws SQLException

This checks whether table correlation names are supported.

Returns: true if table correlation names are supported

supportsTransactions

public boolean supportsTransactions() throws SQLException

This checks whether the database supports transactions.

Returns: true if transactions are supported

supportsTransactionIsolationLevel

public boolean supportsTransactionIsolationLevel(int level) throws SQLException

This checks whether the database supports the given transaction isolation level.

Parameters:

level:

The values are defined in java.sql.Connection.

Returns: true if the transaction isolation level is supported

See also: Connection

supportsUnion

public boolean supportsUnion() throws SQLException

This checks whether the database supports SQL UNION.

Returns: true if UNION is supported

supportsUnionAll

public boolean supportsUnionAll() throws SQLException

This checks whether the database supports SQL UNION ALL.

Returns: true if UNION ALL is supported

updatesAreDetected

public boolean updatesAreDetected(int type) throws SQLException

This checks whether a visible row update can be detected by calling the method ResultSet.rowUpdated().

Parameters:

type:

One of the following ResultSet types:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

Returns: true if updates can be detected

usesLocalFilePerTable

public boolean usesLocalFilePerTable() throws SQLException

This checks whether the database uses a file for each table.

Returns: true if the database uses a local file for each table

usesLocalFiles

public boolean usesLocalFiles() throws SQLException

This checks whether the database stores tables in a local file.

Returns: true if a local file is used


Class Date

public class Date
extends Date

The Date class extends the standard java.util.date class to represent SQL DATE types. It supports the JDBC escape syntax for date values.

Constructors

Date

public Date(int year, int month, int day)

This creates a Date object.

Parameters:

year: | The year minus 1900
month: | 0 to 11
day: | 1 to 31

Date

public Date(long date)

This creates a Date object using a time value in milliseconds.

Parameters:

date:

The milliseconds since January 1, 1970, 00:00:00 GMT

Methods

toString

public String toString()

This converts a date to YYYY-MM-DD format.

Returns: A formatted date String

valueOf

public static Date valueOf(String s)

This converts a YYYY-MM-DD formatted string to a Date value.

Parameters:

s:

The date in format YYYY-MM-DD

Returns: A Date


Interface Driver

public interface Driver
extends Object

Drivers are loaded by the DriverManager to provide connections to specific databases. A user can load and register a JDBC driver by calling Class. forName("a.specific.driver"). The DriverManager will use this driver if it can successfully connect to a given database URL.

See also: DriverManager, Connection

Methods

acceptsURL

public boolean acceptsURL(String url) throws SQLException

This method is used to check whether the URL syntax is recognized by the driver and if it is capable of opening a connection to it. A driver usually returns true if it is able to understand the subprotocol field of the given URL.

Parameters:

url:

The URL of the database

Returns: true if this driver can connect to the given URL

connect

public Connection connect(String url, Properties info) throws SQLException

This method is used to get a Connection object for a particular database URL. The DriverManager invokes this method for all Drivers that are loaded and receives either a null if the Driver isn’t appropriate for this connection or a Connection object in the opposite case. Note that a SQLException is thrown by the Driver if it has trouble connecting to the database.

Connection arguments may be passed as tag/value pairs by way of java.util. Properties. At a minimum, user and password properties are included in the properties.

Parameters:

url: | The URL of the database to connect to
info: | A list of tag/value pairs as connection arguments

Returns: A Connection to the URL

getMajorVersion

public int getMajorVersion()

This gets the driver’s major version number.

getMinorVersion

public int getMinorVersion()

This gets the driver’s minor version number.

getPropertyInfo

public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
throws SQLException

This gets the necessary properties that must be provided to use the driver. The property list may vary according to the values supplied at different points in time, so it may be necessary to iterate though several calls to this method to discover all the mandatory properties.

Parameters:

url: | The URL of the database to connect to
info: | A list of tag/value pair properties

Returns: An array of DriverPropertyInfo objects; this array may be empty if no properties are required.

jdbcCompliant

public boolean jdbcCompliant()

This reports whether the driver is a genuine JDBC compliant driver.

The driver reports true only if it passes the JDBC compliance tests, meaning that it provides full support for both the JDBC API and for SQL 92 Entry Level.

Returns: true if the driver is JDBC compliant


Class DriverManager

public class DriverManager
extends Object

The DriverManager manages JDBC drivers and database connection requests. Although the drivers can be registered and loaded with the class.forName() method, the DriverManager uses the jdbc.drivers property during its initialization phase to find a suitable driver for the connection that is requested.

See also: Driver, Connection

Methods

deregisterDriver

public static void deregisterDriver(Driver driver) throws SQLException

This removes a Driver from the DriverManager’s list. In the case of applets, only Drivers from the applet’s own classloader can be deregistered.

Parameters:

driver:

A JDBC Driver

getConnection

public static synchronized Connection getConnection(String url,
Properties info) throws SQLException

getConnection() returns a Connection object if the DriverManager is able to find an appropriate driver for the requested connection.

Parameters:

url: | A database URL
info: | A list of string tag/value pairs as connection arguments

Returns: A Connection to the database URL

getConnection

public static synchronized Connection getConnection(String url,
String user, String password) throws SQLException

getConnection() returns a Connection object if the DriverManager is able to find an appropriate driver for the requested connection.

Parameters:

url: | A database URL
user: | A database user’s login
password: | The user’s password

Returns: A Connection to the database URL

getConnection

public static synchronized Connection getConnection(String url)
throws SQLException

getConnection() returns a Connection object if the DriverManager is able to find an appropriate driver for the requested connection.

Parameters:

url:

A database URL usually containing user and password strings

Returns: A Connection to the database URL

getDriver

public static Driver getDriver(String url) throws SQLException

This method is used to locate a Driver that is able to connect to the database URL. The Driver is selected from the set of registered Drivers.

Parameters:

url:

A database URL

Returns: A Driver able to connect to the URL

getDrivers

public static Enumeration getDrivers()

This gets an Enumeration of the JDBC drivers that are currently loaded.

Returns: The list of JDBC drivers that are loaded

getLoginTimeout

public static int getLoginTimeout()

This gets the maximum time in seconds that all drivers can wait when attempting to log in to a database.

Returns: The login time limit

getLogStream

public static PrintStream getLogStream()

The DriverManager and JDBC drivers can give detailed information on what they do during a connection. This method returns the PrintStream used by the DriverManager and the drivers.

Returns: The logging/tracing PrintStream or null if logging/tracing is disabled

getLogWriter

public static java.io.PrintWriter getLogWriter()

The DriverManager and JDBC drivers can give detailed information on what they do during a connection. This method returns the PrintWriter used by the DriverManager and the drivers.

Returns: The java.io.PrintWriter object

println

public static void println(Stringmessage)

This prints a string to the current JDBC log stream.

Parameters:

message:

A log message

registerDriver

public static synchronized void registerDriver(Driverdriver) throws SQLException

JDBC drivers must register themselves with the DriverManager in order to be candidates for subsequent connections.

Parameters:

driver:

A JDBC Driver

setLoginTimeout

public static void setLoginTimeout(int seconds)

This sets the maximum time in seconds that all drivers can wait when attempting to log in to a database.

Parameters:

seconds:

The login time limit

setLogStream

public static void setLogStream(PrintStream out)

The DriverManager and JDBC drivers can give detailed information on what they do during a connection. This method sets the PrintStream used by the DriverManager and the drivers.

Parameters:

out:

The logging/tracing PrintStream or null to disable the logging/tracing facility

setLogWriter

public static void setLogWriter(PrintWriter out)

The DriverManager and JDBC drivers can give detailed information on what they do during a connection. This method sets the PrintWriter used by the DriverManager and the drivers. If a SecurityManager exists and its checkPermission method denies setLog, this method throws a SecurityException.

Parameters:

out:

The logging/tracing PrintWriter or null to disable the logging/tracing facility


Class DriverPropertyInfo

public class DriverPropertyInfo
extends Object

The DriverPropertyInfo class is used to specify one tag name/value pair plus its description, possible choices for values, and so on. You can use java.sql.Driver. getPropertyInfo() to obtain an array of DriverPropertyInfo objects. Note the public variables of DriverPropertyInfo.

Fields

choices

public String choices[]

This is an array of the possible values for the property. If no choice is possible, choices[] is null.

description

public String description

This is a description of the property.

name

public String name

This is the name of the property.

required

public boolean required

This variable is set to true if a value must be supplied for the property during Driver.connect. The property is optional in the opposite case.

value

public String value

This string contains the current value of the property. It may be null if no value is known.

Constructors

DriverPropertyInfo

public DriverPropertyInfo(String name, String value)

This constructs a DriverPropertyInfo object, giving it a name and a value.

Parameters:

name: | The name of the property
value: | The value of the property


Interface ParameterMetaData

public interface ParameterMetaData

ParameterMetaData provides information about the parameters of PreparedStatement and CallableStatement objects. The type of the parameter and various properties are available.

Fields

parameterNoNulls

public static final int parameterNoNulls

This is a constant for parameters that don’t allow NULL values.

parameterNullable

public static final int parameterNullable

This is a constant for parameters that allow NULL values.

parameterNullableUnknown

public static final int parameterNullableUnknown

This is a constant for parameters whose nullability isn’t known.

Methods

getParameterClassName

public String getParameterClassName(int param) throws SQLException

This gets the name of the Java class whose instances should be passed to the setObject() method of the PreparedStatement or CallableStatement.

Parameters:

param:

The parameter index begins at 1.

Returns: The name of the Java class that will be used by the method PreparedStatement.setObject() or CallableStatement.setObject() to set the value in the specified parameter. This is the class name used for custom mapping. A SQLException is thrown if an error occurs while accessing this value.

getParameterCount

public int getParameterCount() throws SQLException

This returns the number of parameters for the PreparedStatement or CallableStatement to which the ParameterMetaData object belongs.

Returns: The number of parameters. A SQLException is thrown if an error occurs while accessing this value.

getParameterType

public int getParameterType(int param) throws SQLException

This gets the SQL type of the parameter.

Parameters:

param:

The parameter index begins at 1.

Returns: The SQL type from java.sql.Types; a SQLException is thrown if an error occurs while accessing this value.

getParameterTypeName

public String getParameterTypeName(int param) throws SQLException

This gets the database-specific name for a parameter.

Parameters:

param:

The parameter index begins at 1.

Returns: The database-specific type name. If the parameter type is a user-defined type, a fully qualified type name is returned. A SQLException is thrown if an error occurs while accessing this value.

getPrecision

public int getPrecision(int param) throws SQLException

This gets the number of decimal digits for the parameter.

Parameters:

param:

The parameter index begins at 1.

Returns: The precision for this parameter. A SQLException is thrown if an error occurs while accessing this value.

getScale

public int getScale(int param) throws SQLException

This gets the number of digits to the right of the decimal point for the parameter.

Parameters:

param:

The parameter index begins at 1.

Returns: The scale of the parameter. A SQLException is thrown if an error occurs while accessing this value.

isNullable

public int isNullable(int param) throws SQLException

This checks whether the parameter can be set to null.

Parameters:

param:

The parameter index begins at 1.

Returns: The nullability for the given parameter, which is one of the following:

  • parameterNoNulls

  • parameterNullable

  • parameterNullableUnknown

A SQLException is thrown if an error occurs while accessing this value.

isSigned

public boolean isSigned(int param) throws SQLException

This checks whether the parameter value can be a signed number.

Parameters:

param:

The parameter index begins at 1.

Returns: true if the parameter can be a signed number; false otherwise. A SQLException is thrown if an error occurs while accessing this value.


Interface PreparedStatement

public interface PreparedStatement
extends Object
extends Statement

SQL statements can be precompiled by the database and executed with different parameters as many times as you want. setXXX methods are used to set IN param-eter values. They must specify types compatible with the defined SQL type of the input parameter. Arbitrary parameter type conversions are allowed, but then you should use the setObject method with a SQL type to specify the target type.

See also: prepareStatement, ResultSet

Methods

addBatch

public void addBatch() throws SQLException

This method adds a set of parameters to the PreparedStatement’s batch of SQL commands.

clearParameters

public void clearParameters() throws SQLException

clearParameters() immediately releases the resources used by the current param-eter values. Parameter values aren’t automatically cleared after the execution of a PreparedStatement, so they can be used for repeated use.

Returns: Nothing

execute

public boolean execute() throws SQLException

This method executes the statement with the IN parameter values just set, if any. Note that execute is normally used for prepared statements that return multiple results.

Returns: true if the next result is a ResultSet; false if it is an update count or there is no more result

See also: execute

executeQuery

public ResultSet executeQuery() throws SQLException

executeQuery() is used to execute prepared SQL queries (SELECT only). It returns a ResultSet.

Returns: A ResultSet that contains the data produced by the query; never null

executeUpdate

public int executeUpdate() throws SQLException

executeUpdate is used to execute a SQL INSERT, UPDATE, or DELETE statement. It also supports SQL statements that return nothing, such as SQL DDL.

Returns: The number of rows affected for INSERT, UPDATE, or DELETE or 0 for SQL statements that return nothing

getMetaData

public ResultSetMetaData getMetaData() throws SQLException

This gets the number, types, and properties of a ResultSet’s columns.

Returns: The metadata of a ResultSet

getParameterMetaData

public ParameterMetaData getParameterMetaData() throws SQLException

This gets the number, types, and properties of a PreparedStatement object’s parameters.

Returns: The ParameterMetaData object that contains information about the number, types, and properties of the PreparedStatement parameters

setArray

public void setArray(int parameterIndex, Array x) throws SQLException

This sets the parameter to the given Array object.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The Array object that maps a SQL ARRAY value.

setAsciiStream

public void setAsciiStream(int parameterIndex, InputStream x, int length)
throws SQLException

setAsciiStream() is used to set very large LONGVARCHAR parameters. You can send the ASCII data using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file). ASCII characters are converted to the database CHAR format.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The ASCII data stream.
length: | The data length in bytes.

setBigDecimal

public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException

This supplies a java.math.BigDecimal value that will be converted to a SQL NUMERIC value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setBinaryStream

public void setBinaryStream(int parameterIndex, InputStream x, int length)
throws SQLException

setBinaryStream() is used to set very large LONGVARBINARY parameters. You can send the binary data using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file).

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The binary data stream.
length: | The data length in bytes.

setBlob

public void setBlob(int parameterIndex, Blob x) throws SQLException

This sets the parameter to the given Blob object.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | A Blob object that maps a SQL BLOB value

setBoolean

public void setBoolean(int parameterIndex, boolean x) throws SQLException

This supplies a Java boolean value that is converted to a SQL BIT value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setByte

public void setByte(int parameterIndex, byte x) throws SQLException

This supplies a Java byte value that is converted to a SQL TINYINT value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setBytes

public void setBytes(int parameterIndex, byte x[]) throws SQLException

This supplies a Java array of bytes that is converted to a SQL VARBINARY or LONGVARBINARY when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setCharacterStream

public void setCharacterStream(int parameterIndex, java.io.Reader reader,
int length) throws SQLException

This sets a Unicode character stream to the designated parameter.

Parameters:

parameterIndex: | The parameter index begins at 1.
reader: | The java.io.Reader object containing the Unicode data.
length: | The number of characters in the stream.

setClob

public void setClob(int parameterIndex, Clob x) throws SQLException

This sets the parameter to the given Clob object.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The Clob object that maps a SQL CLOB value.

setDate

public void setDate(int parameterIndex, Date x) throws SQLException

This supplies a java.sql.Date value that is converted to a SQL DATE value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setDate

public void setDate(int parameterIndex, Date x, java.util.Calendar cal)
throws SQLException

This supplies a java.sql.Date value that is converted to a SQL DATE value when sent to the database using the Calendar object provided as a parameter.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.
cal: | The Calendar object the driver will use to construct the date.

setDouble

public void setDouble(int parameterIndex, double x) throws SQLException

This supplies a Java double value that is converted to a SQL DOUBLE value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setFloat

public void setFloat(int parameterIndex, float x) throws SQLException

This supplies a Java float value that is converted to a SQL FLOAT value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setInt

public void setInt(int parameterIndex, int x) throws SQLException

This supplies a Java int value that is converted to a SQL INTEGER value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setLong

public void setLong(int parameterIndex, long x) throws SQLException

This supplies a Java long value that is converted to a SQL BIGINT value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setNull

public void setNull(int parameterIndex, int sqlType) throws SQLException

This supplies a SQL NULL value. The parameter’s SQL type must be supplied.

Parameters:

parameterIndex: | The parameter index begins at 1.
sqlType: | A SQL type code (see java.sql.Types).

setNull

public void setNull(int paramIndex, int sqlType, String typeName)
throws SQLException

This supplies a SQL NULL value. The parameter’s SQL type must be supplied as well as the fully qualified SQL Type name for greater portability.

Parameters:

paramIndex: | The parameter index begins at 1.
sqlType: | A value from java.sql.Types.
typeName: | The fully qualified name of a SQL user-defined type. It is ignored if the parameter isn’t a user-defined type or REF type.

setObject

public void setObject(int parameterIndex, Object x,int targetSqlType,
int scale) throws SQLException

This supplies a parameter value using an object that is converted to the targetSqlType when sent to the database. Data types can be passed using a driver-specific Java type and using java.sql.types.OTHER as targetSqlType.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The object containing the input parameter value.
targetSqlType: | A SQL type code (see java.sql.Types).
scale: | The number of digits after the decimal for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types. Ignored for other types

See also: Types

setObject

public void setObject(int parameterIndex, Object x, int targetSqlType)
throws SQLException

This is the same as setObject(int parameterIndex, Object x,int targetSqlType, int scale) but assumes a scale of zero.

setObject

public void setObject(int parameterIndex, Object x) throws SQLException

This is the same as setObject(int parameterIndex, Object x,int targetSqlType, int scale) but uses the standard mapping from Java Object types to SQL types.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The object containing the input parameter value.

setRef

public void setRef(int parameterIndex, Ref x) throws SQLException

This sets the parameter to the given REF value.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | A SQL REF value.

setShort

public void setShort(int parameterIndex, short x) throws SQLException

This supplies a Java short value that is converted to a SQL SMALLINT value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setString

public void setString(int parameterIndex, String x) throws SQLException

This supplies a Java String value that is converted to a SQL VARCHAR or LONGVARCHAR value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setTime

public void setTime(int parameterIndex, Time x) throws SQLException

This supplies a java.sql.Time value that is converted to a SQL TIME value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setTime

public void setTime(int parameterIndex, Time x, java.util.Calendar cal)
throws SQLException

This supplies a java.sql.Time value that is converted to a SQL TIME value when sent to the database using the Calendar object provided as a parameter.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.
cal: | The Calendar object the driver will use to construct the time.

setTimestamp

public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException

This supplies a java.sql.Timestamp value that is converted to a SQL TIMESTAMP value when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.

setTimestamp

public void setTimestamp(int parameterIndex, Timestamp x, java.util.Calendar cal)
throws SQLException

This supplies a java.sql.Timestamp value that is converted to a SQL TIMESTAMP value when sent to the database using the Calendar object provided as a parameter.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.
cal: | The Calendar object the driver will use to construct the timestamp.

setUnicodeStream

public void setUnicodeStream(int parameterIndex, InputStream x,int length)
throws SQLException

setUnicodeStream() is used to set very large LONGVARCHAR parameters. You can send the Unicode data using a java.io.inputStream. JDBC stops sending data when it reaches EOF (end of file). Unicode characters are converted to the database CHAR format.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The unicode data stream.
length: | The data length in bytes.

setURL

public void setURL(int parameterIndex, java.net.URL x) throws SQLException

This sets the parameter to a java.net.URL value. This value is converted to a SQL DATALINK when sent to the database.

Parameters:

parameterIndex: | The parameter index begins at 1.
x: | The parameter value.


Interface Ref

public interface Ref

The Ref interface represents a database structured type value_—_that is, a SQL REF value. Like SQL REF, a Ref is a logical pointer to the SQL structured type in the database. Retrieving a Ref doesn’t retrieve all the attributes of the structured type.

Methods

getBaseTypeName

public String getBaseTypeName() throws SQLException

This gets the SQL name of the SQL structured type that the Ref object references.

Returns: The SQL name of the referenced SQL structured type. A SQLException is thrown if an error occurs while accessing this value.

getValue

public Object getValue(java.util.Map map) throws SQLException

This gets the referenced object and maps it to a Java type using the type map. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

map:

A java.util.Map object containing the mapping to use

Returns: The object referenced by Ref mapped to a Java class

getValue

public Object getValue() throws SQLException

This gets the referenced object and maps it to a Java type using the type map of the current connection, if available, or to a Struct object if no mapping is provided for this type. A SQLException is thrown if an error occurs while accessing this value.

Returns: The object referenced by Ref mapped to a Java class

setValue

public void setValue(Object value) throws SQLException

This sets the value referenced by the Ref. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

value:

The object to be set


Interface ResultSet

public interface ResultSet
extends Object

SQL queries and many DatabaseMetaData methods return rows of data in ResultSet objects. Such rows must be retrieved in sequence using the ResultSet methods. The next() method is used to scroll through the rows. A ResultSet maintains a cursor pointing to its current row of data. The cursor is initially positioned before the first row. The next method moves the cursor to the next row.

Column values must also be retrieved one by one. The getXXX methods make it possible to access these columns either using the index number of the column or the name of the column (which is case insensitive). Using the column index is the most efficient. Note that the first column is numbered 1. The column values must be retrieved from left to right and only once per column.

See also: executeQuery, getResultSet, ResultSetMetaData

Fields

FETCH_FORWARD

public static final int FETCH_FORWARD

This is a constant for use with setFetchDirection() in order to go forward when fetching results.

FETCH_REVERSE

public static final int FETCH_REVERSE

This is a constant for use with setFetchDirection() in order to go backward when fetching results.

FETCH_UNKNOWN

public static final int FETCH_UNKNOWN

This is a constant for use with setFetchDirection() in order to use the default fetch direction.

TYPE_FORWARD_ONLY

public static final int TYPE_FORWARD_ONLY

This is a constant to specify a move forward cursor.

TYPE_SCROLL_INSENSITIVE

public static final int TYPE_SCROLL_INSENSITIVE

This is a type for a ResultSet object that is scrollable but not sensitive to changes made by others.

TYPE_SCROLL_SENSITIVE

public static final int TYPE_SCROLL_SENSITIVE

This is a type for a ResultSet object that is scrollable and sensitive to changes made by others.

CONCUR_READ_ONLY

public static final int CONCUR_READ_ONLY

This is a concurrency mode for a ResultSet object that can’t be updated.

CONCUR_UPDATABLE

public static final int CONCUR_UPDATABLE

This is a concurrency mode for a ResultSet object that can be updated.

HOLD_CURSORS_OVER_COMMIT

public static final int HOLD_CURSORS_OVER_COMMIT

This indicates that ResultSet objects shouldn’t be closed when the commit is called.

CLOSE_CURSORS_AT_COMMIT

public static final int CLOSE_CURSORS_AT_COMMIT

This indicates that ResultSet objects should be closed at commit time.

Methods

absolute

public boolean absolute(int row) throws SQLException

This moves the cursor to the given row number in the ResultSet object. Negative values are used to position the cursor from the end of the ResultSet.

Parameters:

row:

The number of the row to which the cursor should move

Returns: true if the cursor is on the result set; false otherwise

afterLast

public void afterLast() throws SQLException

This moves the cursor after the last row of the ResultSet object.

beforeFirst

public void beforeFirst() throws SQLException

This moves the cursor before the first row of the ResultSet object.

cancelRowUpdates

public void cancelRowUpdates() throws SQLException

This cancels the updates made to the current row in the ResultSet object. A SQLException is thrown if the cursor is on the insert row.

clearWarnings

public void clearWarnings() throws SQLException

This clears all SQLWarnings. getWarning() returns null after a clearWarning().

close

public void close() throws SQLException

This releases all resources associated with the ResultSet. Normally, a ResultSet is automatically closed by the Statement that generated it when that Statement is closed, reexecuted, or used to retrieve the next result from a sequence of multiple results. The garbage collector also closes ResultSets when they are no longer used.

deleteRow

public void deleteRow() throws SQLException

This deletes the current row from the ResultSet object and from the database. This method cannot be called when the cursor is on the insert row, or a SQLException will be thrown.

findColumn

public int findColumn(String columnName) throws SQLException

This returns the column index from its column name.

Parameters:

columnName:

The name of the column

Returns: The column index

first

public void first() throws SQLException

This moves the cursor to the first row of the ResultSet object.

getArray

public Array getArray(int columnIndex) throws SQLException

This gets the value of the column as an Array object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: An Array object

getArray

public Array getArray(String columnName) throws SQLException

This gets the value of the column as an Array object.

Parameters:

columnName:

The name of the column

Returns: An Array object

getAsciiStream

public InputStream getAsciiStream(int columnIndex) throws SQLException

This method can be used to retrieve large LONGVARCHAR values. If necessary, the JDBC driver converts the data from database format to ASCII.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Java input stream; if the value is SQL NULL, the result is null.

getAsciiStream

public InputStream getAsciiStream(String columnName) throws SQLException

This method can be used to retrieve large LONGVARCHAR values. If necessary, the JDBC driver converts the data from database format to ASCII.

Parameters:

columnName:

The name of the column

Returns: A Java input stream; if the value is SQL NULL, the result is null.

getBigDecimal

public BigDecimal getBigDecimal(int columnIndex) throws SQLException

This gets the value of a column as a java.math.BigDecimal object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is null.

getBigDecimal

public BigDecimal getBigDecimal(String columnName) throws SQLException

This gets the value of a column as a java.math.BigDecimal object.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getBigDecimal

public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException

This gets the value of a column as a java.math.BigDecimal object.

Parameters:

columnIndex: | The column index begins at 1.
scale: | The number of digits to the right of the decimal.

Returns: The column value; if the value is SQL NULL, the result is null.

getBigDecimal

public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException

This gets the value of a column as a java.math.BigDecimal object.

Parameters:

columnName: | The name of the column
scale: | The number of digits to the right of the decimal point

Returns: The column value; if the value is SQL NULL, the result is null.

getBinaryStream

public InputStream getBinaryStream(int columnIndex) throws SQLException

This method can be used to retrieve large LONGVARBINARY values.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, the result is null.

getBinaryStream

public InputStream getBinaryStream(String columnName) throws SQLException

This method can be used to retrieve large LONGVARBINARY values.

Parameters:

columnName:

The name of the column

Returns: A Java input stream that delivers the database column value as a stream of uninterpreted bytes. If the value is SQL NULL, the result is null.

getBlob

public Blob getBlob(int columnIndex) throws SQLException

This gets the value of the column as a Blob object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Blob object

getBlob

public Blob getBlob(String columnName) throws SQLException

This gets the value of the column as a Blob object.

Parameters:

columnName:

The name of the column

Returns: A Blob object

getBoolean

public boolean getBoolean(int columnIndex) throws SQLException

This gets the value of a column as a Java boolean.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is false.

getBoolean

public boolean getBoolean(String columnName) throws SQLException

This gets the value of a column as a Java boolean.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is false.

getByte

public byte getByte(int columnIndex) throws SQLException

This gets the value of a column as a Java byte.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getByte

public byte getByte(String columnName) throws SQLException

This gets the value of a column as a Java byte.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getBytes

public byte[] getBytes(int columnIndex) throws SQLException

This gets the value of a column as an array of Java bytes representing the raw values returned by the driver.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is null.

getBytes

public byte[] getBytes(String columnName) throws SQLException

This gets the value of a column as an array of Java bytes representing the raw values returned by the driver.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getCharacterStream

public Reader getCharacterStream(int columnIndex) throws SQLException

This method can be used to retrieve large LONGVARCHAR values.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Java input stream that delivers the database column value as a stream of characters; if the value is SQL NULL, the result is null.

getCharacterStream

public Reader getCharacterStream(String columnName) throws SQLException

This method can be used to retrieve large LONGVARCHAR values.

Parameters:

columnName:

The name of the column

Returns: A Java input stream that delivers the database column value as a stream of characters; if the value is SQL NULL, the result is null.

getClob

public Clob getClob(int columnIndex) throws SQLException

This gets the value of the column as a Clob object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Clob object

getClob

public Clob getClob(String columnName) throws SQLException

This gets the value of the column as a Clob object.

Parameters:

columnName:

The name of the column

Returns: A Clob object

getConcurrency

public int getConcurrency() throws SQLException

This gets the concurrency mode of the ResultSet object.

Returns: One of the following:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

getCursorName

public String getCursorName() throws SQLException

JDBC supports positioned updates and positioned deletes. This method returns the name of the current SQL cursor used for the ResultSet.

Returns: The ResultSet’s SQL cursor name

getDate

public Date getDate(int columnIndex) throws SQLException

This gets the value of a column as a java.sql.Date object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is null.

getDate

public Date getDate(String columnName) throws SQLException

This gets the value of a column as a java.sql.Date object.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getDate

public Date getDate(int columnIndex, java.util.Calendar cal) throws SQLException

This gets the value of a column as a java.sql.Date object.

Parameters:

columnIndex: | The column index begins at 1.
cal: | The calendar object used to build the date object.

Returns: The column value; if the value is SQL NULL, the result is null.

getDate

public Date getDate(String columnName, java.util.Calendar cal) throws SQLException

This gets the value of a column as a java.sql.Date object.

Parameters:

columnName: | The name of the column
cal: | The calendar object used to build the date object

Returns: The column value; if the value is SQL NULL, the result is null.

getDouble

public double getDouble(int columnIndex) throws SQLException

This gets the value of a column as a Java double.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getDouble

public double getDouble(String columnName) throws SQLException

This gets the value of a column as a Java double.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getFetchDirection

public int getFetchDirection() throws SQLException

This returns the fetch direction for the ResultSet object.

Returns: The current fetch direction

getFetchSize

public int getFetchSize() throws SQLException

This gets the fetch size for the ResultSet object.

Returns: The current fetch size

getFloat

public float getFloat(int columnIndex) throws SQLException

This gets the value of a column as a Java float.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getFloat

public float getFloat(String columnName) throws SQLException

This gets the value of a column as a Java float.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getInt

public int getInt(int columnIndex) throws SQLException

This gets the value of a column as a Java int.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getInt

public int getInt(String columnName) throws SQLException

This gets the value of a column as a Java int.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getLong

public long getLong(int columnIndex) throws SQLException

This gets the value of a column as a Java long.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getLong

public long getLong(String columnName) throws SQLException

This gets the value of a column as a Java long.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getMetaData

public ResultSetMetaData getMetaData() throws SQLException

A ResultSetMetaData object dynamically provides information regarding a ResultSet. This method returns such an object. It is useful, for example, for getting the number of columns and their types from a ResultSet.

Returns: A ResultSetMetaData object

getObject

public Object getObject(int columnIndex) throws SQLException

This gets the value of a column as a Java object. The type of the Java object is the Java object type corresponding to the column’s SQL type according to standard JDBC type mapping. It can also be used to read database-specific data types.

Parameters:

columnIndex:

The column index begins at 1.

Returns: An Object holding the column value

getObject

public Object getObject(String columnName) throws SQLException

This gets the value of a column as a Java object. The type of the Java object is the Java object type corresponding to the column’s SQL type according to the standard JDBC type mapping. It can also be used to read database-specific data types.

Parameters:

columnName:

The name of the column

Returns: An Object holding the column value

getObject

public Object getObject(int columnIndex, java.util.Map map)
throws SQLException

This gets the value of the column as an Object.

Parameters:

columnIndex: | The column index begins at 1.
map: | The type map used to access this column.

Returns: An Object holding the column value

getObject

public Object getObject(String columnName, java.util.Map map)
throws SQLException

This gets the value of the column as an Object.

Parameters:

columnName: | The name of the column
map: | The type map used to access this column

Returns: An Object holding the column value

getRef

public Ref getRef(int columnIndex) throws SQLException

This gets the value of the column as a Ref object.

Parameters:

columnIndex:

The index of the column begins at 1.

Returns: A Ref object

getRef

public Ref getRef(String columnName) throws SQLException

This gets the value of the column as a Ref object.

Parameters:

columnName:

The name of the column

Returns: A Ref object

getRow

public int getRow() throws SQLException

This returns the current row number, starting at 1.

Returns: The current row number; 0 if there is no current row

getShort

public short getShort(int columnIndex) throws SQLException

This gets the value of a column as a Java short.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getShort

public short getShort(String columnName) throws SQLException

This gets the value of a column as a Java short.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is 0.

getStatement

public Statement getStatement() throws SQLException

This gets the Statement object that produced the ResultSet object.

Returns: The Statement object that produced this ResultSet object or null if there was no Statement.

getString

public String getString(int columnIndex) throws SQLException

This gets the value of a column as a Java String.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is 0.

getString

public String getString(String columnName) throws SQLException

This gets the value of a column as a Java String.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getTime

public Time getTime(int columnIndex) throws SQLException

This gets the value of a column as a java.sql.Time object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is null.

getTime

public Time getTime(String columnName) throws SQLException

This gets the value of a column as a java.sql.Time object.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getTime

public Time getTime(int columnIndex, java.util.Calendar cal) throws SQLException

This gets the value of a column as a java.sql.Time object.

Parameters:

columnIndex:

The column index begins at 1.

cal: The calendar object used to build the date object.

Returns: The column value; if the value is SQL NULL, the result is null.

getTime

public Time getTime(String columnName, java.util.Calendar cal) throws SQLException

This gets the value of a column as a java.sql.Time object.

Parameters:

columnName: | The name of the column
cal: | The calendar object used to build the date object

Returns: The column value; if the value is SQL NULL, the result is null.

getTimestamp

public Timestamp getTimestamp(int columnIndex) throws SQLException

This gets the value of a column as a java.sql.Timestamp object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value; if the value is SQL NULL, the result is null.

getTimestamp

public Timestamp getTimestamp(String columnName) throws SQLException

This gets the value of a column as a java.sql.Timestamp object.

Parameters:

columnName:

The name of the column

Returns: The column value; if the value is SQL NULL, the result is null.

getTimestamp

public Timestamp getTimestamp(int columnIndex, java.util.Calendar cal)
throws SQLException

This gets the value of a column as a java.sql.Timestamp object.

Parameters:

columnIndex: | The column index begins at 1.
cal: | The calendar object used to build the date object.

Returns: The column value; if the value is SQL NULL, the result is null.

getTimestamp

public Timestamp getTimestamp(String columnName, java.util.Calendar cal)
throws SQLException

This gets the value of a column as a java.sql.Timestamp object.

Parameters:

columnName: | The name of the column
cal: | The calendar object used to build the date object

Returns: The column value; if the value is SQL NULL, the result is null.

getType

public int getType() throws SQLException

This gets the type of the ResultSet object.

Returns: One of the following:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

getUnicodeStream

public InputStream getUnicodeStream(int columnIndex) throws SQLException

This method can be used to retrieve large LONGVARCHAR values. If necessary, the JDBC driver converts the data from database format to Unicode.

Parameters:

columnIndex:

The column index begins at 1.

Returns: A Java input stream; if the value is SQL NULL, the result is null.

getUnicodeStream

public InputStream getUnicodeStream(String columnName)throws SQLException

This method can be used to retrieve large LONGVARCHAR values. If necessary, the JDBC driver converts the data from database format to Unicode.

Parameters:

columnName:

The name of the column

Returns: A Java input stream representing the column value; if the value is SQL NULL, the result is null.

getURL

public java.net.URL getURL(int columnIndex) throws SQLException,
java.net.MalformedURLException

This returns the value of the column in the current row as a java.net.URL object.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column value as a java.net.URL object or null if the value is SQL NULL

getURL

public java.net.URL getURL(String columnName) throws SQLException,
java.net.MalformedURLException

This returns the value of the column in the current row as a java.net.URL object.

Parameters:

columnName:

The column name

Returns: The column value as a java.net.URL object or null if the value is SQL NULL

getWarnings

public SQLWarning getWarnings() throws SQLException

This gets the first warning reported by calls on the current ResultSet. The next warnings are chained to the SQLWarning and are automatically cleared each time a new row is read.

Returns: The first SQLWarning or null

insertRow

public void insertRow() throws SQLException

This inserts the contents of the insert row in the ResultSet object and database. The cursor must be on the insert row when this method is called. A SQLException occurs

if there is a database error, if the cursor isn’t on the insert row, or if values are missing for some columns.

isAfterLast

public boolean isAfterLast() throws SQLException

This checks whether the cursor is after the last row in the ResultSet object.

Returns: true if the cursor is after the last row

isBeforeFirst

public boolean isBeforeFirst() throws SQLException

This checks whether the cursor is before the first row in the ResultSet object.

Returns: true if the cursor is before the first row

isFirst

public boolean isFirst() throws SQLException

This checks whether the cursor is on the first row in the ResultSet object.

Returns: true if the cursor is on the first row

isLast

public boolean isLast() throws SQLException

This checks whether the cursor is on the last row in the ResultSet object.

Returns: true if the cursor is on the last row

last

public void last() throws SQLException

This moves the cursor to the last row of the ResultSet object.

moveToCurrentRow

public void moveToCurrentRow() throws SQLException

This moves the cursor to the remembered cursor position. A SQLException is thrown if a database access error occurs or the result set isn’t updatable.

moveToInsertRow

public void moveToInsertRow() throws SQLException

This moves the cursor to the insert row. A SQLException is thrown if a database access error occurs or the result set isn’t updatable.

next

public boolean next() throws SQLException

This method is used to scan a ResultSet’s rows. The first call to this method makes the first row the current row, the second call makes the second row the current row, and so on. Note that the next() method automatically closes input streams used in conjunction with the getXXXStream() methods and clears the warning chain of the ResultSet.

Returns: true if the new current row is valid; false when there are no more rows

previous

public boolean previous() throws SQLException

This moves the cursor to the previous row in the ResultSet object.

Returns: true if the cursor is on a valid row; false if it is off the result set

refreshRow

public void refreshRow() throws SQLException

This refreshes the current row with its most recent value in the database. This method can’t be called when the cursor is on the insert row, or a SQLException will be thrown.

relative

public boolean relative(int row) throws SQLException

This moves the cursor to a relative number of rows in the ResultSet object. Negative values are used to position backward.

Parameters:

row:

The number of the rows to move from the current row

Returns: true if the cursor is on the result set; false otherwise

rowDeleted

public boolean rowDeleted() throws SQLException

This checks whether a row has been deleted.

Returns: true if a row has been deleted

rowInserted

public boolean rowInserted() throws SQLException

This checks whether the current row has been just inserted.

Returns: true if the row has been inserted

rowUpdated

public boolean rowUpdated() throws SQLException

This checks whether the current row has been updated.

Returns: true if the row has been updated

setFetchDirection

public void setFetchDirection(int direction) throws SQLException

This specifies the direction in which the rows in the ResultSet object will be processed.

Parameters:

direction:

An int specifying one of the following suggested fetch directions:

  • ResultSet.FETCH_FORWARD

  • ResultSet.FETCH_REVERSE

  • ResultSet.FETCH_UNKNOWN

Throws:

SQLException:

If a database access error occurs or the result set type is TYPE_FORWARD_ONLY and the fetch direction isn’t FETCH_FORWARD

setFetchSize

public void setFetchSize(int rows) throws SQLException

This sets the number of rows that should be fetched from the database when more rows are needed for the ResultSet object.

Parameters:

rows:

The number of rows to fetch

updateArray

public void updateArray(int columnIndex, Array x) throws SQLException

This updates the column with a java.sql.Array value.

Parameters:

columnIndex: | The columnIndex begins at 1.
x: | The new column value.

updateArray

public void updateArray(String columnName, Array x) throws SQLException

This updates the column with a java.sql.Array value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateAsciiStream

public void updateAsciiStream(int columnIndex, java.io.InputStream x,  int length)
throws SQLException

This updates the column with an ASCII stream value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.
length: | The length of the stream.

updateAsciiStream

public void updateAsciiStream(String columnName, java.io.InputStream x,
int length) throws SQLException

This updates the column with an ASCII stream value.

Parameters:

columnName: | The name of the column
x: | The new column value
length: | The length of the stream

updateBigDecimal

public void updateBigDecimal(int columnIndex, java.math.BigDecimal x)
throws SQLException

This updates the column with a java.math.BigDecimal value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateBigDecimal

public void updateBigDecimal(String columnName, java.math.BigDecimal x)
throws SQLException

This updates the column with a java.sql.BigDecimal value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateBinaryStream

public void updateBinaryStream(int columnIndex, java.io.InputStream x, int length)
throws SQLException

This updates the column with a binary stream value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.
length: | The length of the stream.

updateBinaryStream

public void updateBinaryStream(String columnName, java.io.InputStream x,
int length) throws SQLException

This updates the column with a binary stream value.

Parameters:

columnName: | The name of the column
x: | The new column value
length: | The length of the stream

updateBlob

public void updateBlob(int columnIndex, Blob x) throws SQLException

This updates the column with a java.sql.Blob value.

Parameters:

columnIndex: | The columnIndex begins at 1.
x: | The new column value.

updateBlob

public void updateBlob(String columnName, Blob x) throws SQLException

This updates the column with a java.sql.Blob value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateBoolean

public void updateBoolean(int columnIndex, boolean x) throws SQLException

This updates the column with a boolean value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateBoolean

public void updateBoolean(String columnName, boolean x)
throws SQLException

This updates the column with a boolean value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateByte

public void updateByte(int columnIndex, byte x) throws SQLException

This updates the column with a byte value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateByte

public void updateByte(String columnName, byte x) throws SQLException

This updates the column with a byte value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateBytes

public void updateBytes(int columnIndex, byte[] x) throws SQLException

This updates the column with a byte array value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateBytes

public void updateBytes(String columnName, byte[] x) throws SQLException

This updates the column with a byte array value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateCharacterStream

public void updateCharacterStream(int columnIndex, java.io.Reader x, int length)
throws SQLException

This updates the column with a character stream value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.
length: | The length of the stream.

updateCharacterStream

public void updateCharacterStream(String columnName,
java.io.Reader reader, int length) throws SQLException

This updates the column with a character stream value.

Parameters:

columnName: | The name of the column
reader: | The java.io.Reader object containing the new column value
length: | The length of the stream

updateClob

public void updateClob(int columnIndex, Clob x) throws SQLException

This updates the column with a java.sql.Clob value.

Parameters:

columnIndex: | The columnIndex begins at 1.
x: | The new column value.

updateClob

public void updateClob(String columnName, Clob x) throws SQLException

This updates the column with a java.sql.Clob value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateDate

public void updateDate(int columnIndex, Date x) throws SQLException

This updates the column with a java.sql.Date value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateDate

public void updateDate(String columnName, Date x) throws SQLException

This updates the column with a java.sql.Date value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateDouble

public void updateDouble(int columnIndex, double x) throws SQLException

This updates the designated column with a double value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateDouble

public void updateDouble(String columnName, double x)
throws SQLException

This updates the column with a double value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateFloat

public void updateFloat(int columnIndex, float x) throws SQLException

This updates the column with a float value.

Parameters:

columnIndex:

The column index begins at 1.

updateFloat

public void updateFloat(String columnName, float x) throws SQLException

This updates the column with a float value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateInt

public void updateInt(int columnIndex, int x) throws SQLException

This updates the column with an int value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateInt

public void updateInt(String columnName, int x) throws SQLException

This updates the column with an int value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateLong

public void updateLong(int columnIndex, long x) throws SQLException

This updates the column with a long value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateLong

public void updateLong(String columnName, long x) throws SQLException

This updates the column with a long value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateNull

public void updateNull(int columnIndex) throws SQLException

This updates the column with a null value.

Parameters:

columnIndex:

The column index begins at 1.

updateNull

public void updateNull(String columnName) throws SQLException

This updates the column with a null value.

Parameters:

columnName:

The name of the column

updateObject

public void updateObject(int columnIndex, Object x) throws SQLException

This updates the column with an Object value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateObject

public void updateObject(String columnName, Object x)
throws SQLException

This updates the column with an Object value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateObject

public void updateObject(int columnIndex, Object x, int scale)
throws SQLException

This updates the column with an Object value.

Parameters:

columnIndex: The column index begins at 1.

x:

The new column value.

scale:

The number of digits after the decimal point for the following:

  • java.sql.Types.DECIMAL

  • java.sql.Types.NUMERIC

updateObject

public void updateObject(String columnName, Object x,
int scale) throws SQLException

This updates the column with an Object value.

Parameters:

columnName:

The name of the column

x:

The new column value

scale:

The number of digits after the decimal point for the following:

  • java.sql.Types.DECIMAL

  • java.sql.Types.NUMERIC

updateRow

public void updateRow() throws SQLException

This updates the underlying database with the new contents of the current row of the ResultSet object. This method can’t be called when the cursor is on the insert row, or a SQLException will be thrown.

updateRef

public void updateRef(int columnIndex, Ref x) throws SQLException

This updates the column with a java.sql.Ref value.

Parameters:

columnIndex: | The columnIndex begins at 1.
x: | The new column value.

updateRef

public void updateRef(String columnName, Ref x) throws SQLException

This updates the column with a java.sql.Ref value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateShort

public void updateShort(int columnIndex, short x) throws SQLException

This updates the column with a short value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateShort

public void updateShort(String columnName, short x) throws SQLException

This updates the column with a short value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateString

public void updateString(int columnIndex, String x) throws SQLException

This updates the column with a String value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateString

public void updateString(String columnName, String x)
throws SQLException

This updates the column with a String value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateTime

public void updateTime(int columnIndex, Time x) throws SQLException

This updates the column with a java.sql.Time value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateTime

public void updateTime(String columnName, Time x) throws SQLException

This updates the column with a java.sql.Time value.

Parameters:

columnName: | The name of the column
x: | The new column value

updateTimestamp

public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException

This updates the column with a java.sql.Timestamp value.

Parameters:

columnIndex: | The column index begins at 1.
x: | The new column value.

updateTimestamp

public void updateTimestamp(String columnName, Timestamp x)
throws SQLException

This updates the column with a java.sql.Timestamp value.

Parameters:

columnName: | The name of the column
x: | The new column value

wasNull

public boolean wasNull() throws SQLException

If a column contains a SQL NULL value, this method returns true. wasNull() can’t be invoked before getting the column’s value with one of the getXXX() methods.

Returns: true if the last column read was SQL NULL


Interface ResultSetMetaData

public interface ResultSetMetaData
extends Object

All ResultSetMetaData methods return information related to ResultSets. You can use them to dynamically discover the characteristics of a ResultSet.

Fields

columnNoNulls

public static final int columnNoNulls

This specifies that NULL values aren’t allowed.

columnNullable

public static final int columnNullable

This specifies that NULL values are allowed.

columnNullableUnknown

public static final int columnNullableUnknown

This specifies that the nullability is unknown.

Methods

getCatalogName

public String getCatalogName(int column) throws SQLException

This gets the column’s table’s catalog name.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column name; "" if no catalog name available

getColumnClassName

public String getColumnClassName(int columnIndex) throws SQLException

This gets the fully qualified name of the Java class used by ResultSet. getObject() when retrieving the column value.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The fully qualified class name

getColumnCount

public int getColumnCount() throws SQLException

This gets the number of columns in the ResultSet.

Returns: The number

getColumnDisplaySize

public int getColumnDisplaySize(int column) throws SQLException

This gets the column’s normal maximum width in characters.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The maximum width

getColumnLabel

public String getColumnLabel(int column) throws SQLException

This gets the suggested column label.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The suggested column label

getColumnName

public String getColumnName(int column) throws SQLException

This gets a column’s name.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The column name

getColumnType

public int getColumnType(int column) throws SQLException

This gets a column’s SQL type.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The SQL type

See also: Types

getColumnTypeName

public String getColumnTypeName(int column) throws SQLException

This gets a column’s data source–specific type name.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The type name

getPrecision

public int getPrecision(int column) throws SQLException

This gets a column’s number of decimal digits.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The precision

getScale

public int getScale(int column) throws SQLException

This gets a column’s number of digits to right of decimal.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The scale

getSchemaName

public String getSchemaName(int column) throws SQLException

This gets a column’s table schema.

Parameters:

columnIndex:

The column index begins at 1.

Returns: The schema name; "" if no schema name available

getTableName

public String getTableName(int column) throws SQLException

This gets a column’s table name.

Returns: The table name; "" if not available

isAutoIncrement

public boolean isAutoIncrement(int column) throws SQLException

This checks whether the column’s value is auto-incremented.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is auto-incremented

isCaseSensitive

public boolean isCaseSensitive(int column) throws SQLException

This checks whether a column is case sensitive.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is case sensitive

isCurrency

public boolean isCurrency(int column) throws SQLException

This checks whether the column is a currency value.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is a currency value

isDefinitelyWritable

public boolean isDefinitelyWritable(int column) throws SQLException

This checks whether an update of the column will definitely succeed.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is definitely writable

isNullable

public int isNullable(int column) throws SQLException

This checks whether the column can be set to SQL NULL.

Parameters:

columnIndex:

The column index begins at 1.

Returns: columnNoNulls, columnNullable, or columnNullableUnknown

isReadOnly

public boolean isReadOnly(int column) throws SQLException

This checks whether a column is definitely not writable.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is read-only

isSearchable

public boolean isSearchable(int column) throws SQLException

This checks whether the column can be used in a SQL WHERE clause.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is searchable

isSigned

public boolean isSigned(int column) throws SQLException

This checks whether the column is signed.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is signed

isWritable

public boolean isWritable(int column) throws SQLException

This checks whether a column’s value is possibly updatable.

Parameters:

columnIndex:

The column index begins at 1.

Returns: true if the column is writable


Interface Savepoint

public interface Savepoint

Savepoints are used to mark intermediate points within a transaction. After a savepoint has been set, the transaction can be rolled back to that savepoint without affecting preceding work.

Methods

getSavepointId

public int getSavepointId() throws SQLException

This gets the ID of the savepoint. A SQLException is thrown if the savepoint is named instead of being numbered.

Returns: The numeric ID of the savepoint

getSavepointName

public String getSavepointName() throws SQLException

This gets the name of the savepoint. A SQLException is thrown if the savepoint isn’t named but uses number IDs instead.

Returns: The name of the savepoint


Interface SQLData

public interface SQLData

This interface must be implemented by any Java class that is registered in a type mapping.

Methods

getSQLTypeName

public String getSQLTypeName() throws SQLException

This gets the fully qualified name of the user-defined type represented by the object.

Returns: The type name as used when the object was created. A SQLException is thrown if an error occurs while accessing this value.

readSQL

public void readSQL(SQLInput stream, String typeName)
throws SQLException

Reads values from the SQLInput stream and assigns values for all elements of the SQL type. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

stream: | The SQLInput object from which to read the data
typeName: | The SQL type name of the value on the data stream

writeSQL

public void writeSQL(SQLOutput stream) throws SQLException

This writes the value of the object to a SQLOutput stream, converting it back to its SQL value in the data source. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

stream:

The SQLOutput object to which to write the data


Class SQLException

public class SQLException
extends Exception

This type of exception is thrown when database access errors happen. The SQLExceptions are chained together.

Constructors

SQLException

public SQLException(String reason, String SQLState, int vendorCode)

This creates a SQLException object providing a reason, an XOPEN SQLState, and a vendor code.

Parameters:

reason: | A short message for the exception
SQLState: | An XOPEN code to identify the exception
vendorCode: | A database vendor exception code

SQLException

public SQLException(String reason, String SQLState)

This creates a SQLException object providing a reason and an XOPEN SQLState. The vendorCode is set to 0.

Parameters:

reason: | A short message for the exception
SQLState: | An XOPEN code to identify the exception

SQLException

public SQLException(String reason)

This creates a SQLException object providing a reason. The SQLState is set to null and the vendorCode is set to 0.

Parameters:

reason:

A short message for the exception

SQLException

public SQLException()

This creates a SQLException object without providing additional information. The message and the SQLState are set to null, and the vendorCode is set to 0.

Methods

getErrorCode

public int getErrorCode()

This gets the vendor code for the exception.

Returns: The vendorCode value for the exception

getNextException

public SQLException getNextException()

This gets the exception chained to the current exception.

Returns: The next SQLException

getSQLState

public String getSQLState()

This gets the SQLState for the exception.

Returns: The SQLState value for the exception

setNextException

public synchronized void setNextException(SQLException ex)

This adds a SQLExceptions.

Parameters:

ex:

A new SQLException


Interface SQLInput

public interface SQLInput

SQLInput is an input stream containing values of the elements of a SQL structured type or distinct type. This interface is used only for custom mapping by the JDBC driver.

Methods

readArray

public Array readArray() throws SQLException

This reads a SQL ARRAY value from the stream and returns it as an Array object.

Returns: The Array object or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readAsciiStream

public java.io.InputStream readAsciiStream() throws SQLException

This returns the next element in the stream as a stream of ASCII characters.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readBigDecimal

public java.math.BigDecimal readBigDecimal() throws SQLException

This reads the next element in the stream as a java.math.BigDecimal object.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readBinaryStream

public java.io.InputStream readBinaryStream() throws SQLException

This returns the next element in the stream as a stream of bytes.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readBlob

public Blob readBlob() throws SQLException

This reads a SQL BLOB value from the stream and returns it as a Blob object.

Returns: The Blob object or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readBoolean

public boolean readBoolean() throws SQLException

This reads the next element in the stream as a boolean.

Returns: The element or false if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readByte

public byte readByte() throws SQLException

This reads the next element in the stream as a byte.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readBytes

public byte[] readBytes() throws SQLException

This reads the next element in the stream as an array of bytes.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readCharacterStream

public java.io.Reader readCharacterStream() throws SQLException

This returns the next element in the stream as a stream of Unicode characters.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readClob

public Clob readClob() throws SQLException

This reads a SQL CLOB value from the stream and returns it as a Clob object.

Returns: The Clob object or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readDate

public Date readDate() throws SQLException

This reads the next element in the stream as a java.sql.Date object.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readDouble

public double readDouble() throws SQLException

This reads the next element in the stream as a double.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readFloat

public float readFloat() throws SQLException

This reads the next element in the stream as a float.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readInt

public int readInt() throws SQLException

This reads the next element in the stream as an int.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readLong

public long readLong() throws SQLException

This reads the next element in the stream as a long.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readObject

public Object readObject() throws SQLException

This returns the first element in the stream as a Java object. The runtime type of the object is set using the default type mapping and the type map of the stream.

Returns: The object or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readRef

public Ref readRef() throws SQLException

This reads a SQL REF value from the stream and returns it as a Ref object.

Returns: The Ref object or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readShort

public short readShort() throws SQLException

This reads the next element in the stream as a short.

Returns: The element or 0 if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readString

public String readString() throws SQLException

This reads the next element in the stream as a String.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readTime

public Time readTime() throws SQLException

This reads the next element in the stream as a java.sql.Time object.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readTimestamp

public Timestamp readTimestamp() throws SQLException

This reads the next element in the stream as a java.sql.Timestamp object.

Returns: The element or null if the value is SQL NULL. A SQLException is thrown if an error occurs while accessing this value.

readURL

public java.net.URL readURL() throws SQLException, java.net.MalformedURLException

This reads a SQL DATALINK from the stream and returns it as a java.net.URL object.

Returns: The java.net.URL object. A SQLException is thrown if an error occurs while accessing this value.

wasNull

public boolean wasNull() throws SQLException

This method checks if the last value read from the stream was a SQL NULL.

Returns: true if the value was SQL NULL. A SQLException is thrown if an error occurs while accessing this value.


Interface SQLOutput

public interface SQLOutput

SQLOutput is an output stream to which the elements of a user-defined type are written when this type has to be stored in the database. This interface is used only for custom mapping by the JDBC driver.

Methods

writeArray

public void writeArray(Array x) throws SQLException

This writes a SQL ARRAY value to the stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The Array object to store

writeAsciiStream

public void writeAsciiStream(java.io.InputStream x) throws SQLException

This writes the next element to the stream as a stream of ASCII characters. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The character input stream

writeBigDecimal

public void writeBigDecimal(java.math.BigDecimal x) throws SQLException

This writes the next element to the stream as a java.math.BigDecimal object. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeBinaryStream

public void writeBinaryStream(java.io.InputStream x) throws SQLException

This writes the next element to the stream as a stream of bytes. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The byte input stream

writeBlob

public void writeBlob(Blob x) throws SQLException

This writes a SQL BLOB value to the stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The Blob object to store

writeBoolean

public void writeBoolean(boolean x) throws SQLException

This writes the next element to the stream as a boolean. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeByte

public void writeByte(byte x) throws SQLException

This writes the next element to the stream as a byte. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeBytes

public void writeBytes(byte[] x) throws SQLException

This writes the next element to the stream as an array of bytes. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeCharacterStream

public void writeCharacterStream(java.io.Reader x) throws SQLException

This writes the next element to the stream as a stream of Unicode characters. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The character input stream object

writeClob

public void writeClob(Clob x) throws SQLException

This writes a SQL CLOB value to the stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The Clob object to store

writeDate

public void writeDate(Date x) throws SQLException

This writes the next element to the stream as a java.sql.Date object. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeDouble

public void writeDouble(double x) throws SQLException

This writes the next element to the stream as a double. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeFloat

public void writeFloat(float x) throws SQLException

This writes the next element to the stream as a float. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeInt

public void writeInt(int x) throws SQLException

This writes the next element to the stream as an int. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeLong

public void writeLong(long x) throws SQLException

This writes the next element to the stream as a long. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeObject

public void writeObject(SQLData x) throws SQLException

This method is used to send the data of the SQLData object to the current stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The object representing data of a SQL structured or distinct type

writeRef

public void writeRef(Ref x) throws SQLException

This writes a SQL REF value to the stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The Ref object to store

writeShort

public void writeShort(short x) throws SQLException

This writes the next element to the stream as a short. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeString

public void writeString(String x) throws SQLException

This writes the next element to the stream as a String. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeStruct

public void writeStruct(Struct x) throws SQLException

This writes a SQL structured type value to the stream. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The Struct object to store

writeTime

public void writeTime(Time x) throws SQLException

This writes the next element to the stream as a java.sql.Time object. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeTimestamp

public void writeTimestamp(Timestamp x) throws SQLException

This writes the next element to the stream as a java.sql.Timestamp object. A SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The value to store

writeURL

public void writeURL(java.net.URL x) throws SQLException

This writes a SQL SQLException is thrown if an error occurs while accessing this value.

Parameters:

x:

The java.net.URL object to store


Class SQLPermission

public final class SQLPermission
extends java.security.BasicPermission

The SQLPermission is checked by the SecurityManager when the code calls one of the setLogWriter() methods in an applet. The SQLPermission object may contain a named permission: setLog.

See also: BasicPermission, Permission, java.security.Permissions, PermissionCollection, SecurityManager, Serialized Form in the Java 2 Standard Edition javadoc.

Constructors

SQLPermission

public SQLPermission(String name)

This constructs a new SQLPermission instance with the symbolic name provided as a parameter. The only supported name for SQLPermission is setLog.

Parameters:

name:

The symbolic name (setLog)

SQLPermission

public SQLPermission(String name, String actions)

This constructs a new SQLPermission instance with the symbolic name provided as a parameter. The only supported name for SQLPermission is setLog. The actions parameter isn’t used.

Parameters:

name: | The symbolic name (setLog)
actions: | Not used


Class SQLWarning

public class SQLWarning
extends SQLException

SQLWarnings happen when database access warnings occur. The SQLWarning supplies details in order to discover the reason why it was created. Several methods exist to obtain such information.

See also: getWarnings

Constructors

SQLWarning

public SQLWarning(String reason, String SQLstate, int vendorCode)

This creates a SQLWarning object providing a reason, an XOPEN SQLState, and a vendor code.

Parameters:

reason: | A short message for the warning
SQLState: | An XOPEN code to identify the warning
vendorCode: | A database vendor warning code

SQLWarning

public SQLWarning(String reason, String SQLstate)

This creates a SQLWarning object providing a reason and an XOPEN SQLState. The vendor code is set to 0.

Parameters:

reason: | A short message for the warning
SQLState: | An XOPEN code to identify the warning

SQLWarning

public SQLWarning(String reason)

This creates a SQLWarning object providing a reason. The XOPEN SQLState is set to null, and the vendor code is set to 0.

Parameters:

reason: | A short message for the warning
SQLState: | An XOPEN code to identify the warning

SQLWarning

public SQLWarning()

This creates a SQLWarning object without providing additional information. The reason and XOPEN SQLState are set to null, and the vendor code is set to 0.

Methods

getNextWarning

public SQLWarning getNextWarning()

This gets the warning chained to the current warning.

Returns: The next SQLWarning

setNextWarning

public void setNextWarning(SQLWarning w)

This adds a SQLWarnings.

Parameters:

w:

A new SQLWarning


Interface Statement

public interface Statement
extends Object

Statement objects are used to create database and driver resources before and during the execution of static SQL statements. They are also used to obtain the SQL statements’ results after being executed within the database. The results, if they are of the form of rows of data, must be retrieved using ResultSets. Note that a SQL statement can return multiple results, but not at the same time. If necessary, instantiate different Statement objects to fetch different ResultSets simultaneously.

See also: createStatement, ResultSet

Methods

addBatch

public void addBatch(String sql) throws SQLException

This adds a SQL command to the current batch of commands for the statement. A SQLException is thrown if the driver doesn’t support batch statements.

Parameters:

sql:

A SQL statement

cancel

public void cancel() throws SQLException

cancel() is used to terminate the execution of a statement. It can be used only within a thread separate from that executing the statement.

clearBatch

public void clearBatch() throws SQLException

This deletes the set of commands in the current batch. A SQLException is thrown if the driver doesn’t support batch statements.

clearWarnings

public void clearWarnings() throws SQLException

This clears the chain of SQLWarnings for the current Statement.

close

public void close() throws SQLException

close() releases a Statement’s database and JDBC driver resources.

execute

public boolean execute(String sql) throws SQLException

This method executes a SQL statement. The statement can return multiple results, that is, result sets and update counts. In this case, the execute(), getMoreResults(), getResultSet(), and getUpdateCount() methods enable you to fetch those results. execute() indicates whether the first result is a ResultSet or an update count. getResultSet() and getUpdateCount() are used to retrieve the result, and getMoreResults() is used to discover subsequent results, if any.

Parameters:

sql:

A SQL statement

Returns: true if the first result is a ResultSet; false if it is an integer

See also: getResultSet, getUpdateCount, getMoreResults

execute

public int execute(String sql, int flag) throws SQLException

This method executes a SQL statement. The statement can return multiple results, that is, result sets and update counts. In this case, the execute(), getMoreResults(), getResultSet(), and getUpdateCount() methods enable you to fetch those results. execute() indicates whether the first result is a ResultSet or an update count. getResultSet() and getUpdateCount() are used to retrieve the result, and getMoreResults() is used to discover subsequent results, if any.

Parameters:

sql: | A SQL statement
flag: | A flag indicating that auto-generated keys should be returned

Returns: true if the first result is a ResultSet; false if it is an integer

See also: getResultSet, getUpdateCount, getMoreResults

execute

public int execute(String sql, int[] columnIndexes) throws SQLException

This method executes a SQL statement. The statement can return multiple results, that is, result sets and update counts. In this case, the execute(), getMoreResults(),getResultSet(), and getUpdateCount() methods enable you to fetch those results. execute() indicates whether the first result is a ResultSet or an update count. getResultSet() and getUpdateCount() are used to retrieve the result, and getMoreResults() is used to discover subsequent results, if any.

Parameters:

sql: | A SQL statement
columnIndexes: | An array of the ordinals of the columns that should be returned from the inserted or updated rows, if any

Returns: true if the first result is a ResultSet; false if it is an integer

See also: getResultSet, getUpdateCount, getMoreResults

execute

public int execute(String sql, String[] columnNames) throws SQLException

This method executes a SQL statement. The statement can return multiple results, that is, result sets and update counts. In this case, the execute(), getMoreResults(), getResultSet(), and getUpdateCount() methods enable you to fetch those results. execute() indicates whether the first result is a ResultSet or an update count. getResultSet() and getUpdateCount() are used to retrieve the result, and getMoreResults() is used to discover subsequent results, if any.

Parameters:

sql: | A SQL statement
columnNames: | An array of the names of the columns that should be returned from the inserted or updated rows, if any

Returns: true if the first result is a ResultSet; false if it is an integer

See also: getResultSet, getUpdateCount, getMoreResults

executeBatch

public int[] executeBatch() throws SQLException

This method executes the statements contained in the batch. The array that is returned provides an update count per statement. If the value of the update count is SUCCESS_NO_INFO, it means that the number of rows affected isn’t known. A value of EXECUTE_FAILED indicates that the statement failed to execute successfully and occurs only if a driver continues to process commands after a command fails.

Returns: An array of update counts. A SQLException is thrown if a database access error occurs or the driver doesn’t support batch statements. A BatchUpdateException is thrown if one of the commands of the batch fails to execute.

executeQuery

public ResultSet executeQuery(String sql) throws SQLException

Unlike execute(), executeQuery() is used to execute a SQL statement that returns a single ResultSet.

Parameters:

sql:

A SQL SELECT statement

Returns: A ResultSet containing the result rows, if any

executeUpdate

public int executeUpdate(String sql) throws SQLException

This executes a statement that returns an update count or just nothing (for example: SQL INSERT, UPDATE, or DELETE statements, or a SQL DDL statement such as CREATE TABLE).

Parameters:

sql:

A SQL statement that returns an integer or nothing

Returns: The update count for SQL INSERT, UPDATE, or DELETE; 0 for others

executeUpdate

public int executeUpdate(String sql, int flag) throws SQLException

This executes a statement that returns an update count or just nothing (for example: SQL INSERT, UPDATE, or DELETE statements, or a SQL DDL statement such as CREATE TABLE).

Parameters:

sql:

A SQL statement that returns an integer or nothing

flag:

Indicates whether to return generated keys with one of the following:

  • Statement.RETURN_GENERATED_KEYS

  • Statement.NO_GENERATED_KEYS

Returns: The update count for SQL INSERT, UPDATE, or DELETE; 0 for others

executeUpdate

public int executeUpdate(String sql, int[] columnIndexes)
throws SQLException

This executes a statement that returns an update count or just nothing (for example: SQL INSERT, UPDATE, or DELETE statements, or a SQL DDL statement such as CREATE TABLE).

Parameters:

sql: | A SQL statement that returns an integer or nothing
columnIndexes: | An array of the ordinals of the columns that should be returned from the inserted or updated rows

Returns: The update count for SQL INSERT, UPDATE, or DELETE; 0 for others

executeUpdate

public int executeUpdate(String sql, String[] columnNames)
throws SQLException

This executes a statement that returns an update count or just nothing (for example: SQL INSERT, UPDATE, or DELETE statements, or a SQL DDL statement such as CREATE TABLE).

Parameters:

sql: | A SQL statement that returns an integer or nothing
columnNames: | An array of the name of the columns that should be returned from the inserted or updated rows

Returns: The update count for SQL INSERT, UPDATE, or DELETE; 0 for others

getConnection

public Connection getConnection() throws SQLException

This gets the connection object used to create the statement.

Returns: The connection that produced the statement

getGeneratedKeys

public ResultSet getGeneratedKeys() throws SQLException

This returns any auto-generated keys from the current statement or an empty result set if there is no generated key.

Returns: The key or keys in a result set object

getMoreResults

public boolean getMoreResults(int current) throws SQLException

This checks if there is another result set or update count available for retrieval. There are no more results when the following is true: (!getMoreResults() && (getUpdateCount() == -1)

Parameters:

current:

One of the following flags, indicating what happens to the previous result set:

  • CLOSE_CURRENT_RESULT

  • KEEP_CURRENT_RESULT

  • CLOSE_ALL_RESULTS

Returns: true if the next result is a ResultSet object; false if it is an update count or there are no more results

getResultSet

public ResultSet getResultSet() throws SQLException

getResultSet() is used to get the current result as a ResultSet. It can be called only once per result.

Returns: The current result as a ResultSet, or null if the result is an integer or there are no more results

See also: execute

getResultSetHoldability

public int getResultSetHoldability() throws SQLException

This returns the result set holdability for result sets generated by the statement.

Returns: One of the following:

  • ResultSet.HOLD_CURSORS_OVER_COMMIT

  • ResultSet.CLOSE_CURSORS_AT_COMMIT

getUpdateCount

public int getUpdateCount() throws SQLException

getUpdateCount() returns the current result as an update count that represents the number of rows affected by the statement. getUpdateCount can also return -1 if the result is a ResultSet or there are no more results. It can be called only once per result.

Returns: The current result as an update count, or -1 if it is a ResultSet or there are no more results

See also: execute

getMaxFieldSize

public int getMaxFieldSize() throws SQLException

This method returns the maximum length of data returned for any column value. It applies only to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR columns.

Returns: The current maximum column size limit or zero if unlimited

getMaxRows

public int getMaxRows() throws SQLException

This method returns the maximum number of rows allowed for a ResultSet. Excessive rows are discarded.

Returns: The current maximum row limit or zero if unlimited

getMoreResults

public boolean getMoreResults() throws SQLException

getMoreResults() is used to navigate results. If true is returned, the current result is a ResultSet. If false, the result is an update count or there are no more results. (There are no more results when (!getMoreResults() && (getUpdateCount() == -1).) Note that getMoreResults() implicitly closes any current ResultSet obtained with getResultSet.

Returns: true if the next result is a ResultSet; false if it is an integer or there are no more results

See also: execute

getQueryTimeout

public int getQueryTimeout() throws SQLException

This specifies that a driver can wait a number of seconds for a Statement to execute. If the limit is exceeded, a SQLException is thrown.

Returns: The current query time-out limit in seconds or zero if unlimited

getFetchDirection

public int getFetchDirection() throws SQLException

This gets the fetch direction of rows for result sets generated by the statement.

Returns: The fetch direction for result sets

getFetchSize

public int getFetchSize() throws SQLException

This returns the default fetch size for result sets generated from the statement object.

Returns: The fetch size for result sets

getResultSetConcurrency

public int getResultSetConcurrency() throws SQLException

This returns the result set concurrency for result sets generated by the statement.

Returns: One of the following:

  • ResultSet.CONCUR_READ_ONLY

  • ResultSet.CONCUR_UPDATABLE

getResultSetType

public int getResultSetType() throws SQLException

This returns the result set type for result sets generated by the statement.

Returns: One of the following:

  • ResultSet.TYPE_FORWARD_ONLY

  • ResultSet.TYPE_SCROLL_INSENSITIVE

  • ResultSet.TYPE_SCROLL_SENSITIVE

getWarnings

public SQLWarning getWarnings() throws SQLException

Statement and ResultSet warnings are chained together. This method is used to get the first SQLWarning of the chain. The chain is cleared each time a statement is executed.

Returns: The first SQLWarning or null

setCursorName

public void setCursorName(String name) throws SQLException

This method sets the SQL cursor name for the current Statement. The cursor name can then be used in SQL positioned update or delete statements to identify the current row in the ResultSet. Note that cursor names must be unique within a Connection.

Parameters:

name:

The cursor name

setEscapeProcessing

public void setEscapeProcessing(boolean enable) throws SQLException

A driver escapes substitution by default unless this method has been invoked with a parameter of Boolean value false.

Parameters:

enable:

true enables escape substitution; false disables it.

setMaxFieldSize

public void setMaxFieldSize(int max) throws SQLException

This limits the size of data that can be returned for any column value. This applies only to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR columns.

Parameters:

max:

The maximum column size limit or zero for unlimited

setMaxRows

public void setMaxRows(int max) throws SQLException

setMaxRows() can be used to limit the rows returned by a query. Excessive rows are silently discarded.

Parameters:

max:

The maximum rows limit or zero for unlimited

setFetchDirection

public void setFetchDirection(int direction) throws SQLException

This indicates the direction in which the rows of a ResultSet have to be processed. A SQLException is thrown if a database access error occurs or if the parameter value is incorrect.

Parameters:

direction:

The initial direction for processing rows, as indicated by one of the following:

  • ResultSet.FETCH_FORWARD

  • ResultSet.FETCH_REVERSE

  • ResultSet.FETCH_UNKNOWN

setFetchSize

public void setFetchSize(int rows) throws SQLException

This indicates the number of rows to be fetched at once when executing the statement.

Parameters:

rows:

The number of rows to fetch. 0 means no default size.

setQueryTimeout

public void setQueryTimeout(int seconds) throws SQLException

This specifies that a driver can wait a number of seconds for a Statement to execute. If the limit is exceeded, a SQLException is thrown.

Parameters:

seconds:

The query time-out limit in seconds or zero for unlimited


Interface Struct

public interface Struct

The Struct interface is used to map SQL structured types in Java. This object contains a value for each element of the SQL structured type.

Methods

getAttributes

public Object[] getAttributes() throws SQLException

This returns an array of objects that are the elements of the SQL structured type contained in the struct object. The type map of the current connection or the standard mapping if none is available is used for type mapping.

Returns: The array containing the attribute values. A SQLException is thrown if an error occurs while accessing these values.

getAttributes

public Object[] getAttributes(java.util.Map map) throws SQLException

This returns an array of objects that are the elements of the SQL structured type contained in the struct object. The type map provided as a parameter or the standard mapping if no mapping is available for a given type is used for type mapping.

Parameters:

map:

The mapping of SQL type names to Java classes

Returns: The array containing the attribute values. A SQLException is thrown if an error occurs while accessing these values.

getSQLTypeName

public String getSQLTypeName() throws SQLException

This gets the name of the SQL type of the SQL structured type for the struct object.

Returns: The type name of the SQL structured type. A SQLException is thrown if an error occurs while accessing this value.


Class Time

public class Time
extends Date

This class extends the standard java.util.date class to represent SQL TIME types. Only hours, minutes, and seconds are handled. It supports the JDBC escape syntax for time values.

Constructors

Time

public Time(int hour, int minute, int second)

This constructs a Time object.

Parameters:

hour: | 0 to 23
minute: | 0 to 59
second: | 0 to 59

Time

public Time(long time)

This constructs a Time object using a time value in milliseconds since January 1, 1970, 00:00:00 GMT.

Parameters:

time:

The milliseconds since January 1, 1970, 00:00:00 GMT

Methods

toString

public String toString()

This converts the time to HH:MM:SS format.

Returns: A HH:MM:SS formatted time String

valueOf

public static Time valueOf(String s)

This converts an HH:MM:SS formatted string to a Time value.

Parameters:

s:

The time in HH:MM:SS format

Returns: A Time object


Class Timestamp

public class Timestamp
extends Date

This class extends the standard java.util.date to represent SQL TIMESTAMP types. It supports subsecond precision and the JDBC escape syntax for time values.

Constructors

Timestamp

public Timestamp(int year, int month, int date, int hour, int minute,
int second, int nano)

This constructs a Timestamp object.

Parameters:

year: | The year minus 1900
month: | 0 to 11
day: | 1 to 31
hour: | 0 to 23
minute: | 0 to 59
second: | 0 to 59
nano: | 0 to 999,999,999

Timestamp

public Timestamp(long time)

This constructs a Timestamp object using a time value in milliseconds.

Parameters:

time:

The milliseconds since January 1, 1970, 00:00:00 GMT

Methods

compareTo

public int compareTo(Timestamp ts)

This compares two Timestamps for ordering.

Parameters:

ts:

The Timestamp to be compared.

Returns: 0 if the timestamp equals ts; a negative value if the timestamp is anterior to ts; a positive value if the timestamp is posterior to ts

equals

public boolean equals(Timestamp ts)

This compares the current Timestamp object with another.

Parameters:

ts:

The Timestamp value to compare with

Returns: true if they are equal

getNanos

public int getNanos()

This gets the Timestamp’s nanosecond value.

Returns: The Timestamp’s nanosecond value

setNanos

public void setNanos(int n)

This sets the Timestamp’s nanosecond value.

Parameters:

n:

The Timestamp’s nanosecond value

toString

public String toString()

This converts a Timestamp to YYYY-MM-DD HH:MM:SS.F format.

Returns: A YYYY-MM-DD HH:MM:SS.F formatted timestamp String

valueOf

public static Timestamp valueOf(String s)

This converts a YYYY-MM-DD HH:MM:SS.F formatted string to a Timestamp value.

Parameters:

s:

The timestamp formatted as YYYY-MM-DD HH:MM:SS.F

Returns: A Timestamp value


Class Types

public class Types
extends Object

The SQL types constants and their values are defined in this class. The constant values are equivalent to those defined by XOPEN.

Fields

The following attributes are all static final integer values. It’s quite handy to use these attribute names in Java programs instead of the integer values; it makes the code much more readable and portable.

ARRAY

public static final int ARRAY = 2003

BIGINT

public static final int BIGINT = -5

BINARY

public static final int BINARY = -2

BIT

public static final int BIT = -7

BLOB

public static final int BLOB = 2004

BOOLEAN

public static final int BOOLEAN = 16

CHAR

public static final int CHAR = 1

CLOB

public static final int CLOB = 2005

DATALINK

public static final int DATALINK = 70

DATE

public static final int DATE = 91

DECIMAL

public static final int DECIMAL = 3

DISTINCT

public static final int DISTINCT = 2001

DOUBLE

public static final int DOUBLE = 8

FLOAT

public static final int FLOAT = 6

INTEGER

public static final int INTEGER = 4

JAVA_OBJECT

public static final int JAVA_OBJECT = 2000

LONGVARCHAR

public static final int LONGVARCHAR = -4

LONGVARBINARY

public static final int LONGVARBINARY = -1

NULL

public static final int NULL = 0

NUMERIC

public static final int NUMERIC = 2

OTHER

public static final int OTHER = 1111

REAL

public static final int REAL = 7

REF

public static final int REF = 2006

SMALLINT

public static final int SMALLINT = 5

STRUCT

public static final int STRUCT = 2002

TIME

public static final int TIME = 92

TIMESTAMP

public static final int TIMESTAMP = 93

TINYINT

public static final int TINYINT = -6

VARBINARY

public static final int VARBINARY = -3

VARCHAR

public static final int VARCHAR = 12


JDBC Extension Reference

This reference provides information about the JDBC 3 Extension API. Note that JDBC 3–compliant drivers aren’t required to support this API, unlike the JDBC 3 API implementation, which is required by all JDBC drivers that claim to be JDBC 3 compliant.

Note

The interfaces and classes in this reference are sorted alphabetically, as are the attributes and methods that they provide. Repeated method names indicate that several method signatures are available for the same purpose, each one supporting a different set of parameters. Those parameters and the return values are also described in this reference.

Class ConnectionEvent

public class ConnectionEvent
extends java.util.EventObject

Used in combination with the PooledConnection object, the ConnectionEvent notifies of changes such as a connection close, connection error, server crash, and so on. The ConnectionEventListener can be added to PooledConnection objects in order to manage this kind of event.

Constructors

ConnectionEvent

public ConnectionEvent(PooledConnection con)

This builds a ConnectionEvent object with a null SQLException in case of connection error.

Parameters:

con:

The source object of the event

ConnectionEvent

public ConnectionEvent(PooledConnection con, java.sql.SQLException ex)

This builds a ConnectionEvent object with the SQLException provided as a parameter.

Parameters:

con: | The source object of the event
ex: | The SQLException to be thrown after notification

Methods

getSQLException

public java.sql.SQLException getSQLException()

This gets the SQLException associated with the event object.

Returns: The SQLException to be thrown after notification


Interface ConnectionEventListener

public interface ConnectionEventListener
extends java.util.EventListener

You can use a ConnectionEventListener when you want to be notified of events generated by a PooledConnection. ConnectionEventListener is usually implemented by connection pooling services provided in application servers, for example.

Methods

connectionClosed

public void connectionClosed(ConnectionEvent event)

This method is called when a connection obtained from a pool is closed and when it can be returned to the pool.

Parameters:

event:

The source of the event

connectionErrorOccurred

public void connectionErrorOccurred(ConnectionEvent event)

This method is called when an error occurs. A SQLException specified as a constructor parameter is thrown just after calling this method.

Parameters:

event:

The source of the event


Interface ConnectionPoolDataSource

public interface ConnectionPoolDataSource

A ConnectionPoolDataSource represents a data source that manages a pool of connections. It creates ConnectionPool objects. Such connections are opened as needed, although a maximum is usually set. Unused connections are returned to the pool for reuse or disconnection and destruction.

Methods

getLoginTimeout

public int getLoginTimeout() throws java.sql.SQLException

This returns the login time-out. A SQLException is thrown if a database access error occurs.

Returns: The maximum amount of time for the connection

getLogWriter

public java.io.PrintWriter getLogWriter() throws java.sql.SQLException

This gets a character output stream used for logging and tracing. A SQLException is thrown if a database access error occurs.

Returns: The log writer for the data source or null when there is no log writer available

getPooledConnection

public PooledConnection getPooledConnection() throws java.sql.SQLException

This method tries to get a database connection from the pool. Some connection pools may implement a time-out that specifies the amount of time allowed to wait for a connection to become available.

If the time-out value is elapsed, if there is no time-out and no available connection, or if a database access error occurs, this method throws a SQLException. The default login and password for the current data source is used. You can use the getPooledConnection(String user, String password) method to provide another login/password pair for the connection.

Returns: A Connection to the database

getPooledConnection

public PooledConnection getPooledConnection(String user, String password)
throws java.sql.SQLException

This method tries to get a database connection from the pool using the login/password pair provided as parameters. Some connection pools may implement a time-out that specifies the amount of time allowed to wait for a connection to become available.

If the time-out value is elapsed, if there is no time-out and no available connection, or if a database access error occurs, this method throws a SQLException.

Parameters:

user: | The database user’s login for the requested connection
password: | The password for the user

Returns: A Connection to the database

setLoginTimeout

public void setLoginTimeout(int seconds) throws java.sql.SQLException

This provides the maximum time that the data source will wait while attempting to connect to a database. The units are seconds. Zero means that either the database driver internal time-out value is used here at the client side or there is no time-out. A SQLException is thrown if a database access error occurs.

Parameters:

seconds:

The maximum amount of time for the connection

setLogWriter

public void setLogWriter(java.io.PrintWriter out) throws java.sql.SQLException

This sets the log writer for the data source. A SQLException is thrown if a database access error occurs.

Parameters:

out:

The character output stream to use as a log writer for the data source or null if there is no need to provide a log writer


Interface DataSource

public interface DataSource

DataSource objects create Connection objects. The data source and its connections don’t participate in distributed transactions. See XADataSource and XAConnection instead for distributed transaction support.

Methods

getConnection

public java.sql.Connection getConnection() throws java.sql.SQLException

This tries to establish a database connection using the default login and password for the data source. You can use getConnection(String user, String password) to provide another login/password pair if needed. A SQLException is thrown if a database access error occurs.

Returns: A Connection to the database

getConnection

public java.sql.Connection getConnection(String username, String password)
throws java.sql.SQLException

This tries to establish a database connection using the login/password pair provided as parameters to getConnection. A SQLException is thrown if a database access error occurs.

Parameters:

user: | The database user’s login used to connect to the database
password: | The user’s password

Returns: A Connection to the database

getLoginTimeout

public int getLoginTimeout() throws java.sql.SQLException

This returns the login time-out. A SQLException is thrown if a database access error occurs.

Returns: The maximum amount of time for the connection

getLogWriter

public java.io.PrintWriter getLogWriter() throws java.sql.SQLException

This gets a character output stream used for logging and tracing. A SQLException is thrown if a database access error occurs.

Returns: The log writer for this data source or null when there is no log writer available

setLoginTimeout

public void setLoginTimeout(int seconds) throws java.sql.SQLException

This provides the maximum time that the data source will wait while attempting to connect to a database. The units are seconds. Zero means that either the database driver internal time-out value is used here at the client side or there is no time-out. A SQLException is thrown if a database access error occurs.

Parameters:

seconds:

The maximum amount of time for the connection

setLogWriter

public void setLogWriter(java.io.PrintWriter out) throws java.sql.SQLException

This sets the log writer for the data source. A SQLException is thrown if a database access error occurs.

Parameters:

out:

The new log writer for the data source or null if there is no need to provide a log writer


Interface PooledConnection

public interface PooledConnection

A PooledConnection object is a database connection managed by a connection pool. It can be retrieved, used for querying the database, and returned to the pool afterward. Using pooled connections makes sense in multiuser and multithreaded environments, such as application servers.

Methods

addConnectionEventListener

public void addConnectionEventListener(ConnectionEventListener listener)

You can use this to add an event listener to the pooled connection when you want to be notified of connection events such as a close or errors.

Parameters:

listener:

The listener object that needs to be notified of events occurring for the connection

close

public void close() throws java.sql.SQLException

This closes the physical connection. A SQLException is thrown if a database access error occurs.

getConnection

public java.sql.Connection getConnection() throws java.sql.SQLException

This obtains the Connection object associated to the pooled connection. A SQLException is thrown if a database access error occurs.

Returns: A Connection object

removeConnectionEventListener

public void removeConnectionEventListener(ConnectionEventListener listener)

This removes an event listener from the pooled connection.

Parameters:

listener:

The listener object that no longer needs to be notified


Interface RowSet

public interface RowSet
extends java.sql.ResultSet

A RowSet can be created and configured at design time in a JavaBeans visual development environment and executed at runtime. The RowSet interface provides a set of JavaBeans properties that allow a RowSet instance to be configured to connect to a JDBC data source and read some data from the data source. In addition to that, the RowSet interface extends the ResultSet interface, which provides methods necessary to handle query results represented by a RowSet. Changes made to the rows of a RowSet object can be saved to the database.

Methods

addRowSetListener

public void addRowSetListener(RowSetListener listener)

This registers a rowset listener object that is being notified of events occurring on the rowset.

Parameters:

listener:

The event listener

clearParameters

public void clearParameters() throws java.sql.SQLException

This method can be used to free the resources used by the parameter values set for the current rowset. Such values are freed when new parameter values are provided, but in some cases it may be useful to free them all by using this method.

A SQLException is thrown if a database access error occurs.

execute

public void execute() throws java.sql.SQLException

This method executes the command for the rowset and fills it with the result data. A connection can be established for this command to execute: You can use either the connection URL or data source. The database username and password must be set prior to calling execute(). Other properties such as the transaction isolation level, a type map, being read-only, the maximum field size, the maximum rows, the command time-out, and escape processing can be set as well.

A SQLException is thrown if a database access error occurs or when a mandatory parameter is missing.

getCommand

public String getCommand()

This gets the command associated to the rowset. It is a SQL command when the data source is a database. This command will be executed to fill the rowset with data coming from the data source. The default value for the command is null.

Returns: The command string

getDataSourceName

public String getDataSourceName()

This returns the JNDI name for the data source used by the rowset.

Returns: The data source name

getEscapeProcessing

public boolean getEscapeProcessing() throws java.sql.SQLException

Escape processing happens before the SQL statement is sent to the database. This method returns the current setting for escape processing. A SQLException is thrown if a database access error occurs.

Returns: true if enabled or false if disabled

getMaxFieldSize

public int getMaxFieldSize() throws java.sql.SQLException

This returns the maximum number of bytes returned for any column value of the following types:

  • Types.BINARY

  • Types.VARBINARY

  • Types.LONGVARBINARY

  • Types.CHAR

  • Types.VARCHAR

  • Types.LONGVARCHAR

A SQLException is thrown if a database access error occurs.

Returns: The maximum column size limit for this rowset. Zero means unlimited.

getMaxRows

public int getMaxRows() throws java.sql.SQLException

This returns the maximum number of rows that the rowset can contain. A SQLException is thrown if a database access error occurs.

Returns: The current maximum row limit. Zero means unlimited.

getPassword

public String getPassword()

This gets the password for the database user used by the rowset when connecting to the database.

Returns: The user password

getQueryTimeout

public int getQueryTimeout() throws java.sql.SQLException

This returns the number of seconds the driver will wait for a Statement to execute. A SQLException is thrown if a database access error occurs.

Returns: The limit in seconds. A value of zero means unlimited.

getTransactionIsolation

public int getTransactionIsolation()

This gets the transaction isolation level used by the rowset. The possible values are defined in java.sql.Connection.

Returns: The transaction isolation level, which can be any of the following:

  • Connection.TRANSACTION_NONE: Indicates that transactions aren’t supported at all.

  • Connection.TRANSACTION_READ_COMMITTED: Dirty reads are prevented, but non-repeatable reads and phantom reads can occur.

  • Connection.TRANSACTION_READ_UNCOMMITTED: Dirty reads, non-repeatable reads, and phantom reads can occur.

  • Connection.TRANSACTION_REPEATABLE_READ: Dirty reads and non-repeatable reads are prevented, but phantom reads can occur.

  • Connection.TRANSACTION_SERIALIZABLE: Dirty reads, non-repeatable reads, and phantom reads are prevented.

getTypeMap

public java.util.Map getTypeMap() throws java.sql.SQLException

This gets the type-map object associated with the rowset or an empty map if the type map wasn’t set earlier. A SQLException is thrown if a database access error occurs.

Returns: The type map for the rowset

getUrl

public String getUrl() throws java.sql.SQLException

This returns the URL used to create the JDBC connection. A SQLException is thrown if a database access error occurs.

Returns: The URL as a string

getUsername

public String getUsername()

This gets the username (database login) for the connection used by the rowset.

Returns: The username

isReadOnly

public boolean isReadOnly()

This verifies whether a rowset is read-only. The default for a rowset isn’t read-only, when the data source allows it.

Returns: true if updatable, false otherwise

removeRowSetListener

public void removeRowSetListener(RowSetListener listener)

This removes the rowset listener object from the registered listeners for the rowset.

Parameters:

listener: The event listener

setArray

public void setArray(int i, java.sql.Array x) throws java.sql.SQLException

This sets an Array parameter. A SQLException is thrown if a database access error occurs.

Parameters:

i: | The parameter index, starting at 1
x: | An object representing a SQL array

setAsciiStream

public void setAsciiStream( int parameterIndex, java.io.InputStream x,  int length)
throws java.sql.SQLException

This reads the ASCII value from an input stream and inputs it to a LONGVARCHAR parameter. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The Java input stream that contains the ASCII parameter value
length: | The number of bytes to be read from the stream

setBigDecimal

public void setBigDecimal(int parameterIndex, java.math.BigDecimal x)
throws java.sql.SQLException

This sets a parameter to a BigDecimal value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setBinaryStream

public void setBinaryStream( int parameterIndex, java.io.InputStream x, int length)
throws java.sql.SQLException

This reads a binary value from an input stream and inputs it to a LONGVARBINARY parameter. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The java input stream that contains the binary parameter value
length: | The number of bytes to be read from the stream

setBlob

public void setBlob(int i, java.sql.Blob x) throws java.sql.SQLException

This sets a BLOB parameter. A SQLException is thrown if a database access error occurs.

Parameters:

i: | The parameter index, starting at 1
x: | An object representing a BLOB

setBoolean

public void setBoolean(int parameterIndex, boolean x) throws java.sql.SQLException

This sets a parameter to a Java boolean value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setByte

public void setByte(int parameterIndex, byte x) throws java.sql.SQLException

This sets a parameter to a Java byte value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setBytes

public void setBytes(int parameterIndex, byte[] x) throws java.sql.SQLException

This sets a parameter to a Java array of bytes. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setCharacterStream

public void setCharacterStream( int parameterIndex, java.io.Reader reader, int length) throws java.sql.SQL Exception

This reads a Unicode value from an input stream and inputs it to a LONGVARCHAR parameter. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The Java reader that contains the Unicode data
length: | The number of characters in the stream

setClob

public void setClob(int i, java.sql.Clob x) throws java.sql.SQLException

This sets a CLOB parameter. A SQLException is thrown if a database access error occurs.

Parameters:

i: | The parameter index, starting at 1
x: | An object representing a CLOB

setCommand

public void setCommand(String cmd) throws java.sql.SQLException

This sets the SQL command associated to the rowset when the data source is a database or another type of command when the data source isn’t a database. This command will be executed to fill the rowset with data coming from the data source. The default value for the command is null. A SQLException is thrown if a database access error occurs.

Parameters:

cmd:

A command string

setConcurrency

public void setConcurrency(int concurrency) throws java.sql.SQLException

This sets the rowset concurrency level for the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

concurrency:

The concurrency level as defined in ResultSet with one of the following attributes:

  • ResultSet.CONCUR_READ_ONLY: The constant indicating the concurrency mode for a ResultSet object that cannot be updated

  • ResultSet.CONCUR_UPDATABLE: The constant indicating the concurrency mode for a ResultSet object that can be updated

setDataSourceName

public void setDataSourceName(String name) throws java.sql.SQLException

This sets the data source name for the rowset. Note that either a data source name or a JDBC URL can be provided to the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

name:

The name of the data source

setDate

public void setDate(int parameterIndex, java.sql.Date x)
throws java.sql.SQLException

This sets a parameter to a java.sql.Date value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setDate

public void setDate(int parameterIndex, java.sql.Date x, java.util.Calendar cal)
throws java.sql.SQLException

This sets a parameter to a java.sql.Date value that will be converted to a SQL DATE value when it is sent to the database. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value
cal: | The calendar value

setDouble

public void setDouble(int parameterIndex, double x) throws java.sql.SQLException

This sets a parameter to a Java double value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setEscapeProcessing

public void setEscapeProcessing(boolean enable) throws java.sql.SQLException

This enables or disables escape processing by the JDBC driver before sending each SQL statement to the database. A SQLException is thrown if a database access error occurs.

Parameters:

enable: Set to true to enable or false to disable

setFloat

public void setFloat(int parameterIndex, float x) throws java.sql.SQLException

This sets a SQL Float parameter to a Java float value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setInt

public void setInt(int parameterIndex,
                   int x) throws java.sql.SQLException

This sets a parameter to a Java int value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setLong

public void setLong(int parameterIndex, long x) throws java.sql.SQLException

This sets a parameter to a Java long value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setMaxFieldSize

public void setMaxFieldSize(int max) throws java.sql.SQLException

This sets the maximum number of bytes returned for any column value of the following types:

  • Types.BINARY

  • Types.VARBINARY

  • Types.LONGVARBINARY

  • Types.CHAR

  • Types.VARCHAR

  • Types.LONGVARCHAR

A SQLException is thrown if a database access error occurs.

Parameters:

max:

The maximum column size limit for this rowset. Zero means unlimited.

setMaxRows

public void setMaxRows(int max) throws java.sql.SQLException

This sets the maximum number of rows that the rowset can contain. A SQLException is thrown if a database access error occurs.

Parameters:

max:

The maximum rows limit. Zero means unlimited.

setNull

public void setNull(int parameterIndex, int sqlType) throws java.sql.SQLException

This sets a parameter to SQL NULL. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
sqlType: | The SQL type code defined by java.sql.Types

setNull

public void setNull(int paramIndex, int sqlType, String typeName)
throws java.sql.SQLException

This sets a parameter to SQL NULL. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
sqlType: | The SQL type code defined by java.sql.Types
typeName: | The fully qualified name of a SQL user-named type for user-named types or REF types

setObject

public void setObject(int parameterIndex, Object x, int targetSqlType,  int scale)
throws java.sql.SQLException

This sets the value of a parameter using an object, which will be converted to a target SQL type. Basic data types can be passed using their object equivalents (for example, Integer for int).

A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex:

The parameter index, starting at 1

x:

The object containing the input parameter value

targetSqlType:

One of these java.sql.Types types must be used for this parameter:

  • Types.ARRAY

  • Types.BIGINT

  • Types.BINARY

  • Types.BIT

  • Types.BLOB

  • Types.BOOLEAN

  • Types.CHAR

  • Types.CLOB

  • Types.DATALINK

  • Types.DATE

  • Types.DECIMAL

  • Types.DISTINCT

  • Types.DOUBLE

  • Types.FLOAT

  • Types.INTEGER

  • Types.JAVA_OBJECT

  • Types.LONGVARBINARY

  • Types.LONGVARCHAR

  • Types.NULL

  • Types.NUMERIC

  • Types.OTHER

  • Types.REAL

  • Types.REF

  • Types.SMALLINT

  • Types.STRUCT

  • Types.TIME

  • Types.TIMESTAMP

  • Types.TINYINT

  • Types.VARBINARY

  • Types.VARCHAR

scale:

The number of digits after the decimal (only for java.sql.Types.DECIMAL and java.sql.Types.NUMERIC types)

See also: java.sql.Types

setObject

public void setObject(int parameterIndex, Object x, int targetSqlType)
throws java.sql.SQLException

This sets the value of a parameter using an object, which will be converted to a target SQL type. Basic data types can be passed using their object equivalents (for example, Integer for int).

A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The object containing the input parameter value
targetSqlType: | The java.sql.Types type to be used for this parameter

See also: java.sql.Types

setObject

public void setObject(int parameterIndex, Object x) throws java.sql.SQLException

This sets the value of a parameter using an object, which will be converted using the standard JDBC mapping from Java objects to SQL types. Basic data types can be passed using their object equivalents (for example, Integer for int).

A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The object containing the input parameter value

setPassword

public void setPassword(String password) throws java.sql.SQLException

This sets the password used to connect to the database. The password must be set before invoking the execute() method. A SQLException is thrown if a database access error occurs.

Parameters:

password:

The password

setQueryTimeout

public void setQueryTimeout(int seconds) throws java.sql.SQLException

This sets the number of seconds that the driver must wait for a Statement to execute. A SQLException is thrown if a database access error occurs.

Parameters:

seconds:

The limit in seconds. Zero means unlimited.

setReadOnly

public void setReadOnly(boolean value) throws java.sql.SQLException

When value is set to true, attempts to update a read-only rowset will result in a SQLException being thrown. Rowsets are updatable by default if updates are possible.

Parameters:

value:

true if read-only, false otherwise

setRef

public void setRef(int i, java.sql.Ref x) throws java.sql.SQLException

This sets a SQL REF typed parameter. A SQLException is thrown if a database access error occurs.

Parameters:

i:

The parameter index, starting at 1

x:

An object representing data of a SQL REF type

setShort

public void setShort(int parameterIndex, short x) throws java.sql.SQLException

This sets a parameter to a Java short value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setString

public void setString(int parameterIndex, String x) throws java.sql.SQLException

This sets a parameter to a Java String value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setTime

public void setTime(int parameterIndex, java.sql.Time x)
throws java.sql.SQLException

This sets a parameter to a java.sql.Time value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setTime

public void setTime(int parameterIndex, java.sql.Time x, java.util.Calendar cal)
throws java.sql.SQLException

This sets a parameter to a java.sql.Time value that will be converted to a SQL TIME value when it is sent to the database. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value
cal: | The calendar value

setTimestamp

public void setTimestamp(int parameterIndex, java.sql.Timestamp x)
throws java.sql.SQLException

This sets a parameter to a java.sql.Timestamp value. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value

setTimestamp

public void setTimestamp( int parameterIndex, java.sql.Timestamp x, java.util.Calendar cal)
throws java.sql.SQLException

This sets a parameter to a java.sql.Timestamp value that will be converted to a SQL TIMESTAMP value when it is sent to the database. A SQLException is thrown if a database access error occurs.

Parameters:

parameterIndex: | The parameter index, starting at 1
x: | The parameter value
cal: | The calendar value

setTransactionIsolation

public void setTransactionIsolation(int level) throws java.sql.SQLException

This sets the transaction isolation level for the rowset.

Parameters:

level:

The transaction isolation level. Allowed values are defined in the Connection object as follows:

  • Connection.TRANSACTION_NONE: Indicates that transactions aren’t supported at all.

  • Connection.TRANSACTION_READ_COMMITTED: Dirty reads are prevented, but non-repeatable reads and phantom reads can occur.

  • Connection.TRANSACTION_READ_UNCOMMITTED: Dirty reads, non-repeatable reads, and phantom reads can occur.

  • Connection.TRANSACTION_REPEATABLE_READ: Dirty reads and non-repeatable reads are prevented, but phantom reads can occur.

  • Connection.TRANSACTION_SERIALIZABLE: Dirty reads, non-repeatable reads, and phantom reads are prevented.

A SQLException is thrown if a database access error occurs.

setType

public void setType(int type) throws java.sql.SQLException

This sets the rowset type for the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

type:

The rowset type value as defined in ResultSet with one of the following:

  • ResultSet.TYPE_FORWARD_ONLY: The cursor for the result set of the rowset can only move forward.

  • ResultSet.TYPE_SCROLL_INSENSITIVE: The cursor for the result set of the rowset is scrollable and isn’t sensitive to changes made by other queries and updates.

  • ResultSet.TYPE_SCROLL_SENSITIVE: The cursor for the result set of the rowset is scrollable and is sensitive to changes made by other queries and updates.

setTypeMap

public void setTypeMap(java.util.Map map) throws java.sql.SQLException

This registers a type-map object as the default type map for the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

map:

The type-map object

setUrl

public void setUrl(String url) throws java.sql.SQLException

Using this method is not mandatory. If set, the URL passed as a parameter is used to create a database connection when needed; otherwise, the data source name will be used. A SQLException is thrown if a database access error occurs.

Parameters:

url:

The URL as a string value

setUsername

public void setUsername(String name) throws java.sql.SQLException

This sets the username used to connect to the database. The username must be set before invoking the execute() method. A SQLException is thrown if a database access error occurs.

Parameters:

name:

The username


Class RowSetEvent

public class RowSetEvent
extends java.util.EventObject

Significant changes in the state of a rowset such as column value changes generate a RowSetEvent. Other objects can be notified when changes occur if they listen to this event.

Constructors

RowSetEvent

public RowSetEvent(RowSet source)

This builds a RowSetEvent object.

Parameters:

source:

The source object of the event


Interface RowSetInternal

public interface RowSetInternal

A rowset object implements this interface to provide information about its state and parameters to external readers and writers. The internal state can be modified as well by the readers and writers.

Methods

getConnection

public java.sql.Connection getConnection() throws java.sql.SQLException

This gets the Connection object that the rowset uses. A SQLException is thrown if a database access error occurs.

Returns: The Connection object or null if none

getOriginal

public java.sql.ResultSet getOriginal() throws java.sql.SQLException

This returns a result set containing the original value of the rowset. The cursor is positioned before the first row in the result set. A SQLException is thrown if a database access error occurs.

Returns: The original value of the rowset

getOriginalRow

public java.sql.ResultSet getOriginalRow() throws java.sql.SQLException

This returns a result set containing the original value of the current row only. If the current row has no original value, an empty result set is returned. A SQLException is thrown if a database access error occurs or if there is no current row.

Returns: The original value of the row

getParams

public Object[] getParams() throws java.sql.SQLException

This gets all parameters for the rowset. A SQLException is thrown if a database access error occurs.

Returns: An array of parameters

setMetaData

public void setMetaData(RowSetMetaData md) throws java.sql.SQLException

This sets metadata for the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

a:

The metadata object


Interface RowSetListener

public interface RowSetListener
extends java.util.EventListener

Objects that need to be notified of changes in the state of a rowset must implement the RowSetListener interface. RowSetEvents are generated by rowsets when the state of the rowset changes.

Methods

cursorMoved

public void cursorMoved(RowSetEvent event)

This method is invoked when the cursor is moved within a rowset.

Parameters:

event:

An object describing the event

rowChanged

public void rowChanged(RowSetEvent event)

This method is invoked when a row is inserted, updated, or deleted.

Parameters:

event:

An object describing the event

rowSetChanged

public void rowSetChanged(RowSetEvent event)

This method is invoked when the rowset state changes.

Parameters:

event:

An object describing the event


Interface RowSetMetaData

public interface RowSetMetaData
extends java.sql.ResultSetMetaData

This interface provides methods that describe the rowset mainly through the ResultSetMetaData interface. The added methods enable you to set additional parameters to initialize the ResultSetMetaData.

Methods

setAutoIncrement

public void setAutoIncrement(int columnIndex, boolean property)
throws java.sql.SQLException

This sets a column as auto-incrementing. When a column is auto-incremented, its value cannot be updated by the application. This mechanism is used to create database-generated sequence numbers for individual rows in a given table. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The column index, starting at 1
property: | true for auto-increment

setCaseSensitive

public void setCaseSensitive(int columnIndex, boolean property)
throws java.sql.SQLException

This specifies whether the column is case sensitive. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The column index, starting at 1
property: | true for a case-sensitive column

setCatalogName

public void setCatalogName(int columnIndex, String catalogName)
throws java.sql.SQLException

This sets the name of the catalog for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
catalogName: | The column’s catalog name

setColumnCount

public void setColumnCount(int columnCount) throws java.sql.SQLException

This sets the number of columns in the RowSet. A SQLException is thrown if a database access error occurs.

Parameters:

columnCount:

The number of columns

setColumnDisplaySize

public void setColumnDisplaySize(int columnIndex, int size)
throws java.sql.SQLException

This sets the preferred width in characters for the column. Applications should use this value as a minimum field size when displaying it on-screen, for example. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
size: | The size of the column

setColumnLabel

public void setColumnLabel(int columnIndex, String label)
throws java.sql.SQLException

This method is used to provide a column title for a column of the rowset. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
label: | The title for the column

setColumnName

public void setColumnName(int columnIndex, String columnName)
throws java.sql.SQLException

This specifies a name for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
columnName: | The column name

setColumnType

public void setColumnType(int columnIndex, int SQLType)
throws java.sql.SQLException

This sets the SQL type for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex:

The index of the column, starting at 1

SQLType:

The SQL type for the column, as defined by one of the following:

  • Types.ARRAY

  • Types.BIGINT

  • Types.BINARY

  • Types.BIT

  • Types.BLOB

  • Types.BOOLEAN

  • Types.CHAR

  • Types.CLOB

  • Types.DATALINK

  • Types.DATE

  • Types.DECIMAL

  • Types.DISTINCT

  • Types.DOUBLE

  • Types.FLOAT

  • Types.INTEGER

  • Types.JAVA_OBJECT

  • Types.LONGVARBINARY

  • Types.LONGVARCHAR

  • Types.NULL

  • Types.NUMERIC

  • Types.OTHER

  • Types.REAL

  • Types.REF

  • Types.SMALLINT

  • Types.STRUCT

  • Types.TIME

  • Types.TIMESTAMP

  • Types.TINYINT

  • Types.VARBINARY

  • Types.VARCHAR

setColumnTypeName

public void setColumnTypeName(int columnIndex, String typeName)
throws java.sql.SQLException

This sets the type name for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
typeName: | The type name

setCurrency

public void setCurrency(int columnIndex, boolean property)
throws java.sql.SQLException

This method is used to specify whether the column represents a money value. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
property: | true if the column represents a currency

setNullable

public void setNullable(int columnIndex, int property)
throws java.sql.SQLException

This specifies whether the value of the column can be set to NULL in an insert or update. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex:

The index of the column, starting at 1

property:

Either one of columnNoNulls, columnNullable, or columnNullableUnknown, provided as attributes of the ResultSetMetaData class:

  • ResultSetMetaData.columnNoNulls: The specified column doesn’t allow NULL values.

  • ResultSetMetaData.columnNullable: The specified column allows NULL values.

  • ResultSetMetaData.columnNullableUnknown: The nullability of the specified column value is unknown.

setPrecision

public void setPrecision(int columnIndex, int precision)
throws java.sql.SQLException

This specifies the number of decimal digits for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
precision: | The number of decimal digits

setScale

public void setScale(int columnIndex, int scale) throws java.sql.SQLException

This specifies the number of digits to the right of the decimal point for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
scale: | The number of digits to the right of the decimal point

setSchemaName

public void setSchemaName(int columnIndex, String schemaName)
throws java.sql.SQLException

This sets the table schema for the column indicated. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
schemaName: | The schema name

setSearchable

public void setSearchable(int columnIndex, boolean property)
throws java.sql.SQLException

This can be used to specify whether the column can be used in a SQL WHERE clause. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The column index, starting at 1
property: | true if the column can be used in a WHERE clause

setSigned

public void setSigned(int columnIndex, boolean property)
throws java.sql.SQLException

This method sets the signed property for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
property: | true if the column contains signed values

setTableName

public void setTableName(int columnIndex, String tableName)
throws java.sql.SQLException

This sets the table name for the column. A SQLException is thrown if a database access error occurs.

Parameters:

columnIndex: | The index of the column, starting at 1
tableName: | The column’s table name


Interface RowSetReader

public interface RowSetReader

Rowsets can support the reader/writer paradigm. When this is the case, the rowset calls the RowSetReader each time that its rows must be loaded or reloaded.

Methods

readData

public void readData(RowSetInternal caller) throws java.sql.SQLException

RowSet.execute() calls this method when the rowset supports the reader/writer paradigm and the rowset’s rows have to be loaded or reloaded.

A SQLException is thrown if a database access error occurs.

Parameters:

caller:

The rowset that calls the reader


Interface RowSetWriter

public interface RowSetWriter

Rowsets can support the reader/writer paradigm. When this is the case, the rowset calls the RowSetWriter each time that its rows must be saved to the database.

Methods

writeData

public boolean writeData(RowSetInternal caller) throws java.sql.SQLException

The rowset calls this method when the rowset supports the reader/writer paradigm and data needs to be saved to the database to which this rowset is linked. A SQLException is thrown if a database access error occurs.

Parameters:

caller:

The calling rowset

Returns: true if the row can be written


Interface XAConnection

public interface XAConnection
extends PooledConnection

XA is a standard for distributed transactions. XAConnection is a connection object that can participate in such distributed transactions.

Methods

getXAResource

public javax.transaction.xa.XAResource getXAResource()
throws java.sql.SQLException

This obtains an XA resource to the caller in order to register it as a participant in a distributed transaction. A SQLException is thrown if a database access error occurs.

Returns: The XAResource


Interface XADataSource

public interface XADataSource

The XADataSource is normally registered with a naming service using JNDI. It is used to access XAConnection objects.

Methods

getLoginTimeout

public int getLoginTimeout() throws java.sql.SQLException

This method enables you to get the time-out value for the connections. The time-out is the maximum time a connection will wait before determining that the connection cannot be established and throwing a SQLException is thrown if a database access error occurs.

Returns: The maximum amount of time for the login to succeed, in seconds

getLogWriter

public java.io.PrintWriter getLogWriter() throws java.sql.SQLException

This gets a character output stream to which all logging and tracing data is currently written. Logging is null by default, until the log writer is set for the first time. A SQLException is thrown if a database access error occurs.

Returns: The character output stream for the log writer for the data source or null if none is available

getXAConnection

public XAConnection getXAConnection() throws java.sql.SQLException

This establishes a database connection that must participate in distributed transactions using the default login and password for the current data source. You can use the getXAConnection(String user, String password) method to use another user/password pair for the connection. A SQLException is thrown if a database access error occurs.

Returns: A connection to the database

getXAConnection

public XAConnection getXAConnection(String user, String password)
throws java.sql.SQLException

This establishes a database connection that must participate in distributed transactions using the login and password provided. A SQLException is thrown if a database access error occurs.

Parameters:

user: | The database user for the connection
password: | The password

Returns: A connection to the database

setLoginTimeout

public void setLoginTimeout(int seconds) throws java.sql.SQLException

This method enables you to specify a time-out value for the connections. The time-out is the maximum time a connection will wait before determining that the connection cannot be established and throwing a SQLException is thrown if a database access error occurs.

Parameters:

seconds:

The maximum amount of time for the login to succeed, in seconds

setLogWriter

public void setLogWriter(java.io.PrintWriter out) throws java.sql.SQLException

This sets a character output stream to which all logging and tracing data will be written. Logging is null by default, until the log writer is set using this method. A SQLException is thrown if a database access error occurs.

Parameters:

out:

The character output stream used for the log writer of the data source or null if none is available, which disables logging


Index

Symbol

? (question mark), 177–178


Previous Next

Index

A

aborting transactions, 133
abstract data types, passing, 148
Abstract Window Toolkit (AWT), 4
access errors
connections, 520–523
described, 489–491
interactive Structured Query Language (SQL) tool, 278–280
queries, 509
access warnings
clearing, 371
connection, checking, 374
constructors, 501–502
queries and updates, 103–106
value, getting, 509
account, bank
account balance and other controls, 255–256
Account.java class, 257–262
ATM panel, 256–257
business data components, 41–42
business logic components, 41
clock, updating (TimeT.java), 267
HyperText Markup Language (HTML) file, 257
NetBank.java class, 262–266
tables, creating (Data Definition Language (DDL)), 268–269
usefulness, 253
welcome screen, 254
ACID properties. See Transaction Management
addBatch()method, 139–141
airline database example
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
flight information (Flight.java), 239–240
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
HyperText Markup Language (HTML) file, 226
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
Airplet.java, 226–231
AirportChoice.java, 235–236
Airport.java, 231–235
aliasing columns, 421
American National Standards Institute (ANSI), 419–420
API. See application programming interface (API)
applets
applications versus, 48
permissions, checking, 35
traditional applications versus, 48–49
application
applets versus, 48
database transactions, 253–269
driver manager, interaction with, 33
drivers, loading. See DriverManager
interactive Structured Query Language (SQL) client application, 203–217
Java Database Connectivity (JDBC), 26–27
Java database explorer. See Java database explorer
multimedia content, handling, 217–224
multitier applications, remote method invocation and Java Database Connectivity (JDBC), 323–341
Open Database Connectivity (ODBC) component, 20–21
phonebook service example, 186–189
remote database access through browser, 225–252
shopping cart example, 189–191
values, receiving, 146–148
application, database explorer
catalogs, browsing, 275–278
database engine specifications and limitations, 275
described, 271–272
interactive Structured Query Language (SQL) tool, 278–280
logging in, 272–274
navigation graphical control, 274
source code, 280–323
application, multitier
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
interfaces, 330–331
remote method invocation (RMI) server, 340–341
application, remote access
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
described, 225
flight information (Flight.java), 239–240
HyperText Markup Language (HTML) file, 226
application logic
embedding on database. See stored procedures
JDBC 3.0 Extension (J2EE) tier, 39
application programming interface (API)
availability, 54–55
Java Database Connectivity (JDBC), 45
listed, 4–5
usefulness, 3
application servers
components, distributed. See EJB)
connection pool, maintaining, 10
database-mapping code for entity beans, 192
Application Service Providers (ASPs), 9
Array or ARRAY
callable statement, 353
column, updating, 472
column value, 453
data type conversion, 491
defined, 34
Java Database Connectivity (JDBC) interface, 345–348
parameter, setting, 529
PreparedStatement, 441
updating, 134–135
writing, 495
AsciiStream
callable statements, 367
CLOB pointer, 368–369
column, updating, 473
mapping to Java, 491
prepared statements, 441–442
retrieving, 529
updating ResultSet, 134–135
writing, 495
ASPs. See Application Service Providers (ASPs)
ATM panel, banking application, 256–257
atomicity, data, 124
.au, 221
audio synthesis and recognition, 4
auto-generated keys, 422
automobile factories application
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
interface (CarFactory.java), 330–331
interface (Car.java), 327–328
remote method invocation (RMI) server, 340–341
AWT. See Abstract Window Toolkit (AWT)


Previous Next

Index

B

banking application
account balance and other controls, 255–256
Account.java class, 257–262
ATM panel, 256–257
business data components, 41–42
business logic components, 41
clock, updating (TimeT.java), 267
HyperText Markup Language (HTML) file, 257
NetBank.java class, 262–266
tables, creating (Data Definition Language (DDL)), 268–269
usefulness, 253
welcome screen, 254
batch commands
retrieving, 221
sending, 217–220
batch updates
checking for support, 420
described, 139–141
exception, throwing, 348–350
BEA Weblogic, 185
bean-managed persistence, 194–199
BigDecimal
callable statement, 360
column, updating, 473
mapping to Structured Query Language (SQL), 454–455
prepared statement, 442
reading, 529
updating, 134–135
writing, 495–496
BIGINT, 181–182
BINARY, 182
binary large object. See Blob or BLOB
BinaryStream
callable statement, 360
prepared statement, 442
reading, 529–530
retreiving values, 455–456
updating, 474
writing, 496
BIT, 181
Blob or BLOB
callable statements, 360
checking for detection, 390
data type conversion, 221
Java Database Connectivity (JDBC) interface, 350–353
parameter, setting, 530
prepared statement, 442
prepared statements, sending, 154–155
reading, 492
receiving, 94–95
retrieving, 220–224
sending, 217–220
storing, 71–72
updating, 474
value, getting, 456
writing, 496
books, recommended reading, 19
Boolean
callable statements, 360–361
column, updating, 474–475
mapping, 182
parameter, setting, 530
prepared statements, 443
reading, 492
value, getting, 456
writing, 496
bridge driver
application programming (API) interface, 54–55
connection, 56
database management system (DBMS), 32–33
Open Database Connectivity (ODBC), 29–30
business data, Enterprise JavaBeans, 41–42
business logic
described, 8
session beans, 185
byte
callable statements, 361
column, updating, 475–476
mapping, 182
parameter, setting, 530–531
prepared statements, 443
reading, 492
value, getting, 457
writing, 496–497


Previous Next

Index

C

C++, 6
call-level interface (CLI), 131
callable statements
accessing parameters, 180
batch updates, 139–141
creating, 375–376
example, 149–150
information about, 437–440
Java Database Connectivity (JDBC) interface, 353–367
setting parameters, 183
stored procedures, handling, 145–150
canceling
transactions, 253
unwanted results (cancel() method), 87–88
car factories application
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
interface (CarFactory.java), 330–331
interface (Car.java), 327–328
remote method invocation (RMI) server, 340–341
catalogs
browsing with Java database explorer, 275–278
defined, 63
differences among databases, 169
identifiers, checking, 403
methods supported, checking, 420
name, 544–545
tables available, 411–412
chained transaction mode, 125
changes. See also batch updates
auto-increments, 544
canceling, 452
car factory example, 214
clock (TimeT.java), 267
columns, 472–482
columns, automatic, 414–415
concurrency levels, setting, 451
with cursors, 138–139
detecting, 543
dirty reads, 125
dynamically typed data, 180–183
interactive Structured Query Language (SQL) tool in Web browser, 278–280
noncritical events during (SQLWarning), 103–106
performing, 70–71
ResultSets with cursors, 135–139
ResultSets without cursors, 134–135
tables, 26–27
char or CHAR, 181
character large objects. See clob or CLOB
character stream
callable statements, 366
CLOB pointer, 367
converting, 468
parameter, setting, 531
prepared statements, 448–449
character strings, mapping, 112–113
CLI. See call-level interface (CLI)
client/server architecture
car factory example, illustrated, 324
embedded Structured Query Language (SQL), limitations of, 16
interactive Structured Query Language (SQL), 203–217
JDBC 3.0 Extension (J2EE) client tier, 38
relational databases, 14–15
remote method invocation, 334–340
clob or CLOB
callable statements, 361
column, updating, 476–477
data type conversion, 179
Java Database Connectivity (JDBC) interface, 367–370
parameter, setting, 531
prepared statements, 444
reading, 492–493
Structured Query Language (SQL) statements, 71–72
values, getting, 458
writing, 497
clock, updating (TimeT.java), banking application, 267
close() method, 371
closing
connection, checking, 374
database connections, 524
memory, 62
result set, 88
rows, 452–453
Structured Query Language (SQL) statements, 71
Cloudscape
sample driver, 59
sample URL, 58
Codd, E.F., 13
code
Account.java banking application, 257–262
airline example, 227–252
compiling, 55
connection for Java database explorer, 280–299
database connectivity for car factory example, 331–334
error box for Java database explorer, 299–301
generated by entity bean container, 199–200
generated by programmer, 194–200
help box for Java database explorer, 302–304
implementation for car factory example, 328–330
interfaces for car factory example, 330–331
login for Java database explorer, 305–306
main frame for Java database explorer, 306–312
navigator for Java database explorer, 313–320
NetBank.java banking application, 262–266
reference look-up for car factory example, 334–340
registry binding for car factory example, 340–341
retrieving BLOBs, 221–224
sending BLOBs, 218–220
Structured Query Language (SQL) commands for Java database explorer, 320–323
TimeT.java banking application, 267
codes, airport, 235–236
collaboration, 4
ColumnLayout.java, 237–239
columns
adding to tables, 419
aliasing, 421
arranging in single, 237–239
attributes, relationship to (deployment descriptors), 192
browsing, 277–278
counting, 545
field size, maximum, 534
finding, 453
foreign keys, 395–396
name, 545
number and label, getting, 78–79
properties, 483–484
ResultSetMetaData interface, 174
rows, identifying, 391–392
updates, 472–482
columns, accessing
by column indexes, 80–82
by name, 82–83
as objects, 179–180
reading, 79–80
commands, batch
retrieving, 221
sending, 217–220
commands, general behavior of, 63–64
committing transactions
autocommit mode, 126
checking database requirements, 371–373
closing after, 133
defined, 125
intermediate, allowing, 35
Common Object Request Broker Architecture (CORBA) Internet Inter-Orb Protocol (IIOP), 4
communication protocol, 29–30
completing transactions, 125
computers, distributing Java objects across
car factory implementation (CarFactoryImpl.java), 331–334
car factory interface (CarFactory.java), 330–331
car implementation (CarImpl.java), 328–330
car interface (Car.java), 327–328
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
concurrency levels
availability, checking, 459
levels, checking, 509
setting, 531–532
updates, 133
Connect Software, Inc., 225
Connect SW
sample driver, 59
sample URL, 58
Connection
defined, 46
driver, finding, 433–434
establishing (Airplet.java), remote database access through browser, 226–231
events notification, 520–521
factory, 36
Java Database Connectivity (JDBC) interface, 370–381
maximum allowable, 404
needs, 8
objects, 522–524
statements, 506–507
connection pool
advantages, 9–10
described, 524–525
Enterprise JavaBeans, 185
managing (ConnectionPoolDataSource), 521–522
tier location, 40
ConnectionEvent, 519–520
ConnectionEventListener, 520–521
ConnectionPoolDataSource, 521–522
consistency, data, 124–125
constants, Structured Query Language (SQL) types, 515–518
constructors
BatchUpdateException class, 349–350
ConnectionEvent class, 519–520
DataTruncation, 381
Date, 430
DriverPropertyInfo, 437
RowSetEvent, 541
SQLException, 489–490
SQLPermission, 500
SQLWarning, 501–502
Time, 512–513
Timestamp, 513–514
container-managed persistence
bean-managed persistence versus, 199–200
defined, 10
entity beans, 192–194
converting
availability, checking, 421
changing, 381
connection, checking, 528
data, implicit, 103
Java Database Connectivity (JDBC) interface (SQLData), 488–489
parameters, setting, 540–541
result types, 89–94
Structured Query Language (SQL) data type conversions, 449–450
tables, 115–117
CORBA. See Common Object Request Broker Architecture (CORBA) Internet Inter-Orb Protocol (IIOP)
counters, automatic. See auto-generated keys
currency, 547
cursors
checking, 469–470
closing at commit, 451–452
creating, 98
database, 15
monitoring, 543
moving, 542
name, 510
scanning ResultSets, 132–134
Structured Query Language (SQL), creating, 98
updating ResultSets, 135–139


Previous Next

Index

D

2D or 3D graphical routines, 4
data. See also entity beans
Enterprise JavaBeans, 41–42
entry, auto-generated keys, 158–159
modifying, 18
structure, multitier applications, 324–325
Data Definition Language (DDL)
checking, 421
defined, 17
tables, creating, 268–269
data logic, 8
Data Manipulation Language (DML), 427
data source
Java Database Connectivity (JDBC), 28
multiple. See distributed transactions
name, setting, 532
Open Database Connectivity (ODBC), 22
data stores. See resource tier
data streams, 72
data truncation
defined, 72
unexpected (DataTruncation exception), 381–382
data types, mapping
ARRAY, 345–348
BIGINT, 181–182
BINARY, 182
BIT, 181
Blob or BLOB, 221
Boolean, 182
byte, 182
char or CHAR, 181
clob or CLOB, 179
DATALINK, 500
date or DATE, 430
DECIMAL, 181
DISTINCT, 179
double or DOUBLE, 181
entity beans, 200
FLOAT or float, 180–181
int or INTEGER, 180–181
JAVA_OBJECT, 93
LONGVARBINARY, 182
LONGVARCHAR, 458
NUMERIC, 181
REAL, 179–181
Ref or REF, 179
short, 113
SMALLINT, 180–181
String, 182
Struct or STRUCT, 511–512
time or TIME, 182
timestamp or TIMESTAMP, 182
TINYINT, 180–181
Unicode character stream, 468
VARBINARY, 182
VARCHAR, 181
database
applets, 48
client/server architecture, 14–15
connection method, 46
driver, 34
engine specifications and limitations, 275
errors (SQLException), 489–491
information, 162–165
integrating, 23–36
integrating changes made in RowSet, 36
limitations, 275
objects, 168–174
Open Database Connectivity (ODBC) standard, 20–22
relational, explained, 13–14
sample URLs, 58
Structured Query Language (SQL) standard, 16–20
tier location, 40
version numbers, getting, 396–397
warnings (SQLWarning), 501–502
database connections
closing, 62–63
creating, 60–62
Java Database Connectivity (JDBC) driver, specifying, 58–60
multiple, 10
naming scheme, 56–58
parameters, necessary, 55–56
properties, adjusting, 63–64
steps, 64–66
database cursors, 15
database engine, 162–165
database explorer application
catalogs, browsing, 275–278
database engine specifications and limitations, 275
described, 271–272
interactive Structured Query Language (SQL) tool, 278–280
logging in, 272–274
navigation graphical control, 274
source code, 280–323
database management system (DBMS)
applications sending Structured Query Language (SQL) statements. See JDBC)
defined, 13
examples listed, 32–33
interfaces, 53–55
database transactions
account balance and other controls, 255–256
ATM panel, 256–257
clock, updating (TimeT.java), 267
HyperText Markup Language (HTML) file, 257
interface, 35
isolation mode, 539–540
multiple, 424
NetBank.java class, 262–266
preserving ResultSets across, 133
processing monitors, 12
support, checking, 428
tables, creating (Data Definition Language (DDL)), 268–269
usefulness, 253
welcome screen, 254
DatabaseMetaData
features supported, 165–166
field, 383–389
information, 373
limitations, 166–168
objects, 168–174
DATALINK
callable statement, 366–367
data type conversion, 500
DataSource objects, 522–524
DataTruncation exception, 381–382
date and time functions
listing, 411–412
Structured Query Language (SQL) escape syntax, 122–123
date or DATE
callable statements, 361–362
column, getting as, 459–460
column, updating, 477
parameter, setting, 532
prepared statements, 444
reading, 493
String, converting to, 89
type conversions, 430
writing, 497
DB2
sample driver, 59
sample URL, 58
DBMS. See database management system (DBMS)
DCE. See Distributed Computing Environment (DCE) naming service
DDL. See Data Definition Language (DDL)
deadlocks, preventing, 126
DECIMAL, 181
deleting
with cursors, 137–138
detecting, 543
positioned, 426
rows, 453
savepoint, 378
tables, 17
deployment descriptors, 192
development, 37
direct invocation, Structured Query Language (SQL), 16
dirty reads, 539–540
DISTINCT data, 179
Distributed Computing Environment (DCE) naming service, 57
distributed services, 4
distributed transactions
advantages, 10
JDBC 3.0 Extension (J2EE) interface (XAConnection), 550
transaction management, 130–131
DML. See Data Manipulation Language (DML)
double or DOUBLE
callable statements, 362
column, updating, 477
column value, getting, 460
parameter, setting, 533
prepared statements, 444
reading, 493
type conversions, 181
writing, 497
driver
choosing, 59
integration tier, 40
Java Database Connectivity (JDBC), 431–432
Open Database Connectivity (ODBC), 51
required to use book, 11
sample, 59–60
specifying, 58–60
time outs, setting, 73–74
version number, getting, 398
DriverManager
choosing driver, 59
defined, 46
methods, 432–436
Open Database Connectivity (ODBC), 21
queries and updates, refining, 109–112
user application and, 33
DriverPropertyInfo class, 436–437
durability, data, 125
dynamic bindings, 5
dynamic Structured Query Language (SQL), 34
dynamically typed data
inserting or updating, 180–183
retrieving, 178–180


Previous Next

Index

E

EJB. See Enterprise JavaBeans (EJB)
embedded Structured Query Language (SQL), 16
embedding, application logic on database
callable statements, 353–367
client-server architecture, 15
creating, 19
creating object, 375
descriptions, 427–428
Structured Query Language (SQL) escape syntax, 120
unchained transactions, 125
employees
adding photographs to table, 218–220
retrieving photographs from table, 221–224
encapsulation, 5
Enterprise JavaBeans (EJB)
advantages, 5
business data components, 41–42
business logic components, 41
container-managed persistence, 10
entity beans, 192–200
interface, 36
RowSet properties, 525–541
session beans, 186–191
types, 185
usefulness, 40–41
enterprise platform, Java’s acceptance as, 3–6
entity beans
banking application, 41–42
bean-managed persistence, 194–199
container-managed persistence, 192–194
container-managed versus bean-managed persistence, 199–200
defined, 185
tier location, 39
errors
DataTruncation, 106–107
driver or database, 35
interactive Structured Query Language (SQL) tool in Web browser, 278–280
SQLException, 101–103
escape processing, 526
escape string, wildcard characters, 423
examples. See sample
exception
batch updates, 348–350
connections, 523
described, 489–491
driver or database error, 35
interactive Structured Query Language (SQL) tool, 278–280
queries, 509
unsupported conversions, 89
execute() statement, 70–71
executing, prepared statements, 151–153
explorer, database explorer
catalogs, browsing, 275–278
database engine specifications and limitations, 275
described, 271–272
interactive Structured Query Language (SQL) tool, 278–280
logging in, 272–274
navigation graphical control, 274
source code, 280–323
exported keys, 398


Previous Next

Index

F

factories application
CarFactory.java interface, 330–331
Car.java interface, 327–328
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
remote method invocation (RMI) server, 340–341
fetching
columns, 79–83
direction, 472
result types, 511
field
Connection, 370–371
DatabaseMetaData, 383–389
DriverPropertyInfo, 436–437
ParameterMetaData, 437
ResultSet, 450–452
ResultSetMetaData, 483
Types, 515–518
field size, maximum
getting, 526–527
setting, 534
filenames, referring to data with, 115
firewalls, 31
first(), 132
fixed-point numbers, 113
flights
between airports (FlightsVector.java), 243–244
information (Flight.java), 239–240
x-y coordinates (MapInfo.java), 249–250
FLOAT or float
callable statements, 362
column, updating, 478
column value, 461
parameters, setting, 533
prepared statements, 445
type conversions, 180–181
writing, 497–498
foreign keys
descriptions, 400–401
tables, 395–396
Forte for Java, 11
function calls
call-level interface (CLI) library. See SAG-X/Open CLI
Open Database Connectivity (ODBC) interface, 20
processing. See driver
functions, checking database for availability, 165–166


Previous Next

Index

G

garbage collector, automatic, 5
getAutoClose() method, 62–63
getConnection() method, 61
getPropertyInfo() method, 111
graphical user interface, properties, prompting, 111
grouping SQL statements
defined, 124–125
distributed transactions, 130–131
Enterprise JavaBeans, 185
isolation levels, 125–126
managing, 126–128
modes, 125
savepoints, 129–130
.gui files, 253


Previous Next

Index

H

handheld devices, 50
Hypersonic
sample driver, 59
sample URL, 58
HyperText Markup Language (HTML) file
advantages, 38
banking application, 257
client applet example, 209–217
remote database access through browser, 226
thin-client applications, 50
HyperText Transfer Protocol (HTTP)
applets, 48
proxy awareness, 341
tunneling, 50


Previous Next

Index

I

IBM San Jose Research Lab, 13–14
IBM WebSphere, 185
IDE. See Integrated Development Environment (IDE)
ImageCanvas.java, 244–246
impedance mismatch, 23
IN parameters
callable statements, 353
dynamically typed data, 180–183
setting, 146–148
subqueries, 428
indexes
catalogs, checking use, 420
columns, accessing by, 453
creating, 18–19
data truncation, 382
length, maximum, 405
ResultSet, 347
table, describing, 402–403
information, holding from session to session, 189–191
Informix
sample driver, 59
sample URL, 58
inheritance, support, 5
input, SQL stream (SQLInput), Java Database Connectivity (JDBC) interface, 491–495
INSERT, money transfers, 253
inserting
auto-generated keys, 158–159
BLOBs into table, 217–220
detecting, 543
dynamically typed data, 180–183
rows, 471
int or INTEGER
callable statements, 362–363
column value, getting, 478
parameters, setting, 533
prepared statements, 445
reading, 493
type conversions, 180–181
writing, 498
Integrated Development Environment (IDE), 11
integration tier, JDBC 3.0 Extension (J2EE), 40
Interactive SQL client, Web browser, 209–217
Interactive Structured Query Language (ISQL)
client application, 203–217
Java database explorer, 278–280
interface
application, multitier, 330–331
Array or ARRAY, 345–348
binary large object, 350–353
call-level (CLI), 131
callable statements, 353–367
car factories application, 330–331
columns, 174
Connection, 370–381
database management system (DBMS), 53–55
distributed transactions, 550
driver, 431–432
Enterprise JavaBeans (EJB), 36
graphical user, 111
Java Database Connectivity (JDBC), 46–47
Java Naming and Directory Interface (JNDI), 551
Java Native Interface (JNI), 5
multitier application example, 330–331
Open Database Connectivity (ODBC), 20
output, Structured Query Language (SQL) stream (SQLOutput), Java Database Connectivity (JDBC) interface, 495–500
prepared statements, 34
ResultSet, 35
RowSet, 36
interface, application programming (API)
availability, 54–55
Java Database Connectivity (JDBC), 45
listed, 4–5
usefulness, 3
interface, Java Database Connectivity (JDBC)
Array, 345–348
Blob, 350–353
callable statements, 353–367
Clob, 367–370
Connection, 370–381
database information, returning. See DatabaseMetaData
driver, 431–432
input, Structured Query Language (SQL) stream (SQLInput), 491–495
intermediate points in transactions, marking (Savepoint), 488
map Structured Query Language (SQL) structured types (Struct), 511–512
output, Structured Query Language (SQL) stream (SQLOutput), 495–500
PreparedStatement and CallableStatement objects, information about (ParameterMetaData), 437–440
ResultSet objects, 483–487
Structured Query Language (SQL) REF value (Ref), 449–450
Structured Query Language (SQL) statements, 502–511
type mapping (SQLData), 488–489
interface, JDBC 3.0 Extension (J2EE)
connection events, notifications (ConnectionEventListener), 520–521
Connection objects, creating (DataSource objects), 522–524
connection pool, managing (ConnectionPoolDataSource), 521–522
connection pool (PooledConnection), 524–525
distributed transactions (XAConnection), 550
naming service (XADataSource), 551–552
ResultSetMetaData, additional initialization parameters (RowSetMetaData), 544–549
rows, 549–550
RowSet JavaBeans properties, 525–541
rowset state and parameters, obtaining information (RowSetInternal), 542–543
interface, metadata
connection, getting, 462
DatabaseMetaData, 278
dynamic data access, 178–183
Java database explorer example, 275
ParameterMetaData, 177–178
ResultSetMetaData, 174–177
usefulness, 161–162
intermediate steps, marking
deleting, 378
setting, 380
supported, 426
transaction management, 129–130
Internet
e-commerce, shopping cart example, 189–191
Java, suitability for, 3
rich-client applications, 50
Internet Web browser
BLOB data type, specifying, 221
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
history, 9
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
proxies, 31
Structured Query Language (SQL) client using, 209–217
Internet Web browser, remote access example
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
described, 225
flight information (Flight.java), 239–240
HyperText Markup Language (HTML) file, 226
intranets, 50
iPlanet Application Server, 192
isolation levels, transaction management, 125–126


Previous Next

Index

J

JAAS. See Java Authentication and Authorization Service (JAAS)
JAI. See Java Advanced Imaging API (JAI)
JAIN APIs, 4
Java 2 Micro Edition for Connected, Limited Device Configuration (CLDC), 5
Java Advanced Imaging API (JAI), 4
Java Authentication and Authorization Service (JAAS), 4
Java client drivers. See Type 4 driver
Java COMM, 4
Java Cryptography Extension (JCE), 4
Java Database Connectivity (JDBC)
API (application programming interface), 45
applets, 48–49
application, 26–27
BLOBs, receiving, 94–95
characteristics, 24–25
class BatchUpdateException, 348–350
columns, 78–83
connecting, 55–66
cursors, creating, 98
data source, 28
data value, unexpected truncation (DataTruncation exception), 381–382
database, method for connecting, 46
database access warnings (SQLWarning), 501–502
Date class, 430
DriverManager, 432–436
drivers, 27–33
errors and warnings, managing, 101–107
fetchable result types, 75–76
interfaces, 53–55
new features, 28–29
Open Database Connectivity (ODBC) versus, 51
package contents, 34–35
package extensions, 35–36
permission, checking (SQLPermission), 500
properties, adjusting, 95–98
result set, 88
result types, managing multiple, 83–87
rich-client applications, 50
role, 23–24
rows, retrieving, 76–78
SQL types constants and values, defined (Types), 515–518
statements, sending, 66–74
thin-client applications, 50
time, handling (Time), 512–513
time values (Timestamp), 513–515
types, converting, 89–94
typical uses, 47
unwanted results, canceling, 87–88
user application and driver manager, interaction between, 33
Java Database Connectivity (JDBC) drivers, property information (DriverPropertyInfo class), 436–437
Java Database Connectivity (JDBC) exceptions, database access errors (SQLException), 489–491
Java Database Connectivity (JDBC) interface
Array, 345–348
Blob, 350–353
callable statements, 353–367
Clob, 367–370
Connection, 370–381
database information, returning. See DatabaseMetaData
driver, 431–432
input, Structured Query Language (SQL) stream (SQLInput), 491–495
intermediate points in transactions, marking (Savepoint), 488
map Structured Query Language (SQL) structured types (Struct), 511–512
output, Structured Query Language (SQL) stream (SQLOutput), 495–500
PreparedStatement and CallableStatement objects, information about (ParameterMetaData), 437–440
ResultSet objects, 483–487
Structured Query Language (SQL) REF value (Ref), 449–450
Structured Query Language (SQL) statements, 502–511
type mapping (SQLData), 488–489
Java Database Connectivity (JDBC) queries and updates, refining
batch updates, 139–141
Driver and DriverManager, internals, 109–112
ResultSets, types of, 131–139
Structured Query Language (SQL) data type conversions, 112–119
Structured Query Language (SQL) escape syntax, 120–124
transaction management, 124–131
Java database explorer
catalogs, browsing, 275–278
database engine specifications and limitations, 275
described, 271–272
interactive Structured Query Language (SQL) tool, 278–280
logging in, 272–274
navigation graphical control, 274
source code, 280–323
Java drivers. See Type 2 driver
Java Dynamic Management Kit (JDMK), 4
Java Foundation Classes (JFC), 4
Java Management Extensions (JMX), 4
Java Messaging Service (JMS), 40
Java Naming and Directory Interface (JNDI), 551
Java Native Interface (JNI), 5
Java Server Pages (JSP), 4
Java Shared Data Toolkit (JSDT), 5
Java Telephony call control API (JTAPI), 4
Java Transaction API (JTA), 4
Java Transaction Service (JTS), 4
Java Virtual Machine (JVM), 6
JavaBeans (EJB)
advantages, 5
business data components, 41–42
business logic components, 41
container-managed persistence, 10
entity beans, 192–200
interface, 36
RowSet properties, 525–541
session beans, 186–191
types, 185
usefulness, 40–41
JavaCard, 4
JavaIDL, 4
JavaMail, 4
JAVA_OBJECT, data type conversion, 93
JavaPhone, 4
JavaSoft, 341
JavaSpaces, 4
JavaSpeech, 4
JavaTV, 4
JBuilder, 11
JCE. See Java Cryptography Extension (JCE)
JDBC 3.0 Extension (J2EE)
advantages of using, 37–38
application logic tier, 39
client tier, 38
connection events, notifications (ConnectionEventListener), 520–521
connections, managing pool (ConnectionPoolDataSource), 521–522
connections (ConnectionEvent), 519–520
databases, 9–10
Enterprise JavaBeans, 40–42
integration tier, 40
presentation tier, 39
resource tier, 40
rowset state, significant changes in (RowSetEvent), 541
JDBC 3.0 Extension (J2EE) interface
connection events, notifications (ConnectionEventListener), 520–521
Connection objects, creating (DataSource objects), 522–524
connection pool (PooledConnection), 524–525
connections, managing pool (ConnectionPoolDataSource), 521–522
distributed transactions (XAConnection), 550
naming service (XADataSource), 551–552
ResultSetMetaData, additional initialization parameters (RowSetMetaData), 544–549
rows, 549–550
RowSet JavaBeans properties, 525–541
rowset state and parameters, obtaining information (RowSetInternal), 542–543
JDMK. See Java Dynamic Management Kit (JDMK)
J2EE. See JDBC 3.0 Extension (J2EE)
JFC. See Java Foundation Classes (JFC)
Jini, 4
J2ME CLDC. See Java 2 Micro Edition for Connected, Limited Device Configuration (CLDC)
JMS. See Java Messaging Service (JMS)
JMX. See Java Management Extensions (JMX)
JNDI. See Java Naming and Directory Interface (JNDI)
JNI. See Java Native Interface (JNI)
JPEG, 221
JSDT. See Java Shared Data Toolkit (JSDT)
JSP. See Java Server Pages (JSP)
JTA. See Java Transaction API (JTA)
JTAPI. See Java Telephony call control API (JTAPI)
JTree, 274


Previous Next

Index

K

Kawa, 11
keys
auto-generated, 422
exported, 398
primary, 324
keywords, information, getting, 409


Previous Next

Index

L

label
column, displaying, 545
remote database access through browser, 250–252
results, getting, 78–79
last(), 132
LDAP. See Lightweight Directory Access Protocol (LDAP) directory server
legacy systems, JDBC 3.0 Extension (J2EE) connections. See J2EE)
libraries
call-level interface (CLI), 19–20
client-server architecture, 14
database-native. See Type 2 driver
forwarding calls to, 30
Open Database Connectivity (ODBC), 20
programming without learning many, 3
Lightweight Directory Access Protocol (LDAP) directory server, 144
loading (RowSetReader), rows, 549–550
log stream, 551
logging in
Java database explorer, 272–274
money transfer application, 254
SQLExceptions, 102
timeout, 523–524
username, maximum length, 406
logic
application tier, 39
business, session beans
client-server architecture, 15
three-tier architecture, 8
login. See logging in
Long
callable statements, 356
column, updating, 478–479
column value, getting, 462
parameters, setting, 533–534
prepared statements, 445
reading, 493
writing, 498
LONGVARBINARY, 182
LONGVARCHAR, 458


Previous Next

Index

M

Macintosh, 272
mail libraries, 4
maintenance, 37
map, displaying appropriate, 246–249
MapCanvas.java, 246–249
MapInfo.java, 249–250
mapping
to another database connectivity API. See Type 1 driver
ARRAY, 345–348
BIGINT, 181–182
BINARY, 182
BIT, 181
Blob or BLOB, 221
Boolean, 182
byte, 182
char or CHAR, 181
clob or CLOB, 179
DATALINK, 500
date or DATE, 430
DECIMAL, 181
DISTINCT, 179
double or DOUBLE, 181
entity beans, 200
FLOAT or float, 180–181
int or INTEGER, 180–181
JAVA_OBJECT, 93
LONGVARBINARY, 182
LONGVARCHAR, 458
NUMERIC, 181
REAL, 179–181
Ref or REF, 179
short, 113
SMALLINT, 180–181
String, 182
Struct or STRUCT, 511–512
time or TIME, 182
timestamp or TIMESTAMP, 182
TINYINT, 180–181
Unicode character stream, 468
VARBINARY, 182
VARCHAR, 181
Marimba Bongo, 253
marking intermediate points in transactions, 488
math functions, supported, 406
memory
closing connections, 62
closing result set, 88
Message Oriented Middleware (MOM), 40
messages, listing employees with pending, 124
metadata interfaces
connection, getting, 462
DatabaseMetaData, 278
dynamic data access, 178–183
Java database explorer example, 275
ParameterMetaData, 177–178
ResultSetMetaData, 174–177
usefulness, 161–162
Microsoft, Open Database Connectivity (ODBC). See ODBC)
Microsoft Access, cursors, nonsupport of, 135
Microsoft Windows, 272
middleware peer on server. See Type 3 driver
MiniSQL
sample driver, 59
sample URL, 58
modifying data, 18
modules
Open Database Connectivity (ODBC), 20
Structured Query Language (SQL), defined, 16
MOM. See Message Oriented Middleware (MOM)
money transfers
account balance and other controls, 255–256
Account.java class, 257–262
ATM panel, 256–257
money transfers continued
clock, updating (TimeT.java), 267
HyperText Markup Language (HTML) file, 257
NetBank.java class, 262–266
tables, creating (Data Definition Language (DDL)), 268–269
usefulness, 253
welcome screen, 254
Motif, 272
MPEG (Motion Pictures Experts Group), 221
MultilineLabel.java, 250–252
multimedia, API, 4
multimedia content. See Blob or BLOB
Multimedia Internet Mail Extension (MIME), 221
multiple-tier drivers, 22
multiple types, results, managing, 83–87
multitier application example
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
interfaces, 330–331
remote method invocation (RMI) server, 340–341


Previous Next

Index

N

N-tiered computing, 7–8
names
catalog, 544–545
tables, 549
names, columns
accessing by, 82–83
checking maximum, 403
specifying, 545–546
naming scheme, database connections, 56–58
naming service (XADataSource), 551–552
native code drivers. See Type 2 driver
native form, 68
navigation
Java database explorer, 274
ResultSets, 132–134
Net driver, 29–30
NetBank.java, 262–266
networks
distributing Java objects across. See RMI)
remote access latency, 14–15
services APIs, 4
new features, Java Database Connectivity (JDBC), 28–29
next() method, 131–132
notifications, connection events, 520–521
null or NULL
callable statements, 437
column, updating, 482–483
detecting, 416
information, getting, 486
parameter, setting, 547–548
prepared statements, 445–446
reading, 495
number
data, mapping to Java, 113
results, getting, 78–79
rows, jumping to, 132
numbers, auto-generated keys, 158–159
NUMERIC, 181
numeric functions, Structured Query Language (SQL) escape syntax, 121–122


Previous Next

Index

O

Object Database Management Group (ODMG), 11
Object Query Language (OQL), 11
objects. See also entity beans
bridges, 11
callable statements, 363–364
column, updating, 479–480
connection. See Connection
data, representing, 185
default mapping from Structured Query Language (SQL), 178–179
impedance mismatch with Structured Query Language (SQL), 23
information, getting, 462–464
Java orientation, 5–6
parameters, setting, 535–537
persistence, 10
prepared statements, 446–447
reading, 493–494
reference types, handling. See Ref or REF
registered to receive events from pooled connections, 36
schema, 169
sharing, 4
storing in database, 148
writing, 498
ODBC. See Open Database Connectivity (ODBC)
ODMG. See Object Database Management Group (ODMG)
Online Transaction Processing (OLTP), 12
open call-level interface (CLI), Structured Query Language (SQL), 19–20
Open Database Connectivity (ODBC)
application component, 20–21
bridge driver, 29–30
Core Structured Query Language (SQL) grammar support, checking, 423
data source, 22
driver, 21–22
driver manager, 21
interface, 20
Java Database Connectivity (JDBC) versus, 22
versus specific drivers as a subprotocol, 51
standard, 20–22
Open Database Connectivity (ODBC) bridge
sample driver, 59
sample URL, 58
operating systems. See portability
Oracle
sample driver, 60
sample URL, 58
stored procedures, 150
Oracle Application Server, 185
Oracle Lite
sample driver, 60
sample URL, 58
OUT parameters
callable statements, 358
registering, 148–149
retrieving dynamically typed data, 178–180
outer joins
Structured Query Language (SQL) escape syntax, 124
support, checking, 425
output, Structured Query Language (SQL) stream (SQLOutput), Java Database Connectivity (JDBC) interface, 495–500


Previous Next

Index

P

Palm handhelds, 50
ParameterMetaData interface, 177–178
parameters
callable statements, 146–149
data truncation, 382
database connections, 55–56
prepared statements, 153–154
passing IN parameters, prepared statements, 153–154
password
errors, 102
maximum length, 527
parameter, setting, 552
sending with Uniform Resource Locator (URL), 60
performance, persistence, 199
permissions, checking (SQLPermission), 500
persistence
bean-managed, 194–199
car factory example, 324
container-managed, 192–194
container-managed versus bean-managed, 199–200
phantoms, 126
phonebook service example, 186–189
pictures, storing. See Blob or BLOB
PIN code, 254
platforms, availability on different, 51
polymorphism, 5
pooled connections
described, 524–525
managing, 521–522
status, 35–36
portability
drivers, 30–31
.gui files, 253
Java, 24
persistence, container-managed versus bean-managed, 199
platforms, availability on different, 51
precompiling Structured Query Language (SQL) statements, 440–449
PreparedStatement
batch updates, 139–141
BLOBs, sending, 154–155
creating, 376–378
defined, 150
executing, 151–153
information about, 437–449
interface, 34
parameters, setting, 183
passing IN parameters, 153–154
query, executing, 154
results, retrieving, 154
presentation tier
described, 8
JDBC 3.0 Extension (J2EE), 39
username, maximum length, 406
previous(), 132
primary keys
descriptions, 406
foreign keys, 395–396
interactive Structured Query Language (SQL), 324
programmatic interfaces, 16
programming editor, 11
programming languages, Structured Query Language (SQL)’s difference from, 16
properties
database connections, adjusting, 63–64
drivers, 436–437
results, adjusting, 95–98
Structured Query Language (SQL) statements, adjusting, 72–73


Previous Next

Index

Q

query
executing, 70
interactive Structured Query Language (SQL) tool in Web browser, 278–280
limiting number of rows returned, 96–97
noncritical events during (SQLWarning), 103–106
prepared statements, 154
retrieving results in text-based interface. See Interactive Structured Query Language (ISQL)
steps needed before, 69
time-out, 537
question mark (?), 177–178


Previous Next

Index

R

RDBMS. See relational databases
read-only mode, connections
checking, 374
detecting, 415–416
isolation mode, 528
parameters, setting, 549–550
setting, 63
verifying, 451
reads
columns, 79–80
data isolation levels, 125–126
data management, 370–371
data truncation on, 382
REAL, 179–181
receiving, BLOBs, 94–95
Ref or REF
callable statements, 364
column, updating, 480–481
column value, getting, 464
data type conversions, 93
Java Database Connectivity (JDBC) interface, 449–450
parameters, setting, 538
prepared statements, 447
reading, 494
writing, 498
registration
drivers, 435
OUT parameters, 358–359
rowset listener, 528
XAConnection, 550
Registry, 325–326
relational databases
client/server architecture, 14–15
defined, 13–14
mapping to Java classes, 25
object-orientation and, 6
Open Database Connectivity (ODBC) standard, 20–22
Structured Query Language (SQL) standard, 16–20
remote database access
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
client-server architecture, 14–15
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
described, 225
flight information (Flight.java), 239–240
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
HyperText Markup Language (HTML) file, 226
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
remote method invocation (RMI)
car factory implementation (CarFactoryImpl.java), 331–334
car factory interface (CarFactory.java), 330–331
car implementation (CarImpl.java), 328–330
car interface (Car.java), 327–328
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
remote method invocation (RMI) server
defined, 5
HTTP tunneling, 50
multitier applications, 340–341
Remote Procedure Calls (RPCs)
callable statements, 353–367
client-server architecture, 15
creating, 19
creating object, 375
descriptions, 427–428
Structured Query Language (SQL) escape syntax, 120
unchained transactions, 125
reservations database
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
flight information (Flight.java), 239–240
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
HyperText Markup Language (HTML) file, 226
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
resource tier
defined, 8
JDBC 3.0 Extension (J2EE), 40
results
BLOBs, receiving, 94–95
columns, 78–83
fetchable types, 75–76
multiple types, managing, 83–87
prepared statements, retrieving, 154
properties, adjusting, 95–98
result set, closing, 88
returning. See driver
rows, retrieving, 76–78
set, getting, 76
Structured Query Language (SQL) cursors, creating, 98
types, converting, 89–94
unwanted, canceling, 87–88
ResultSet
characteristics, 483–487
closing, 88
column values, accessing as objects, 179–180
cursors, creating, 98
defined, 131
executing, 505
holdability, 507
interface, 35
method for examining results, 97–98
multiple, 424
navigating, 132–134
objects, 450–482
rows, retrieving, 76–78
scanning, 470–471
Structured Query Language (SQL) ARRAY, returning results, 347
updating with cursors, 135–139
updating without cursors, 134–135
ResultSetMetaData
additional initialization parameters (RowSetMetaData), 544–549
column properties, 174–177
columns, 174
retrieving
BLOBs, 220–224
BLOBs from table, 220–224
data, 18
dynamically typed data, 178–180
reviewing query results
creating cursors, 98
ResultSets, 77–78
rich-client applications, Java Database Connectivity (JDBC), 50
RMI. See remote method invocation (RMI)
rollbacks
complete, 126
cursors, holding open, 425
defined, 125
intermediate savepoints, 379
routes, airport map, 240–243
rows
BLOBs, inserting, 217
checking for maximum size, 527
deleting, 18
dirty reads, 127–128
entity beans. See entity beans
identifying, 464
inserting, 471
interface, 35
loading (RowSetReader), 549–550
maximum number, 534
navigating, 132–134
property information, 175
results, retrieving, 76–78
retrieving, 76–78
saving (RowSetWriter), 550
updating, 508
RowSet
defined, 155
designing and using, 157
interface, 36
JavaBeans properties, 550
methods, 156
RowSet state
notifying of changes (RowSetListener), 543
obtaining (RowSetInternal), 542–543
significant changes in (RowSetEvent), 541
RPCs. See Remote Procedure Calls (RPCs)
runtime
discovering database objects, 168–174
Structured Query Language (SQL) queries, building, 174


Previous Next

Index

S

SAG-X/Open CLI, Structured Query Language (SQL), 19–20
sample
database transactions, 253–269
interactive Structured Query Language (SQL) client application, 203–217
Java database explorer. See Java database explorer
multimedia content, handling, 217–224
multitier applications, remote method invocation and Java Database Connectivity (JDBC), 323–341
phonebook service example, 186–189
shopping cart example, 189–191
sample airline database
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
flight information (Flight.java), 239–240
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
HyperText Markup Language (HTML) file, 226
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
sample database explorer application
catalogs, browsing, 275–278
database engine specifications and limitations, 275
described, 271–272
interactive Structured Query Language (SQL) tool, 278–280
logging in, 272–274
navigation graphical control, 274
source code, 280–323
sample multitier application
client class (CarSales.java), 334–340
client programs, 326–327
data structure, 324–325
described, 323–324
implementation, 328–334
interfaces, 330–331
remote method invocation (RMI) server, 340–341
sample remote access application
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
described, 225
flight information (Flight.java), 239–240
HyperText Markup Language (HTML) file, 226
savepoint
deleting, 378
setting, 380
supported, 426
transaction management, 129–130
scalar functions
date and time, 122–123
numeric, 121–122
string, 122
Structured Query Language (SQL) escape syntax, 121–123
system, 121
scanning query results
creating cursors, 98
ResultSets, 77–78
schema, 548
scrolling, rows, 451
searchability
setting, 548–549
verifying, 487
security, drivers, choosing, 31
SELECT queries, 135
sending
BLOBs, 217–220
prepared statements, 154–155
Structured Query Language (SQL) statements, 68–71
serial communications, 4
server, remote method invocation (RMI)
defined, 5
HTTP tunneling, 50
multitier applications, 340–341
servers
car factory example, illustrated, 324
embedded Structured Query Language (SQL), limitations of, 16
interactive Structured Query Language (SQL), 203–217
JDBC 3.0 Extension (J2EE) client tier, 38
relational databases, 14–15
remote method invocation, 334–340
servers, application
components, distributed. See EJB)
connection pool, maintaining, 10
database-mapping code for entity beans, 192
servlets, 50
session beans
banking application, 41
defined, 185
stateful, 189–191
stateless, 186–189
tier location, 39
setXXX() methods, 146–148
shopping cart example, 189–191
short
callable statements, 365
column, updating, 481
column value, getting, 464–465
mapping, 113
prepared statements, 447
reading, 494
writing, 499
Simple Network Management Protocol (SNMP), 4
simultaneous connections, checking for maximum, 166–167
single-tier drivers, 22
size, row maximum, 166–167
SMALLINT, 180–181
smartcards, 6
SNMP. See Simple Network Management Protocol (SNMP)
software partitioning, defined, 323
software reuse, 5
software tier, 15
sound files. See Blob or BLOB
source code
Account.java banking application, 257–262
airline example, 227–252
BLOBs, 221–224
compiling, 55
connection for Java database explorer, 280–299
database connectivity for car factory example, 331–334
error box for Java database explorer, 299–301
help box for Java database explorer, 302–304
implementation for car factory example, 328–330
interfaces for car factory example, 330–331
login for Java database explorer, 305–306
main frame for Java database explorer, 306–312
navigator for Java database explorer, 313–320
NetBank.java banking application, 262–266
reference look-up for car factory example, 334–340
registry binding for car factory example, 340–341
Structured Query Language (SQL) commands for Java database explorer, 320–323
TimeT.java banking application, 267
space padding, 113
special characters
availability, checking, 400
Structured Query Language (SQL) escape syntax, 123
speech synthesis and recognition, 4
SQL-92, 16
SQLData, 488–489
SQLException
connections, 520–523
described, 489–491
interactive SQL tool, 278–280
queries, 509
SQLInput, 491–495
SQLOutput, 495–500
SQLPermission, 500
SQLWarning
clearing, 371
connection, checking, 374
constructors, 501–502
during query or update, 103–106
value, getting, 509
stateful session beans, 189–191
stateless session beans, 186–189
Statement
batch updates, 139–141
database and driver resources, creating, 502–511
delayed execution. See time-outs
getting, 465
length, maximum, 405
sending, 46
stored procedures
callable statements, 353–367
client-server architecture, 15
creating, 375
descriptions, 427–428
Structured Query Language (SQL) escape syntax, 120
unchained transactions, 125
streams, retrieving, 94–95
String
auto-generated keys, 158–159
callable statement, 365
CLOB pointer, 369–370
DATE, converting from, 89
date, converting to, 430
getting, 465
mapping, 182
parameters, accessing, 180
prepared statements, 447
reading, 494
Structured Query Language (SQL) escape syntax, 122
supported, 410
updating, 481
writing, 499
Structured Query Language (SQL)
constants and values, defined (Types), Java Database Connectivity (JDBC), 515–518
cursors, creating, 98
defined, 14
dynamic, creating. See Prepared Statements
grammar support, checking, 419–420
impedance mismatch with object-oriented programming language, 23
inheritance, 119
keywords, information, getting, 163–165
mapping. See type mapping
relational databases, 16–20
SAG-X/Open CLI, 19–20
syntax, 17–19
uses, 16–17
Structured Query Language (SQL) data type conversions
accessing data using type map, 119
defining, 117–119
mapping data types to Java, 112–115
object-orientation and, 6
SQL inheritance, 119
type mapping tables, 115–117
Structured Query Language (SQL) escape syntax
callable statements, 353
outer joins, 124
scalar functions, 121–123
special characters, 123
stored procedures, 120
time and date, 120
Structured Query Language (SQL) statements
BLOBs and CLOBs, storing, 71–72
building, 67–68
closing, 71
creating database and driver resources (Statement), 502–511
defined, 66
grouping to treat as whole. See transaction management
precompiling (PreparedStatement), 440–449
properties, adjusting, 72–73
sending, 68–71
sending to specific data source. See driver
time-outs, setting, 73–74
structured types (Struct or STRUCT)
data type conversion, 511–512
Structured Query Language (SQL) name, getting, 449
writing, 499
Sun Microsystems, Inc., 3
suppliers, database
drivers, 31–33
Java adoption, 9
stored procedures, 15
SWING, 274
Sybase
catalog information, 170–172
employees with messages, listing, 124
keywords, getting, 164–165
sample drivers, 226
sample URL, 58
stored procedures, 150
Sybase Jaguar, 185
synchronizing
client-server networks, 14–15
entity bean with data in database table. See persistence


Previous Next

Index

T

tables
browsing, 276–278
checking whether selectable, 389
correlation names, 422
Data Definition Language (DDL), 268–269
foreign keys, 395–396
hierarchies, 410
inserting BLOBs, 217–220
list available, 411–412
maximum columns allowed, 404
names, 549
privileges, 411
retrieving BLOBs, 220–224
rows, handling by entity beans. See entity beans
structure, 226
Structured Query Language (SQL), 17
updating, 26–27
TCP/IP. See Transmission Control Protocol/Internet Protocol (TCP/IP) port
telephone interface, 4
television, 4
text, very large. See clob or CLOB
text-based interface, retrieving results in. See Interactive SQL (ISQL)
text editor, 11
thin-client application, 50
tiers
N-tiered computing, 7–8
Open Database Connectivity (ODBC) drivers, 22
three, 143
two. See client-server architecture
time
clock, updating (TimeT.java), 267
data, mapping to Java, 113–114
functions, listing, 412
handling (Time), 512–513
parameters, setting, 538–539
Structured Query Language (SQL) escape syntax, 120
values (Timestamp), 513–515
time or TIME
callable statements, 365
column, updating, 482
prepared statements, 447–448
reading, 494
type conversions, 182
value, getting, 465–466
writing, 499
time-outs
login, 522
queries, 537
Structured Query Language (SQL) statements, setting, 73–74
timestamp or TIMESTAMP
callable statements, 366
column, updating, 482
parameters, setting, 539
prepared statements, 448
reading, 494
type conversions, 182
value, getting, 466–467
writing, 499
TINYINT, 180–181
Transact Structured Query Language (SQL), 268–269
transaction coordinator, 40
transaction management
defined, 124–125
distributed transactions, 130–131
Enterprise JavaBeans, 185
isolation levels, 125–126
managing, 126–128
modes, 125
savepoints, 129–130
transaction rollback, 253
transactions
account balance and other controls, 255–256
Account.java class, 257–262
ATM panel, 256–257
clock, updating (TimeT.java), 267
HyperText Markup Language (HTML) file, 257
interface, 35
isolation mode, 539–540
multiple, 424
NetBank.java class, 262–266
preserving ResultSets across, 133
processing monitors, 12
support, checking, 428
tables, creating (Data Definition Language (DDL)), 268–269
usefulness, 253
welcome screen, 254
transactions, distributed
advantages, 10
JDBC 3.0 Extension (J2EE) interface (XAConnection), 550
transaction management, 130–131
Transmission Control Protocol/Internet Protocol (TCP/IP) port, 57
truncation
defined, 34
indexes, 382
unexpected (DataTruncation exception), 381–382
write, 72–73
two-phase commit, 130–131
Type 1 driver, 32–33
Type 2 driver, 32–33
Type 3 driver, 30–33
Type 4 driver, 32–33
type mapping
to another database connectivity API. See Type 1 driver
ARRAY, 345–348
BIGINT, 181–182
BINARY, 182
BIT, 181
Blob or BLOB, 221
Boolean, 182
byte, 182
changing, 381
char or CHAR, 181
clob or CLOB, 179
connection, checking, 528
DATALINK, 500
date or DATE, 430
DECIMAL, 181
DISTINCT, 179
double or DOUBLE, 181
entity beans, 200
FLOAT or float, 180–181
int or INTEGER, 180–181
Java Database Connectivity (JDBC) interface (SQLData), 488–489
JAVA_OBJECT, 93
LONGVARBINARY, 182
LONGVARCHAR, 458
NUMERIC, 181
parameters, setting, 540–541
REAL, 179–181
Ref or REF, 179
short, 113
SMALLINT, 180–181
String, 182
Struct or STRUCT, 511–512
Structured Query Language (SQL) data type conversions, 449–450
tables, 115–117
time or TIME, 182
timestamp or TIMESTAMP, 182
TINYINT, 180–181
Unicode character stream, 468
VARBINARY, 182
VARCHAR, 181
Types, 515–518


Previous Next

Index

U

UDTs. See user-defined types (UDTs)
unchained transaction mode, 125
Unicode character stream
callable statements, 366
CLOB pointer, 367
converting, 468
parameter, setting, 531
prepared statements, 448–449
Uniform Resource Locator (URL)
callable statements, 366
database, getting, 528
Driver interface, 431
parameters, setting, 541
prepared statements, 449
reading, 494–495
string, passing to driver manager, 60–62
syntax. See JDBC) database naming scheme
value, getting, 468–469
writing, 500
UNIX audio file, 221
updates
auto-increments, 544
canceling, 452
car factory example, 214
clock (TimeT.java), 267
columns, 472–482
columns, automatic, 414–415
concurrency levels, setting, 451
with cursors, 138–139
detecting, 543
dirty reads, 125
dynamically typed data, 180–183
Interactive Structured Query Language (ISQL) tool in Web browser, 278–280
noncritical events during (SQLWarning), 103–106
performing, 70–71
ResultSets with cursors, 135–139
ResultSets without cursors, 134–135
tables, 26–27
updates, batch
checking for support, 420
described, 139–141
exception, throwing, 348–350
URL. See Uniform Resource Locator (URL)
user application. See application
user-defined types (UDTs)
listing, 488
type mapping, customized, 117
user ID, 60
user interface. See presentation tier
user session, reusing procedures. See stored procedures
user statements, database storage. See stored procedures
username
database, getting, 528
setting, 552
users, graphic interfaces. See client tier


Previous Next

Index

V

values
new records, 17
receiving from user’s application. See INparameters
Structured Query Language (SQL) types, 515–518
updating. See update
VARBINARY, 182
VARCHAR, 181
vendors, database
drivers, 31–33
Java adoption, 9
stored procedures, 15
vi, 11
voice synthesis and recognition, 4


Previous Next

Index

W

WAP. See Wireless Application Protocol (WAP) phones
warnings
clearing, 371
connection, checking, 374
constructors, 501–502
during query or update, 103–106
value, getting, 509
Web browser
BLOB data type, specifying, 221
flight string x-y coordinates (MapInfo.java), 249–250
flights between airports (FlightsVector.java), 243–244
history, 9
images (ImageCanvas.java), 244–246
label (MultilineLabel.java), 250–252
map, displaying appropriate (MapCanvas.java), 246–249
proxies, 31
Structured Query Language (SQL) client using, 209–217
Web browser, remote access example
airport codes (AirportChoice.java), 235–236
airport information (Airport.java), 231–235
airport map with routes (FlightsPanel.java), 240–243
columns, arranging in single (ColumnLayout.java), 237–239
connection, establishing (Airplet.java), 226–231
described, 225
flight information (Flight.java), 239–240
HyperText Markup Language (HTML) file, 226
Web sites, addresses listed
book’s companion, 226
Object Database Management Group (ODMG), 11
sample Java Database Connectivity (JDBC), 58
Structured Query Language (SQL) syntax and complex operations, 19
Sun Microsystems, Inc., 31
Web store, 189–191
welcome screen, banking application, 254
wildcard characters, escape string, 409
Windows (Microsoft), 272
Wireless Application Protocol (WAP) phones, 38
write, data truncation on, 72–73


Previous Next

Index

X

X/Open and SQL Access Group, 24
XAConnection, 550
XADataSource, 551–552
XEmacs, 11
XML APIs, 5


List of Figures

Chapter 2: Database Fundamentals

Figure 2-1: The typical client/server architecture with a DBMS.
Figure 2-2: The two-tier architecture.
Figure 2-3: The three-tier architecture.
Figure 2-4: The four ODBC components.

Chapter 3: Integrating Databases with JDBC

Figure 3-1: Java clients running on different platforms.
Figure 3-2: JDBC is located on the client side.
Figure 3-3: The JDBC-ODBC Bridge driver.
Figure 3-4: Native API, partly Java drivers.
Figure 3-5: The Net driver.
Figure 3-6: Native-protocol, all-Java drivers.
Figure 3-7: The complete JDBC architecture.

Chapter 5: Getting Started with JDBC

Figure 5-1: The JDBC APIs.
Figure 5-2: Actions performed on the client and DBMS sides.
Figure 5-3: The relationship between the main JDBC interfaces.
Figure 5-4: An applet communicating with a server.
Figure 5-5: Three-tier design.
Figure 5-6: The parts of a standalone Java application.

Chapter 6: Database Connectivity, Step by Step

Figure 6-1: An overview of the connection.
Figure 6-2: JDBC mechanism to name a data source.
Figure 6-3: Overview: Building a SQL statement.
Figure 6-4: Sending a SQL statement.
Figure 6-5: An overview of sending a SQL statement.
Figure 6-6: An overview of getting the result set.
Figure 6-7: The next() method is used to scan a result set.
Figure 6-8: An overview of accessing columns.
Figure 6-9: Accessing columns with getXXX().
Figure 6-10: An overview of managing multiple result types.
Figure 6-11: An overview of all the steps for communicating with a database.

Chapter 7: Refining JDBC Queries and Updates

Figure 7-1: The cursor mechanism.

Chapter 8: Advanced Techniques

Figure 8-1: Invoking a stored procedure.
Figure 8-2: An overview of dealing with parameters.
Figure 8-3: Sending a static statement.
Figure 8-4: Sending parameters to a prepared statement.
Figure 8-5: An overview of prepared statements.

Chapter 9: Accessing Database Metadata

Figure 9-1: Processing methods that return a ResultSet.

Chapter 11: Examples of Java Applications

Figure 11-1: The ISQL standalone application.
Figure 11-2: The ISQL applet.
Figure 11-3: Executing SQL statements.
Figure 11-4: Connect Software’s JDBC Airlines applet.
Figure 11-5: The JavaBank applet login screen.
Figure 11-6: The JavaBank applet account balance.
Figure 11-7: The JavaBank applet transfer screen.
Figure 11-8: The JavaBank applet cash withdrawal.

Chapter 12: Complex Examples of Java Applications

Figure 12-1: The JDBCExplorer main window.
Figure 12-2: Supplying login data.
Figure 12-3: The main navigation control widget.
Figure 12-4: Database specifications.
Figure 12-5: Database catalog nodes.
Figure 12-6: Table objects.
Figure 12-7: Columns.
Figure 12-8: Primary keys.
Figure 12-9: An Interactive SQL tool.
Figure 12-10: A SQLException message window.
Figure 12-11: JDBCExplorer help.
Figure 12-12: The JDBCExplorer About box.
Figure 12-13: The three-tiered architecture of the car factory example.
Figure 12-14: The RMI client window.


List of Tables

Chapter 1: Java as an Enterprise Platform

Table 1-1: JAVA AND ITS APIS: THE BIG PICTURE

Chapter 3: Integrating Databases with JDBC

Table 3-1: JDBC DRIVER TYPES
Table 3-2: EXAMPLES OF DRIVERS

Chapter 6: Database Connectivity, Step by Step

Table 6-1: SAMPLE JDBC URLS
Table 6-2: SAMPLE JDBC DRIVERS
Table 6-3: DIFFERENT STATEMENTS RETURN DIFFERENT RESULT TYPES
Table 6-4: JAVA TO SQL TYPE CONVERSIONS

Chapter 7: Refining JDBC Queries and Updates

Table 7-1: MAPPING TABLE FROM SQL TYPES TO JAVA TYPES
Table 7-1: MAPPING TABLE FROM JAVA TYPES TO SQL TYPES

Chapter 9: Accessing Database Metadata

Table 9-1: DEFAULT MAPPING FROM SQL TYPES TO JAVA OBJECT TYPES
Table 9-2: CONVERSIONS BETWEEN JAVA OBJECT TYPES AND TARGET SQL TYPES
Table 9-3: DEFAULT MAPPING FROM JAVA OBJECT TYPES TO SQL TYPES

Chapter 10: Accessing Databases with Enterprise JavaBeans

Table 10-1: CONTAINER-MANAGED PERSISTENCE (CMP) VERSUS BEAN-MANAGED PERSISTENCE (BMP)


List of Listings

Chapter 3: Integrating Databases with JDBC

Listing 3-1: An Example of a JDBC Program

Chapter 6: Database Connectivity, Step by Step

Listing 6-1: A Typical Package Tree
Listing 6-2: Opening a Connection
Listing 6-3: Closing a Connection
Listing 6-4: Adjusting Connection Properties
Listing 6-5: A Do-Nothing Client
Listing 6-6: The JDBC Log Stream
Listing 6-7: Creating a Statement
Listing 6-8: Native SQL Translation
Listing 6-9: Executing a Query
Listing 6-10: Performing an Update
Listing 6-11: Data Truncation on Write
Listing 6-12: Setting a Statement Time-out
Listing 6-13: Executing a Statement
Listing 6-14: Scanning a Result Set
Listing 6-15: Getting the Number and Label of Columns
Listing 6-16: Using Column Indexes
Listing 6-17: Using Column Names
Listing 6-18: Discovering the Result Type
Listing 6-19: Handling Multiple Result Types
Listing 6-20: Canceling Unwanted Results
Listing 6-21: Type Conversion of DATE to String
Listing 6-22: Retrieving BLOBs
Listing 6-23: Managing Data Truncation on Reads
Listing 6-24: Limiting the Number of Rows Returned by a Query
Listing 6-25: Examining the Columns of a Result Set
Listing 6-26: Retrieving Results
Listing 6-27: Catching SQLExceptions
Listing 6-28: Checking SQLWarnings
Listing 6-29: Catching a Data Truncation Exception

Chapter 7: Refining JDBC Queries and Updates

Listing 7-1: Getting Information about the Driver
Listing 7-2: Customized Type Mapping
Listing 7-3: Setting the Map
Listing 7-4: Accessing Data Using a Type Map
Listing 7-5: An Example of SQL DELETEs Grouped in a Transaction
Listing 7-6: Using Transaction Savepoints
Listing 7-7: Distributed Transactions
Listing 7-8: Updating a ResultSet without Using Cursors
Listing 7-9: A Positioned Delete
Listing 7-10: A Positioned Update
Listing 7-11: Performing Batch Updates

Chapter 8: Advanced Techniques

Listing 8-1: Dealing with Stored Procedure Parameters
Listing 8-2: Dealing with Prepared Statement Parameters
Listing 8-3: Sending Very Large Parameters to the Database
Listing 8-4: Using RowSets
Listing 8-5: Using Auto-generated Keys

Chapter 9: Accessing Database Metadata

Listing 9-1: Obtaining Information with DatabaseMetaData Methods
Listing 9-2: A Metadata Method for Discovering the ANSI Compliance Level
Listing 9-3: Metadata about Database Objects
Listing 9-4: ResultSetMetaData: Getting Column Characteristics
Listing 9-5: ParameterMetaData: Getting Column Labels
Listing 9-6: Accessing Parameters of CallableStatements

Chapter 10: Accessing Databases with Enterprise JavaBeans

Listing 10-1: A Stateless Session Bean
Listing 10-2: A Stateless Session Bean Client
Listing 10-3: A Stateful Session Bean
Listing 10-4: Entity Bean with Container-Managed Persistence
Listing 10-5: Entity Bean with Bean-Managed Persistence

Chapter 11: Examples of Java Applications

Listing 11-1: Simple Java ISQL
Listing 11-2: An Interactive SQL Client
Listing 11-3: An Interactive SQL Applet
Listing 11-4: txblob.java
Listing 11-5: Batch Command
Listing 11-6: rxblob.java
Listing 11-7: Airplet.java
Listing 11-8: Airport.java
Listing 11-9: AirportChoice.java
Listing 11-10: ColumnLayout.java
Listing 11-11: Flight.java
Listing 11-12: FlightsPanel.java
Listing 11-13: FlightsVector.java
Listing 11-14: ImageCanvas.java
Listing 11-15: MapCanvas.java
Listing 11-16: MapInfo.java
Listing 11-17: MultilineLabel.java
Listing 11-18: Account.java
Listing 11-19: NetBank.java
Listing 11-20: TimeT.java
Listing 11-21: DDL to Create the Tables for the Bank of Java Applet

Chapter 12: Complex Examples of Java Applications

Listing 12-1: connections.properties
Listing 12-2: AboutBox.java
Listing 12-3: ConnectionBox.java
Listing 12-4: DatabaseConnection.java
Listing 12-5: ErrorBox.java
Listing 12-6: HelpBox.java
Listing 12-7: JDBCExplorer.java
Listing 12-8: Mainframe.java
Listing 12-9: Navigator.java
Listing 12-10: SQLCommandBox.java
Listing 12-11: Car.java
Listing 12-12: CarImpl.java
Listing 12-13: CarFactory.java
Listing 12-14: CarFactoryImpl.java
Listing 12-15: CarSales.java
Listing 12-16: CarSupplierServer.java
Previous


Your JDBC 3.0 Road Map

As the latest revision of Sun's popular and versatile enterprise API, JDBC 3.0 is poised to become one of the most important enabling technolgies in distributed computing. Whether you're a JDBC veteran or a Java newcomer, this essential reference will bring you up to speed fast on the latest techniques for storing, retrieving, searching, and updating various data formats in enterprise databases. Step-by-step tutorials, numerous examples, and in-depth coverage of advanced techniques make this the only JDBC guide you'll need to delever robust database-enabled Internet applications, Web services, N-tiered applications, and client/server applications for corporations of all sizes.

Put JDBC 3.0 to Work

  • Become familiar with new features such as batch updates, DataSource objects, transaction savepoints, and distributed transaction support
  • Understand the architectural concerns and issues involved in developing applications for intranets and Internet
  • Master the fundamentals of database connectivity and SQL data type conversions
  • Build applications that access legacy databases and data formats via new channels such as wireless Internet and Web services
  • Use persistance mechanisms such as Enterprise JavaBeans to access traditional, non-object-oriented databases
  • Find answers fast in a quick reference that lists the JDBC packages and extensions

About the Author

Bernard Van Haecke is senior consultant and Java Practice team leader at Sun Microsystems Professional Services. A Java developer since the introduction of the technology in 1996, he has helped companies build and implement numerous complex applications, including Java- and J2EE-based e-banking and e-trading solutions.