superwaba.ext.xplat.sql.db2e
Class Driver
java.lang.Object
|
+--superwaba.ext.xplat.sql.Driver
|
+--superwaba.ext.xplat.sql.db2e.Driver
- public class Driver
- extends Driver
There are currently no example apps ready to show how to use the DB2e WDBC
driver. If you have experience with JDBC, then it should be fairly easy
to get up to speed with DB2e on SW. Be sure to read this entire file for
information regarding WDBC driver capabilities.
Here is a short code example that shows how to load the WDBC driver for DB2e:
try
{
Class.forName("superwaba.ext.xplat.sql.db2e.Driver");
}
catch(ClassNotFoundException cnfe)
{
// Code to handle if driver not found or unable to load...
}
Connect to the DB2e driver using a URL of the form:
wdbc:db2e:[regular db2e connection string]
DB2e currently connects only to the local database, so does not need any additional connection information (such as server, user, password, etc). For now, just use a dummy string for the [regular db2e connection string] portion. Here is example code that obtains a DB2e connection:
import superwaba.ext.xplat.sql.*;
import superwaba.ext.xplat.sql.db2e.*;
...
Connection connection = null;
try
{
connection = DriverManager.getConnection("wdbc:db2e:server");
}
catch(SQLException sqlError)
{
// Code to handle connection error...
}
These are just a few tips concerning Db2e WDBC driver:
1. To keep the driver as simple as possible, we had to impose a few limitations:
a. Access fields consistently in relation to the data type you use to retrieve the field's value. In other words, don't use "getString(...)" on a column and then "getInt(...)" on the same column. An exception will be thrown. This is because the driver caches the objects it uses to access the column so that it can minimize the creation of new instances while retrieving the value. This holds across rows too. If you use getString(...) on a column and then reposition the result set to a new row, you must still use getString(...) on the same column. In fact, this even goes across separate ResultSets returned from a prepared statement. If you re-execute the prepared statement, it will reuse the same column types, so you must still use the same access method you used before.
b. This is a DB2e limitation: you can have only one ResultSet per (Prepared)Statement.
c. Other DB2e limitations (as of V8.1): Max connections: 1. Max open (Prepared)Statements: 20. Max transactions: 1 (transaction is on a Connection basis).
d. To save space, we did not implement updatable ResultSets (CONCUR_UPDATABLE). You will have to manually update rows/data by using SQL: INSERT, UPDATE, DELETE, etc. DB2e does not provide any kind of "updatable" interface, so we would have had to implement it by dynamically building SQL statement anyway, which would have just added more overhead to the whole process.
e. We have not implements ResultSets that can fetch row sets. We fetch one row at a time from Db2e.
f. We have not implemented FETCH_REVERSE, to save having to check a "direction" flag everytime a "next()" is performed. If you need to go in reverse, do it manually using previous(), relative(), or absolute() (which are all implemented and fully functional).
g. To the best of our knowledge, DB2e supports only TYPE_FORWARD_ONLY and TYPE_SCROLL_SENSITIVE.
h. To the best of our knowledge, DB2e is TRANSACTION_READ_COMMITTED only.
i. We have not implemented any of the DatabaseMetaData methods that would return a "ResultSet". If you need any of this information, you currently have to query it manually using SQL tailored specifically for DB2e's system table structure.
j. The content of the data within a Blob instance returned from getBlob(...) is temporary! This means that it will not survive a call to any of the position methods (next, previous, relative, absolute). When you call a position method, it will overwrite the Blob byte buffer with new data. This is because the driver reuses the exact same Blob instance for that column throughout the life of a Statement to minimize object creation. If you want to keep the data around, you will have to manually copy it out of the Blob byte[] buffer (Vm.copyArray, anyone?).
k. We don't attempt data type conversion. We let DB2e handle that for us. So if you are trying to getX(...) on a field that isn't X, then it will work so long as DB2e will automatically convert to that type for you. Oh, and once you call getX(...) on a field that isn't X, you must always call getX(...) and cannot use any other get*(...) methods on that field.
l. There is no Long data type in this implementation. getLong(...) is currently implemented as 'return (long)getInt(...)'
m. We have not yet implemented float or double types!! I know this is important to some people, but we didn't need it and didn't spend the time to implement it... maybe someone could volunteer?
n. We have not implemented getObject yet. It will throw an exception. Would you like to volunteer?
2. Tips for optimizing your usage of the DB2e WDBC driver:
a. Believe it or not, getBlob(...) is much more effecient than getBytes(...). This is because getBytes() must allocate a new byte[] array every time it is called, while getBlob(...) can reuse the same Blob instance for a particular column. getBytes() just calls getBlob() and returns a copy of the byte array.
b. A SuperWaba only method (not found in the JDBC Blob interface) is Blob.getByteBuffer(). This was added because it can be made so much more effecient than Blob.getBytes(long pos, int length) in certain scenarios. The DB2e driver allocates a byte[] buffer large enough to hold the largest Blob when a Blob column is first accessed. This buffer is returned when you call getByteBuffer, which is more effecient because a new byte[] array instance does not need to be created, and also means that the buffer could actually be larger than the Blob data for this row, so you must be careful to read only Blob.length() bytes from the buffer.
c. Try to avoid using the getX(String columnName) methods, as they impose a relatively heavy hit to look up the column name and then call their getX(int columnIndex) brother.
d. We have tried to optimize PreparedStatement so that you take a light hit when you reexecute the statement. Basically, the ResultSet instance is reused, avoiding an object allocation and allows the query information to be cached (such as column info and types).
e. Same for ResultSetMetaData.
f. Take advantage of setMaxFieldSize() when you can. It will save memory and CPU cycles if your max size is less than the sizes of your fields.
g. Use common sense. Reuse as much as possible. We try to stick by this in our code (though we aren't perfect).
h. getLong() is currently implemented as 'return (long)getInt(...)'. But don't worry, because ints in SW are 32-bit, so getInt actually uses DB2e's notion of LONG.
i. We have not yet optimized Time/Date/Timestamp functions for reuse, so a new Time/Date/Timestamp instance will be created every time a 'get' method is called for one of these.
j. We have not implemented getRef. This may be pulled from SW anyway.
k. getInt(...) is faster than getShort() and getLong().
l. Try to call getString(...) just once per column per row, for you shall pay the penalty of a new String instance every time you call.
Driver
public Driver()
acceptsURL
public boolean acceptsURL(String url)
throws SQLException
- This method tests whether or not the driver believes it can connect to
the specified database. The driver should only test whether it
understands and accepts the URL. It should not necessarily attempt to
probe the database for a connection.
- Overrides:
- acceptsURL in class Driver
- Parameters:
The
- database URL string.- Returns:
true
if the drivers can connect to the database,
false
otherwise.- Throws:
- SQLException - If an error occurs.
connect
public Connection connect(String url,
Hashtable info)
throws SQLException
- This method connects to the specified database using the connection
properties supplied. If the driver does not understand the database
URL, it should return
null
instead of throwing an
exception since the DriverManager
will probe a driver
in this manner.
- Overrides:
- connect in class Driver
- Parameters:
url
- The URL string for this connection.properties
- The list of database connection properties.- Returns:
- A
Connection
object for the newly established
connection, or null
if the URL is not understood. - Throws:
- SQLException - If an error occurs.
checkEnvironment
protected void checkEnvironment()
throws SQLException
getMajorVersion
public int getMajorVersion()
- This method returns the major version number of the driver.
- Overrides:
- getMajorVersion in class Driver
- Returns:
- The major version number of the driver.
getMinorVersion
public int getMinorVersion()
- This method returns the minor version number of the driver.
- Overrides:
- getMinorVersion in class Driver
- Returns:
- The minor version number of the driver.
getPropertyInfo
public DriverPropertyInfo[] getPropertyInfo(String url,
Hashtable properties)
throws SQLException
- This method returns an array of possible properties that could be
used to connect to the specified database.
- Overrides:
- getPropertyInfo in class Driver
- Parameters:
url
- The URL string of the database to connect to.properties
- The list of properties the caller is planning to use
to connect to the database.- Returns:
- A list of possible additional properties for a connection to this
database. This list may be empty.
- Throws:
- SQLException - If an error occurs.
jdbcCompliant
public boolean jdbcCompliant()
- This method tests whether or not the driver is JDBC compliant. This
method should only return
true
if the driver has been
certified as JDBC compliant.
- Overrides:
- jdbcCompliant in class Driver
- Returns:
true
if the driver has been certified JDBC compliant,
false
otherwise.