Subject | Release notes rev 1 |
---|---|
Author | Rick Fincher |
Post date | 2002-09-06T21:37:52Z |
Hi All,
Below is rev 1 of the release notes for the JCA-JDBC Driver (Jaybird?).
It is very long so please delete all but the pertinent parts when you reply,
otherwise we'll all be getting monster messages with multiple copies of
this.
I started with the old release notes and stole every other scrap of info I
could find on this driver, and using Java with Firebird/Interbase in
general. Some of it may be outdated, please say so. I don't useJBuilder,
for example, so I don't have a clue if that info is correct.
I'm also not real sure of the current state of the extra jar files, so those
in the know please check those parts.
Please comment. We need your help to make this a useful document. I
particularly need help with "Common Errors", "Frequently Asked Questions",
and "Using Multi-Byte Character Sets". A better title for the latter might
be "Character Encoding".
When we decide on a name (Jaybird seems favored right now) I'll replace all
the references to "the driver" with that name. This should help sorting
references to this driver as opposed to Interclient and others.
If the web site for this driver is up, I'll be happy to maintain a FAQ and
build an HTML page for it.
Please suggest any changes: spelling, grammar, code syntax, new sections,
different section names, etc.
If my tortured prose sets your teeth on edge please feel free to suggest
alternate language.
Thanks,
Rick
#####################################################
#
# JCA/JDBC Firebird Driver Release Notes
#
#####################################################
- Last Updated 09/06/02 -
CONTENTS
1. Introduction
2. What Is and Is NOT Supported
3. Where to get the driver
4. Installing the driver
5. Connection Pooling
6. Using the Driver in Java Code
7. Using the Driver with JBoss
8. Using the Driver with Tomcat
9. Using the Driver With JBuilder
10. Using Blobs
11. Using Multi-Byte Character sets
12. Reporting Bugs
13. Obtaining Sources from SourceForge using CVS
14. Participating in the Development Project
15. Where to get help
16. Joining the Mailing List
17. Known Bugs
18. Additional JAR libraries needed to use the driver
19. Code Examples
20. Common Errors
21. Compliance and Performance Information
22. History
23. Frequently Asked Questions
********************************************************
1- Introduction
********************************************************
The firebird team has implemented a pure java driver for firebirdsql. This
driver allows a Java program to
connect to, send queries to, and get results from a Firebird SQL Database.
It is an alternative to the
Interclient JDBC Driver. The open source version of Interclient is not
actively supported at this time. This
makes the JCA-JDBC Driver the best option for Java development with an open
source driver.
This driver is based on both the new JCA standard for application server
connections to enterprise information
systems and the well known jdbc standard. The JCA standard specifies an
architecture in which an application
server can cooperate with a driver so that the application server manages
transactions, security, and resource
pooling, and the driver supplies only the connection functionality. While
similar to the JDBC 2 XADataSource
idea, the JCA specification is considerably clearer on the division of
responsibility between the application
server and driver.
The JCA-JDBC driver has several major advantages over Interclient. Because
it Implements the JCA
specification, it can be used seamlessly with J2EE containers that support
JCA functionality.
It also has a built-in connection pooling capability for use with
stand-alone programs or J2EE containers that
don't support connection pooling internally. Java programs run much faster
with connection pooling because the
overhead of connection setup and teardown is greatly reduced.
Perhaps the biggest advantage is that Interserver is not needed with this
driver. Interserver had to be
installed on the Firebird/Interbase server machine for the Interclient JDBC
driver to work. The elimination of
Interserver simplifies the installation of the Firebird database, and
reduces the load on and maintenance of
the database server system.
The driver implements much of the JDBC Type 4 Driver Specification. More
information on the JDBC Type 4 Driver
Specification can be found on the net at http://java.sun.com
********************************************************
2- What Is and Is NOT Supported
********************************************************
The driver complies with the JDBC 2.0 core with some features and methods
not implemented. Some of the
unimplemented items are required by the specification and some are optional.
Implemented features:
Most useful jdbc functionality ("useful" in the opinion of the developers).
Complete jca spi support: may be used directly in jca-supporting application
servers such as JBoss.
XA transactions with true two phase commit when used as a jca resource
adapter in a managed environment (with a
TransactionManager and jca deployment support).
Includes optional internal connection pooling for standalone use and use in
non-jca environments such as Tomcat
4.
ObjectFactory implementation for use in environments with JNDI but no
TransactionManager such as Tomcat 4.
DataSource implementations with or without pooling.
Driver implementation for use in legacy applications.
Complete access to all Firebird database parameter block and transaction
parameter block settings.
Optional integrated logging through log4j.
JMX mbean for database management (so far just database create and drop).
The following optional features are NOT supported:
Batch Updates.
Scrollable cursors.
Updatable cursors.
Cursors/Positioned update/delete
Ref, Clob and Array types
User Defined Types/Type Maps.
The methods that support those features return SQLExceptions when used.
In addition to the non supported features above, the following methods are
not implemented:
java.sql.ResultSetMetaData
isReadOnly(i)
isWritable(i)
isDefinitivelyWritable(i)
java.sql.Statement
setEscapeProcessing(boolean)
cancel()
java.sql.PreparedStatement
setObject(index,object,type,scale)
setCharacterStream(i)
setDate(i,date,calendar)
setTime(i,time,calendar)
setTimestamp(i,timestamp,calendar)
java.sql.ResultSet
getDate(i,calendar)
getTime(i,calendar)
getTimestamp(i,calendar)
The following methods are implemented but do not work as expected
java.sql.ResultSet
get/setFetchSize does nothing
java.sql.Statement
get/setFetchSize does nothing
get/setMaxFieldSize does nothing
get/setQueryTimeout does nothing
java.sql.PreparedStatement
setObject(index,object,type) This method is supported but behaves as
setObject(index,object)
********************************************************
3- Where to get the driver
********************************************************
In your browser go to:
http://sourceforge.net/projects/firebird/
scroll down the page and find the row containing:
firebird-jca-jdbc-driver
Click the link "Download" in the rightmost column of the table in that row.
This links you to another page
with the zip files of the various versions of the driver available to be
downloaded. The driver will have the
heading "firebird-jca-jdbc-driver". Click on the version you wish to
download. It looks something like:
FirebirdSQL-1.x.zip.
This will download the driver files to your system. Unzip the file and copy
the contents to the appropriate
directories on your system as described in #4 "Installing the Driver" below.
More recent bugfix versions of the driver can be obtained by downloading the
daily snapshot of the project
through CVS and building the project. See #13 below for details.
********************************************************
4- Installing the Driver
********************************************************
The classes from firebirdsql.jar must be in the classpath of the Java
application being compiled, or otherwise
made available to your application. The classes from the following packages
must also be available:
concurrent.jar
connector.jar
jaas.jar
jta-spec1_0_1.jar
log4j-core.jar (if you want logging available)
either the jdbc 2 or 3 classes.
These archives are included in the binary package.
You can use the jmx management mbean either in a jmx agent (MBeanServer) or
as a standalone class. So far it
has been tested in jbossmx and the jmxri, although since it is extremely
simple it should have no problems in
any jmx implementation. Use of jbossmx is highly recommended due to its
smaller bug count and because it is in
active development.
For use in a managed environment as a jca resource adapter, deploy
firebirdsql.rar according to the
environment's deployment mechanism.
For installation in Tomcat, JBoss, JBuilder, and for use with stand alone
Java programs see the corresponding
sections below.
********************************************************
5- Connection Pooling
********************************************************
The JCA-JDBC Driver features built-in connection pooling. This is very
useful because it eliminates the need
for external connection pooling routines like Poolman or DBCP.
Setting up and shutting down JDBC connections to databases tend to be very
time and CPU intensive operations.
Connection pooling allows connections to be stored and re-used by
applications, or even by different
applications without going through the time consuming task of setting up the
connection again.
Using a connection pool effectively while preventing data corruption and
unauthorized access requires a
slightly different mindset.
The Firebird database uses the concept of user logins. To access the
database a user must log in and provide a
password that the database recognizes. This is set up by the database
administrator.
This can lead to problems with a connection pool. Suppose "joe" logs in
using his password and works with the
database. If he logs out and his connection is kept alive and given to the
next user, "bob", without
re-authorizing, "bob" may be able to see confidential data that he is not
intended to see. Worse he can change
or delete data he should not have access to.
If we only allow users to use connections previously opened with their
username, we drastically reduce the
effectiveness of the pool.
To make the pool most effective we have to login with the same username
every time. This requires us to manage
the user access to the database in our code rather that allowing Firebird to
do it for us. This is usually
accomplished by creating a table of usernames, passwords, and roles separate
from those maintained by the
database.
When a user logs in, all database access is done under a single username and
password known to Firebird, for
example username "calendar", password "calpass". The program then opens a
user table created for the
application and retrieves the username, password, and role of the user,
which might be "joe", "joespassword",
and "manager". The retrieved username and password is compared by your
program to those provided by the user.
If they match, your program allows the user to perform actions on the
database allowed for users with their
role, all under the Firebird username of "calendar".
When the next user, "bob", logs in, transactions are still done with your
program using the connection opened
with the "calendar" Firebird username with the database, but the program
checks the "bob" password and role in
the application user table before allowing transactions.
This results in maximum efficiency of connection pools. It is also
compatibe with the way that web application
servers handle container managed security. So even if your program starts
out as a standalone Java program,
you can "webify" the database access part of it very easily.
Be aware that the JCA-JDBC Driver provides no encryption. If you use the
driver in a standalone Java program,
anyone who can listen to your network connection can see your usernames,
passwords, and data as it crosses the
net. You must take steps to secure your data. You can do this by all the
standard methods: Secure networks,
VPN, etc.
A popular way to provide wide acess to your database while still providing
security is to write your
application as a web application that is viewed in a browser, rather than as
a stand-alone application. Then
you can restrict your web app to running under secure HTTP.
If you are using the driver in stand-alone Java applications there is little
need to use anything other than
the built-in pooling.
However, in some cases, you may not want to use the built-in connection
pooling. If you are using the driver
with a J2EE server that manages connection pooling, like JBoss, you are
probably better off to let the
container manage the pooling.
In such cases the container (J2EE Server) can manage the pooling more
efficiently for several different web
applications that use the driver. Certain internal functions of the J2EE
Container may be dependent on its
internal pooling. Bypassing it may cause problems.
In such a web application server environment, the server system's memory can
be quickly overburdened if large
numbers of sessions are started, each with their own copy of the driver and
their own pool. Extra load is also
placed on the CPU when each session has to perform its own connection and
pool setup rather than using a single
pooled setup.
If you are using a limited J2EE server you may need to use the built-in
pooling. Versions of Tomcat before 4.1
are an example. From version 4.1, Tomcat has provided connection pooling
via DBCP. Tomcat is a Servlet and
Java Server Pages (JSP) server, but does not provide full J2EE web
application server suport.
Since a large number of installations use only servlets and JSP's,
application servers like Tomcat, JRun, Cold
Fusion, Servlet Exec, and Resin have become very popular. These have
varying support for connection pooling.
You will have to check the features of the particular version of your app
server to see if pooling is offered
or if you will need to use the built-in pool from the Driver.
See the sections below on JBoss, Tomcat, and Using the Driver in Java code
for specific information on those
environments.
********************************************************
6- Using the Driver in Java Code
********************************************************
Two forms of the driver can be used. FBDriver is used much like the old
Interclient driver.
FBWrappingDataSource has internal connection pooling capability. Example of
both are included here.
The driver supports two URL syntax formats:
Standard format= jdbc:firebirdsql:[//host[:port]/]<database>
FB old format= jdbc:firebirdsql:[host[/port]:]<database>
For all environments that do not support jca deployment, make the classes in
firebirdsql.jar available to your
application. You will probably have to use some of the jars mentioned above
as necessary.
For use in a somewhat managed environment with JNDI but no jca support or
transaction manager, use the
FBDataSourceObjectFactory to bind a reference to a DataSource into jndi.
Tomcat 4 is an example of this
scenario. The JNDI implementation must support use of
References/Referenceable. This will not work if the JNDI
implementation only supports binding serialized objects.
For use in a standalone application that only needs one connection, use
either FBWrappingDataSource or
FBDriver.
A typical use of the FBDriver class would use code something like this:
Class.forName("org.firebirdsql.jdbc.FBDriver");
Connection conn =
DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:/firebird/test.
gdb", "sysdba",
"masterkey");
or in windows
DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:E:\\database\\c
arwash.gdb", "sysdba",
"masterkey");
For use in a standalone application with multiple connections that would
benefit from connection pooling, use
an instance of FBWrappingDataSource configured for pooling.
A simple example is listed below:
boolean FBDriverLoaded=false;
if (!FBDriverLoaded)
{ // don't load the driver more than once.
try
{
org.firebirdsql.jdbc.FBWrappingDataSource fbwds = new
org.firebirdsql.jdbc.FBWrappingDataSource();
}
catch (ResourceException e)
{
System.out.println("Could Not create
org.firebirdsql.jdbc.FBWrappingDataSource, error:"+e+"\n");
}
interclientLoaded = true;
fbwds.setDatabaseName("//localhost:3050/dir1/subdir/myDatabase.gdb");
// an old format version of the same url
//
fbwds.setDatabaseName("localhost/3050:/dir1/subdir/myDatabase.gdb");
fbwds.setUser("sysdba");
fbwds.setPassword("masterkey");
fbwds.setIdleTimeoutMinutes(30);
fbwds.setPooling(true); // this turns on pooling for this data
source. Max and min must be set.
fbwds.setMinSize(5); // this sets the minimum number of connections
to keep in the pool
fbwds.setMaxSize(30); // this sets the maximum number of connections
that can be open at one time.
try
{
fbwds.setLoginTimeout(10);
}
catch (SQLException e)
{
System.out.println("Could not set Login Timout in SQLDriver\n");
}
}
else
{
//System.out.println("Firebird Driver already exists, not
reloaded.\n");
}
Connection c;
try
{
c = fbwds.getConnection();
}
catch (SQLException e)
{
system.out.println("getting new fbwds connection failed! Error:
"+e+"\n");
handleError(e);
}
// Use the connection "c" like any other connection then close it.
c.close();
// closing c returns it to the pool.
Be aware that no security or encryption is built into the driver. If you
use stand-alone Java programs you
must provide secure access to your database to protect your passwords and
data.
More Java code for a driver example and a DataSource example are included in
the #19 Code Examples section
below.
********************************************************
7- Using the Driver with JBoss
********************************************************
Deployment in JBoss 3 beta2 and later:
The additional jars/classes mentioned above are already available in JBoss.
Put firebirdsql.rar in the deploy
directory. Get firebird-service.xml from jboss cvs (or the distribution when
available) at
connector[jbosscx]/src/etc/example-config/firebird-service.xml and modify
the URL to point to the desired
database location. Add a security domain to auth.conf of the form:
FirebirdDBRealm {
//
// Security domain for new jca framework.
// One per ManagedConnectionFactory are required.
org.jboss.resource.security.ConfiguredIdentityLoginModule required
principal="sysdba"
userName="sysdba"
password="masterkey"
managedConnectionFactoryName="jboss.jca:service=XaTxCM,name=FirebirdDS"
;
};
where FirebirdDBRealm exactly matches the SecurityDomainJndiName attribute
of your ConnectionManager mbean
configuration and the managedConnectionFactoryName exactly matches the
object name of the ConnectionManager
mbean.
If you see log messages such as principal=null when trying to get a
connection, you have the wrong
managedConnectionFactoryName. If you see attempts to use
UserRolesLoginModule, you have mismatched
SecurityDomainJndiName. Other login modules supporting multiple user login
should be available in JBoss soon.
********************************************************
8- Using the Driver with Tomcat
********************************************************
CATALINA_HOME is the installation directory for Tomcat 4.x or greater. An
environment variable of that name is
set up on the Tomcat server. TOMCAT_HOME was used in versions before Tomcat
4.
To use the driver with Tomcat You must put the jar files where your web apps
can access them. Once they are
available to you web apps you use the driver in your servlets or beans just
as you would in standalone
programs.
If you have only one webapp using the drivers or you need to keep the
drivers separate from other web apps, put
the jar files in the WEB-INF/lib/ subdirectory of your web app.
It is more likely that Firebird will be used by all of your web apps and
Tomcat itself. To have universal
access to the drivers put the jars in CATALINA_HOME/common/lib/.
If you configure a JNDI entry in CATALINA_HOME/conf/server.xml to use
FBDataSourceObjectFactory, and you
configure DBCP connection pooling (in Tomcat 4.1.x or greater) only one
connection pool is started for all web
apps. However, some users have reported problems with DBCP under certain
circumstances.
To use the driver's internal connection pooling, you can configure an
FBWrapping Data Source for pooling just
as you would in a stand alone program. If you put a class for doing that in
a servlet and start it when Tomcat
is initialized, you can share a pool among web applications. If you do this
take care to make it thread safe
and synchronize access to methods.
Tomcat can also use Firebird for BASIC or FORM based user authentication.
See the Tomcat docs for more
details. An example realm for this is listed below. This goes in the
CATALINA_HOME/conf/server.xml file.
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="0"
driverName="org.firebirdsql.jdbc.FBDriver"
userNameCol="USER_NAME"
connectionName="sysdba"
userTable="USERS"
userCredCol="USER_PASS"
validate="true"
connectionURL="jdbc:firebirdsql:localhost/3050:/dir1/subdir/usersdb.gdb"
userRoleTable="USER_ROLES"
roleNameCol="ROLE_NAME"
connectionPassword="masterkey"/>
If your web app is set up to allow Tomcat to authenticate users this tells
Tomcat to use Firebird to look up
user names ans passwords. It does this by calling the Firebird driver
FBDriver to login to a database named
usersdb.gdb located on localhost in the directory /dir/subdir/, using the
username sysdba and the password
masterkey.
Tomcat then takes the username that is typed into the browser by the person
logging into the web app and
searches the table named USERS to see if it is in the field USER_NAME of a
record. If it is, it checks to see
if the password typed into the browser is the same as the one in the field
USER_PASS for that record. If it
is, the user is allowed to login and Tomcat opens the table USER_ROLES and
searches for all entries with
USER_NAME. For each record it finds, it looks in the ROLE_NAME column and
adds that role name to a list of
roles for the user. It then allows access to web apps based on the roles
listed by the database.
You can configure your web apps in WEB-INF/web.xml to only allow users with
certain roles access to the web
app. You can even use the role inside your JSP's to only draw certain parts
of an HTML page if a user has the
appropriate role. This alows you to customize each page based on a user's
role.
To use Tomcat's online GUI management web app to control your Tomcat
installation, you must have the role
"manager" in the USER_ROLES table under your name.
See the Tomcat docs for more information.
********************************************************
9. Using the Pure Java JCA-JDBC Firebird Driver with JBuilder 6 Personal
********************************************************
Last updated: 2002.04.11
Thanks to Marcelo.lopezruiz for this section.
If you have any comments/suggestions, drop me an mail at
marcelo.lopezruiz@.... If you have some spare
time, check out the rest of the site at
http://www.xlprueba.com.ar/marce/index.htm.
1. First, download the .zip file from SourceForge and unzip it to a
temporary directory.
2. Read the release_notes.html document.
3. Unless you are doing funny things with your JDK, you use the default JDK
installed with JBuilder6. In this
case, you will need to download the javax.sql.* package, named the JDBC 2.0
Optional Package API (formerly
known as the JDBC 2.0 Standard Extension API) from Sun, at
http://java.sun.com/products/jdbc/download.html.
Select the last option (option package binary), accept the license
agreement, and download the .jar file.
4. Start JBuilder 6 Personal.
5. Create a new project (File | New Project...). Select a directory and a
project name, then click Next. In
step 2, select the Required Libraries tab - here, the required libraries
will be registered with JBuilder and
then added to the project.
6. Click the Add button. A list of libraries JBuilder is aware of will be
shown. Click the New button to
register the required libraries. Enter FireBird JCA-JDBC in the Name field,
select JBuilder in the Location
combo box, and click the Add button. Select the firebirdsql.jar you
unzipped, and click OK. Click OK again to
close the library. Verify that the new library is selected, and click OK to
close the "Select One or More
Libraries" dialog box.
7. Repeat the previous steps with the following libraries, found in the lib
subdirectory of the binary
distribution (except for the last package, which you downloaded from Sun).
concurrent.jar, named Concurrency Utilities
connector.jar, named Connector
jta-spec1_0_1.jar, named Java Transaction API
jdbc2_0-stdext.jar, named JDBC 2 Optional Package
8. Click Next, enter the desired project information, and click Finish.
9. Create a new application (File | New, then Application in the New tab).
Enter the information you want for
your application, and complete the wizard.
10. Click on the Design tab, and double-click on the button with the opening
folder icon to create an event
handler.
11. Type the following code for the event handler (note the small helper
method above).
private void feedback(String text) {
statusBar.setText(text);
}
void jButton1_actionPerformed(ActionEvent e) {
// Hard-coded parameters
String pathToDatabase = "C:\\Program
Files\\Firebird\\examples\\EMPLOYEE.GDB";
String userName = "sysdba";
String password = "masterkey";
String sql = "SELECT * FROM EMPLOYEE";
// Load the FireBird driver.
try {
Class.forName("org.firebirdsql.jdbc.FBDriver");
} catch(ClassNotFoundException cnfe) {
feedback("org.firebirdsql.jdbc.FBDriver not found");
return;
}
// Retrieve a connection.
try {
Statement stmt = null;
ResultSet rst = null;
Connection conn = DriverManager.getConnection(
"jdbc:firebirdsql:localhost/3050:" + pathToDatabase, userName,
password);
try {
// Create a statement and retrieve its result set.
stmt = conn.createStatement();
rst = stmt.executeQuery(sql);
// Show the result set through the standard output.
int columnCount = rst.getMetaData().getColumnCount();
int recordIndex = 0;
while(rst.next()) {
recordIndex++;
System.out.println("Record: " + recordIndex);
for (int i=1;i<=columnCount;i++) {
System.out.print(rst.getMetaData().getColumnName(i));
System.out.print(": ");
System.out.println(rst.getString(i));
}
}
} finally {
// close the database resources immediately, rather than waiting
// for the finalizer to kick in later
if (rst != null) rst.close();
if (stmt != null) stmt.close();
conn.close();
}
} catch(SQLException se) {
feedback(se.toString());
se.printStackTrace();
}
}
12. Type the following code at the beginning of the file, after the import
statements.
import java.sql.*;
13. Run the application, click the button, and view the output.
14. For the morbidly curious, the following link provides an overview of the
classes offered by the
concurrent.jar package.
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.h
tml
15. When using this library, note that there are still unimplemented things.
To view the source for the
Connection class and check which methods will return null values or an
unimplemented exception, see the
following URL.
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/firebird/client-java/src/org/
firebirdsql/jdbc/FBConnection.java?
rev=HEAD&content-type=text/vnd.viewcvs-markup
********************************************************
10- Using Blobs
********************************************************
Blobs are Binary Large OBjects. Blobs are used to store blocks of binary
data of varying size in the database.
An example would be a database table to store gif or jpeg images for a
photo album program. Such a program
could be written using the database to store file names of images files to
be loaded from disk, but this could
easily be corrupted if a file name were changed, a file inadvertently
deleted, or the database moved to a
system with different file naming conventions.
Blobs allow the binary image data to be stored, retrieved, backed up, and
migrated like any other database
data.
The Interclient JDBC driver did not implement many of the blob handling
methods in the JDBC interfaces. So the
programmer had limited tools for using blobs with Interclient. That is no
longer the case with the JCA-JDBC
driver. If you come across old code or help files dealing with blobs and
Interbase/Interclient, be aware that
it may be outdated and easier ways of dealing with blobs are available with
the JCA-JDBC Driver.
Firebird BLOB fields are accessed through different JDBC interfaces
depending on their subtype. For subtype <0,
they are accessed as Blob fields. Subtype 1 is a LongVarChar, and Subtype 2
is LongVarBinary.
Below is some example code written for use with Interclient that may be
helpful.
Storing BLOB Data:
The example given below shows a method that inserts an array of bytes into a
BLOB column in the database. The
PreparedStatement class is used so we can set the parameters independant of
the actual SQL command string.
Example 2.0: Inserting a BLOB
import java.io.*;
import java.sql.*;
...
public void insertBlob( int rowid, byte[] bindata ) {
// In this example I'm assuming there's an open, active
// Connection instance called 'con'.
// This examples uses an imaginary SQL table of the following
// form:
//
// CREATE TABLE blobs (
// ROWID INT NOT NULL,
// ROWDATA BLOB,
//
// PRIMARY KEY (rowid)
// );
try {
ByteArrayInputStream bais = new ByteArrayInputStream(bindata);
String sql = "INSERT INTO blobs ( rowid, rowdata ) VALUES ( ?, ? )";
PreparedStatement ps = con.prepareStatement(sql);
// Set up the parameter index for convenience (JDBC column
// indices start from 1):
int paramindex = 1;
// Set the first parameter, the Row ID:
ps.setInt(paramindex++, rowid);
// Now set the actual binary column data by passing the
// ByteArrayInputStream instance and its length:
ps.setBinaryStream(paramindex++, bais, bindata.length);
// Finally, execute the command and close the statement:
ps.executeUpdate();
ps.close();
} catch ( SQLException se ) {
System.err.println("Couldn't insert binary data: "+se);
} catch ( IOException ioe ) {
System.err.println("Couldn't insert binary data: "+ioe);
} finally {
con.close();
}
}
Retrieving BLOB Data:
The example given below shows a method that retrieves an array of bytes from
the database.
Example 2.0: Selecting a BLOB
import java.io.*;
import java.sql.*;
...
public byte[] selectBlob( int rowid ) {
// In this example I'm assuming there's an open, active
// Connection instance called 'con'.
// This examples uses an imaginary SQL table of the following
// form:
//
// CREATE TABLE blobs (
// ROWID INT NOT NULL,
// ROWDATA BLOB,
//
// PRIMARY KEY (rowid)
// );
try {
Statement sment = con.createStatement();
String sql = "SELECT rowid, rowdata FROM blobs WHERE rowid = " +
rowid;
ResultSet rs = sment.executeQuery(sql);
byte[] returndata = null;
if ( rs.next() ) {
try {
// The ByteArrayOutputStream buffers all bytes written to it
// until we call getBytes() which returns to us an array of
bytes:
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
// Create an input stream from the BLOB column. By default,
rs.getBinaryStream()
// returns a vanilla InputStream instance. We override this for
efficiency
// but you don't have to:
BufferedInputStream bis = new BufferedInputStream(
rs.getBinaryStream("fieldblob") );
// A temporary buffer for the byte data:
byte bindata[1024];
// Used to return how many bytes are read with each read() of
the input stream:
int bytesread = 0;
// Make sure its not a NULL value in the column:
if ( !rs.wasNull() ) {
if ( (bytesread = bis.read(bindata,0,bindata.length)) != -1 )
{
// Write out 'bytesread' bytes to the writer instance:
baos.write(bindata,0,bytesread);
} else {
// When the read() method returns -1 we've hit the end of
the stream,
// so now we can get our bytes out of the writer object:
returndata = baos.getBytes();
}
}
// Close the binary input stream:
bis.close();
} catch ( IOException ioe ) {
System.err.println("Problem retrieving binary data: " + ioe);
} catch ( ClassNotFoundException cnfe ) {
System.err.println("Problem retrieving binary data: " + cnfe);
}
}
rs.close();
sment.close();
} catch ( SQLException se ) {
System.err.println("Couldn't retrieve binary data: " + se);
} finally {
con.close();
}
return returndata;
********************************************************
11- Using Multi-Byte Character Sets
********************************************************
Character Encodings:
Support for character encodings has just been added. This is easily
accessible only from the FBDriver class. To
use it, request a connection with a properties object containing a
name-value pair lc_ctype=WIN1250 or other
appropriate encoding name.
URL-encoded params are fully supported only when you get a connection from
java.sql.DriverManager (using
FBDriver class). For example:
jdbc:firebirdsql://localhost//home/databases/sample.gdb?lc_ctype=UNICODE_FSS
It is also possible to set lc_ctype in a deployment descriptor by adding
the following to your deployment
descriptor:
<config-property>
<config-property-name>Encoding</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>UNICODE_FSS</config-property-value>
</config-property>
********************************************************
12- Reporting Bugs
********************************************************
The developers attempt to follow the Firebird-Java@yahoogroups.com list.
Join the list (see #16 below) and
post information about suspected bugs. This is a good idea because what is
often thought to be a bug turns out
to be something else. List members may be able o help out and get you going
again, whereas bug fixes might
take awhile.
You may also report bugs in the firebird bugtracker at:
http://sourceforge.net/tracker/?group_id=9028&atid=109028
********************************************************
13- Obtaining Sources from SourceForge using CVS
********************************************************
CVS is a source code control system for managing access to source code in a
project that is being developed by
multiple programmers. A full explanation of CVS is beyond the scope of this
document, but information is
available at sorceforge.net.
To get the project containing the source from sourceforge, install CVS on
your system and use it to download
the module named "client-java". The user name is "anonymous".
To build the source you will need several programs installed on your system.
One is ant which can be
downloaded from http://jakarta.apache.org/ant/index.html.
Ant is a Java based build tool similar to make on Unix that uses xml files
as its input files containing
instructions for building a project.
Ant, of course, requires that Java be installed on your system.
If you use a GUI based CVS tool like WinCVS on Windows, be sure that you
also have your system set up to run
CVS from the command line.
This is necessary because the newest version of the driver uses libraries
from the JBoss project to avoid
licensing issues related to distributing some libraries from Sun. The Ant
build scripts use command line CVS
to check out the code needed from the JBoss project.
Once you install these tools and download the source, you should be able to
go into the client-java folder
(wherever you had CVS put it) and type "build" from the command line to
build the driver.
There is a file in the client-java directory called "build.bat" for Windows
systems and one called "build.sh"
for Unix systems. Under certain Unix shells you will have to type
"build.sh" from the command line, the csh
under Solaris for example.
********************************************************
14- Participating in the Development Project
********************************************************
Use Firebird-Java@yahoogroups.com list to contact the developers about
helping out (see #16 below). Perhaps the
most crucial need right now is for more and better setup and usage guides,
and to produce a reasonable section
of the Firebird web site devoted to this driver. Work on this would be
greatly appreciated.
********************************************************
15- Where to get help
********************************************************
Firebird-Java@yahoogroups.com (see #16 below)
www.IBPhoenix.com
java.sun.com
********************************************************
16- Joining the Mailing List
********************************************************
To join the Firebird-java mailing list, go to www.yahoogroups.com. Follow
the instructions there for joining a
group. The name of the group is Firebird-java.
Please set your Yahoo settings to use plain text instead of HTML. All the
ads drive some folks nuts and cause
an automatic internet hookup for some folks in Europe who have to pay for
outgoing phone calls.
********************************************************
17- Known Bugs
********************************************************
You may report bugs in the firebird bugtracker at
http://sourceforge.net/tracker/?group_id=9028&atid=109028
********************************************************
18- Additional JAR libraries needed to use the driver
********************************************************
Certain Sun libraries are needed that are distributed with JDK 1.4
Also:
mini-j2ee.jar
concurrent.jar
jaas.jar
log4j-core.jar (if you want logging available).
********************************************************
19- Code Examples
********************************************************
There are two examples below, a driver example and a DataSource example.
They are separated by a dashed line.
Driver Example:
// Original version of this file was part of InterClient 2.01 examples
//
// Copyright InterBase Software Corporation, 1998.
// Written by com.inprise.interbase.interclient.r&d.PaulOstler :-)
//
// Code was modified by Roman Rokytskyy to show that Firebird JCA-JDBC
driver
// does not introduce additional complexity in normal driver usage scenario.
//
// A small application to demonstrate basic, but not necessarily simple,
JDBC features.
//
// Note: you will need to hardwire the path to your copy of employee.gdb
// as well as supply a user/password in the code below at the
// beginning of method main().
public class DriverExample
{
// Make a connection to an employee.gdb on your local machine,
// and demonstrate basic JDBC features.
// Notice that main() uses its own local variables rather than
// static class variables, so it need not be synchronized.
public static void main (String args[]) throws Exception
{
// Modify the following hardwired settings for your environment.
// Note: localhost is a TCP/IP keyword which resolves to your local
machine's IP address.
// If localhost is not recognized, try using your local machine's
name or
// the loopback IP address 127.0.0.1 in place of localhost.
String databaseURL =
"jdbc:firebirdsql:localhost/3050:c:/database/employee.gdb";
String user = "sysdba";
String password = "masterkey";
String driverName = "org.firebirdsql.jdbc.FBDriver";
// As an exercise to the reader, add some code which extracts
databaseURL,
// user, and password from the program args[] to main().
// As a further exercise, allow the driver name to be passed as well,
// and modify the code below to use driverName rather than the hardwired
// string "org.firebirdsql.jdbc.FBDriver" so that this code becomes
// driver independent. However, the code will still rely on the
// predefined table structure of employee.gdb.
// See comment about closing JDBC objects at the end of this main()
method.
System.runFinalizersOnExit (true);
// Here are the JDBC objects we're going to work with.
// We're defining them outside the scope of the try block because
// they need to be visible in a finally clause which will be used
// to close everything when we are done.
// The finally clause will be executed even if an exception occurs.
java.sql.Driver d = null;
java.sql.Connection c = null;
java.sql.Statement s = null;
java.sql.ResultSet rs = null;
// Any return from this try block will first execute the finally clause
// towards the bottom of this file.
try {
// Let's try to register the Firebird JCA-JDBC driver with the driver
manager
// using one of various registration alternatives...
int registrationAlternative = 1;
switch (registrationAlternative) {
case 1:
// This is the standard alternative and simply loads the driver
class.
// Class.forName() instructs the java class loader to load
// and initialize a class. As part of the class initialization
// any static clauses associated with the class are executed.
// Every driver class is required by the jdbc specification to
automatically
// create an instance of itself and register that instance with the
driver
// manager when the driver class is loaded by the java class loader
// (this is done via a static clause associated with the driver
class).
//
// Notice that the driver name could have been supplied dynamically,
// so that an application is not hardwired to any particular driver
// as would be the case if a driver constructor were used, eg.
// new org.firebirdsql.jdbc.FBDriver().
try {
Class.forName ("org.firebirdsql.jdbc.FBDriver");
}
catch (java.lang.ClassNotFoundException e) {
// A call to Class.forName() forces us to consider this exception
:-)...
System.out.println ("Firebird JCA-JDBC driver not found in class
path");
System.out.println (e.getMessage ());
return;
}
break;
case 2:
// There is a bug in some JDK 1.1 implementations, eg. with
Microsoft
// Internet Explorer, such that the implicit driver instance created
during
// class initialization does not get registered when the driver is
loaded
// with Class.forName().
// See the FAQ at http://java.sun.com/jdbc for more info on this
problem.
// Notice that in the following workaround for this bug, that if the
bug
// is not present, then two instances of the driver will be
registered
// with the driver manager, the implicit instance created by the
driver
// class's static clause and the one created explicitly with
newInstance().
// This alternative should not be used except to workaround a JDK
1.1
// implementation bug.
try {
java.sql.DriverManager.registerDriver (
(java.sql.Driver) Class.forName
("org.firebirdsql.jdbc.FBDriver").newInstance ()
);
}
catch (java.lang.ClassNotFoundException e) {
// A call to Class.forName() forces us to consider this exception
:-)...
System.out.println ("Driver not found in class path");
System.out.println (e.getMessage ());
return;
}
catch (java.lang.IllegalAccessException e) {
// A call to newInstance() forces us to consider this exception
:-)...
System.out.println ("Unable to access driver constructor, this
shouldn't happen!");
System.out.println (e.getMessage ());
return;
}
catch (java.lang.InstantiationException e) {
// A call to newInstance() forces us to consider this exception
:-)...
// Attempt to instantiate an interface or abstract class.
System.out.println ("Unable to create an instance of driver class,
this shouldn't happen!");
System.out.println (e.getMessage ());
return;
}
catch (java.sql.SQLException e) {
// A call to registerDriver() forces us to consider this exception
:-)...
System.out.println ("Driver manager failed to register driver");
showSQLException (e);
return;
}
break;
case 3:
// Add the Firebird JCA-JDBC driver name to your system's
jdbc.drivers property list.
// The driver manager will load drivers from this system property
list.
// System.getProperties() may not be allowed for applets in some
browsers.
// For applets, use one of the Class.forName() alternatives above.
java.util.Properties sysProps = System.getProperties ();
StringBuffer drivers = new StringBuffer
("org.firebirdsql.jdbc.FBDriver");
String oldDrivers = sysProps.getProperty ("jdbc.drivers");
if (oldDrivers != null)
drivers.append (":" + oldDrivers);
sysProps.put ("jdbc.drivers", drivers.toString ());
System.setProperties (sysProps);
break;
case 4:
// Advanced: This is a non-standard alternative, and is tied to
// a particular driver implementation, but is very flexible.
//
// It may be possible to configure a driver explicitly, either thru
// the use of non-standard driver constructors, or non-standard
// driver "set" methods which somehow tailor the driver to behave
// differently from the default driver instance.
// Under this alternative, a driver instance is created explicitly
// using a driver specific constructor. The driver may then be
// tailored differently from the default driver instance which is
// created automatically when the driver class is loaded by the java
class loader.
// For example, perhaps a driver instance could be created which
// is to behave like some older version of the driver.
//
// d = new org.firebirdsql.jdbc.FBDriver ();
// DriverManager.registerDriver (d);
// c = DriverManager.getConnection (...);
//
// Since two drivers, with differing behavior, are now registered
with
// the driver manager, they presumably must recognize different jdbc
// subprotocols. For example, the tailored driver may only
recognize
// "jdbc:interbase:old_version://...", whereas the default driver
instance
// would recognize the standard "jdbc:interbase://...".
// There are currently no methods, such as the hypothetical
setVersion(),
// for tailoring an Firebird JCA-JDBC driver so this 4th alternative
is academic
// and not necessary for Firebird JCA-JDBC driver.
//
// It is also possible to create a tailored driver instance which
// is *not* registered with the driver manager as follows
//
// d = new org.firebirdsql.jdbc.FBDriver ();
// c = d.connect (...);
//
// this is the most usual case as this does not require differing
// jdbc subprotocols since the connection is obtained thru the
driver
// directly rather than thru the driver manager.
d = new org.firebirdsql.jdbc.FBDriver ();
}
// At this point the driver should be registered with the driver
manager.
// Try to find the registered driver that recognizes interbase URLs...
try {
// We pass the entire database URL, but we could just pass
"jdbc:interbase:"
d = java.sql.DriverManager.getDriver (databaseURL);
System.out.println ("Firebird JCA-JDBC driver version " +
d.getMajorVersion () +
"." +
d.getMinorVersion () +
" registered with driver manager.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to find Firebird JCA-JDBC driver among
the registered drivers.");
showSQLException (e);
return;
}
// Advanced info: Class.forName() loads the java class for the driver.
// All JDBC drivers are required to have a static clause that
automatically
// creates an instance of themselves and registers that instance
// with the driver manager. So there is no need to call
// DriverManager.registerDriver() explicitly unless the driver allows
// for tailored driver instances to be created (each instance
recognizing
// a different jdbc sub-protocol).
// Now that Firebird JCA-JDBC driver is registered with the driver
manager,
// try to get a connection to an employee.gdb database on this local
machine
// using one of two alternatives for obtaining connections...
int connectionAlternative = 1;
switch (connectionAlternative) {
case 1:
// This alternative is driver independent;
// the driver manager will find the right driver for you based on
the jdbc subprotocol.
// In the past, this alternative did not work with applets in some
browsers because of a
// bug in the driver manager. I believe this has been fixed in the
jdk 1.1 implementations.
try {
c = java.sql.DriverManager.getConnection (databaseURL, user,
password);
System.out.println ("Connection established.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to establish a connection through the
driver manager.");
showSQLException (e);
return;
}
break;
case 2:
// If you're working with a particular driver d, which may or may
not be registered,
// you can get a connection directly from it, bypassing the driver
manager...
try {
java.util.Properties connectionProperties = new
java.util.Properties ();
connectionProperties.put ("user", user);
connectionProperties.put ("password", password);
c = d.connect (databaseURL, connectionProperties);
System.out.println ("Connection established.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to establish a connection through the
driver.");
showSQLException (e);
return;
}
break;
}
// Let's disable the default autocommit so we can undo our changes
later...
try {
c.setAutoCommit (false);
System.out.println ("Auto-commit is disabled.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to disable autocommit.");
showSQLException (e);
return;
}
// Now that we have a connection, let's try to get some meta data...
try {
java.sql.DatabaseMetaData dbMetaData = c.getMetaData ();
// Ok, let's query a driver/database capability
if (dbMetaData.supportsTransactions ())
System.out.println ("Transactions are supported.");
else
System.out.println ("Transactions are not supported.");
// What are the views defined on this database?
java.sql.ResultSet tables = dbMetaData.getTables (null, null, "%",
new String[] {"VIEW"});
while (tables.next ()) {
System.out.println (tables.getString ("TABLE_NAME") + " is a
view.");
}
tables.close ();
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to extract database meta data.");
showSQLException (e);
// What the heck, who needs meta data anyway ;-(, let's continue
on...
}
// Let's try to submit some static SQL on the connection.
// Note: This SQL should throw an exception on employee.gdb because
// of an integrity constraint violation.
try {
s = c.createStatement ();
s.executeUpdate ("update employee set salary = salary + 10000");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to increase everyone's salary.");
showSQLException (e);
// We expected this to fail, so don't return, let's keep going...
}
// Let's submit some static SQL which produces a result set.
// Notice that the statement s is reused with a new SQL string.
try {
rs = s.executeQuery ("select full_name from employee where salary <
50000");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to submit a static SQL query.");
showSQLException (e);
// We can't go much further without a result set, return...
return;
}
// The query above could just as easily have been dynamic SQL,
// eg. if the SQL had been entered as user input.
// As a dynamic query, we'd need to query the result set meta data
// for information about the result set's columns.
try {
java.sql.ResultSetMetaData rsMetaData = rs.getMetaData ();
System.out.println ("The query executed has " +
rsMetaData.getColumnCount () +
" result columns.");
System.out.println ("Here are the columns: ");
for (int i = 1; i <= rsMetaData.getColumnCount (); i++) {
System.out.println (rsMetaData.getColumnName (i) +
" of type " +
rsMetaData.getColumnTypeName (i));
}
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to extract result set meta data.");
showSQLException (e);
// What the heck, who needs meta data anyway ;-(, let's continue
on...
}
// Ok, lets step thru the results of the query...
try {
System.out.println ("Here are the employee's whose salary <
$50,000");
while (rs.next ()) {
System.out.println (rs.getString ("full_name"));
}
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to step thru results of query");
showSQLException (e);
return;
}
// As an exercise to the reader, rewrite this code so that required
// table structures are created dynamically using executeUpdate() on
DDL.
// In this way the code will be able to run against any database file
rather
// than just a previously setup employee.gdb.
// Just to get you started, you'll want to define a method something
like
// the following...
//
// private static void createTableStructures (java.sql.Connection c)
throws java.sql.SQLException
// {
// // Some drivers don't force commit on DDL, Firebird JCA-JDBC
driver does,
// // see DatabaseMetaData.dataDefinitionCausesTransactionCommit().
// // This is not necessary for Firebird JCA-JDBC driver, but may be
for other drivers...
// c.setAutoCommit (true);
//
// java.sql.Statement s = c.createStatement();
//
// // Drop table EMPLOYEE if it already exists, if not that's ok
too.
// try { s.executeUpdate ("drop table EMPLOYEE"); } catch
(java.sql.SQLException e) {}
//
// // Ok, now that we're sure the table isn't already there, create
it...
// s.executeUpdate ("create table EMPLOYEE (...)");
//
// // Ok, now populate the EMPLOYEE table...
// s.executeUpdate ("insert into EMPLOYEE values (...)");
//
// s.close();
// c.setAutoCommit (false);
// }
//
}
// This finally clause will be executed even if "return" was called in
case of any exceptions above.
finally {
System.out.println ("Closing database resources and rolling back any
changes we made to the database.");
// Now that we're all finished, let's release database resources.
try { if (rs!=null) rs.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
try { if (s!=null) s.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
// Before we close the connection, let's rollback any changes we may
have made.
try { if (c!=null) c.rollback (); } catch (java.sql.SQLException e)
{ showSQLException (e); }
try { if (c!=null) c.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
// If you don't close your database objects explicitly as above,
// they may be closed by the object's finalizer, but there's
// no guarantee if or when the finalizer will be called.
// In general, object finalizers are not called on program exit.
// It's recommended to close your JDBC objects explictly,
// but you can use System.runFinalizersOnExit(true), as at the
beginning
// of this method main(), to force finalizers to be called before
// program exit.
}
}
// Display an SQLException which has occured in this application.
private static void showSQLException (java.sql.SQLException e)
{
// Notice that a SQLException is actually a chain of SQLExceptions,
// let's not forget to print all of them...
java.sql.SQLException next = e;
while (next != null) {
System.out.println (next.getMessage ());
System.out.println ("Error Code: " + next.getErrorCode ());
System.out.println ("SQL State: " + next.getSQLState ());
next = next.getNextException ();
}
}
}
-----------------------------------------------------------------
Data Source Example
// Original version of this file was part of InterClient 2.01 examples
//
// Copyright InterBase Software Corporation, 1998.
// Written by com.inprise.interbase.interclient.r&d.PaulOstler :-)
//
// Code was modified by Roman Rokytskyy to show that Firebird JCA-JDBC
driver
// does not introduce additional complexity in normal driver usage scenario.
//
// An example of using a JDBC 2 Standard Extension DataSource.
// The DataSource facility provides an alternative to the JDBC
DriverManager,
// essentially duplicating all of the driver manager's useful functionality.
// Although, both mechanisms may be used by the same application if desired,
// JavaSoft encourages developers to regard the DriverManager as a legacy
// feature of the JDBC API.
// Applications should use the DataSource API whenever possible.
// A JDBC implementation that is accessed via the DataSource API is not
// automatically registered with the DriverManager.
// The DriverManager, Driver, and DriverPropertyInfo interfaces
// may be deprecated in the future.
import org.firebirdsql.jdbc.FBWrappingDataSource;
import org.firebirdsql.jca.FBConnectionRequestInfo;
import org.firebirdsql.gds.GDS;
public final class DataSourceExample
{
static public void main (String args[]) throws Exception
{
// Create an Firebird data source manually;
FBWrappingDataSource dataSource = new FBWrappingDataSource();
// Set the standard properties
dataSource.setDatabaseName ("localhost/3050:c:/database/employee.gdb");
dataSource.setDescription ("An example database of employees");
/*
* Following properties were not deleted in order to show differences
* between InterClient 2.01 data source implementation and Firebird one.
*/
//dataSource.setDataSourceName ("Employee");
//dataSource.setPortNumber (3060);
//dataSource.setNetworkProtocol ("jdbc:interbase:");
//dataSource.setRoleName (null);
// Set the non-standard properties
//dataSource.setCharSet (interbase.interclient.CharacterEncodings.NONE);
//dataSource.setSuggestedCachePages (0);
//dataSource.setSweepOnConnect (false);
/*
* This is an example how to use FBConnectionRequestInfo to specify
* DPB that will be used for this data source.
*/
FBConnectionRequestInfo cri = dataSource.getConnectionRequestInfo();
cri.setProperty(GDS.isc_dpb_lc_ctype, "NONE");
cri.setProperty(GDS.isc_dpb_num_buffers, 1);
cri.setProperty(GDS.isc_dpb_sql_dialect, 1);
dataSource.setConnectionRequestInfo(cri);
// Connect to the Firebird DataSource
try {
dataSource.setLoginTimeout (10);
java.sql.Connection c = dataSource.getConnection ("sysdba",
"masterkey");
// At this point, there is no implicit driver instance
// registered with the driver manager!
System.out.println ("got connection");
c.close ();
}
catch (java.sql.SQLException e) {
e.printStackTrace();
System.out.println ("sql exception: " + e.getMessage ());
}
}
}
********************************************************
20- Common Errors
********************************************************
1. Wrong URL
The most common error is having the wrong URL format for the database.
The two formats accepted are:
Standard format= jdbc:firebirdsql:[//host[:port]/]<database>
FB old format= jdbc:firebirdsql:[host[/port]:]<database>
Most Firebird/Interbase database file names end in ".gdb".
People frequently forget to put that in the url.
2. Wrong spelling in xml files.
When using JBoss or Tomcat or any environment that uses XML files for
configuration, don't forget that case is important. Windows users
often make this mistake because Windows is insensitive to case.
********************************************************
21. Compliance and Performance Information
********************************************************
Compliance Tests:
The compliance was check with jDataMaster, which include more than 1000
tests, excluding:
CallableStatements
Escape Syntax
FB type 4 driver passed all the tests excluding
ResultSetMetaData.isReadOnly(i)
ResultSetMetaData.isWritable(i)
ResultSetMetaData.isDefinitivelyWritable(i)
The set/get tests don't include Blobs.
Firebird driver is the most JDBC compliant driver of those tested with this
tool, the next one fails on 90
tests, including all of the most known RDBMS.
Performance tests compared with Interclient
The results of the jDataMaster basic performance tests, are the following:
Local test
Duron 800MHz with 512MB and FB 1.0 without forced Writes
Interclient Firebird Type 4 FB as % of Interclient
Insert 5000 records with autocommit 8510 ms 14307 ms 168 %
Read 5000 records with autocommit (x5) 3052 ms 3056 ms 100 %
Insert 5000 records with one transaction 6650 ms 5552 ms 83 %
Read 5000 records inside one transaction(x5) 3990 ms 3819 ms 95 %
Remote test
Client: Windows 2000 on Duron 800MHz with 512MB.
Server: Suse 7.2 on AMD 500MHz with 256MB and FB 1.0.
Interclient Firebird Type 4 FB as % of Interclient
Insert 5000 records with autocommit 16588 ms 17525 ms 106 %
Read 5000x5 records with autocommit 8082 ms 6247 ms 77 %
Insert 5000 records with one transaction 13009 ms 6311 ms 49 %
Read 5000x5 records inside one transaction 11639 ms 8670 ms 75 %
The time in each test is the average of 5 executions.
June-24-2002
********************************************************
22- History
********************************************************
The idea of writing a java translation of the C client library and using it
in an all-java driver originated in
some discussions between David Jencks and Jim Starkey. Alejandro Alberola
provided the initial translation of
most of the clie<br/><br/>(Message over 64 KB, truncated)
Below is rev 1 of the release notes for the JCA-JDBC Driver (Jaybird?).
It is very long so please delete all but the pertinent parts when you reply,
otherwise we'll all be getting monster messages with multiple copies of
this.
I started with the old release notes and stole every other scrap of info I
could find on this driver, and using Java with Firebird/Interbase in
general. Some of it may be outdated, please say so. I don't useJBuilder,
for example, so I don't have a clue if that info is correct.
I'm also not real sure of the current state of the extra jar files, so those
in the know please check those parts.
Please comment. We need your help to make this a useful document. I
particularly need help with "Common Errors", "Frequently Asked Questions",
and "Using Multi-Byte Character Sets". A better title for the latter might
be "Character Encoding".
When we decide on a name (Jaybird seems favored right now) I'll replace all
the references to "the driver" with that name. This should help sorting
references to this driver as opposed to Interclient and others.
If the web site for this driver is up, I'll be happy to maintain a FAQ and
build an HTML page for it.
Please suggest any changes: spelling, grammar, code syntax, new sections,
different section names, etc.
If my tortured prose sets your teeth on edge please feel free to suggest
alternate language.
Thanks,
Rick
#####################################################
#
# JCA/JDBC Firebird Driver Release Notes
#
#####################################################
- Last Updated 09/06/02 -
CONTENTS
1. Introduction
2. What Is and Is NOT Supported
3. Where to get the driver
4. Installing the driver
5. Connection Pooling
6. Using the Driver in Java Code
7. Using the Driver with JBoss
8. Using the Driver with Tomcat
9. Using the Driver With JBuilder
10. Using Blobs
11. Using Multi-Byte Character sets
12. Reporting Bugs
13. Obtaining Sources from SourceForge using CVS
14. Participating in the Development Project
15. Where to get help
16. Joining the Mailing List
17. Known Bugs
18. Additional JAR libraries needed to use the driver
19. Code Examples
20. Common Errors
21. Compliance and Performance Information
22. History
23. Frequently Asked Questions
********************************************************
1- Introduction
********************************************************
The firebird team has implemented a pure java driver for firebirdsql. This
driver allows a Java program to
connect to, send queries to, and get results from a Firebird SQL Database.
It is an alternative to the
Interclient JDBC Driver. The open source version of Interclient is not
actively supported at this time. This
makes the JCA-JDBC Driver the best option for Java development with an open
source driver.
This driver is based on both the new JCA standard for application server
connections to enterprise information
systems and the well known jdbc standard. The JCA standard specifies an
architecture in which an application
server can cooperate with a driver so that the application server manages
transactions, security, and resource
pooling, and the driver supplies only the connection functionality. While
similar to the JDBC 2 XADataSource
idea, the JCA specification is considerably clearer on the division of
responsibility between the application
server and driver.
The JCA-JDBC driver has several major advantages over Interclient. Because
it Implements the JCA
specification, it can be used seamlessly with J2EE containers that support
JCA functionality.
It also has a built-in connection pooling capability for use with
stand-alone programs or J2EE containers that
don't support connection pooling internally. Java programs run much faster
with connection pooling because the
overhead of connection setup and teardown is greatly reduced.
Perhaps the biggest advantage is that Interserver is not needed with this
driver. Interserver had to be
installed on the Firebird/Interbase server machine for the Interclient JDBC
driver to work. The elimination of
Interserver simplifies the installation of the Firebird database, and
reduces the load on and maintenance of
the database server system.
The driver implements much of the JDBC Type 4 Driver Specification. More
information on the JDBC Type 4 Driver
Specification can be found on the net at http://java.sun.com
********************************************************
2- What Is and Is NOT Supported
********************************************************
The driver complies with the JDBC 2.0 core with some features and methods
not implemented. Some of the
unimplemented items are required by the specification and some are optional.
Implemented features:
Most useful jdbc functionality ("useful" in the opinion of the developers).
Complete jca spi support: may be used directly in jca-supporting application
servers such as JBoss.
XA transactions with true two phase commit when used as a jca resource
adapter in a managed environment (with a
TransactionManager and jca deployment support).
Includes optional internal connection pooling for standalone use and use in
non-jca environments such as Tomcat
4.
ObjectFactory implementation for use in environments with JNDI but no
TransactionManager such as Tomcat 4.
DataSource implementations with or without pooling.
Driver implementation for use in legacy applications.
Complete access to all Firebird database parameter block and transaction
parameter block settings.
Optional integrated logging through log4j.
JMX mbean for database management (so far just database create and drop).
The following optional features are NOT supported:
Batch Updates.
Scrollable cursors.
Updatable cursors.
Cursors/Positioned update/delete
Ref, Clob and Array types
User Defined Types/Type Maps.
The methods that support those features return SQLExceptions when used.
In addition to the non supported features above, the following methods are
not implemented:
java.sql.ResultSetMetaData
isReadOnly(i)
isWritable(i)
isDefinitivelyWritable(i)
java.sql.Statement
setEscapeProcessing(boolean)
cancel()
java.sql.PreparedStatement
setObject(index,object,type,scale)
setCharacterStream(i)
setDate(i,date,calendar)
setTime(i,time,calendar)
setTimestamp(i,timestamp,calendar)
java.sql.ResultSet
getDate(i,calendar)
getTime(i,calendar)
getTimestamp(i,calendar)
The following methods are implemented but do not work as expected
java.sql.ResultSet
get/setFetchSize does nothing
java.sql.Statement
get/setFetchSize does nothing
get/setMaxFieldSize does nothing
get/setQueryTimeout does nothing
java.sql.PreparedStatement
setObject(index,object,type) This method is supported but behaves as
setObject(index,object)
********************************************************
3- Where to get the driver
********************************************************
In your browser go to:
http://sourceforge.net/projects/firebird/
scroll down the page and find the row containing:
firebird-jca-jdbc-driver
Click the link "Download" in the rightmost column of the table in that row.
This links you to another page
with the zip files of the various versions of the driver available to be
downloaded. The driver will have the
heading "firebird-jca-jdbc-driver". Click on the version you wish to
download. It looks something like:
FirebirdSQL-1.x.zip.
This will download the driver files to your system. Unzip the file and copy
the contents to the appropriate
directories on your system as described in #4 "Installing the Driver" below.
More recent bugfix versions of the driver can be obtained by downloading the
daily snapshot of the project
through CVS and building the project. See #13 below for details.
********************************************************
4- Installing the Driver
********************************************************
The classes from firebirdsql.jar must be in the classpath of the Java
application being compiled, or otherwise
made available to your application. The classes from the following packages
must also be available:
concurrent.jar
connector.jar
jaas.jar
jta-spec1_0_1.jar
log4j-core.jar (if you want logging available)
either the jdbc 2 or 3 classes.
These archives are included in the binary package.
You can use the jmx management mbean either in a jmx agent (MBeanServer) or
as a standalone class. So far it
has been tested in jbossmx and the jmxri, although since it is extremely
simple it should have no problems in
any jmx implementation. Use of jbossmx is highly recommended due to its
smaller bug count and because it is in
active development.
For use in a managed environment as a jca resource adapter, deploy
firebirdsql.rar according to the
environment's deployment mechanism.
For installation in Tomcat, JBoss, JBuilder, and for use with stand alone
Java programs see the corresponding
sections below.
********************************************************
5- Connection Pooling
********************************************************
The JCA-JDBC Driver features built-in connection pooling. This is very
useful because it eliminates the need
for external connection pooling routines like Poolman or DBCP.
Setting up and shutting down JDBC connections to databases tend to be very
time and CPU intensive operations.
Connection pooling allows connections to be stored and re-used by
applications, or even by different
applications without going through the time consuming task of setting up the
connection again.
Using a connection pool effectively while preventing data corruption and
unauthorized access requires a
slightly different mindset.
The Firebird database uses the concept of user logins. To access the
database a user must log in and provide a
password that the database recognizes. This is set up by the database
administrator.
This can lead to problems with a connection pool. Suppose "joe" logs in
using his password and works with the
database. If he logs out and his connection is kept alive and given to the
next user, "bob", without
re-authorizing, "bob" may be able to see confidential data that he is not
intended to see. Worse he can change
or delete data he should not have access to.
If we only allow users to use connections previously opened with their
username, we drastically reduce the
effectiveness of the pool.
To make the pool most effective we have to login with the same username
every time. This requires us to manage
the user access to the database in our code rather that allowing Firebird to
do it for us. This is usually
accomplished by creating a table of usernames, passwords, and roles separate
from those maintained by the
database.
When a user logs in, all database access is done under a single username and
password known to Firebird, for
example username "calendar", password "calpass". The program then opens a
user table created for the
application and retrieves the username, password, and role of the user,
which might be "joe", "joespassword",
and "manager". The retrieved username and password is compared by your
program to those provided by the user.
If they match, your program allows the user to perform actions on the
database allowed for users with their
role, all under the Firebird username of "calendar".
When the next user, "bob", logs in, transactions are still done with your
program using the connection opened
with the "calendar" Firebird username with the database, but the program
checks the "bob" password and role in
the application user table before allowing transactions.
This results in maximum efficiency of connection pools. It is also
compatibe with the way that web application
servers handle container managed security. So even if your program starts
out as a standalone Java program,
you can "webify" the database access part of it very easily.
Be aware that the JCA-JDBC Driver provides no encryption. If you use the
driver in a standalone Java program,
anyone who can listen to your network connection can see your usernames,
passwords, and data as it crosses the
net. You must take steps to secure your data. You can do this by all the
standard methods: Secure networks,
VPN, etc.
A popular way to provide wide acess to your database while still providing
security is to write your
application as a web application that is viewed in a browser, rather than as
a stand-alone application. Then
you can restrict your web app to running under secure HTTP.
If you are using the driver in stand-alone Java applications there is little
need to use anything other than
the built-in pooling.
However, in some cases, you may not want to use the built-in connection
pooling. If you are using the driver
with a J2EE server that manages connection pooling, like JBoss, you are
probably better off to let the
container manage the pooling.
In such cases the container (J2EE Server) can manage the pooling more
efficiently for several different web
applications that use the driver. Certain internal functions of the J2EE
Container may be dependent on its
internal pooling. Bypassing it may cause problems.
In such a web application server environment, the server system's memory can
be quickly overburdened if large
numbers of sessions are started, each with their own copy of the driver and
their own pool. Extra load is also
placed on the CPU when each session has to perform its own connection and
pool setup rather than using a single
pooled setup.
If you are using a limited J2EE server you may need to use the built-in
pooling. Versions of Tomcat before 4.1
are an example. From version 4.1, Tomcat has provided connection pooling
via DBCP. Tomcat is a Servlet and
Java Server Pages (JSP) server, but does not provide full J2EE web
application server suport.
Since a large number of installations use only servlets and JSP's,
application servers like Tomcat, JRun, Cold
Fusion, Servlet Exec, and Resin have become very popular. These have
varying support for connection pooling.
You will have to check the features of the particular version of your app
server to see if pooling is offered
or if you will need to use the built-in pool from the Driver.
See the sections below on JBoss, Tomcat, and Using the Driver in Java code
for specific information on those
environments.
********************************************************
6- Using the Driver in Java Code
********************************************************
Two forms of the driver can be used. FBDriver is used much like the old
Interclient driver.
FBWrappingDataSource has internal connection pooling capability. Example of
both are included here.
The driver supports two URL syntax formats:
Standard format= jdbc:firebirdsql:[//host[:port]/]<database>
FB old format= jdbc:firebirdsql:[host[/port]:]<database>
For all environments that do not support jca deployment, make the classes in
firebirdsql.jar available to your
application. You will probably have to use some of the jars mentioned above
as necessary.
For use in a somewhat managed environment with JNDI but no jca support or
transaction manager, use the
FBDataSourceObjectFactory to bind a reference to a DataSource into jndi.
Tomcat 4 is an example of this
scenario. The JNDI implementation must support use of
References/Referenceable. This will not work if the JNDI
implementation only supports binding serialized objects.
For use in a standalone application that only needs one connection, use
either FBWrappingDataSource or
FBDriver.
A typical use of the FBDriver class would use code something like this:
Class.forName("org.firebirdsql.jdbc.FBDriver");
Connection conn =
DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:/firebird/test.
gdb", "sysdba",
"masterkey");
or in windows
DriverManager.getConnection("jdbc:firebirdsql:localhost/3050:E:\\database\\c
arwash.gdb", "sysdba",
"masterkey");
For use in a standalone application with multiple connections that would
benefit from connection pooling, use
an instance of FBWrappingDataSource configured for pooling.
A simple example is listed below:
boolean FBDriverLoaded=false;
if (!FBDriverLoaded)
{ // don't load the driver more than once.
try
{
org.firebirdsql.jdbc.FBWrappingDataSource fbwds = new
org.firebirdsql.jdbc.FBWrappingDataSource();
}
catch (ResourceException e)
{
System.out.println("Could Not create
org.firebirdsql.jdbc.FBWrappingDataSource, error:"+e+"\n");
}
interclientLoaded = true;
fbwds.setDatabaseName("//localhost:3050/dir1/subdir/myDatabase.gdb");
// an old format version of the same url
//
fbwds.setDatabaseName("localhost/3050:/dir1/subdir/myDatabase.gdb");
fbwds.setUser("sysdba");
fbwds.setPassword("masterkey");
fbwds.setIdleTimeoutMinutes(30);
fbwds.setPooling(true); // this turns on pooling for this data
source. Max and min must be set.
fbwds.setMinSize(5); // this sets the minimum number of connections
to keep in the pool
fbwds.setMaxSize(30); // this sets the maximum number of connections
that can be open at one time.
try
{
fbwds.setLoginTimeout(10);
}
catch (SQLException e)
{
System.out.println("Could not set Login Timout in SQLDriver\n");
}
}
else
{
//System.out.println("Firebird Driver already exists, not
reloaded.\n");
}
Connection c;
try
{
c = fbwds.getConnection();
}
catch (SQLException e)
{
system.out.println("getting new fbwds connection failed! Error:
"+e+"\n");
handleError(e);
}
// Use the connection "c" like any other connection then close it.
c.close();
// closing c returns it to the pool.
Be aware that no security or encryption is built into the driver. If you
use stand-alone Java programs you
must provide secure access to your database to protect your passwords and
data.
More Java code for a driver example and a DataSource example are included in
the #19 Code Examples section
below.
********************************************************
7- Using the Driver with JBoss
********************************************************
Deployment in JBoss 3 beta2 and later:
The additional jars/classes mentioned above are already available in JBoss.
Put firebirdsql.rar in the deploy
directory. Get firebird-service.xml from jboss cvs (or the distribution when
available) at
connector[jbosscx]/src/etc/example-config/firebird-service.xml and modify
the URL to point to the desired
database location. Add a security domain to auth.conf of the form:
FirebirdDBRealm {
//
// Security domain for new jca framework.
// One per ManagedConnectionFactory are required.
org.jboss.resource.security.ConfiguredIdentityLoginModule required
principal="sysdba"
userName="sysdba"
password="masterkey"
managedConnectionFactoryName="jboss.jca:service=XaTxCM,name=FirebirdDS"
;
};
where FirebirdDBRealm exactly matches the SecurityDomainJndiName attribute
of your ConnectionManager mbean
configuration and the managedConnectionFactoryName exactly matches the
object name of the ConnectionManager
mbean.
If you see log messages such as principal=null when trying to get a
connection, you have the wrong
managedConnectionFactoryName. If you see attempts to use
UserRolesLoginModule, you have mismatched
SecurityDomainJndiName. Other login modules supporting multiple user login
should be available in JBoss soon.
********************************************************
8- Using the Driver with Tomcat
********************************************************
CATALINA_HOME is the installation directory for Tomcat 4.x or greater. An
environment variable of that name is
set up on the Tomcat server. TOMCAT_HOME was used in versions before Tomcat
4.
To use the driver with Tomcat You must put the jar files where your web apps
can access them. Once they are
available to you web apps you use the driver in your servlets or beans just
as you would in standalone
programs.
If you have only one webapp using the drivers or you need to keep the
drivers separate from other web apps, put
the jar files in the WEB-INF/lib/ subdirectory of your web app.
It is more likely that Firebird will be used by all of your web apps and
Tomcat itself. To have universal
access to the drivers put the jars in CATALINA_HOME/common/lib/.
If you configure a JNDI entry in CATALINA_HOME/conf/server.xml to use
FBDataSourceObjectFactory, and you
configure DBCP connection pooling (in Tomcat 4.1.x or greater) only one
connection pool is started for all web
apps. However, some users have reported problems with DBCP under certain
circumstances.
To use the driver's internal connection pooling, you can configure an
FBWrapping Data Source for pooling just
as you would in a stand alone program. If you put a class for doing that in
a servlet and start it when Tomcat
is initialized, you can share a pool among web applications. If you do this
take care to make it thread safe
and synchronize access to methods.
Tomcat can also use Firebird for BASIC or FORM based user authentication.
See the Tomcat docs for more
details. An example realm for this is listed below. This goes in the
CATALINA_HOME/conf/server.xml file.
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="0"
driverName="org.firebirdsql.jdbc.FBDriver"
userNameCol="USER_NAME"
connectionName="sysdba"
userTable="USERS"
userCredCol="USER_PASS"
validate="true"
connectionURL="jdbc:firebirdsql:localhost/3050:/dir1/subdir/usersdb.gdb"
userRoleTable="USER_ROLES"
roleNameCol="ROLE_NAME"
connectionPassword="masterkey"/>
If your web app is set up to allow Tomcat to authenticate users this tells
Tomcat to use Firebird to look up
user names ans passwords. It does this by calling the Firebird driver
FBDriver to login to a database named
usersdb.gdb located on localhost in the directory /dir/subdir/, using the
username sysdba and the password
masterkey.
Tomcat then takes the username that is typed into the browser by the person
logging into the web app and
searches the table named USERS to see if it is in the field USER_NAME of a
record. If it is, it checks to see
if the password typed into the browser is the same as the one in the field
USER_PASS for that record. If it
is, the user is allowed to login and Tomcat opens the table USER_ROLES and
searches for all entries with
USER_NAME. For each record it finds, it looks in the ROLE_NAME column and
adds that role name to a list of
roles for the user. It then allows access to web apps based on the roles
listed by the database.
You can configure your web apps in WEB-INF/web.xml to only allow users with
certain roles access to the web
app. You can even use the role inside your JSP's to only draw certain parts
of an HTML page if a user has the
appropriate role. This alows you to customize each page based on a user's
role.
To use Tomcat's online GUI management web app to control your Tomcat
installation, you must have the role
"manager" in the USER_ROLES table under your name.
See the Tomcat docs for more information.
********************************************************
9. Using the Pure Java JCA-JDBC Firebird Driver with JBuilder 6 Personal
********************************************************
Last updated: 2002.04.11
Thanks to Marcelo.lopezruiz for this section.
If you have any comments/suggestions, drop me an mail at
marcelo.lopezruiz@.... If you have some spare
time, check out the rest of the site at
http://www.xlprueba.com.ar/marce/index.htm.
1. First, download the .zip file from SourceForge and unzip it to a
temporary directory.
2. Read the release_notes.html document.
3. Unless you are doing funny things with your JDK, you use the default JDK
installed with JBuilder6. In this
case, you will need to download the javax.sql.* package, named the JDBC 2.0
Optional Package API (formerly
known as the JDBC 2.0 Standard Extension API) from Sun, at
http://java.sun.com/products/jdbc/download.html.
Select the last option (option package binary), accept the license
agreement, and download the .jar file.
4. Start JBuilder 6 Personal.
5. Create a new project (File | New Project...). Select a directory and a
project name, then click Next. In
step 2, select the Required Libraries tab - here, the required libraries
will be registered with JBuilder and
then added to the project.
6. Click the Add button. A list of libraries JBuilder is aware of will be
shown. Click the New button to
register the required libraries. Enter FireBird JCA-JDBC in the Name field,
select JBuilder in the Location
combo box, and click the Add button. Select the firebirdsql.jar you
unzipped, and click OK. Click OK again to
close the library. Verify that the new library is selected, and click OK to
close the "Select One or More
Libraries" dialog box.
7. Repeat the previous steps with the following libraries, found in the lib
subdirectory of the binary
distribution (except for the last package, which you downloaded from Sun).
concurrent.jar, named Concurrency Utilities
connector.jar, named Connector
jta-spec1_0_1.jar, named Java Transaction API
jdbc2_0-stdext.jar, named JDBC 2 Optional Package
8. Click Next, enter the desired project information, and click Finish.
9. Create a new application (File | New, then Application in the New tab).
Enter the information you want for
your application, and complete the wizard.
10. Click on the Design tab, and double-click on the button with the opening
folder icon to create an event
handler.
11. Type the following code for the event handler (note the small helper
method above).
private void feedback(String text) {
statusBar.setText(text);
}
void jButton1_actionPerformed(ActionEvent e) {
// Hard-coded parameters
String pathToDatabase = "C:\\Program
Files\\Firebird\\examples\\EMPLOYEE.GDB";
String userName = "sysdba";
String password = "masterkey";
String sql = "SELECT * FROM EMPLOYEE";
// Load the FireBird driver.
try {
Class.forName("org.firebirdsql.jdbc.FBDriver");
} catch(ClassNotFoundException cnfe) {
feedback("org.firebirdsql.jdbc.FBDriver not found");
return;
}
// Retrieve a connection.
try {
Statement stmt = null;
ResultSet rst = null;
Connection conn = DriverManager.getConnection(
"jdbc:firebirdsql:localhost/3050:" + pathToDatabase, userName,
password);
try {
// Create a statement and retrieve its result set.
stmt = conn.createStatement();
rst = stmt.executeQuery(sql);
// Show the result set through the standard output.
int columnCount = rst.getMetaData().getColumnCount();
int recordIndex = 0;
while(rst.next()) {
recordIndex++;
System.out.println("Record: " + recordIndex);
for (int i=1;i<=columnCount;i++) {
System.out.print(rst.getMetaData().getColumnName(i));
System.out.print(": ");
System.out.println(rst.getString(i));
}
}
} finally {
// close the database resources immediately, rather than waiting
// for the finalizer to kick in later
if (rst != null) rst.close();
if (stmt != null) stmt.close();
conn.close();
}
} catch(SQLException se) {
feedback(se.toString());
se.printStackTrace();
}
}
12. Type the following code at the beginning of the file, after the import
statements.
import java.sql.*;
13. Run the application, click the button, and view the output.
14. For the morbidly curious, the following link provides an overview of the
classes offered by the
concurrent.jar package.
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.h
tml
15. When using this library, note that there are still unimplemented things.
To view the source for the
Connection class and check which methods will return null values or an
unimplemented exception, see the
following URL.
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/firebird/client-java/src/org/
firebirdsql/jdbc/FBConnection.java?
rev=HEAD&content-type=text/vnd.viewcvs-markup
********************************************************
10- Using Blobs
********************************************************
Blobs are Binary Large OBjects. Blobs are used to store blocks of binary
data of varying size in the database.
An example would be a database table to store gif or jpeg images for a
photo album program. Such a program
could be written using the database to store file names of images files to
be loaded from disk, but this could
easily be corrupted if a file name were changed, a file inadvertently
deleted, or the database moved to a
system with different file naming conventions.
Blobs allow the binary image data to be stored, retrieved, backed up, and
migrated like any other database
data.
The Interclient JDBC driver did not implement many of the blob handling
methods in the JDBC interfaces. So the
programmer had limited tools for using blobs with Interclient. That is no
longer the case with the JCA-JDBC
driver. If you come across old code or help files dealing with blobs and
Interbase/Interclient, be aware that
it may be outdated and easier ways of dealing with blobs are available with
the JCA-JDBC Driver.
Firebird BLOB fields are accessed through different JDBC interfaces
depending on their subtype. For subtype <0,
they are accessed as Blob fields. Subtype 1 is a LongVarChar, and Subtype 2
is LongVarBinary.
Below is some example code written for use with Interclient that may be
helpful.
Storing BLOB Data:
The example given below shows a method that inserts an array of bytes into a
BLOB column in the database. The
PreparedStatement class is used so we can set the parameters independant of
the actual SQL command string.
Example 2.0: Inserting a BLOB
import java.io.*;
import java.sql.*;
...
public void insertBlob( int rowid, byte[] bindata ) {
// In this example I'm assuming there's an open, active
// Connection instance called 'con'.
// This examples uses an imaginary SQL table of the following
// form:
//
// CREATE TABLE blobs (
// ROWID INT NOT NULL,
// ROWDATA BLOB,
//
// PRIMARY KEY (rowid)
// );
try {
ByteArrayInputStream bais = new ByteArrayInputStream(bindata);
String sql = "INSERT INTO blobs ( rowid, rowdata ) VALUES ( ?, ? )";
PreparedStatement ps = con.prepareStatement(sql);
// Set up the parameter index for convenience (JDBC column
// indices start from 1):
int paramindex = 1;
// Set the first parameter, the Row ID:
ps.setInt(paramindex++, rowid);
// Now set the actual binary column data by passing the
// ByteArrayInputStream instance and its length:
ps.setBinaryStream(paramindex++, bais, bindata.length);
// Finally, execute the command and close the statement:
ps.executeUpdate();
ps.close();
} catch ( SQLException se ) {
System.err.println("Couldn't insert binary data: "+se);
} catch ( IOException ioe ) {
System.err.println("Couldn't insert binary data: "+ioe);
} finally {
con.close();
}
}
Retrieving BLOB Data:
The example given below shows a method that retrieves an array of bytes from
the database.
Example 2.0: Selecting a BLOB
import java.io.*;
import java.sql.*;
...
public byte[] selectBlob( int rowid ) {
// In this example I'm assuming there's an open, active
// Connection instance called 'con'.
// This examples uses an imaginary SQL table of the following
// form:
//
// CREATE TABLE blobs (
// ROWID INT NOT NULL,
// ROWDATA BLOB,
//
// PRIMARY KEY (rowid)
// );
try {
Statement sment = con.createStatement();
String sql = "SELECT rowid, rowdata FROM blobs WHERE rowid = " +
rowid;
ResultSet rs = sment.executeQuery(sql);
byte[] returndata = null;
if ( rs.next() ) {
try {
// The ByteArrayOutputStream buffers all bytes written to it
// until we call getBytes() which returns to us an array of
bytes:
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
// Create an input stream from the BLOB column. By default,
rs.getBinaryStream()
// returns a vanilla InputStream instance. We override this for
efficiency
// but you don't have to:
BufferedInputStream bis = new BufferedInputStream(
rs.getBinaryStream("fieldblob") );
// A temporary buffer for the byte data:
byte bindata[1024];
// Used to return how many bytes are read with each read() of
the input stream:
int bytesread = 0;
// Make sure its not a NULL value in the column:
if ( !rs.wasNull() ) {
if ( (bytesread = bis.read(bindata,0,bindata.length)) != -1 )
{
// Write out 'bytesread' bytes to the writer instance:
baos.write(bindata,0,bytesread);
} else {
// When the read() method returns -1 we've hit the end of
the stream,
// so now we can get our bytes out of the writer object:
returndata = baos.getBytes();
}
}
// Close the binary input stream:
bis.close();
} catch ( IOException ioe ) {
System.err.println("Problem retrieving binary data: " + ioe);
} catch ( ClassNotFoundException cnfe ) {
System.err.println("Problem retrieving binary data: " + cnfe);
}
}
rs.close();
sment.close();
} catch ( SQLException se ) {
System.err.println("Couldn't retrieve binary data: " + se);
} finally {
con.close();
}
return returndata;
********************************************************
11- Using Multi-Byte Character Sets
********************************************************
Character Encodings:
Support for character encodings has just been added. This is easily
accessible only from the FBDriver class. To
use it, request a connection with a properties object containing a
name-value pair lc_ctype=WIN1250 or other
appropriate encoding name.
URL-encoded params are fully supported only when you get a connection from
java.sql.DriverManager (using
FBDriver class). For example:
jdbc:firebirdsql://localhost//home/databases/sample.gdb?lc_ctype=UNICODE_FSS
It is also possible to set lc_ctype in a deployment descriptor by adding
the following to your deployment
descriptor:
<config-property>
<config-property-name>Encoding</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>UNICODE_FSS</config-property-value>
</config-property>
********************************************************
12- Reporting Bugs
********************************************************
The developers attempt to follow the Firebird-Java@yahoogroups.com list.
Join the list (see #16 below) and
post information about suspected bugs. This is a good idea because what is
often thought to be a bug turns out
to be something else. List members may be able o help out and get you going
again, whereas bug fixes might
take awhile.
You may also report bugs in the firebird bugtracker at:
http://sourceforge.net/tracker/?group_id=9028&atid=109028
********************************************************
13- Obtaining Sources from SourceForge using CVS
********************************************************
CVS is a source code control system for managing access to source code in a
project that is being developed by
multiple programmers. A full explanation of CVS is beyond the scope of this
document, but information is
available at sorceforge.net.
To get the project containing the source from sourceforge, install CVS on
your system and use it to download
the module named "client-java". The user name is "anonymous".
To build the source you will need several programs installed on your system.
One is ant which can be
downloaded from http://jakarta.apache.org/ant/index.html.
Ant is a Java based build tool similar to make on Unix that uses xml files
as its input files containing
instructions for building a project.
Ant, of course, requires that Java be installed on your system.
If you use a GUI based CVS tool like WinCVS on Windows, be sure that you
also have your system set up to run
CVS from the command line.
This is necessary because the newest version of the driver uses libraries
from the JBoss project to avoid
licensing issues related to distributing some libraries from Sun. The Ant
build scripts use command line CVS
to check out the code needed from the JBoss project.
Once you install these tools and download the source, you should be able to
go into the client-java folder
(wherever you had CVS put it) and type "build" from the command line to
build the driver.
There is a file in the client-java directory called "build.bat" for Windows
systems and one called "build.sh"
for Unix systems. Under certain Unix shells you will have to type
"build.sh" from the command line, the csh
under Solaris for example.
********************************************************
14- Participating in the Development Project
********************************************************
Use Firebird-Java@yahoogroups.com list to contact the developers about
helping out (see #16 below). Perhaps the
most crucial need right now is for more and better setup and usage guides,
and to produce a reasonable section
of the Firebird web site devoted to this driver. Work on this would be
greatly appreciated.
********************************************************
15- Where to get help
********************************************************
Firebird-Java@yahoogroups.com (see #16 below)
www.IBPhoenix.com
java.sun.com
********************************************************
16- Joining the Mailing List
********************************************************
To join the Firebird-java mailing list, go to www.yahoogroups.com. Follow
the instructions there for joining a
group. The name of the group is Firebird-java.
Please set your Yahoo settings to use plain text instead of HTML. All the
ads drive some folks nuts and cause
an automatic internet hookup for some folks in Europe who have to pay for
outgoing phone calls.
********************************************************
17- Known Bugs
********************************************************
You may report bugs in the firebird bugtracker at
http://sourceforge.net/tracker/?group_id=9028&atid=109028
********************************************************
18- Additional JAR libraries needed to use the driver
********************************************************
Certain Sun libraries are needed that are distributed with JDK 1.4
Also:
mini-j2ee.jar
concurrent.jar
jaas.jar
log4j-core.jar (if you want logging available).
********************************************************
19- Code Examples
********************************************************
There are two examples below, a driver example and a DataSource example.
They are separated by a dashed line.
Driver Example:
// Original version of this file was part of InterClient 2.01 examples
//
// Copyright InterBase Software Corporation, 1998.
// Written by com.inprise.interbase.interclient.r&d.PaulOstler :-)
//
// Code was modified by Roman Rokytskyy to show that Firebird JCA-JDBC
driver
// does not introduce additional complexity in normal driver usage scenario.
//
// A small application to demonstrate basic, but not necessarily simple,
JDBC features.
//
// Note: you will need to hardwire the path to your copy of employee.gdb
// as well as supply a user/password in the code below at the
// beginning of method main().
public class DriverExample
{
// Make a connection to an employee.gdb on your local machine,
// and demonstrate basic JDBC features.
// Notice that main() uses its own local variables rather than
// static class variables, so it need not be synchronized.
public static void main (String args[]) throws Exception
{
// Modify the following hardwired settings for your environment.
// Note: localhost is a TCP/IP keyword which resolves to your local
machine's IP address.
// If localhost is not recognized, try using your local machine's
name or
// the loopback IP address 127.0.0.1 in place of localhost.
String databaseURL =
"jdbc:firebirdsql:localhost/3050:c:/database/employee.gdb";
String user = "sysdba";
String password = "masterkey";
String driverName = "org.firebirdsql.jdbc.FBDriver";
// As an exercise to the reader, add some code which extracts
databaseURL,
// user, and password from the program args[] to main().
// As a further exercise, allow the driver name to be passed as well,
// and modify the code below to use driverName rather than the hardwired
// string "org.firebirdsql.jdbc.FBDriver" so that this code becomes
// driver independent. However, the code will still rely on the
// predefined table structure of employee.gdb.
// See comment about closing JDBC objects at the end of this main()
method.
System.runFinalizersOnExit (true);
// Here are the JDBC objects we're going to work with.
// We're defining them outside the scope of the try block because
// they need to be visible in a finally clause which will be used
// to close everything when we are done.
// The finally clause will be executed even if an exception occurs.
java.sql.Driver d = null;
java.sql.Connection c = null;
java.sql.Statement s = null;
java.sql.ResultSet rs = null;
// Any return from this try block will first execute the finally clause
// towards the bottom of this file.
try {
// Let's try to register the Firebird JCA-JDBC driver with the driver
manager
// using one of various registration alternatives...
int registrationAlternative = 1;
switch (registrationAlternative) {
case 1:
// This is the standard alternative and simply loads the driver
class.
// Class.forName() instructs the java class loader to load
// and initialize a class. As part of the class initialization
// any static clauses associated with the class are executed.
// Every driver class is required by the jdbc specification to
automatically
// create an instance of itself and register that instance with the
driver
// manager when the driver class is loaded by the java class loader
// (this is done via a static clause associated with the driver
class).
//
// Notice that the driver name could have been supplied dynamically,
// so that an application is not hardwired to any particular driver
// as would be the case if a driver constructor were used, eg.
// new org.firebirdsql.jdbc.FBDriver().
try {
Class.forName ("org.firebirdsql.jdbc.FBDriver");
}
catch (java.lang.ClassNotFoundException e) {
// A call to Class.forName() forces us to consider this exception
:-)...
System.out.println ("Firebird JCA-JDBC driver not found in class
path");
System.out.println (e.getMessage ());
return;
}
break;
case 2:
// There is a bug in some JDK 1.1 implementations, eg. with
Microsoft
// Internet Explorer, such that the implicit driver instance created
during
// class initialization does not get registered when the driver is
loaded
// with Class.forName().
// See the FAQ at http://java.sun.com/jdbc for more info on this
problem.
// Notice that in the following workaround for this bug, that if the
bug
// is not present, then two instances of the driver will be
registered
// with the driver manager, the implicit instance created by the
driver
// class's static clause and the one created explicitly with
newInstance().
// This alternative should not be used except to workaround a JDK
1.1
// implementation bug.
try {
java.sql.DriverManager.registerDriver (
(java.sql.Driver) Class.forName
("org.firebirdsql.jdbc.FBDriver").newInstance ()
);
}
catch (java.lang.ClassNotFoundException e) {
// A call to Class.forName() forces us to consider this exception
:-)...
System.out.println ("Driver not found in class path");
System.out.println (e.getMessage ());
return;
}
catch (java.lang.IllegalAccessException e) {
// A call to newInstance() forces us to consider this exception
:-)...
System.out.println ("Unable to access driver constructor, this
shouldn't happen!");
System.out.println (e.getMessage ());
return;
}
catch (java.lang.InstantiationException e) {
// A call to newInstance() forces us to consider this exception
:-)...
// Attempt to instantiate an interface or abstract class.
System.out.println ("Unable to create an instance of driver class,
this shouldn't happen!");
System.out.println (e.getMessage ());
return;
}
catch (java.sql.SQLException e) {
// A call to registerDriver() forces us to consider this exception
:-)...
System.out.println ("Driver manager failed to register driver");
showSQLException (e);
return;
}
break;
case 3:
// Add the Firebird JCA-JDBC driver name to your system's
jdbc.drivers property list.
// The driver manager will load drivers from this system property
list.
// System.getProperties() may not be allowed for applets in some
browsers.
// For applets, use one of the Class.forName() alternatives above.
java.util.Properties sysProps = System.getProperties ();
StringBuffer drivers = new StringBuffer
("org.firebirdsql.jdbc.FBDriver");
String oldDrivers = sysProps.getProperty ("jdbc.drivers");
if (oldDrivers != null)
drivers.append (":" + oldDrivers);
sysProps.put ("jdbc.drivers", drivers.toString ());
System.setProperties (sysProps);
break;
case 4:
// Advanced: This is a non-standard alternative, and is tied to
// a particular driver implementation, but is very flexible.
//
// It may be possible to configure a driver explicitly, either thru
// the use of non-standard driver constructors, or non-standard
// driver "set" methods which somehow tailor the driver to behave
// differently from the default driver instance.
// Under this alternative, a driver instance is created explicitly
// using a driver specific constructor. The driver may then be
// tailored differently from the default driver instance which is
// created automatically when the driver class is loaded by the java
class loader.
// For example, perhaps a driver instance could be created which
// is to behave like some older version of the driver.
//
// d = new org.firebirdsql.jdbc.FBDriver ();
// DriverManager.registerDriver (d);
// c = DriverManager.getConnection (...);
//
// Since two drivers, with differing behavior, are now registered
with
// the driver manager, they presumably must recognize different jdbc
// subprotocols. For example, the tailored driver may only
recognize
// "jdbc:interbase:old_version://...", whereas the default driver
instance
// would recognize the standard "jdbc:interbase://...".
// There are currently no methods, such as the hypothetical
setVersion(),
// for tailoring an Firebird JCA-JDBC driver so this 4th alternative
is academic
// and not necessary for Firebird JCA-JDBC driver.
//
// It is also possible to create a tailored driver instance which
// is *not* registered with the driver manager as follows
//
// d = new org.firebirdsql.jdbc.FBDriver ();
// c = d.connect (...);
//
// this is the most usual case as this does not require differing
// jdbc subprotocols since the connection is obtained thru the
driver
// directly rather than thru the driver manager.
d = new org.firebirdsql.jdbc.FBDriver ();
}
// At this point the driver should be registered with the driver
manager.
// Try to find the registered driver that recognizes interbase URLs...
try {
// We pass the entire database URL, but we could just pass
"jdbc:interbase:"
d = java.sql.DriverManager.getDriver (databaseURL);
System.out.println ("Firebird JCA-JDBC driver version " +
d.getMajorVersion () +
"." +
d.getMinorVersion () +
" registered with driver manager.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to find Firebird JCA-JDBC driver among
the registered drivers.");
showSQLException (e);
return;
}
// Advanced info: Class.forName() loads the java class for the driver.
// All JDBC drivers are required to have a static clause that
automatically
// creates an instance of themselves and registers that instance
// with the driver manager. So there is no need to call
// DriverManager.registerDriver() explicitly unless the driver allows
// for tailored driver instances to be created (each instance
recognizing
// a different jdbc sub-protocol).
// Now that Firebird JCA-JDBC driver is registered with the driver
manager,
// try to get a connection to an employee.gdb database on this local
machine
// using one of two alternatives for obtaining connections...
int connectionAlternative = 1;
switch (connectionAlternative) {
case 1:
// This alternative is driver independent;
// the driver manager will find the right driver for you based on
the jdbc subprotocol.
// In the past, this alternative did not work with applets in some
browsers because of a
// bug in the driver manager. I believe this has been fixed in the
jdk 1.1 implementations.
try {
c = java.sql.DriverManager.getConnection (databaseURL, user,
password);
System.out.println ("Connection established.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to establish a connection through the
driver manager.");
showSQLException (e);
return;
}
break;
case 2:
// If you're working with a particular driver d, which may or may
not be registered,
// you can get a connection directly from it, bypassing the driver
manager...
try {
java.util.Properties connectionProperties = new
java.util.Properties ();
connectionProperties.put ("user", user);
connectionProperties.put ("password", password);
c = d.connect (databaseURL, connectionProperties);
System.out.println ("Connection established.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to establish a connection through the
driver.");
showSQLException (e);
return;
}
break;
}
// Let's disable the default autocommit so we can undo our changes
later...
try {
c.setAutoCommit (false);
System.out.println ("Auto-commit is disabled.");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to disable autocommit.");
showSQLException (e);
return;
}
// Now that we have a connection, let's try to get some meta data...
try {
java.sql.DatabaseMetaData dbMetaData = c.getMetaData ();
// Ok, let's query a driver/database capability
if (dbMetaData.supportsTransactions ())
System.out.println ("Transactions are supported.");
else
System.out.println ("Transactions are not supported.");
// What are the views defined on this database?
java.sql.ResultSet tables = dbMetaData.getTables (null, null, "%",
new String[] {"VIEW"});
while (tables.next ()) {
System.out.println (tables.getString ("TABLE_NAME") + " is a
view.");
}
tables.close ();
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to extract database meta data.");
showSQLException (e);
// What the heck, who needs meta data anyway ;-(, let's continue
on...
}
// Let's try to submit some static SQL on the connection.
// Note: This SQL should throw an exception on employee.gdb because
// of an integrity constraint violation.
try {
s = c.createStatement ();
s.executeUpdate ("update employee set salary = salary + 10000");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to increase everyone's salary.");
showSQLException (e);
// We expected this to fail, so don't return, let's keep going...
}
// Let's submit some static SQL which produces a result set.
// Notice that the statement s is reused with a new SQL string.
try {
rs = s.executeQuery ("select full_name from employee where salary <
50000");
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to submit a static SQL query.");
showSQLException (e);
// We can't go much further without a result set, return...
return;
}
// The query above could just as easily have been dynamic SQL,
// eg. if the SQL had been entered as user input.
// As a dynamic query, we'd need to query the result set meta data
// for information about the result set's columns.
try {
java.sql.ResultSetMetaData rsMetaData = rs.getMetaData ();
System.out.println ("The query executed has " +
rsMetaData.getColumnCount () +
" result columns.");
System.out.println ("Here are the columns: ");
for (int i = 1; i <= rsMetaData.getColumnCount (); i++) {
System.out.println (rsMetaData.getColumnName (i) +
" of type " +
rsMetaData.getColumnTypeName (i));
}
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to extract result set meta data.");
showSQLException (e);
// What the heck, who needs meta data anyway ;-(, let's continue
on...
}
// Ok, lets step thru the results of the query...
try {
System.out.println ("Here are the employee's whose salary <
$50,000");
while (rs.next ()) {
System.out.println (rs.getString ("full_name"));
}
}
catch (java.sql.SQLException e) {
System.out.println ("Unable to step thru results of query");
showSQLException (e);
return;
}
// As an exercise to the reader, rewrite this code so that required
// table structures are created dynamically using executeUpdate() on
DDL.
// In this way the code will be able to run against any database file
rather
// than just a previously setup employee.gdb.
// Just to get you started, you'll want to define a method something
like
// the following...
//
// private static void createTableStructures (java.sql.Connection c)
throws java.sql.SQLException
// {
// // Some drivers don't force commit on DDL, Firebird JCA-JDBC
driver does,
// // see DatabaseMetaData.dataDefinitionCausesTransactionCommit().
// // This is not necessary for Firebird JCA-JDBC driver, but may be
for other drivers...
// c.setAutoCommit (true);
//
// java.sql.Statement s = c.createStatement();
//
// // Drop table EMPLOYEE if it already exists, if not that's ok
too.
// try { s.executeUpdate ("drop table EMPLOYEE"); } catch
(java.sql.SQLException e) {}
//
// // Ok, now that we're sure the table isn't already there, create
it...
// s.executeUpdate ("create table EMPLOYEE (...)");
//
// // Ok, now populate the EMPLOYEE table...
// s.executeUpdate ("insert into EMPLOYEE values (...)");
//
// s.close();
// c.setAutoCommit (false);
// }
//
}
// This finally clause will be executed even if "return" was called in
case of any exceptions above.
finally {
System.out.println ("Closing database resources and rolling back any
changes we made to the database.");
// Now that we're all finished, let's release database resources.
try { if (rs!=null) rs.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
try { if (s!=null) s.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
// Before we close the connection, let's rollback any changes we may
have made.
try { if (c!=null) c.rollback (); } catch (java.sql.SQLException e)
{ showSQLException (e); }
try { if (c!=null) c.close (); } catch (java.sql.SQLException e) {
showSQLException (e); }
// If you don't close your database objects explicitly as above,
// they may be closed by the object's finalizer, but there's
// no guarantee if or when the finalizer will be called.
// In general, object finalizers are not called on program exit.
// It's recommended to close your JDBC objects explictly,
// but you can use System.runFinalizersOnExit(true), as at the
beginning
// of this method main(), to force finalizers to be called before
// program exit.
}
}
// Display an SQLException which has occured in this application.
private static void showSQLException (java.sql.SQLException e)
{
// Notice that a SQLException is actually a chain of SQLExceptions,
// let's not forget to print all of them...
java.sql.SQLException next = e;
while (next != null) {
System.out.println (next.getMessage ());
System.out.println ("Error Code: " + next.getErrorCode ());
System.out.println ("SQL State: " + next.getSQLState ());
next = next.getNextException ();
}
}
}
-----------------------------------------------------------------
Data Source Example
// Original version of this file was part of InterClient 2.01 examples
//
// Copyright InterBase Software Corporation, 1998.
// Written by com.inprise.interbase.interclient.r&d.PaulOstler :-)
//
// Code was modified by Roman Rokytskyy to show that Firebird JCA-JDBC
driver
// does not introduce additional complexity in normal driver usage scenario.
//
// An example of using a JDBC 2 Standard Extension DataSource.
// The DataSource facility provides an alternative to the JDBC
DriverManager,
// essentially duplicating all of the driver manager's useful functionality.
// Although, both mechanisms may be used by the same application if desired,
// JavaSoft encourages developers to regard the DriverManager as a legacy
// feature of the JDBC API.
// Applications should use the DataSource API whenever possible.
// A JDBC implementation that is accessed via the DataSource API is not
// automatically registered with the DriverManager.
// The DriverManager, Driver, and DriverPropertyInfo interfaces
// may be deprecated in the future.
import org.firebirdsql.jdbc.FBWrappingDataSource;
import org.firebirdsql.jca.FBConnectionRequestInfo;
import org.firebirdsql.gds.GDS;
public final class DataSourceExample
{
static public void main (String args[]) throws Exception
{
// Create an Firebird data source manually;
FBWrappingDataSource dataSource = new FBWrappingDataSource();
// Set the standard properties
dataSource.setDatabaseName ("localhost/3050:c:/database/employee.gdb");
dataSource.setDescription ("An example database of employees");
/*
* Following properties were not deleted in order to show differences
* between InterClient 2.01 data source implementation and Firebird one.
*/
//dataSource.setDataSourceName ("Employee");
//dataSource.setPortNumber (3060);
//dataSource.setNetworkProtocol ("jdbc:interbase:");
//dataSource.setRoleName (null);
// Set the non-standard properties
//dataSource.setCharSet (interbase.interclient.CharacterEncodings.NONE);
//dataSource.setSuggestedCachePages (0);
//dataSource.setSweepOnConnect (false);
/*
* This is an example how to use FBConnectionRequestInfo to specify
* DPB that will be used for this data source.
*/
FBConnectionRequestInfo cri = dataSource.getConnectionRequestInfo();
cri.setProperty(GDS.isc_dpb_lc_ctype, "NONE");
cri.setProperty(GDS.isc_dpb_num_buffers, 1);
cri.setProperty(GDS.isc_dpb_sql_dialect, 1);
dataSource.setConnectionRequestInfo(cri);
// Connect to the Firebird DataSource
try {
dataSource.setLoginTimeout (10);
java.sql.Connection c = dataSource.getConnection ("sysdba",
"masterkey");
// At this point, there is no implicit driver instance
// registered with the driver manager!
System.out.println ("got connection");
c.close ();
}
catch (java.sql.SQLException e) {
e.printStackTrace();
System.out.println ("sql exception: " + e.getMessage ());
}
}
}
********************************************************
20- Common Errors
********************************************************
1. Wrong URL
The most common error is having the wrong URL format for the database.
The two formats accepted are:
Standard format= jdbc:firebirdsql:[//host[:port]/]<database>
FB old format= jdbc:firebirdsql:[host[/port]:]<database>
Most Firebird/Interbase database file names end in ".gdb".
People frequently forget to put that in the url.
2. Wrong spelling in xml files.
When using JBoss or Tomcat or any environment that uses XML files for
configuration, don't forget that case is important. Windows users
often make this mistake because Windows is insensitive to case.
********************************************************
21. Compliance and Performance Information
********************************************************
Compliance Tests:
The compliance was check with jDataMaster, which include more than 1000
tests, excluding:
CallableStatements
Escape Syntax
FB type 4 driver passed all the tests excluding
ResultSetMetaData.isReadOnly(i)
ResultSetMetaData.isWritable(i)
ResultSetMetaData.isDefinitivelyWritable(i)
The set/get tests don't include Blobs.
Firebird driver is the most JDBC compliant driver of those tested with this
tool, the next one fails on 90
tests, including all of the most known RDBMS.
Performance tests compared with Interclient
The results of the jDataMaster basic performance tests, are the following:
Local test
Duron 800MHz with 512MB and FB 1.0 without forced Writes
Interclient Firebird Type 4 FB as % of Interclient
Insert 5000 records with autocommit 8510 ms 14307 ms 168 %
Read 5000 records with autocommit (x5) 3052 ms 3056 ms 100 %
Insert 5000 records with one transaction 6650 ms 5552 ms 83 %
Read 5000 records inside one transaction(x5) 3990 ms 3819 ms 95 %
Remote test
Client: Windows 2000 on Duron 800MHz with 512MB.
Server: Suse 7.2 on AMD 500MHz with 256MB and FB 1.0.
Interclient Firebird Type 4 FB as % of Interclient
Insert 5000 records with autocommit 16588 ms 17525 ms 106 %
Read 5000x5 records with autocommit 8082 ms 6247 ms 77 %
Insert 5000 records with one transaction 13009 ms 6311 ms 49 %
Read 5000x5 records inside one transaction 11639 ms 8670 ms 75 %
The time in each test is the average of 5 executions.
June-24-2002
********************************************************
22- History
********************************************************
The idea of writing a java translation of the C client library and using it
in an all-java driver originated in
some discussions between David Jencks and Jim Starkey. Alejandro Alberola
provided the initial translation of
most of the clie<br/><br/>(Message over 64 KB, truncated)