[RSS]

Extensions to CachedRowSet

This page documents the changes to the standard CachedRowSet API and implementation that were made for Creator/VisualWeb's implementation of CachedRowSet. These changes are grouped into areas of functionality, rather than focusing on specific code details. The intent is to understand the impact of this functionality going away, and what work we may need to do to adapt and be able to work with the RI.

Constructing the implementation class

The RI constructor for CachedRowSet throws a SQLException. This causes InSync to generate code that will not compile because it does not expect a Java Bean to throw an exception. Sandip and Deva are working on this and are extending InSync to allow a DesignBean to provide an initialization string that can be used when InSync generates initialization code for the bean in the application.

Package name change

A minor item, but important. The package name used to construct the CachedRowSet implementation class changes (com.sun.rowset.CachedRowSetImpl versus com.sun.sql.rowset.CachedRowSetXImpl. This needs to be taken into account during code generation.

Getting metadata without executing

The Creator version of CachedRowSet will return valid metadata even if the rowset has not been executed. It does this by using the command to prepare a statement, and then getting the metadata from the prepared statement. There is one workaround here for Oracle because it doesn't support metadata for a prepared statement; in this case we "munge" the SQL from the command so that no rows are processed or returned, and then execute it.

This is not the prettiest piece of code, but it gets the job done, and gets around a real limitation for design time work. You definitely do not want to execute a large query involving sorts and millions of rows at design time just to get the metadata.

We can move this code into CachedRowSetDataProvider.getFieldKeys(), which is how our design time stuff gets the metadata anyway.

Lance has indicated he is not interested in adding support for metadata prior to execution of the rowset to the spec. So we'll have to do this workaround for the foreseeable future.

Property change listener

Our extension of CachedRowSet allows a user to install a property change listener. A key client of this is the data binding code. When a user through the property editor or Visual Query Editor updates the command, url, dataSourceName or username properties, this fires off a property change event. This in turn caused the metadata that was cached in the rowset and CachedRowSetDataProvider to be flushed out, and then the metadata was re-fetched and any bound components refreshed to reflect the new metadata.

It is very unlikely that users made use of the property change listener functionality.

Internally, we have to change how we detect changes to the rowset. There are two approaches I am investigating.

The preferable approach is to use the DesignInfo pattern to detect changes. In NetBeans 5.5, CachedRowSet does not have a DesignInfo class. But in M10, we have added this class. As long as our code correctly sets properties by going through bean.getProperty("foo").setValue("bar"), then we can detect property changes in the DesignInfo class, and use this as our new implementation of a property change listener. The one trick I have yet to figure out is how to wire up the CachedRowSetDataProvider as a PropertyChangeListener on the rowset.

A plan B for this is to implement a dynamic proxy that wraps the rowset and intercepts any method calls. I'd like to avoid this approach if possible, but it is a viable alternative.

Support for writable/updatable joins

When you get the metadata for a join from a driver, it will always say all columns are read-only. However, our implementation allows a join to be writeable.

The RI does not allow rowsets based on a join to be writeable. In general, CachedRowSet was intended to work with a single table. Note for example, that it has a "tableName" property.

We will not support updatable rowsets for joins in NB 6 for new projects. We will allow users to continue to use our forked rowset in their old projects, but they will be warned that this feature is going into EOL.

For more details around this decision, see UpdatableCachedRowsetIssues

Metadata fixes

There are a few fixes in the Creator cached rowset code to handle issues with JDBC driver metadata. These fixes will not be in the standard RI. Hopefully they will be integrated into the latest RI and made available in Java SE 6 Update 3, which is expected to ship this fall.

We could potentially apply some of these fixes in our code (e.g. in the CachedRowSetDataProvider), but it seems more reasonable to just tell customers to upgrade to the new JDK if they want these fixes.

initMetadata()

  • Line 875: PostgreSQL driver sometimes returns a negative column display size. The fix
is to set the size to zero.
  • Line 890: Some drivers return strange results for precision and scale. If precision < 0, set precision to zero. If scale < 0, set scale to 0

Additional properties

  • catalogName: the name of the catalog that contains the table referred to by tablename -- not sure how this is used
  • schemaName: the name of the schema that contains the table referred to by tableName -- not sure how this is used
  • columnCatalogNames: an array of String, one for each column, which contains the name of catalog of the corresponding column -- this is needed to support join rowsets. Note again that CachedRowSet has a tableName property and assumes only one table per rowset. These extensions are a way to work around this assumption.
  • columnSchemaNames: an array of String, one for each column, which contains the name of the schema of the corresponding column -- needed to support join rowsets.
  • columnTableNames: an array of String, one for each column, which contains the name of the table of the corresponding column -- needed to support join rowsets
  • columnNames: an array of String, one for each column, which contains the name of the corresponding column -- not sure how this is used
  • insertableColumns: an array of boolean, one for each column, which contains true if the corresponding column can be inserted, else it contains false -- needed for join rowsets
  • updatableColumns: an array of boolean, one for each column, which contains true if the corresponding column can be updated, else it contains false -- needed for join rowsets
  • printStatements: a boolean that when true will result in internally generated INSERT, UPDATE, and DELETE SQL statements being written to System.out. This output is useful in determining why inserts,updates and/or deletes are falling and in deciding what advanced properties to set in order to address the problems. -- This is a debug feature and we'll just have to do without. Used mostly in debugging updatable join rowsets.