Path: blob/master/src/java.sql.rowset/share/classes/javax/sql/rowset/CachedRowSet.java
40948 views
/*1* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sql.rowset;2627import java.sql.*;28import javax.sql.*;29import javax.naming.*;30import java.io.*;31import java.math.*;32import java.util.*;3334import javax.sql.rowset.spi.*;3536/**37* The interface that all standard implementations of38* <code>CachedRowSet</code> must implement.39* <P>40* The reference implementation of the <code>CachedRowSet</code> interface provided41* by Oracle Corporation is a standard implementation. Developers may use this implementation42* just as it is, they may extend it, or they may choose to write their own implementations43* of this interface.44* <P>45* A <code>CachedRowSet</code> object is a container for rows of data46* that caches its rows in memory, which makes it possible to operate without always being47* connected to its data source. Further, it is a48* JavaBeans component and is scrollable,49* updatable, and serializable. A <code>CachedRowSet</code> object typically50* contains rows from a result set, but it can also contain rows from any file51* with a tabular format, such as a spread sheet. The reference implementation52* supports getting data only from a <code>ResultSet</code> object, but53* developers can extend the <code>SyncProvider</code> implementations to provide54* access to other tabular data sources.55* <P>56* An application can modify the data in a <code>CachedRowSet</code> object, and57* those modifications can then be propagated back to the source of the data.58* <P>59* A <code>CachedRowSet</code> object is a <i>disconnected</i> rowset, which means60* that it makes use of a connection to its data source only briefly. It connects to its61* data source while it is reading data to populate itself with rows and again62* while it is propagating changes back to its underlying data source. The rest63* of the time, a <code>CachedRowSet</code> object is disconnected, including64* while its data is being modified. Being disconnected makes a <code>RowSet</code>65* object much leaner and therefore much easier to pass to another component. For66* example, a disconnected <code>RowSet</code> object can be serialized and passed67* over the wire to a thin client such as a personal digital assistant (PDA).68*69*70* <h2>1.0 Creating a <code>CachedRowSet</code> Object</h2>71* The following line of code uses the default constructor for72* <code>CachedRowSet</code>73* supplied in the reference implementation (RI) to create a default74* <code>CachedRowSet</code> object.75* <PRE>76* CachedRowSetImpl crs = new CachedRowSetImpl();77* </PRE>78* This new <code>CachedRowSet</code> object will have its properties set to the79* default properties of a <code>BaseRowSet</code> object, and, in addition, it will80* have an <code>RIOptimisticProvider</code> object as its synchronization provider.81* <code>RIOptimisticProvider</code>, one of two <code>SyncProvider</code>82* implementations included in the RI, is the default provider that the83* <code>SyncFactory</code> singleton will supply when no synchronization84* provider is specified.85* <P>86* A <code>SyncProvider</code> object provides a <code>CachedRowSet</code> object87* with a reader (a <code>RowSetReader</code> object) for reading data from a88* data source to populate itself with data. A reader can be implemented to read89* data from a <code>ResultSet</code> object or from a file with a tabular format.90* A <code>SyncProvider</code> object also provides91* a writer (a <code>RowSetWriter</code> object) for synchronizing any92* modifications to the <code>CachedRowSet</code> object's data made while it was93* disconnected with the data in the underlying data source.94* <P>95* A writer can be implemented to exercise various degrees of care in checking96* for conflicts and in avoiding them.97* (A conflict occurs when a value in the data source has been changed after98* the rowset populated itself with that value.)99* The <code>RIOptimisticProvider</code> implementation assumes there will be100* few or no conflicts and therefore sets no locks. It updates the data source101* with values from the <code>CachedRowSet</code> object only if there are no102* conflicts.103* Other writers can be implemented so that they always write modified data to104* the data source, which can be accomplished either by not checking for conflicts105* or, on the other end of the spectrum, by setting locks sufficient to prevent data106* in the data source from being changed. Still other writer implementations can be107* somewhere in between.108* <P>109* A <code>CachedRowSet</code> object may use any110* <code>SyncProvider</code> implementation that has been registered111* with the <code>SyncFactory</code> singleton. An application112* can find out which <code>SyncProvider</code> implementations have been113* registered by calling the following line of code.114* <PRE>115* java.util.Enumeration providers = SyncFactory.getRegisteredProviders();116* </PRE>117* <P>118* There are two ways for a <code>CachedRowSet</code> object to specify which119* <code>SyncProvider</code> object it will use.120* <UL>121* <LI>Supplying the name of the implementation to the constructor<BR>122* The following line of code creates the <code>CachedRowSet</code>123* object <i>crs2</i> that is initialized with default values except that its124* <code>SyncProvider</code> object is the one specified.125* <PRE>126* CachedRowSetImpl crs2 = new CachedRowSetImpl(127* "com.fred.providers.HighAvailabilityProvider");128* </PRE>129* <LI>Setting the <code>SyncProvider</code> using the <code>CachedRowSet</code>130* method <code>setSyncProvider</code><BR>131* The following line of code resets the <code>SyncProvider</code> object132* for <i>crs</i>, the <code>CachedRowSet</code> object created with the133* default constructor.134* <PRE>135* crs.setSyncProvider("com.fred.providers.HighAvailabilityProvider");136* </PRE>137* </UL>138* See the comments for <code>SyncFactory</code> and <code>SyncProvider</code> for139* more details.140*141*142* <h2>2.0 Retrieving Data from a <code>CachedRowSet</code> Object</h2>143* Data is retrieved from a <code>CachedRowSet</code> object by using the144* getter methods inherited from the <code>ResultSet</code>145* interface. The following examples, in which <code>crs</code> is a146* <code>CachedRowSet</code>147* object, demonstrate how to iterate through the rows, retrieving the column148* values in each row. The first example uses the version of the149* getter methods that take a column number; the second example150* uses the version that takes a column name. Column numbers are generally151* used when the <code>RowSet</code> object's command152* is of the form <code>SELECT * FROM TABLENAME</code>; column names are most153* commonly used when the command specifies columns by name.154* <PRE>155* while (crs.next()) {156* String name = crs.getString(1);157* int id = crs.getInt(2);158* Clob comment = crs.getClob(3);159* short dept = crs.getShort(4);160* System.out.println(name + " " + id + " " + comment + " " + dept);161* }162* </PRE>163*164* <PRE>165* while (crs.next()) {166* String name = crs.getString("NAME");167* int id = crs.getInt("ID");168* Clob comment = crs.getClob("COM");169* short dept = crs.getShort("DEPT");170* System.out.println(name + " " + id + " " + comment + " " + dept);171* }172* </PRE>173* <h3>2.1 Retrieving <code>RowSetMetaData</code></h3>174* An application can get information about the columns in a <code>CachedRowSet</code>175* object by calling <code>ResultSetMetaData</code> and <code>RowSetMetaData</code>176* methods on a <code>RowSetMetaData</code> object. The following code fragment,177* in which <i>crs</i> is a <code>CachedRowSet</code> object, illustrates the process.178* The first line creates a <code>RowSetMetaData</code> object with information179* about the columns in <i>crs</i>. The method <code>getMetaData</code>,180* inherited from the <code>ResultSet</code> interface, returns a181* <code>ResultSetMetaData</code> object, which is cast to a182* <code>RowSetMetaData</code> object before being assigned to the variable183* <i>rsmd</i>. The second line finds out how many columns <i>jrs</i> has, and184* the third line gets the JDBC type of values stored in the second column of185* <code>jrs</code>.186* <PRE>187* RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData();188* int count = rsmd.getColumnCount();189* int type = rsmd.getColumnType(2);190* </PRE>191* The <code>RowSetMetaData</code> interface differs from the192* <code>ResultSetMetaData</code> interface in two ways.193* <UL>194* <LI><i>It includes <code>setter</code> methods:</i> A <code>RowSet</code>195* object uses these methods internally when it is populated with data from a196* different <code>ResultSet</code> object.197*198* <LI><i>It contains fewer <code>getter</code> methods:</i> Some199* <code>ResultSetMetaData</code> methods to not apply to a <code>RowSet</code>200* object. For example, methods retrieving whether a column value is writable201* or read only do not apply because all of a <code>RowSet</code> object's202* columns will be writable or read only, depending on whether the rowset is203* updatable or not.204* </UL>205* NOTE: In order to return a <code>RowSetMetaData</code> object, implementations must206* override the <code>getMetaData()</code> method defined in207* <code>java.sql.ResultSet</code> and return a <code>RowSetMetaData</code> object.208*209* <h2>3.0 Updating a <code>CachedRowSet</code> Object</h2>210* Updating a <code>CachedRowSet</code> object is similar to updating a211* <code>ResultSet</code> object, but because the rowset is not connected to212* its data source while it is being updated, it must take an additional step213* to effect changes in its underlying data source. After calling the method214* <code>updateRow</code> or <code>insertRow</code>, a215* <code>CachedRowSet</code>216* object must also call the method <code>acceptChanges</code> to have updates217* written to the data source. The following example, in which the cursor is218* on a row in the <code>CachedRowSet</code> object <i>crs</i>, shows219* the code required to update two column values in the current row and also220* update the <code>RowSet</code> object's underlying data source.221* <PRE>222* crs.updateShort(3, 58);223* crs.updateInt(4, 150000);224* crs.updateRow();225* crs.acceptChanges();226* </PRE>227* <P>228* The next example demonstrates moving to the insert row, building a new229* row on the insert row, inserting it into the rowset, and then calling the230* method <code>acceptChanges</code> to add the new row to the underlying data231* source. Note that as with the getter methods, the updater methods may take232* either a column index or a column name to designate the column being acted upon.233* <PRE>234* crs.moveToInsertRow();235* crs.updateString("Name", "Shakespeare");236* crs.updateInt("ID", 10098347);237* crs.updateShort("Age", 58);238* crs.updateInt("Sal", 150000);239* crs.insertRow();240* crs.moveToCurrentRow();241* crs.acceptChanges();242* </PRE>243* <P>244* NOTE: Where the <code>insertRow()</code> method inserts the contents of a245* <code>CachedRowSet</code> object's insert row is implementation-defined.246* The reference implementation for the <code>CachedRowSet</code> interface247* inserts a new row immediately following the current row, but it could be248* implemented to insert new rows in any number of other places.249* <P>250* Another thing to note about these examples is how they use the method251* <code>acceptChanges</code>. It is this method that propagates changes in252* a <code>CachedRowSet</code> object back to the underlying data source,253* calling on the <code>RowSet</code> object's writer internally to write254* changes to the data source. To do this, the writer has to incur the expense255* of establishing a connection with that data source. The256* preceding two code fragments call the method <code>acceptChanges</code>257* immediately after calling <code>updateRow</code> or <code>insertRow</code>.258* However, when there are multiple rows being changed, it is more efficient to call259* <code>acceptChanges</code> after all calls to <code>updateRow</code>260* and <code>insertRow</code> have been made. If <code>acceptChanges</code>261* is called only once, only one connection needs to be established.262*263* <h2>4.0 Updating the Underlying Data Source</h2>264* When the method <code>acceptChanges</code> is executed, the265* <code>CachedRowSet</code> object's writer, a <code>RowSetWriterImpl</code>266* object, is called behind the scenes to write the changes made to the267* rowset to the underlying data source. The writer is implemented to make a268* connection to the data source and write updates to it.269* <P>270* A writer is made available through an implementation of the271* <code>SyncProvider</code> interface, as discussed in section 1,272* "Creating a <code>CachedRowSet</code> Object."273* The default reference implementation provider, <code>RIOptimisticProvider</code>,274* has its writer implemented to use an optimistic concurrency control275* mechanism. That is, it maintains no locks in the underlying database while276* the rowset is disconnected from the database and simply checks to see if there277* are any conflicts before writing data to the data source. If there are any278* conflicts, it does not write anything to the data source.279* <P>280* The reader/writer facility281* provided by the <code>SyncProvider</code> class is pluggable, allowing for the282* customization of data retrieval and updating. If a different concurrency283* control mechanism is desired, a different implementation of284* <code>SyncProvider</code> can be plugged in using the method285* <code>setSyncProvider</code>.286* <P>287* In order to use the optimistic concurrency control routine, the288* <code>RIOptimisticProvider</code> maintains both its current289* value and its original value (the value it had immediately preceding the290* current value). Note that if no changes have been made to the data in a291* <code>RowSet</code> object, its current values and its original values are the same,292* both being the values with which the <code>RowSet</code> object was initially293* populated. However, once any values in the <code>RowSet</code> object have been294* changed, the current values and the original values will be different, though at295* this stage, the original values are still the initial values. With any subsequent296* changes to data in a <code>RowSet</code> object, its original values and current297* values will still differ, but its original values will be the values that298* were previously the current values.299* <P>300* Keeping track of original values allows the writer to compare the <code>RowSet</code>301* object's original value with the value in the database. If the values in302* the database differ from the <code>RowSet</code> object's original values, which means that303* the values in the database have been changed, there is a conflict.304* Whether a writer checks for conflicts, what degree of checking it does, and how305* it handles conflicts all depend on how it is implemented.306*307* <h2>5.0 Registering and Notifying Listeners</h2>308* Being JavaBeans components, all rowsets participate in the JavaBeans event309* model, inheriting methods for registering listeners and notifying them of310* changes from the <code>BaseRowSet</code> class. A listener for a311* <code>CachedRowSet</code> object is a component that wants to be notified312* whenever there is a change in the rowset. For example, if a313* <code>CachedRowSet</code> object contains the results of a query and314* those315* results are being displayed in, say, a table and a bar graph, the table and316* bar graph could be registered as listeners with the rowset so that they can317* update themselves to reflect changes. To become listeners, the table and318* bar graph classes must implement the <code>RowSetListener</code> interface.319* Then they can be added to the <Code>CachedRowSet</code> object's list of320* listeners, as is illustrated in the following lines of code.321* <PRE>322* crs.addRowSetListener(table);323* crs.addRowSetListener(barGraph);324* </PRE>325* Each <code>CachedRowSet</code> method that moves the cursor or changes326* data also notifies registered listeners of the changes, so327* <code>table</code> and <code>barGraph</code> will be notified when there is328* a change in <code>crs</code>.329*330* <h2>6.0 Passing Data to Thin Clients</h2>331* One of the main reasons to use a <code>CachedRowSet</code> object is to332* pass data between different components of an application. Because it is333* serializable, a <code>CachedRowSet</code> object can be used, for example,334* to send the result of a query executed by an enterprise JavaBeans component335* running in a server environment over a network to a client running in a336* web browser.337* <P>338* While a <code>CachedRowSet</code> object is disconnected, it can be much339* leaner than a <code>ResultSet</code> object with the same data.340* As a result, it can be especially suitable for sending data to a thin client341* such as a PDA, where it would be inappropriate to use a JDBC driver342* due to resource limitations or security considerations.343* Thus, a <code>CachedRowSet</code> object provides a means to "get rows in"344* without the need to implement the full JDBC API.345*346* <h2>7.0 Scrolling and Updating</h2>347* A second major use for <code>CachedRowSet</code> objects is to provide348* scrolling and updating for <code>ResultSet</code> objects that349* do not provide these capabilities themselves. In other words, a350* <code>CachedRowSet</code> object can be used to augment the351* capabilities of a JDBC technology-enabled driver (hereafter called a352* "JDBC driver") when the DBMS does not provide full support for scrolling and353* updating. To achieve the effect of making a non-scrollable and read-only354* <code>ResultSet</code> object scrollable and updatable, a programmer355* simply needs to create a <code>CachedRowSet</code> object populated356* with that <code>ResultSet</code> object's data. This is demonstrated357* in the following code fragment, where <code>stmt</code> is a358* <code>Statement</code> object.359* <PRE>360* ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES");361* CachedRowSetImpl crs = new CachedRowSetImpl();362* crs.populate(rs);363* </PRE>364* <P>365* The object <code>crs</code> now contains the data from the table366* <code>EMPLOYEES</code>, just as the object <code>rs</code> does.367* The difference is that the cursor for <code>crs</code> can be moved368* forward, backward, or to a particular row even if the cursor for369* <code>rs</code> can move only forward. In addition, <code>crs</code> is370* updatable even if <code>rs</code> is not because by default, a371* <code>CachedRowSet</code> object is both scrollable and updatable.372* <P>373* In summary, a <code>CachedRowSet</code> object can be thought of as simply374* a disconnected set of rows that are being cached outside of a data source.375* Being thin and serializable, it can easily be sent across a wire,376* and it is well suited to sending data to a thin client. However, a377* <code>CachedRowSet</code> object does have a limitation: It is limited in378* size by the amount of data it can store in memory at one time.379*380* <h2>8.0 Getting Universal Data Access</h2>381* Another advantage of the <code>CachedRowSet</code> class is that it makes it382* possible to retrieve and store data from sources other than a relational383* database. The reader for a rowset can be implemented to read and populate384* its rowset with data from any tabular data source, including a spreadsheet385* or flat file.386* Because both a <code>CachedRowSet</code> object and its metadata can be387* created from scratch, a component that acts as a factory for rowsets388* can use this capability to create a rowset containing data from389* non-SQL data sources. Nevertheless, it is expected that most of the time,390* <code>CachedRowSet</code> objects will contain data that was fetched391* from an SQL database using the JDBC API.392*393* <h2>9.0 Setting Properties</h2>394* All rowsets maintain a set of properties, which will usually be set using395* a tool. The number and kinds of properties a rowset has will vary,396* depending on what the rowset does and how it gets its data. For example,397* rowsets that get their data from a <code>ResultSet</code> object need to398* set the properties that are required for making a database connection.399* If a rowset uses the <code>DriverManager</code> facility to make a400* connection, it needs to set a property for the JDBC URL that identifies401* the appropriate driver, and it needs to set the properties that give the402* user name and password.403* If, on the other hand, the rowset uses a <code>DataSource</code> object404* to make the connection, which is the preferred method, it does not need to405* set the property for the JDBC URL. Instead, it needs to set406* properties for the logical name of the data source, for the user name,407* and for the password.408* <P>409* NOTE: In order to use a <code>DataSource</code> object for making a410* connection, the <code>DataSource</code> object must have been registered411* with a naming service that uses the Java Naming and Directory412* Interface (JNDI) API. This registration413* is usually done by a person acting in the capacity of a system414* administrator.415* <P>416* In order to be able to populate itself with data from a database, a rowset417* needs to set a command property. This property is a query that is a418* <code>PreparedStatement</code> object, which allows the query to have419* parameter placeholders that are set at run time, as opposed to design time.420* To set these placeholder parameters with values, a rowset provides421* setter methods for setting values of each data type,422* similar to the setter methods provided by the <code>PreparedStatement</code>423* interface.424* <P>425* The following code fragment illustrates how the <code>CachedRowSet</code>426* object <code>crs</code> might have its command property set. Note that if a427* tool is used to set properties, this is the code that the tool would use.428* <PRE>{@code429* crs.setCommand("SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS " +430* "WHERE CREDIT_LIMIT > ? AND REGION = ?");431* } </PRE>432* <P>433* The values that will be used to set the command's placeholder parameters are434* contained in the <code>RowSet</code> object's <code>params</code> field, which is a435* <code>Vector</code> object.436* The <code>CachedRowSet</code> class provides a set of setter437* methods for setting the elements in its <code>params</code> field. The438* following code fragment demonstrates setting the two parameters in the439* query from the previous example.440* <PRE>441* crs.setInt(1, 5000);442* crs.setString(2, "West");443* </PRE>444* <P>445* The <code>params</code> field now contains two elements, each of which is446* an array two elements long. The first element is the parameter number;447* the second is the value to be set.448* In this case, the first element of <code>params</code> is449* <code>1</code>, <code>5000</code>, and the second element is <code>2</code>,450* <code>"West"</code>. When an application calls the method451* <code>execute</code>, it will in turn call on this <code>RowSet</code> object's reader,452* which will in turn invoke its <code>readData</code> method. As part of453* its implementation, <code>readData</code> will get the values in454* <code>params</code> and use them to set the command's placeholder455* parameters.456* The following code fragment gives an idea of how the reader457* does this, after obtaining the <code>Connection</code> object458* <code>con</code>.459* <PRE>{@code460* PreparedStatement pstmt = con.prepareStatement(crs.getCommand());461* reader.decodeParams();462* // decodeParams figures out which setter methods to use and does something463* // like the following:464* // for (i = 0; i < params.length; i++) {465* // pstmt.setObject(i + 1, params[i]);466* // }467* }</PRE>468* <P>469* At this point, the command for <code>crs</code> is the query {@code "SELECT470* FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS WHERE CREDIT_LIMIT > 5000471* AND REGION = "West"}. After the <code>readData</code> method executes472* this command with the following line of code, it will have the data from473* <code>rs</code> with which to populate <code>crs</code>.474* <PRE>{@code475* ResultSet rs = pstmt.executeQuery();476* }</PRE>477* <P>478* The preceding code fragments give an idea of what goes on behind the479* scenes; they would not appear in an application, which would not invoke480* methods like <code>readData</code> and <code>decodeParams</code>.481* In contrast, the following code fragment shows what an application might do.482* It sets the rowset's command, sets the command's parameters, and executes483* the command. Simply by calling the <code>execute</code> method,484* <code>crs</code> populates itself with the requested data from the485* table <code>CUSTOMERS</code>.486* <PRE>{@code487* crs.setCommand("SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS" +488* "WHERE CREDIT_LIMIT > ? AND REGION = ?");489* crs.setInt(1, 5000);490* crs.setString(2, "West");491* crs.execute();492* }</PRE>493*494* <h2>10.0 Paging Data</h2>495* Because a <code>CachedRowSet</code> object stores data in memory,496* the amount of data that it can contain at any one497* time is determined by the amount of memory available. To get around this limitation,498* a <code>CachedRowSet</code> object can retrieve data from a <code>ResultSet</code>499* object in chunks of data, called <i>pages</i>. To take advantage of this mechanism,500* an application sets the number of rows to be included in a page using the method501* <code>setPageSize</code>. In other words, if the page size is set to five, a chunk502* of five rows of503* data will be fetched from the data source at one time. An application can also504* optionally set the maximum number of rows that may be fetched at one time. If the505* maximum number of rows is set to zero, or no maximum number of rows is set, there is506* no limit to the number of rows that may be fetched at a time.507* <P>508* After properties have been set,509* the <code>CachedRowSet</code> object must be populated with data510* using either the method <code>populate</code> or the method <code>execute</code>.511* The following lines of code demonstrate using the method <code>populate</code>.512* Note that this version of the method takes two parameters, a <code>ResultSet</code>513* handle and the row in the <code>ResultSet</code> object from which to start514* retrieving rows.515* <PRE>516* CachedRowSet crs = new CachedRowSetImpl();517* crs.setMaxRows(20);518* crs.setPageSize(4);519* crs.populate(rsHandle, 10);520* </PRE>521* When this code runs, <i>crs</i> will be populated with four rows from522* <i>rsHandle</i> starting with the tenth row.523* <P>524* The next code fragment shows populating a <code>CachedRowSet</code> object using the525* method <code>execute</code>, which may or may not take a <code>Connection</code>526* object as a parameter. This code passes <code>execute</code> the <code>Connection</code>527* object <i>conHandle</i>.528* <P>529* Note that there are two differences between the following code530* fragment and the previous one. First, the method <code>setMaxRows</code> is not531* called, so there is no limit set for the number of rows that <i>crs</i> may contain.532* (Remember that <i>crs</i> always has the overriding limit of how much data it can533* store in memory.) The second difference is that the you cannot pass the method534* <code>execute</code> the number of the row in the <code>ResultSet</code> object535* from which to start retrieving rows. This method always starts with the first row.536* <PRE>537* CachedRowSet crs = new CachedRowSetImpl();538* crs.setPageSize(5);539* crs.execute(conHandle);540* </PRE>541* After this code has run, <i>crs</i> will contain five rows of data from the542* <code>ResultSet</code> object produced by the command for <i>crs</i>. The writer543* for <i>crs</i> will use <i>conHandle</i> to connect to the data source and544* execute the command for <i>crs</i>. An application is then able to operate on the545* data in <i>crs</i> in the same way that it would operate on data in any other546* <code>CachedRowSet</code> object.547* <P>548* To access the next page (chunk of data), an application calls the method549* <code>nextPage</code>. This method creates a new <code>CachedRowSet</code> object550* and fills it with the next page of data. For example, assume that the551* <code>CachedRowSet</code> object's command returns a <code>ResultSet</code> object552* <i>rs</i> with 1000 rows of data. If the page size has been set to 100, the first553* call to the method <code>nextPage</code> will create a <code>CachedRowSet</code> object554* containing the first 100 rows of <i>rs</i>. After doing what it needs to do with the555* data in these first 100 rows, the application can again call the method556* <code>nextPage</code> to create another <code>CachedRowSet</code> object557* with the second 100 rows from <i>rs</i>. The data from the first <code>CachedRowSet</code>558* object will no longer be in memory because it is replaced with the data from the559* second <code>CachedRowSet</code> object. After the tenth call to the method <code>nextPage</code>,560* the tenth <code>CachedRowSet</code> object will contain the last 100 rows of data from561* <i>rs</i>, which are stored in memory. At any given time, the data from only one562* <code>CachedRowSet</code> object is stored in memory.563* <P>564* The method <code>nextPage</code> returns <code>true</code> as long as the current565* page is not the last page of rows and <code>false</code> when there are no more pages.566* It can therefore be used in a <code>while</code> loop to retrieve all of the pages,567* as is demonstrated in the following lines of code.568* <PRE>569* CachedRowSet crs = CachedRowSetImpl();570* crs.setPageSize(100);571* crs.execute(conHandle);572*573* while(crs.nextPage()) {574* while(crs.next()) {575* . . . // operate on chunks (of 100 rows each) in crs,576* // row by row577* }578* }579* </PRE>580* After this code fragment has been run, the application will have traversed all581* 1000 rows, but it will have had no more than 100 rows in memory at a time.582* <P>583* The <code>CachedRowSet</code> interface also defines the method <code>previousPage</code>.584* Just as the method <code>nextPage</code> is analogous to the <code>ResultSet</code>585* method <code>next</code>, the method <code>previousPage</code> is analogous to586* the <code>ResultSet</code> method <code>previous</code>. Similar to the method587* <code>nextPage</code>, <code>previousPage</code> creates a <code>CachedRowSet</code>588* object containing the number of rows set as the page size. So, for instance, the589* method <code>previousPage</code> could be used in a <code>while</code> loop at590* the end of the preceding code fragment to navigate back through the pages from the last591* page to the first page.592* The method <code>previousPage</code> is also similar to <code>nextPage</code>593* in that it can be used in a <code>while</code>594* loop, except that it returns <code>true</code> as long as there is another page595* preceding it and <code>false</code> when there are no more pages ahead of it.596* <P>597* By positioning the cursor after the last row for each page,598* as is done in the following code fragment, the method <code>previous</code>599* navigates from the last row to the first row in each page.600* The code could also have left the cursor before the first row on each page and then601* used the method <code>next</code> in a <code>while</code> loop to navigate each page602* from the first row to the last row.603* <P>604* The following code fragment assumes a continuation from the previous code fragment,605* meaning that the cursor for the tenth <code>CachedRowSet</code> object is on the606* last row. The code moves the cursor to after the last row so that the first607* call to the method <code>previous</code> will put the cursor back on the last row.608* After going through all of the rows in the last page (the <code>CachedRowSet</code>609* object <i>crs</i>), the code then enters610* the <code>while</code> loop to get to the ninth page, go through the rows backwards,611* go to the eighth page, go through the rows backwards, and so on to the first row612* of the first page.613*614* <PRE>615* crs.afterLast();616* while(crs.previous()) {617* . . . // navigate through the rows, last to first618* {619* while(crs.previousPage()) {620* crs.afterLast();621* while(crs.previous()) {622* . . . // go from the last row to the first row of each page623* }624* }625* </PRE>626*627* @author Jonathan Bruce628* @since 1.5629*/630631public interface CachedRowSet extends RowSet, Joinable {632633/**634* Populates this <code>CachedRowSet</code> object with data from635* the given <code>ResultSet</code> object.636* <P>637* This method can be used as an alternative to the <code>execute</code> method when an638* application has a connection to an open <code>ResultSet</code> object.639* Using the method <code>populate</code> can be more efficient than using640* the version of the <code>execute</code> method that takes no parameters641* because it does not open a new connection and re-execute this642* <code>CachedRowSet</code> object's command. Using the <code>populate</code>643* method is more a matter of convenience when compared to using the version644* of <code>execute</code> that takes a <code>ResultSet</code> object.645*646* @param data the <code>ResultSet</code> object containing the data647* to be read into this <code>CachedRowSet</code> object648* @throws SQLException if a null <code>ResultSet</code> object is supplied649* or this <code>CachedRowSet</code> object cannot650* retrieve the associated <code>ResultSetMetaData</code> object651* @see #execute652* @see java.sql.ResultSet653* @see java.sql.ResultSetMetaData654*/655public void populate(ResultSet data) throws SQLException;656657/**658* Populates this <code>CachedRowSet</code> object with data, using the659* given connection to produce the result set from which the data will be read.660* This method should close any database connections that it creates to661* ensure that this <code>CachedRowSet</code> object is disconnected except when662* it is reading data from its data source or writing data to its data source.663* <P>664* The reader for this <code>CachedRowSet</code> object665* will use <i>conn</i> to establish a connection to the data source666* so that it can execute the rowset's command and read data from the667* the resulting <code>ResultSet</code> object into this668* <code>CachedRowSet</code> object. This method also closes <i>conn</i>669* after it has populated this <code>CachedRowSet</code> object.670* <P>671* If this method is called when an implementation has already been672* populated, the contents and the metadata are (re)set. Also, if this method is673* called before the method <code>acceptChanges</code> has been called674* to commit outstanding updates, those updates are lost.675*676* @param conn a standard JDBC <code>Connection</code> object with valid677* properties678* @throws SQLException if an invalid <code>Connection</code> object is supplied679* or an error occurs in establishing the connection to the680* data source681* @see #populate682* @see java.sql.Connection683*/684public void execute(Connection conn) throws SQLException;685686/**687* Propagates row update, insert and delete changes made to this688* <code>CachedRowSet</code> object to the underlying data source.689* <P>690* This method calls on this <code>CachedRowSet</code> object's writer691* to do the work behind the scenes.692* Standard <code>CachedRowSet</code> implementations should use the693* <code>SyncFactory</code> singleton694* to obtain a <code>SyncProvider</code> instance providing a695* <code>RowSetWriter</code> object (writer). The writer will attempt696* to propagate changes made in this <code>CachedRowSet</code> object697* back to the data source.698* <P>699* When the method <code>acceptChanges</code> executes successfully, in700* addition to writing changes to the data source, it701* makes the values in the current row be the values in the original row.702* <P>703* Depending on the synchronization level of the <code>SyncProvider</code>704* implementation being used, the writer will compare the original values705* with those in the data source to check for conflicts. When there is a conflict,706* the <code>RIOptimisticProvider</code> implementation, for example, throws a707* <code>SyncProviderException</code> and does not write anything to the708* data source.709* <P>710* An application may choose to catch the <code>SyncProviderException</code>711* object and retrieve the <code>SyncResolver</code> object it contains.712* The <code>SyncResolver</code> object lists the conflicts row by row and713* sets a lock on the data source to avoid further conflicts while the714* current conflicts are being resolved.715* Further, for each conflict, it provides methods for examining the conflict716* and setting the value that should be persisted in the data source.717* After all conflicts have been resolved, an application must call the718* <code>acceptChanges</code> method again to write resolved values to the719* data source. If all of the values in the data source are already the720* values to be persisted, the method <code>acceptChanges</code> does nothing.721* <P>722* Some provider implementations may use locks to ensure that there are no723* conflicts. In such cases, it is guaranteed that the writer will succeed in724* writing changes to the data source when the method <code>acceptChanges</code>725* is called. This method may be called immediately after the methods726* <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code>727* have been called, but it is more efficient to call it only once after728* all changes have been made so that only one connection needs to be729* established.730* <P>731* Note: The <code>acceptChanges()</code> method will determine if the732* <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set733* to true, all updates in the synchronization are committed to the data734* source. Otherwise, the application <b>must</b> explicitly call the735* <code>commit()</code> or <code>rollback()</code> methods as appropriate.736*737* @throws SyncProviderException if the underlying738* synchronization provider's writer fails to write the updates739* back to the data source740* @see #acceptChanges(java.sql.Connection)741* @see javax.sql.RowSetWriter742* @see javax.sql.rowset.spi.SyncFactory743* @see javax.sql.rowset.spi.SyncProvider744* @see javax.sql.rowset.spi.SyncProviderException745* @see javax.sql.rowset.spi.SyncResolver746*/747public void acceptChanges() throws SyncProviderException;748749/**750* Propagates all row update, insert and delete changes to the751* data source backing this <code>CachedRowSet</code> object752* using the specified <code>Connection</code> object to establish a753* connection to the data source.754* <P>755* The other version of the <code>acceptChanges</code> method is not passed756* a connection because it uses757* the <code>Connection</code> object already defined within the <code>RowSet</code>758* object, which is the connection used for populating it initially.759* <P>760* This form of the method <code>acceptChanges</code> is similar to the761* form that takes no arguments; however, unlike the other form, this form762* can be used only when the underlying data source is a JDBC data source.763* The updated <code>Connection</code> properties must be used by the764* <code>SyncProvider</code> to reset the <code>RowSetWriter</code>765* configuration to ensure that the contents of the <code>CachedRowSet</code>766* object are synchronized correctly.767* <P>768* When the method <code>acceptChanges</code> executes successfully, in769* addition to writing changes to the data source, it770* makes the values in the current row be the values in the original row.771* <P>772* Depending on the synchronization level of the <code>SyncProvider</code>773* implementation being used, the writer will compare the original values774* with those in the data source to check for conflicts. When there is a conflict,775* the <code>RIOptimisticProvider</code> implementation, for example, throws a776* <code>SyncProviderException</code> and does not write anything to the777* data source.778* <P>779* An application may choose to catch the <code>SyncProviderException</code>780* object and retrieve the <code>SyncResolver</code> object it contains.781* The <code>SyncResolver</code> object lists the conflicts row by row and782* sets a lock on the data source to avoid further conflicts while the783* current conflicts are being resolved.784* Further, for each conflict, it provides methods for examining the conflict785* and setting the value that should be persisted in the data source.786* After all conflicts have been resolved, an application must call the787* <code>acceptChanges</code> method again to write resolved values to the788* data source. If all of the values in the data source are already the789* values to be persisted, the method <code>acceptChanges</code> does nothing.790* <P>791* Some provider implementations may use locks to ensure that there are no792* conflicts. In such cases, it is guaranteed that the writer will succeed in793* writing changes to the data source when the method <code>acceptChanges</code>794* is called. This method may be called immediately after the methods795* <code>updateRow</code>, <code>insertRow</code>, or <code>deleteRow</code>796* have been called, but it is more efficient to call it only once after797* all changes have been made so that only one connection needs to be798* established.799* <P>800* Note: The <code>acceptChanges()</code> method will determine if the801* <code>COMMIT_ON_ACCEPT_CHANGES</code> is set to true or not. If it is set802* to true, all updates in the synchronization are committed to the data803* source. Otherwise, the application <b>must</b> explicitly call the804* <code>commit</code> or <code>rollback</code> methods as appropriate.805*806* @param con a standard JDBC <code>Connection</code> object807* @throws SyncProviderException if the underlying808* synchronization provider's writer fails to write the updates809* back to the data source810* @see #acceptChanges()811* @see javax.sql.RowSetWriter812* @see javax.sql.rowset.spi.SyncFactory813* @see javax.sql.rowset.spi.SyncProvider814* @see javax.sql.rowset.spi.SyncProviderException815* @see javax.sql.rowset.spi.SyncResolver816*/817public void acceptChanges(Connection con) throws SyncProviderException;818819/**820* Restores this <code>CachedRowSet</code> object to its original821* value, that is, its value before the last set of changes. If there822* have been no changes to the rowset or only one set of changes,823* the original value is the value with which this <code>CachedRowSet</code> object824* was populated; otherwise, the original value is825* the value it had immediately before its current value.826* <P>827* When this method is called, a <code>CachedRowSet</code> implementation828* must ensure that all updates, inserts, and deletes to the current829* rowset instance are replaced by the previous values. In addition,830* the cursor should be831* reset to the first row and a <code>rowSetChanged</code> event832* should be fired to notify all registered listeners.833*834* @throws SQLException if an error occurs rolling back the current value of835* this <code>CachedRowSet</code> object to its previous value836* @see javax.sql.RowSetListener#rowSetChanged837*/838public void restoreOriginal() throws SQLException;839840/**841* Releases the current contents of this <code>CachedRowSet</code>842* object and sends a <code>rowSetChanged</code> event to all843* registered listeners. Any outstanding updates are discarded and844* the rowset contains no rows after this method is called. There845* are no interactions with the underlying data source, and any rowset846* content, metadata, and content updates should be non-recoverable.847* <P>848* This <code>CachedRowSet</code> object should lock until its contents and849* associated updates are fully cleared, thus preventing 'dirty' reads by850* other components that hold a reference to this <code>RowSet</code> object.851* In addition, the contents cannot be released852* until all components reading this <code>CachedRowSet</code> object853* have completed their reads. This <code>CachedRowSet</code> object854* should be returned to normal behavior after firing the855* <code>rowSetChanged</code> event.856* <P>857* The metadata, including JDBC properties and Synchronization SPI858* properties, are maintained for future use. It is important that859* properties such as the <code>command</code> property be860* relevant to the originating data source from which this <code>CachedRowSet</code>861* object was originally established.862* <P>863* This method empties a rowset, as opposed to the <code>close</code> method,864* which marks the entire rowset as recoverable to allow the garbage collector865* the rowset's Java VM resources.866*867* @throws SQLException if an error occurs flushing the contents of this868* <code>CachedRowSet</code> object869* @see javax.sql.RowSetListener#rowSetChanged870* @see java.sql.ResultSet#close871*/872public void release() throws SQLException;873874/**875* Cancels the deletion of the current row and notifies listeners that876* a row has changed. After this method is called, the current row is877* no longer marked for deletion. This method can be called at any878* time during the lifetime of the rowset.879* <P>880* In addition, multiple cancellations of row deletions can be made881* by adjusting the position of the cursor using any of the cursor882* position control methods such as:883* <ul>884* <li><code>CachedRowSet.absolute</code>885* <li><code>CachedRowSet.first</code>886* <li><code>CachedRowSet.last</code>887* </ul>888*889* @throws SQLException if (1) the current row has not been deleted or890* (2) the cursor is on the insert row, before the first row, or891* after the last row892* @see javax.sql.rowset.CachedRowSet#undoInsert893* @see java.sql.ResultSet#cancelRowUpdates894*/895public void undoDelete() throws SQLException;896897/**898* Immediately removes the current row from this <code>CachedRowSet</code>899* object if the row has been inserted, and also notifies listeners that a900* row has changed. This method can be called at any time during the901* lifetime of a rowset and assuming the current row is within902* the exception limitations (see below), it cancels the row insertion903* of the current row.904* <P>905* In addition, multiple cancellations of row insertions can be made906* by adjusting the position of the cursor using any of the cursor907* position control methods such as:908* <ul>909* <li><code>CachedRowSet.absolute</code>910* <li><code>CachedRowSet.first</code>911* <li><code>CachedRowSet.last</code>912* </ul>913*914* @throws SQLException if (1) the current row has not been inserted or (2)915* the cursor is before the first row, after the last row, or on the916* insert row917* @see javax.sql.rowset.CachedRowSet#undoDelete918* @see java.sql.ResultSet#cancelRowUpdates919*/920public void undoInsert() throws SQLException;921922923/**924* Immediately reverses the last update operation if the925* row has been modified. This method can be926* called to reverse updates on all columns until all updates in a row have927* been rolled back to their state just prior to the last synchronization928* (<code>acceptChanges</code>) or population. This method may also be called929* while performing updates to the insert row.930* <P>931* <code>undoUpdate</code> may be called at any time during the lifetime of a932* rowset; however, after a synchronization has occurred, this method has no933* effect until further modification to the rowset data has occurred.934*935* @throws SQLException if the cursor is before the first row or after the last936* row in this <code>CachedRowSet</code> object937* @see #undoDelete938* @see #undoInsert939* @see java.sql.ResultSet#cancelRowUpdates940*/941public void undoUpdate() throws SQLException;942943/**944* Indicates whether the designated column in the current row of this945* <code>CachedRowSet</code> object has been updated.946*947* @param idx an <code>int</code> identifying the column to be checked for updates948* @return <code>true</code> if the designated column has been visibly updated;949* <code>false</code> otherwise950* @throws SQLException if the cursor is on the insert row, before the first row,951* or after the last row952* @see java.sql.DatabaseMetaData#updatesAreDetected953*/954public boolean columnUpdated(int idx) throws SQLException;955956957/**958* Indicates whether the designated column in the current row of this959* <code>CachedRowSet</code> object has been updated.960*961* @param columnName a <code>String</code> object giving the name of the962* column to be checked for updates963* @return <code>true</code> if the column has been visibly updated;964* <code>false</code> otherwise965* @throws SQLException if the cursor is on the insert row, before the first row,966* or after the last row967* @see java.sql.DatabaseMetaData#updatesAreDetected968*/969public boolean columnUpdated(String columnName) throws SQLException;970971/**972* Converts this <code>CachedRowSet</code> object to a <code>Collection</code>973* object that contains all of this <code>CachedRowSet</code> object's data.974* Implementations have some latitude in975* how they can represent this <code>Collection</code> object because of the976* abstract nature of the <code>Collection</code> framework.977* Each row must be fully represented in either a978* general purpose <code>Collection</code> implementation or a specialized979* <code>Collection</code> implementation, such as a <code>TreeMap</code>980* object or a <code>Vector</code> object.981* An SQL <code>NULL</code> column value must be represented as a <code>null</code>982* in the Java programming language.983* <P>984* The standard reference implementation for the <code>CachedRowSet</code>985* interface uses a <code>TreeMap</code> object for the rowset, with the986* values in each row being contained in <code>Vector</code> objects. It is987* expected that most implementations will do the same.988* <P>989* The <code>TreeMap</code> type of collection guarantees that the map will be in990* ascending key order, sorted according to the natural order for the991* key's class.992* Each key references a <code>Vector</code> object that corresponds to one993* row of a <code>RowSet</code> object. Therefore, the size of each994* <code>Vector</code> object must be exactly equal to the number of995* columns in the <code>RowSet</code> object.996* The key used by the <code>TreeMap</code> collection is determined by the997* implementation, which may choose to leverage a set key that is998* available within the internal <code>RowSet</code> tabular structure by999* virtue of a key already set either on the <code>RowSet</code> object1000* itself or on the underlying SQL data.1001*1002* @return a <code>Collection</code> object that contains the values in1003* each row in this <code>CachedRowSet</code> object1004* @throws SQLException if an error occurs generating the collection1005* @see #toCollection(int)1006* @see #toCollection(String)1007*/1008public Collection<?> toCollection() throws SQLException;10091010/**1011* Converts the designated column in this <code>CachedRowSet</code> object1012* to a <code>Collection</code> object. Implementations have some latitude in1013* how they can represent this <code>Collection</code> object because of the1014* abstract nature of the <code>Collection</code> framework.1015* Each column value should be fully represented in either a1016* general purpose <code>Collection</code> implementation or a specialized1017* <code>Collection</code> implementation, such as a <code>Vector</code> object.1018* An SQL <code>NULL</code> column value must be represented as a <code>null</code>1019* in the Java programming language.1020* <P>1021* The standard reference implementation uses a <code>Vector</code> object1022* to contain the column values, and it is expected1023* that most implementations will do the same. If a <code>Vector</code> object1024* is used, it size must be exactly equal to the number of rows1025* in this <code>CachedRowSet</code> object.1026*1027* @param column an <code>int</code> indicating the column whose values1028* are to be represented in a <code>Collection</code> object1029* @return a <code>Collection</code> object that contains the values1030* stored in the specified column of this <code>CachedRowSet</code>1031* object1032* @throws SQLException if an error occurs generating the collection or1033* an invalid column id is provided1034* @see #toCollection1035* @see #toCollection(String)1036*/1037public Collection<?> toCollection(int column) throws SQLException;10381039/**1040* Converts the designated column in this <code>CachedRowSet</code> object1041* to a <code>Collection</code> object. Implementations have some latitude in1042* how they can represent this <code>Collection</code> object because of the1043* abstract nature of the <code>Collection</code> framework.1044* Each column value should be fully represented in either a1045* general purpose <code>Collection</code> implementation or a specialized1046* <code>Collection</code> implementation, such as a <code>Vector</code> object.1047* An SQL <code>NULL</code> column value must be represented as a <code>null</code>1048* in the Java programming language.1049* <P>1050* The standard reference implementation uses a <code>Vector</code> object1051* to contain the column values, and it is expected1052* that most implementations will do the same. If a <code>Vector</code> object1053* is used, it size must be exactly equal to the number of rows1054* in this <code>CachedRowSet</code> object.1055*1056* @param column a <code>String</code> object giving the name of the1057* column whose values are to be represented in a collection1058* @return a <code>Collection</code> object that contains the values1059* stored in the specified column of this <code>CachedRowSet</code>1060* object1061* @throws SQLException if an error occurs generating the collection or1062* an invalid column id is provided1063* @see #toCollection1064* @see #toCollection(int)1065*/1066public Collection<?> toCollection(String column) throws SQLException;10671068/**1069* Retrieves the <code>SyncProvider</code> implementation for this1070* <code>CachedRowSet</code> object. Internally, this method is used by a rowset1071* to trigger read or write actions between the rowset1072* and the data source. For example, a rowset may need to get a handle1073* on the rowset reader (<code>RowSetReader</code> object) from the1074* <code>SyncProvider</code> to allow the rowset to be populated.1075* <pre>1076* RowSetReader rowsetReader = null;1077* SyncProvider provider =1078* SyncFactory.getInstance("javax.sql.rowset.provider.RIOptimisticProvider");1079* if (provider instanceof RIOptimisticProvider) {1080* rowsetReader = provider.getRowSetReader();1081* }1082* </pre>1083* Assuming <i>rowsetReader</i> is a private, accessible field within1084* the rowset implementation, when an application calls the <code>execute</code>1085* method, it in turn calls on the reader's <code>readData</code> method1086* to populate the <code>RowSet</code> object.1087*<pre>1088* rowsetReader.readData((RowSetInternal)this);1089* </pre>1090* <P>1091* In addition, an application can use the <code>SyncProvider</code> object1092* returned by this method to call methods that return information about the1093* <code>SyncProvider</code> object, including information about the1094* vendor, version, provider identification, synchronization grade, and locks1095* it currently has set.1096*1097* @return the <code>SyncProvider</code> object that was set when the rowset1098* was instantiated, or if none was set, the default provider1099* @throws SQLException if an error occurs while returning the1100* <code>SyncProvider</code> object1101* @see #setSyncProvider1102*/1103public SyncProvider getSyncProvider() throws SQLException;11041105/**1106* Sets the <code>SyncProvider</code> object for this <code>CachedRowSet</code>1107* object to the one specified. This method1108* allows the <code>SyncProvider</code> object to be reset.1109* <P>1110* A <code>CachedRowSet</code> implementation should always be instantiated1111* with an available <code>SyncProvider</code> mechanism, but there are1112* cases where resetting the <code>SyncProvider</code> object is desirable1113* or necessary. For example, an application might want to use the default1114* <code>SyncProvider</code> object for a time and then choose to use a provider1115* that has more recently become available and better fits its needs.1116* <P>1117* Resetting the <code>SyncProvider</code> object causes the1118* <code>RowSet</code> object to request a new <code>SyncProvider</code> implementation1119* from the <code>SyncFactory</code>. This has the effect of resetting1120* all previous connections and relationships with the originating1121* data source and can potentially drastically change the synchronization1122* behavior of a disconnected rowset.1123*1124* @param provider a <code>String</code> object giving the fully qualified class1125* name of a <code>SyncProvider</code> implementation1126* @throws SQLException if an error occurs while attempting to reset the1127* <code>SyncProvider</code> implementation1128* @see #getSyncProvider1129*/1130public void setSyncProvider(String provider) throws SQLException;11311132/**1133* Returns the number of rows in this <code>CachedRowSet</code>1134* object.1135*1136* @return number of rows in the rowset1137*/1138public int size();11391140/**1141* Sets the metadata for this <code>CachedRowSet</code> object with1142* the given <code>RowSetMetaData</code> object. When a1143* <code>RowSetReader</code> object is reading the contents of a rowset,1144* it creates a <code>RowSetMetaData</code> object and initializes1145* it using the methods in the <code>RowSetMetaData</code> implementation.1146* The reference implementation uses the <code>RowSetMetaDataImpl</code>1147* class. When the reader has completed reading the rowset contents,1148* this method is called internally to pass the <code>RowSetMetaData</code>1149* object to the rowset.1150*1151* @param md a <code>RowSetMetaData</code> object containing1152* metadata about the columns in this <code>CachedRowSet</code> object1153* @throws SQLException if invalid metadata is supplied to the1154* rowset1155*/1156public void setMetaData(RowSetMetaData md) throws SQLException;11571158/**1159* Returns a <code>ResultSet</code> object containing the original value of this1160* <code>CachedRowSet</code> object.1161* <P>1162* The cursor for the <code>ResultSet</code>1163* object should be positioned before the first row.1164* In addition, the returned <code>ResultSet</code> object should have the following1165* properties:1166* <UL>1167* <LI>ResultSet.TYPE_SCROLL_INSENSITIVE1168* <LI>ResultSet.CONCUR_UPDATABLE1169* </UL>1170* <P>1171* The original value for a <code>RowSet</code> object is the value it had before1172* the last synchronization with the underlying data source. If there have been1173* no synchronizations, the original value will be the value with which the1174* <code>RowSet</code> object was populated. This method is called internally1175* when an application calls the method <code>acceptChanges</code> and the1176* <code>SyncProvider</code> object has been implemented to check for conflicts.1177* If this is the case, the writer compares the original value with the value1178* currently in the data source to check for conflicts.1179*1180* @return a <code>ResultSet</code> object that contains the original value for1181* this <code>CachedRowSet</code> object1182* @throws SQLException if an error occurs producing the1183* <code>ResultSet</code> object1184*/1185public ResultSet getOriginal() throws SQLException;11861187/**1188* Returns a <code>ResultSet</code> object containing the original value for the1189* current row only of this <code>CachedRowSet</code> object.1190* <P>1191* The cursor for the <code>ResultSet</code>1192* object should be positioned before the first row.1193* In addition, the returned <code>ResultSet</code> object should have the following1194* properties:1195* <UL>1196* <LI>ResultSet.TYPE_SCROLL_INSENSITIVE1197* <LI>ResultSet.CONCUR_UPDATABLE1198* </UL>1199*1200* @return the original result set of the row1201* @throws SQLException if there is no current row1202* @see #setOriginalRow1203*/1204public ResultSet getOriginalRow() throws SQLException;12051206/**1207* Sets the current row in this <code>CachedRowSet</code> object as the original1208* row.1209* <P>1210* This method is called internally after the any modified values in the current1211* row have been synchronized with the data source. The current row must be tagged1212* as no longer inserted, deleted or updated.1213* <P>1214* A call to <code>setOriginalRow</code> is irreversible.1215*1216* @throws SQLException if there is no current row or an error is1217* encountered resetting the contents of the original row1218* @see #getOriginalRow1219*/1220public void setOriginalRow() throws SQLException;12211222/**1223* Returns an identifier for the object (table) that was used to1224* create this <code>CachedRowSet</code> object. This name may be set on multiple occasions,1225* and the specification imposes no limits on how many times this1226* may occur or whether standard implementations should keep track1227* of previous table names.1228*1229* @return a <code>String</code> object giving the name of the table that is the1230* source of data for this <code>CachedRowSet</code> object or <code>null</code>1231* if no name has been set for the table1232* @throws SQLException if an error is encountered returning the table name1233* @see javax.sql.RowSetMetaData#getTableName1234*/1235public String getTableName() throws SQLException;12361237/**1238* Sets the identifier for the table from which this <code>CachedRowSet</code>1239* object was derived to the given table name. The writer uses this name to1240* determine which table to use when comparing the values in the data source with the1241* <code>CachedRowSet</code> object's values during a synchronization attempt.1242* The table identifier also indicates where modified values from this1243* <code>CachedRowSet</code> object should be written.1244* <P>1245* The implementation of this <code>CachedRowSet</code> object may obtain the1246* the name internally from the <code>RowSetMetaDataImpl</code> object.1247*1248* @param tabName a <code>String</code> object identifying the table from which this1249<code>CachedRowSet</code> object was derived; cannot be <code>null</code>1250* but may be an empty string1251* @throws SQLException if an error is encountered naming the table or1252* <i>tabName</i> is <code>null</code>1253* @see javax.sql.RowSetMetaData#setTableName1254* @see javax.sql.RowSetWriter1255* @see javax.sql.rowset.spi.SyncProvider1256*/1257public void setTableName(String tabName) throws SQLException;12581259/**1260* Returns an array containing one or more column numbers indicating the columns1261* that form a key that uniquely1262* identifies a row in this <code>CachedRowSet</code> object.1263*1264* @return an array containing the column number or numbers that indicate which columns1265* constitute a primary key1266* for a row in this <code>CachedRowSet</code> object. This array should be1267* empty if no columns are representative of a primary key.1268* @throws SQLException if this <code>CachedRowSet</code> object is empty1269* @see #setKeyColumns1270* @see Joinable#getMatchColumnIndexes1271* @see Joinable#getMatchColumnNames1272*/1273public int[] getKeyColumns() throws SQLException;12741275/**1276* Sets this <code>CachedRowSet</code> object's <code>keyCols</code>1277* field with the given array of column numbers, which forms a key1278* for uniquely identifying a row in this <code>CachedRowSet</code> object.1279* <p>1280* If a <code>CachedRowSet</code> object becomes part of a <code>JoinRowSet</code>1281* object, the keys defined by this method and the resulting constraints are1282* maintained if the columns designated as key columns also become match1283* columns.1284*1285* @param keys an array of <code>int</code> indicating the columns that form1286* a primary key for this <code>CachedRowSet</code> object; every1287* element in the array must be greater than <code>0</code> and1288* less than or equal to the number of columns in this rowset1289* @throws SQLException if any of the numbers in the given array1290* are not valid for this rowset1291* @see #getKeyColumns1292* @see Joinable#setMatchColumn(String)1293* @see Joinable#setMatchColumn(int)12941295*/1296public void setKeyColumns(int[] keys) throws SQLException;129712981299/**1300* Returns a new <code>RowSet</code> object backed by the same data as1301* that of this <code>CachedRowSet</code> object. In effect, both1302* <code>CachedRowSet</code> objects have a cursor over the same data.1303* As a result, any changes made by a duplicate are visible to the original1304* and to any other duplicates, just as a change made by the original is visible1305* to all of its duplicates. If a duplicate calls a method that changes the1306* underlying data, the method it calls notifies all registered listeners1307* just as it would when it is called by the original <code>CachedRowSet</code>1308* object.1309* <P>1310* In addition, any <code>RowSet</code> object1311* created by this method will have the same properties as this1312* <code>CachedRowSet</code> object. For example, if this <code>CachedRowSet</code>1313* object is read-only, all of its duplicates will also be read-only. If it is1314* changed to be updatable, the duplicates also become updatable.1315* <P>1316* NOTE: If multiple threads access <code>RowSet</code> objects created from1317* the <code>createShared()</code> method, the following behavior is specified1318* to preserve shared data integrity: reads and writes of all1319* shared <code>RowSet</code> objects should be made serially between each1320* object and the single underlying tabular structure.1321*1322* @return a new shared <code>RowSet</code> object that has the same properties1323* as this <code>CachedRowSet</code> object and that has a cursor over1324* the same data1325* @throws SQLException if an error occurs or cloning is not1326* supported in the underlying platform1327* @see javax.sql.RowSetEvent1328* @see javax.sql.RowSetListener1329*/1330public RowSet createShared() throws SQLException;13311332/**1333* Creates a <code>RowSet</code> object that is a deep copy of the data in1334* this <code>CachedRowSet</code> object. In contrast to1335* the <code>RowSet</code> object generated from a <code>createShared</code>1336* call, updates made to the copy of the original <code>RowSet</code> object1337* must not be visible to the original <code>RowSet</code> object. Also, any1338* event listeners that are registered with the original1339* <code>RowSet</code> must not have scope over the new1340* <code>RowSet</code> copies. In addition, any constraint restrictions1341* established must be maintained.1342*1343* @return a new <code>RowSet</code> object that is a deep copy1344* of this <code>CachedRowSet</code> object and is1345* completely independent of this <code>CachedRowSet</code> object1346* @throws SQLException if an error occurs in generating the copy of1347* the of this <code>CachedRowSet</code> object1348* @see #createShared1349* @see #createCopySchema1350* @see #createCopyNoConstraints1351* @see javax.sql.RowSetEvent1352* @see javax.sql.RowSetListener1353*/1354public CachedRowSet createCopy() throws SQLException;13551356/**1357* Creates a <code>CachedRowSet</code> object that is an empty copy of this1358* <code>CachedRowSet</code> object. The copy1359* must not contain any contents but only represent the table1360* structure of the original <code>CachedRowSet</code> object. In addition, primary1361* or foreign key constraints set in the originating <code>CachedRowSet</code> object must1362* be equally enforced in the new empty <code>CachedRowSet</code> object.1363* In contrast to1364* the <code>RowSet</code> object generated from a <code>createShared</code> method1365* call, updates made to a copy of this <code>CachedRowSet</code> object with the1366* <code>createCopySchema</code> method must not be visible to it.1367* <P>1368* Applications can form a <code>WebRowSet</code> object from the <code>CachedRowSet</code>1369* object returned by this method in order1370* to export the <code>RowSet</code> schema definition to XML for future use.1371* @return An empty copy of this {@code CachedRowSet} object1372* @throws SQLException if an error occurs in cloning the structure of this1373* <code>CachedRowSet</code> object1374* @see #createShared1375* @see #createCopySchema1376* @see #createCopyNoConstraints1377* @see javax.sql.RowSetEvent1378* @see javax.sql.RowSetListener1379*/1380public CachedRowSet createCopySchema() throws SQLException;13811382/**1383* Creates a <code>CachedRowSet</code> object that is a deep copy of1384* this <code>CachedRowSet</code> object's data but is independent of it.1385* In contrast to1386* the <code>RowSet</code> object generated from a <code>createShared</code>1387* method call, updates made to a copy of this <code>CachedRowSet</code> object1388* must not be visible to it. Also, any1389* event listeners that are registered with this1390* <code>CachedRowSet</code> object must not have scope over the new1391* <code>RowSet</code> object. In addition, any constraint restrictions1392* established for this <code>CachedRowSet</code> object must <b>not</b> be maintained1393* in the copy.1394*1395* @return a new <code>CachedRowSet</code> object that is a deep copy1396* of this <code>CachedRowSet</code> object and is1397* completely independent of this <code>CachedRowSet</code> object1398* @throws SQLException if an error occurs in generating the copy of1399* the of this <code>CachedRowSet</code> object1400* @see #createCopy1401* @see #createShared1402* @see #createCopySchema1403* @see javax.sql.RowSetEvent1404* @see javax.sql.RowSetListener1405*/1406public CachedRowSet createCopyNoConstraints() throws SQLException;14071408/**1409* Retrieves the first warning reported by calls on this <code>RowSet</code> object.1410* Subsequent warnings on this <code>RowSet</code> object will be chained to the1411* <code>RowSetWarning</code> object that this method returns.1412*1413* The warning chain is automatically cleared each time a new row is read.1414* This method may not be called on a RowSet object that has been closed;1415* doing so will cause a <code>SQLException</code> to be thrown.1416*1417* @return RowSetWarning the first <code>RowSetWarning</code>1418* object reported or null if there are none1419* @throws SQLException if this method is called on a closed RowSet1420* @see RowSetWarning1421*/1422public RowSetWarning getRowSetWarnings() throws SQLException;14231424/**1425* Retrieves a <code>boolean</code> indicating whether rows marked1426* for deletion appear in the set of current rows. If <code>true</code> is1427* returned, deleted rows are visible with the current rows. If1428* <code>false</code> is returned, rows are not visible with the set of1429* current rows. The default value is <code>false</code>.1430* <P>1431* Standard rowset implementations may choose to restrict this behavior1432* due to security considerations or to better fit certain deployment1433* scenarios. This is left as implementation defined and does not1434* represent standard behavior.1435* <P>1436* Note: Allowing deleted rows to remain visible complicates the behavior1437* of some standard JDBC <code>RowSet</code> Implementations methods.1438* However, most rowset users can simply ignore this extra detail because1439* only very specialized applications will likely want to take advantage of1440* this feature.1441*1442* @return <code>true</code> if deleted rows are visible;1443* <code>false</code> otherwise1444* @throws SQLException if a rowset implementation is unable to1445* to determine whether rows marked for deletion are visible1446* @see #setShowDeleted1447*/1448public boolean getShowDeleted() throws SQLException;14491450/**1451* Sets the property <code>showDeleted</code> to the given1452* <code>boolean</code> value, which determines whether1453* rows marked for deletion appear in the set of current rows.1454* If the value is set to <code>true</code>, deleted rows are immediately1455* visible with the set of current rows. If the value is set to1456* <code>false</code>, the deleted rows are set as invisible with the1457* current set of rows.1458* <P>1459* Standard rowset implementations may choose to restrict this behavior1460* due to security considerations or to better fit certain deployment1461* scenarios. This is left as implementations defined and does not1462* represent standard behavior.1463*1464* @param b <code>true</code> if deleted rows should be shown;1465* <code>false</code> otherwise1466* @exception SQLException if a rowset implementation is unable to1467* to reset whether deleted rows should be visible1468* @see #getShowDeleted1469*/1470public void setShowDeleted(boolean b) throws SQLException;14711472/**1473* Each <code>CachedRowSet</code> object's <code>SyncProvider</code> contains1474* a <code>Connection</code> object from the <code>ResultSet</code> or JDBC1475* properties passed to it's constructors. This method wraps the1476* <code>Connection</code> commit method to allow flexible1477* auto commit or non auto commit transactional control support.1478* <p>1479* Makes all changes that are performed by the <code>acceptChanges()</code>1480* method since the previous commit/rollback permanent. This method should1481* be used only when auto-commit mode has been disabled.1482*1483* @throws SQLException if a database access error occurs or this1484* Connection object within this <code>CachedRowSet</code> is in auto-commit mode1485* @see java.sql.Connection#setAutoCommit1486*/1487public void commit() throws SQLException;14881489/**1490* Each <code>CachedRowSet</code> object's <code>SyncProvider</code> contains1491* a <code>Connection</code> object from the original <code>ResultSet</code>1492* or JDBC properties passed to it.1493* <p>1494* Undoes all changes made in the current transaction. This method1495* should be used only when auto-commit mode has been disabled.1496*1497* @throws SQLException if a database access error occurs or this Connection1498* object within this <code>CachedRowSet</code> is in auto-commit mode.1499*/1500public void rollback() throws SQLException;15011502/**1503* Each <code>CachedRowSet</code> object's <code>SyncProvider</code> contains1504* a <code>Connection</code> object from the original <code>ResultSet</code>1505* or JDBC properties passed to it.1506* <p>1507* Undoes all changes made in the current transaction back to the last1508* <code>Savepoint</code> transaction marker. This method should be used only1509* when auto-commit mode has been disabled.1510*1511* @param s A <code>Savepoint</code> transaction marker1512* @throws SQLException if a database access error occurs or this Connection1513* object within this <code>CachedRowSet</code> is in auto-commit mode.1514*/1515public void rollback(Savepoint s) throws SQLException;15161517/**1518* Causes the <code>CachedRowSet</code> object's <code>SyncProvider</code>1519* to commit the changes when <code>acceptChanges()</code> is called. If1520* set to false, the changes will <b>not</b> be committed until one of the1521* <code>CachedRowSet</code> interface transaction methods is called.1522*1523* @deprecated Because this field is final (it is part of an interface),1524* its value cannot be changed.1525* @see #commit1526* @see #rollback1527*/1528@Deprecated1529public static final boolean COMMIT_ON_ACCEPT_CHANGES = true;15301531/**1532* Notifies registered listeners that a RowSet object in the given RowSetEvent1533* object has populated a number of additional rows. The <code>numRows</code> parameter1534* ensures that this event will only be fired every <code>numRow</code>.1535* <p>1536* The source of the event can be retrieved with the method event.getSource.1537*1538* @param event a <code>RowSetEvent</code> object that contains the1539* <code>RowSet</code> object that is the source of the events1540* @param numRows when populating, the number of rows interval on which the1541* <code>CachedRowSet</code> populated should fire; the default value1542* is zero; cannot be less than <code>fetchSize</code> or zero1543* @throws SQLException {@code numRows < 0 or numRows < getFetchSize() }1544*/1545public void rowSetPopulated(RowSetEvent event, int numRows) throws SQLException;15461547/**1548* Populates this <code>CachedRowSet</code> object with data from1549* the given <code>ResultSet</code> object. While related to the <code>populate(ResultSet)</code>1550* method, an additional parameter is provided to allow starting position within1551* the <code>ResultSet</code> from where to populate the CachedRowSet1552* instance.1553* <P>1554* This method can be used as an alternative to the <code>execute</code> method when an1555* application has a connection to an open <code>ResultSet</code> object.1556* Using the method <code>populate</code> can be more efficient than using1557* the version of the <code>execute</code> method that takes no parameters1558* because it does not open a new connection and re-execute this1559* <code>CachedRowSet</code> object's command. Using the <code>populate</code>1560* method is more a matter of convenience when compared to using the version1561* of <code>execute</code> that takes a <code>ResultSet</code> object.1562*1563* @param startRow the position in the <code>ResultSet</code> from where to start1564* populating the records in this <code>CachedRowSet</code>1565* @param rs the <code>ResultSet</code> object containing the data1566* to be read into this <code>CachedRowSet</code> object1567* @throws SQLException if a null <code>ResultSet</code> object is supplied1568* or this <code>CachedRowSet</code> object cannot1569* retrieve the associated <code>ResultSetMetaData</code> object1570* @see #execute1571* @see #populate(ResultSet)1572* @see java.sql.ResultSet1573* @see java.sql.ResultSetMetaData1574*/1575public void populate(ResultSet rs, int startRow) throws SQLException;15761577/**1578* Sets the <code>CachedRowSet</code> object's page-size. A <code>CachedRowSet</code>1579* may be configured to populate itself in page-size sized batches of rows. When1580* either <code>populate()</code> or <code>execute()</code> are called, the1581* <code>CachedRowSet</code> fetches an additional page according to the1582* original SQL query used to populate the RowSet.1583*1584* @param size the page-size of the <code>CachedRowSet</code>1585* @throws SQLException if an error occurs setting the <code>CachedRowSet</code>1586* page size or if the page size is less than 0.1587*/1588public void setPageSize(int size) throws SQLException;15891590/**1591* Returns the page-size for the <code>CachedRowSet</code> object1592*1593* @return an <code>int</code> page size1594*/1595public int getPageSize();15961597/**1598* Increments the current page of the <code>CachedRowSet</code>. This causes1599* the <code>CachedRowSet</code> implementation to fetch the next page-size1600* rows and populate the RowSet, if remaining rows remain within scope of the1601* original SQL query used to populated the RowSet.1602*1603* @return true if more pages exist; false if this is the last page1604* @throws SQLException if an error occurs fetching the next page, or if this1605* method is called prematurely before populate or execute.1606*/1607public boolean nextPage() throws SQLException;16081609/**1610* Decrements the current page of the <code>CachedRowSet</code>. This causes1611* the <code>CachedRowSet</code> implementation to fetch the previous page-size1612* rows and populate the RowSet. The amount of rows returned in the previous1613* page must always remain within scope of the original SQL query used to1614* populate the RowSet.1615*1616* @return true if the previous page is successfully retrieved; false if this1617* is the first page.1618* @throws SQLException if an error occurs fetching the previous page, or if1619* this method is called prematurely before populate or execute.1620*/1621public boolean previousPage() throws SQLException;16221623}162416251626