< prev index next >

src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java

Print this page

        

*** 41,184 **** import javax.sql.rowset.serial.SerialStruct; import javax.sql.rowset.spi.*; /** ! * The facility called on internally by the <code>RIOptimisticProvider</code> implementation to * propagate changes back to the data source from which the rowset got its data. * <P> ! * A <code>CachedRowSetWriter</code> object, called a writer, has the public ! * method <code>writeData</code> for writing modified data to the underlying data source. * This method is invoked by the rowset internally and is never invoked directly by an application. * A writer also has public methods for setting and getting ! * the <code>CachedRowSetReader</code> object, called a reader, that is associated * with the writer. The remainder of the methods in this class are private and * are invoked internally, either directly or indirectly, by the method ! * <code>writeData</code>. * <P> ! * Typically the <code>SyncFactory</code> manages the <code>RowSetReader</code> and ! * the <code>RowSetWriter</code> implementations using <code>SyncProvider</code> objects. * Standard JDBC RowSet implementations provide an object instance of this ! * writer by invoking the <code>SyncProvider.getRowSetWriter()</code> method. * * @version 0.2 * @author Jonathan Bruce * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncFactoryException */ public class CachedRowSetWriter implements TransactionalWriter, Serializable { /** ! * The <code>Connection</code> object that this writer will use to make a * connection to the data source to which it will write data. * */ private transient Connection con; /** ! * The SQL <code>SELECT</code> command that this writer will call ! * internally. The method <code>initSQLStatements</code> builds this * command by supplying the words "SELECT" and "FROM," and using * metadata to get the table name and column names . * * @serial */ private String selectCmd; /** ! * The SQL <code>UPDATE</code> command that this writer will call * internally to write data to the rowset's underlying data source. ! * The method <code>initSQLStatements</code> builds this <code>String</code> * object. * * @serial */ private String updateCmd; /** ! * The SQL <code>WHERE</code> clause the writer will use for update ! * statements in the <code>PreparedStatement</code> object * it sends to the underlying data source. * * @serial */ private String updateWhere; /** ! * The SQL <code>DELETE</code> command that this writer will call * internally to delete a row in the rowset's underlying data source. * * @serial */ private String deleteCmd; /** ! * The SQL <code>WHERE</code> clause the writer will use for delete ! * statements in the <code>PreparedStatement</code> object * it sends to the underlying data source. * * @serial */ private String deleteWhere; /** ! * The SQL <code>INSERT INTO</code> command that this writer will internally use * to insert data into the rowset's underlying data source. The method ! * <code>initSQLStatements</code> builds this command with a question * mark parameter placeholder for each column in the rowset. * * @serial */ private String insertCmd; /** * An array containing the column numbers of the columns that are ! * needed to uniquely identify a row in the <code>CachedRowSet</code> object ! * for which this <code>CachedRowSetWriter</code> object is the writer. * * @serial */ private int[] keyCols; /** * An array of the parameters that should be used to set the parameter ! * placeholders in a <code>PreparedStatement</code> object that this * writer will execute. * * @serial */ private Object[] params; /** ! * The <code>CachedRowSetReader</code> object that has been ! * set as the reader for the <code>CachedRowSet</code> object ! * for which this <code>CachedRowSetWriter</code> object is the writer. * * @serial */ private CachedRowSetReader reader; /** ! * The <code>ResultSetMetaData</code> object that contains information ! * about the columns in the <code>CachedRowSet</code> object ! * for which this <code>CachedRowSetWriter</code> object is the writer. * * @serial */ private ResultSetMetaData callerMd; /** ! * The number of columns in the <code>CachedRowSet</code> object ! * for which this <code>CachedRowSetWriter</code> object is the writer. * * @serial */ private int callerColumnCount; /** ! * This <code>CachedRowSet<code> will hold the conflicting values * retrieved from the db and hold it. */ private CachedRowSetImpl crsResolve; /** --- 41,184 ---- import javax.sql.rowset.serial.SerialStruct; import javax.sql.rowset.spi.*; /** ! * The facility called on internally by the {@code RIOptimisticProvider} implementation to * propagate changes back to the data source from which the rowset got its data. * <P> ! * A {@code CachedRowSetWriter} object, called a writer, has the public ! * method {@code writeData} for writing modified data to the underlying data source. * This method is invoked by the rowset internally and is never invoked directly by an application. * A writer also has public methods for setting and getting ! * the {@code CachedRowSetReader} object, called a reader, that is associated * with the writer. The remainder of the methods in this class are private and * are invoked internally, either directly or indirectly, by the method ! * {@code writeData}. * <P> ! * Typically the {@code SyncFactory} manages the {@code RowSetReader} and ! * the {@code RowSetWriter} implementations using {@code SyncProvider} objects. * Standard JDBC RowSet implementations provide an object instance of this ! * writer by invoking the {@code SyncProvider.getRowSetWriter()} method. * * @version 0.2 * @author Jonathan Bruce * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncFactory * @see javax.sql.rowset.spi.SyncFactoryException */ public class CachedRowSetWriter implements TransactionalWriter, Serializable { /** ! * The {@code Connection} object that this writer will use to make a * connection to the data source to which it will write data. * */ private transient Connection con; /** ! * The SQL {@code SELECT} command that this writer will call ! * internally. The method {@code initSQLStatements} builds this * command by supplying the words "SELECT" and "FROM," and using * metadata to get the table name and column names . * * @serial */ private String selectCmd; /** ! * The SQL {@code UPDATE} command that this writer will call * internally to write data to the rowset's underlying data source. ! * The method {@code initSQLStatements} builds this {@code String} * object. * * @serial */ private String updateCmd; /** ! * The SQL {@code WHERE} clause the writer will use for update ! * statements in the {@code PreparedStatement} object * it sends to the underlying data source. * * @serial */ private String updateWhere; /** ! * The SQL {@code DELETE} command that this writer will call * internally to delete a row in the rowset's underlying data source. * * @serial */ private String deleteCmd; /** ! * The SQL {@code WHERE} clause the writer will use for delete ! * statements in the {@code PreparedStatement} object * it sends to the underlying data source. * * @serial */ private String deleteWhere; /** ! * The SQL {@code INSERT INTO} command that this writer will internally use * to insert data into the rowset's underlying data source. The method ! * {@code initSQLStatements} builds this command with a question * mark parameter placeholder for each column in the rowset. * * @serial */ private String insertCmd; /** * An array containing the column numbers of the columns that are ! * needed to uniquely identify a row in the {@code CachedRowSet} object ! * for which this {@code CachedRowSetWriter} object is the writer. * * @serial */ private int[] keyCols; /** * An array of the parameters that should be used to set the parameter ! * placeholders in a {@code PreparedStatement} object that this * writer will execute. * * @serial */ private Object[] params; /** ! * The {@code CachedRowSetReader} object that has been ! * set as the reader for the {@code CachedRowSet} object ! * for which this {@code CachedRowSetWriter} object is the writer. * * @serial */ private CachedRowSetReader reader; /** ! * The {@code ResultSetMetaData} object that contains information ! * about the columns in the {@code CachedRowSet} object ! * for which this {@code CachedRowSetWriter} object is the writer. * * @serial */ private ResultSetMetaData callerMd; /** ! * The number of columns in the {@code CachedRowSet} object ! * for which this {@code CachedRowSetWriter} object is the writer. * * @serial */ private int callerColumnCount; /** ! * This {@code CachedRowSet} will hold the conflicting values * retrieved from the db and hold it. */ private CachedRowSetImpl crsResolve; /**
*** 207,270 **** throw new RuntimeException(ioe); } } /** ! * Propagates changes in the given <code>RowSet</code> object ! * back to its underlying data source and returns <code>true</code> * if successful. The writer will check to see if * the data in the pre-modified rowset (the original values) differ * from the data in the underlying data source. If data in the data * source has been modified by someone else, there is a conflict, * and in that case, the writer will not write to the data source. * In other words, the writer uses an optimistic concurrency algorithm: * It checks for conflicts before making changes rather than restricting * access for concurrent users. * <P> * This method is called by the rowset internally when ! * the application invokes the method <code>acceptChanges</code>. ! * The <code>writeData</code> method in turn calls private methods that * it defines internally. * The following is a general summary of what the method ! * <code>writeData</code> does, much of which is accomplished * through calls to its own internal methods. * <OL> ! * <LI>Creates a <code>CachedRowSet</code> object from the given ! * <code>RowSet</code> object * <LI>Makes a connection with the data source * <UL> * <LI>Disables autocommit mode if it is not already disabled * <LI>Sets the transaction isolation level to that of the rowset * </UL> * <LI>Checks to see if the reader has read new data since the writer * was last called and, if so, calls the method ! * <code>initSQLStatements</code> to initialize new SQL statements * <UL> ! * <LI>Builds new <code>SELECT</code>, <code>UPDATE</code>, ! * <code>INSERT</code>, and <code>DELETE</code> statements ! * <LI>Uses the <code>CachedRowSet</code> object's metadata to * determine the table name, column names, and the columns * that make up the primary key * </UL> * <LI>When there is no conflict, propagates changes made to the ! * <code>CachedRowSet</code> object back to its underlying data source * <UL> ! * <LI>Iterates through each row of the <code>CachedRowSet</code> object * to determine whether it has been updated, inserted, or deleted * <LI>If the corresponding row in the data source has not been changed * since the rowset last read its * values, the writer will use the appropriate command to update, * insert, or delete the row * <LI>If any data in the data source does not match the original values ! * for the <code>CachedRowSet</code> object, the writer will roll * back any changes it has made to the row in the data source. * </UL> * </OL> * ! * @return <code>true</code> if changes to the rowset were successfully * written to the rowset's underlying data source; ! * <code>false</code> otherwise */ public boolean writeData(RowSetInternal caller) throws SQLException { long conflicts = 0; boolean showDel = false; PreparedStatement pstmtIns = null; --- 207,270 ---- throw new RuntimeException(ioe); } } /** ! * Propagates changes in the given {@code RowSet} object ! * back to its underlying data source and returns {@code true} * if successful. The writer will check to see if * the data in the pre-modified rowset (the original values) differ * from the data in the underlying data source. If data in the data * source has been modified by someone else, there is a conflict, * and in that case, the writer will not write to the data source. * In other words, the writer uses an optimistic concurrency algorithm: * It checks for conflicts before making changes rather than restricting * access for concurrent users. * <P> * This method is called by the rowset internally when ! * the application invokes the method {@code acceptChanges}. ! * The {@code writeData} method in turn calls private methods that * it defines internally. * The following is a general summary of what the method ! * {@code writeData} does, much of which is accomplished * through calls to its own internal methods. * <OL> ! * <LI>Creates a {@code CachedRowSet} object from the given ! * {@code RowSet} object * <LI>Makes a connection with the data source * <UL> * <LI>Disables autocommit mode if it is not already disabled * <LI>Sets the transaction isolation level to that of the rowset * </UL> * <LI>Checks to see if the reader has read new data since the writer * was last called and, if so, calls the method ! * {@code initSQLStatements} to initialize new SQL statements * <UL> ! * <LI>Builds new {@code SELECT}, {@code UPDATE}, ! * {@code INSERT}, and {@code DELETE} statements ! * <LI>Uses the {@code CachedRowSet} object's metadata to * determine the table name, column names, and the columns * that make up the primary key * </UL> * <LI>When there is no conflict, propagates changes made to the ! * {@code CachedRowSet} object back to its underlying data source * <UL> ! * <LI>Iterates through each row of the {@code CachedRowSet} object * to determine whether it has been updated, inserted, or deleted * <LI>If the corresponding row in the data source has not been changed * since the rowset last read its * values, the writer will use the appropriate command to update, * insert, or delete the row * <LI>If any data in the data source does not match the original values ! * for the {@code CachedRowSet} object, the writer will roll * back any changes it has made to the row in the data source. * </UL> * </OL> * ! * @return {@code true} if changes to the rowset were successfully * written to the rowset's underlying data source; ! * {@code false} otherwise */ public boolean writeData(RowSetInternal caller) throws SQLException { long conflicts = 0; boolean showDel = false; PreparedStatement pstmtIns = null;
*** 432,458 **** } */ } //end writeData ! /** ! * Updates the given <code>CachedRowSet</code> object's underlying data * source so that updates to the rowset are reflected in the original ! * data source, and returns <code>false</code> if the update was successful. ! * A return value of <code>true</code> indicates that there is a conflict, * meaning that a value updated in the rowset has already been changed by * someone else in the underlying data source. A conflict can also exist * if, for example, more than one row in the data source would be affected * by the update or if no rows would be affected. In any case, if there is * a conflict, this method does not update the underlying data source. * <P> ! * This method is called internally by the method <code>writeData</code> ! * if a row in the <code>CachedRowSet</code> object for which this ! * <code>CachedRowSetWriter</code> object is the writer has been updated. * ! * @return <code>false</code> if the update to the underlying data source is ! * successful; <code>true</code> otherwise * @throws SQLException if a database access error occurs */ private boolean updateOriginalRow(CachedRowSet crs) throws SQLException { PreparedStatement pstmt; --- 432,458 ---- } */ } //end writeData ! /** ! * Updates the given {@code CachedRowSet} object's underlying data * source so that updates to the rowset are reflected in the original ! * data source, and returns {@code false} if the update was successful. ! * A return value of {@code true} indicates that there is a conflict, * meaning that a value updated in the rowset has already been changed by * someone else in the underlying data source. A conflict can also exist * if, for example, more than one row in the data source would be affected * by the update or if no rows would be affected. In any case, if there is * a conflict, this method does not update the underlying data source. * <P> ! * This method is called internally by the method {@code writeData} ! * if a row in the {@code CachedRowSet} object for which this ! * {@code CachedRowSetWriter} object is the writer has been updated. * ! * @return {@code false} if the update to the underlying data source is ! * successful; {@code true} otherwise * @throws SQLException if a database access error occurs */ private boolean updateOriginalRow(CachedRowSet crs) throws SQLException { PreparedStatement pstmt;
*** 803,822 **** } } /** * Inserts a row that has been inserted into the given ! * <code>CachedRowSet</code> object into the data source from which ! * the rowset is derived, returning <code>false</code> if the insertion * was successful. * ! * @param crs the <code>CachedRowSet</code> object that has had a row inserted * and to whose underlying data source the row will be inserted ! * @param pstmt the <code>PreparedStatement</code> object that will be used * to execute the insertion ! * @return <code>false</code> to indicate that the insertion was successful; ! * <code>true</code> otherwise * @throws SQLException if a database access error occurs */ private boolean insertNewRow(CachedRowSet crs, PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException { --- 803,822 ---- } } /** * Inserts a row that has been inserted into the given ! * {@code CachedRowSet} object into the data source from which ! * the rowset is derived, returning {@code false} if the insertion * was successful. * ! * @param crs the {@code CachedRowSet} object that has had a row inserted * and to whose underlying data source the row will be inserted ! * @param pstmt the {@code PreparedStatement} object that will be used * to execute the insertion ! * @return {@code false} to indicate that the insertion was successful; ! * {@code true} otherwise * @throws SQLException if a database access error occurs */ private boolean insertNewRow(CachedRowSet crs, PreparedStatement pstmt, CachedRowSetImpl crsRes) throws SQLException {
*** 915,940 **** return true; } } } ! /** * Deletes the row in the underlying data source that corresponds to ! * a row that has been deleted in the given <code> CachedRowSet</code> object ! * and returns <code>false</code> if the deletion was successful. * <P> ! * This method is called internally by this writer's <code>writeData</code> * method when a row in the rowset has been deleted. The values in the * deleted row are the same as those that are stored in the original row ! * of the given <code>CachedRowSet</code> object. If the values in the * original row differ from the row in the underlying data source, the row ! * in the data source is not deleted, and <code>deleteOriginalRow</code> ! * returns <code>true</code> to indicate that there was a conflict. * * ! * @return <code>false</code> if the deletion was successful, which means that ! * there was no conflict; <code>true</code> otherwise * @throws SQLException if there was a database access error */ private boolean deleteOriginalRow(CachedRowSet crs, CachedRowSetImpl crsRes) throws SQLException { PreparedStatement pstmt; int i; --- 915,940 ---- return true; } } } ! /** * Deletes the row in the underlying data source that corresponds to ! * a row that has been deleted in the given {@code CachedRowSet} object ! * and returns {@code false} if the deletion was successful. * <P> ! * This method is called internally by this writer's {@code writeData} * method when a row in the rowset has been deleted. The values in the * deleted row are the same as those that are stored in the original row ! * of the given {@code CachedRowSet} object. If the values in the * original row differ from the row in the underlying data source, the row ! * in the data source is not deleted, and {@code deleteOriginalRow} ! * returns {@code true} to indicate that there was a conflict. * * ! * @return {@code false} if the deletion was successful, which means that ! * there was no conflict; {@code true} otherwise * @throws SQLException if there was a database access error */ private boolean deleteOriginalRow(CachedRowSet crs, CachedRowSetImpl crsRes) throws SQLException { PreparedStatement pstmt; int i;
*** 1054,1070 **** public CachedRowSetReader getReader() throws SQLException { return reader; } /** ! * Composes a <code>SELECT</code>, <code>UPDATE</code>, <code>INSERT</code>, ! * and <code>DELETE</code> statement that can be used by this writer to ! * write data to the data source backing the given <code>CachedRowSet</code> * object. * ! * @ param caller a <code>CachedRowSet</code> object for which this ! * <code>CachedRowSetWriter</code> object is the writer * @throws SQLException if a database access error occurs */ private void initSQLStatements(CachedRowSet caller) throws SQLException { int i; --- 1054,1070 ---- public CachedRowSetReader getReader() throws SQLException { return reader; } /** ! * Composes a {@code SELECT}, {@code UPDATE}, {@code INSERT}, ! * and {@code DELETE} statement that can be used by this writer to ! * write data to the data source backing the given {@code CachedRowSet} * object. * ! * @param caller a {@code CachedRowSet} object for which this ! * {@code CachedRowSetWriter} object is the writer * @throws SQLException if a database access error occurs */ private void initSQLStatements(CachedRowSet caller) throws SQLException { int i;
*** 1175,1191 **** /** * Returns a fully qualified table name built from the given catalog and * table names. The given metadata object is used to get the proper order * and separator. * ! * @param dbmd a <code>DatabaseMetaData</code> object that contains metadata ! * about this writer's <code>CachedRowSet</code> object ! * @param catalog a <code>String</code> object with the rowset's catalog * name ! * @param table a <code>String</code> object with the name of the table from * which this writer's rowset was derived ! * @return a <code>String</code> object with the fully qualified name of the * table from which this writer's rowset was derived * @throws SQLException if a database access error occurs */ private String buildTableName(DatabaseMetaData dbmd, String catalog, String schema, String table) throws SQLException { --- 1175,1191 ---- /** * Returns a fully qualified table name built from the given catalog and * table names. The given metadata object is used to get the proper order * and separator. * ! * @param dbmd a {@code DatabaseMetaData} object that contains metadata ! * about this writer's {@code CachedRowSet} object ! * @param catalog a {@code String} object with the rowset's catalog * name ! * @param table a {@code String} object with the name of the table from * which this writer's rowset was derived ! * @return a {@code String} object with the fully qualified name of the * table from which this writer's rowset was derived * @throws SQLException if a database access error occurs */ private String buildTableName(DatabaseMetaData dbmd, String catalog, String schema, String table) throws SQLException {
*** 1219,1243 **** cmd += " "; return cmd; } /** ! * Assigns to the given <code>CachedRowSet</code> object's ! * <code>params</code> * field an array whose length equals the number of columns needed * to uniquely identify a row in the rowset. The array is given ! * values by the method <code>buildWhereClause</code>. * <P> ! * If the <code>CachedRowSet</code> object's <code>keyCols</code> ! * field has length <code>0</code> or is <code>null</code>, the array * is set with the column number of every column in the rowset. ! * Otherwise, the array in the field <code>keyCols</code> is set with only * the column numbers of the columns that are required to form a unique * identifier for a row. * ! * @param crs the <code>CachedRowSet</code> object for which this ! * <code>CachedRowSetWriter</code> object is the writer * * @throws SQLException if a database access error occurs */ private void buildKeyDesc(CachedRowSet crs) throws SQLException { --- 1219,1243 ---- cmd += " "; return cmd; } /** ! * Assigns to the given {@code CachedRowSet} object's ! * {@code params} * field an array whose length equals the number of columns needed * to uniquely identify a row in the rowset. The array is given ! * values by the method {@code buildWhereClause}. * <P> ! * If the {@code CachedRowSet} object's {@code keyCols} ! * field has length {@code 0} or is {@code null}, the array * is set with the column number of every column in the rowset. ! * Otherwise, the array in the field {@code keyCols} is set with only * the column numbers of the columns that are required to form a unique * identifier for a row. * ! * @param crs the {@code CachedRowSet} object for which this ! * {@code CachedRowSetWriter} object is the writer * * @throws SQLException if a database access error occurs */ private void buildKeyDesc(CachedRowSet crs) throws SQLException {
*** 1261,1290 **** } params = new Object[keyCols.length]; } /** ! * Constructs an SQL <code>WHERE</code> clause using the given * string as a starting point. The resulting clause will contain * a column name and " = ?" for each key column, that is, each column * that is needed to form a unique identifier for a row in the rowset. ! * This <code>WHERE</code> clause can be added to ! * a <code>PreparedStatement</code> object that updates, inserts, or * deletes a row. * <P> * This method uses the given result set to access values in the ! * <code>CachedRowSet</code> object that called this writer. These * values are used to build the array of parameters that will serve as * replacements for the "?" parameter placeholders in the ! * <code>PreparedStatement</code> object that is sent to the ! * <code>CachedRowSet</code> object's underlying data source. * ! * @param whereClause a <code>String</code> object that is an empty * string ("") ! * @param rs a <code>ResultSet</code> object that can be used ! * to access the <code>CachedRowSet</code> object's data ! * @return a <code>WHERE</code> clause of the form "<code>WHERE</code> * columnName = ? AND columnName = ? AND columnName = ? ..." * @throws SQLException if a database access error occurs */ private String buildWhereClause(String whereClause, ResultSet rs) throws SQLException { --- 1261,1290 ---- } params = new Object[keyCols.length]; } /** ! * Constructs an SQL {@code WHERE} clause using the given * string as a starting point. The resulting clause will contain * a column name and " = ?" for each key column, that is, each column * that is needed to form a unique identifier for a row in the rowset. ! * This {@code WHERE} clause can be added to ! * a {@code PreparedStatement} object that updates, inserts, or * deletes a row. * <P> * This method uses the given result set to access values in the ! * {@code CachedRowSet} object that called this writer. These * values are used to build the array of parameters that will serve as * replacements for the "?" parameter placeholders in the ! * {@code PreparedStatement} object that is sent to the ! * {@code CachedRowSet} object's underlying data source. * ! * @param whereClause a {@code String} object that is an empty * string ("") ! * @param rs a {@code ResultSet} object that can be used ! * to access the {@code CachedRowSet} object's data ! * @return a {@code WHERE} clause of the form "{@code WHERE} * columnName = ? AND columnName = ? AND columnName = ? ..." * @throws SQLException if a database access error occurs */ private String buildWhereClause(String whereClause, ResultSet rs) throws SQLException {
< prev index next >