UpdatableResultSet.java
上传用户:tanyanyong
上传日期:2013-06-23
资源大小:1355k
文件大小:77k
源码类别:

电子政务应用

开发平台:

MultiPlatform

  1. /*
  2.    Copyright (C) 2002 MySQL AB
  3.       This program is free software; you can redistribute it and/or modify
  4.       it under the terms of the GNU General Public License as published by
  5.       the Free Software Foundation; either version 2 of the License, or
  6.       (at your option) any later version.
  7.       This program is distributed in the hope that it will be useful,
  8.       but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.       GNU General Public License for more details.
  11.       You should have received a copy of the GNU General Public License
  12.       along with this program; if not, write to the Free Software
  13.       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  14.  */
  15. package com.mysql.jdbc;
  16. import java.io.UnsupportedEncodingException;
  17. import java.math.BigDecimal;
  18. import java.sql.SQLException;
  19. import java.util.ArrayList;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. /**
  23.  * A result set that is updatable.
  24.  *
  25.  * @author Mark Matthews
  26.  */
  27. public class UpdatableResultSet extends ResultSet {
  28.     /** Marker for 'stream' data when doing INSERT rows */
  29.     private final static byte[] STREAM_DATA_MARKER = "** STREAM DATA **"
  30.         .getBytes();
  31.     /** List of primary keys */
  32.     private List primaryKeyIndicies = null;
  33.     /** PreparedStatement used to delete data */
  34.     private com.mysql.jdbc.PreparedStatement deleter = null;
  35.     /** PreparedStatement used to insert data */
  36.     private com.mysql.jdbc.PreparedStatement inserter = null;
  37.     /** PreparedStatement used to refresh data */
  38.     private com.mysql.jdbc.PreparedStatement refresher;
  39.     /** PreparedStatement used to delete data */
  40.     private com.mysql.jdbc.PreparedStatement updater = null;
  41.     private SingleByteCharsetConverter charConverter;
  42.     private String charEncoding;
  43.     private String deleteSQL = null;
  44.     private String insertSQL = null;
  45.     private String quotedIdChar = null;
  46.     private String refreshSQL = null;
  47.     private String tableName;
  48.     /** SQL for in-place modifcation */
  49.     private String updateSQL = null;
  50.     /** What is the default value for the column? */
  51.     private byte[][] defaultColumnValue;
  52.     /** The binary data for the 'current' row */
  53.     private byte[][] savedCurrentRow;
  54.     /** Is this result set updateable? */
  55.     private boolean isUpdatable = false;
  56.     /**
  57.      * Creates a new UpdatableResultSet object.
  58.      *
  59.      * @param updateCount DOCUMENT ME!
  60.      * @param updateID DOCUMENT ME!
  61.      */
  62.     public UpdatableResultSet(long updateCount, long updateID) {
  63.         super(updateCount, updateID);
  64.     }
  65.     // ****************************************************************
  66.     //
  67.     //                       END OF PUBLIC INTERFACE
  68.     //
  69.     // ****************************************************************
  70.     /**
  71.      * Create a new ResultSet - Note that we create ResultSets to represent the
  72.      * results of everything.
  73.      *
  74.      * @param catalog the database in use when this result set was created
  75.      * @param fields an array of Field objects (basically, the ResultSet
  76.      *        MetaData)
  77.      * @param rows Vector of the actual data
  78.      * @param conn the status string returned from the back end
  79.      *
  80.      * @throws SQLException DOCUMENT ME!
  81.      */
  82.     public UpdatableResultSet(String catalog, Field[] fields, RowData rows,
  83.         com.mysql.jdbc.Connection conn) throws SQLException {
  84.         super(catalog, fields, rows, conn);
  85.         isUpdatable = checkUpdatability();
  86.     }
  87.     /**
  88.      * Creates a new UpdatableResultSet object.
  89.      *
  90.      * @param fields DOCUMENT ME!
  91.      * @param rows DOCUMENT ME!
  92.      *
  93.      * @throws SQLException DOCUMENT ME!
  94.      */
  95.     public UpdatableResultSet(Field[] fields, RowData rows)
  96.         throws SQLException {
  97.         super(fields, rows);
  98.         isUpdatable = checkUpdatability();
  99.     }
  100.     /**
  101.      * JDBC 2.0
  102.      * 
  103.      * <p>
  104.      * Determine if the cursor is after the last row in the result  set.
  105.      * </p>
  106.      *
  107.      * @return true if after the last row, false otherwise.  Returns false when
  108.      *         the result set contains no rows.
  109.      *
  110.      * @exception SQLException if a database-access error occurs.
  111.      */
  112.     public synchronized boolean isAfterLast() throws SQLException {
  113.         return super.isAfterLast();
  114.     }
  115.     /**
  116.      * JDBC 2.0
  117.      * 
  118.      * <p>
  119.      * Determine if the cursor is before the first row in the result  set.
  120.      * </p>
  121.      *
  122.      * @return true if before the first row, false otherwise. Returns false
  123.      *         when the result set contains no rows.
  124.      *
  125.      * @exception SQLException if a database-access error occurs.
  126.      */
  127.     public synchronized boolean isBeforeFirst() throws SQLException {
  128.         return super.isBeforeFirst();
  129.     }
  130.     /**
  131.      * JDBC 2.0 Return the concurrency of this result set.  The concurrency
  132.      * used is determined by the statement that created the result set.
  133.      *
  134.      * @return the concurrency type, CONCUR_READ_ONLY, etc.
  135.      *
  136.      * @exception SQLException if a database-access error occurs
  137.      */
  138.     public int getConcurrency() throws SQLException {
  139.         return (isUpdatable ? CONCUR_UPDATABLE : CONCUR_READ_ONLY);
  140.     }
  141.     /**
  142.      * JDBC 2.0
  143.      * 
  144.      * <p>
  145.      * Determine if the cursor is on the first row of the result set.
  146.      * </p>
  147.      *
  148.      * @return true if on the first row, false otherwise.
  149.      *
  150.      * @exception SQLException if a database-access error occurs.
  151.      */
  152.     public synchronized boolean isFirst() throws SQLException {
  153.         return super.isFirst();
  154.     }
  155.     /**
  156.      * JDBC 2.0
  157.      * 
  158.      * <p>
  159.      * Determine if the cursor is on the last row of the result set.    Note:
  160.      * Calling isLast() may be expensive since the JDBC driver might need to
  161.      * fetch ahead one row in order to determine  whether the current row is
  162.      * the last row in the result set.
  163.      * </p>
  164.      *
  165.      * @return true if on the last row, false otherwise.
  166.      *
  167.      * @exception SQLException if a database-access error occurs.
  168.      */
  169.     public synchronized boolean isLast() throws SQLException {
  170.         return super.isLast();
  171.     }
  172.     /**
  173.      * JDBC 2.0
  174.      * 
  175.      * <p>
  176.      * Move to an absolute row number in the result set.
  177.      * </p>
  178.      * 
  179.      * <p>
  180.      * If row is positive, moves to an absolute row with respect to the
  181.      * beginning of the result set.  The first row is row 1, the second is row
  182.      * 2, etc.
  183.      * </p>
  184.      * 
  185.      * <p>
  186.      * If row is negative, moves to an absolute row position with respect to
  187.      * the end of result set.  For example, calling absolute(-1) positions the
  188.      * cursor on the last row, absolute(-2) indicates the next-to-last row,
  189.      * etc.
  190.      * </p>
  191.      * 
  192.      * <p>
  193.      * An attempt to position the cursor beyond the first/last row in the
  194.      * result set, leaves the cursor before/after the first/last row,
  195.      * respectively.
  196.      * </p>
  197.      * 
  198.      * <p>
  199.      * Note: Calling absolute(1) is the same as calling first(). Calling
  200.      * absolute(-1) is the same as calling last().
  201.      * </p>
  202.      *
  203.      * @param row DOCUMENT ME!
  204.      *
  205.      * @return true if on the result set, false if off.
  206.      *
  207.      * @exception SQLException if a database-access error occurs, or  row is 0,
  208.      *            or result set type is TYPE_FORWARD_ONLY.
  209.      */
  210.     public synchronized boolean absolute(int row) throws SQLException {
  211.         return super.absolute(row);
  212.     }
  213.     /**
  214.      * JDBC 2.0
  215.      * 
  216.      * <p>
  217.      * Moves to the end of the result set, just after the last row.  Has no
  218.      * effect if the result set contains no rows.
  219.      * </p>
  220.      *
  221.      * @exception SQLException if a database-access error occurs, or result set
  222.      *            type is TYPE_FORWARD_ONLY.
  223.      */
  224.     public synchronized void afterLast() throws SQLException {
  225.         super.afterLast();
  226.     }
  227.     /**
  228.      * JDBC 2.0
  229.      * 
  230.      * <p>
  231.      * Moves to the front of the result set, just before the first row. Has no
  232.      * effect if the result set contains no rows.
  233.      * </p>
  234.      *
  235.      * @exception SQLException if a database-access error occurs, or result set
  236.      *            type is TYPE_FORWARD_ONLY
  237.      */
  238.     public synchronized void beforeFirst() throws SQLException {
  239.         super.beforeFirst();
  240.     }
  241.     /**
  242.      * JDBC 2.0 The cancelRowUpdates() method may be called after calling an
  243.      * updateXXX() method(s) and before calling updateRow() to rollback  the
  244.      * updates made to a row.  If no updates have been made or  updateRow()
  245.      * has already been called, then this method has no  effect.
  246.      *
  247.      * @exception SQLException if a database-access error occurs, or if called
  248.      *            when on the insert row.
  249.      */
  250.     public synchronized void cancelRowUpdates() throws SQLException {
  251.         if (doingUpdates) {
  252.             doingUpdates = false;
  253.             updater.clearParameters();
  254.         }
  255.     }
  256.     /**
  257.      * After this call, getWarnings returns null until a new warning is
  258.      * reported for this ResultSet
  259.      *
  260.      * @exception java.sql.SQLException if a database access error occurs
  261.      */
  262.     public synchronized void clearWarnings() throws java.sql.SQLException {
  263.         warningChain = null;
  264.     }
  265.     /**
  266.      * In some cases, it is desirable to immediately release a ResultSet
  267.      * database and JDBC resources instead of waiting for this to happen when
  268.      * it is automatically closed.  The close method provides this immediate
  269.      * release.
  270.      * 
  271.      * <p>
  272.      * <B>Note:</B> A ResultSet is automatically closed by the Statement the
  273.      * Statement that generated it when that Statement is closed, re-executed,
  274.      * or is used to retrieve the next result from a sequence of multiple
  275.      * results.  A ResultSet is also automatically closed when it is garbage
  276.      * collected.
  277.      * </p>
  278.      *
  279.      * @exception java.sql.SQLException if a database access error occurs
  280.      */
  281.     public synchronized void close() throws java.sql.SQLException {
  282.         super.close();
  283.     }
  284.     /**
  285.      * JDBC 2.0 Delete the current row from the result set and the underlying
  286.      * database.  Cannot be called when on the insert row.
  287.      *
  288.      * @exception SQLException if a database-access error occurs, or if called
  289.      *            when on the insert row.
  290.      * @throws SQLException if the ResultSet is not updatable or some other
  291.      *         error occurs
  292.      */
  293.     public synchronized void deleteRow() throws SQLException {
  294.         if (!isUpdatable) {
  295.             throw new NotUpdatable();
  296.         }
  297.         if (onInsertRow) {
  298.             throw new SQLException(
  299.                 "Can not call deleteRow() when on insert row");
  300.         } else if (rowData.size() == 0) {
  301.             throw new SQLException("Can't deleteRow() on empty result set");
  302.         } else if (isBeforeFirst()) {
  303.             throw new SQLException(
  304.                 "Before start of result set. Can not call deleteRow().");
  305.         } else if (isAfterLast()) {
  306.             throw new SQLException(
  307.                 "After end of result set. Can not call deleteRow().");
  308.         }
  309.         if (deleter == null) {
  310.             if (deleteSQL == null) {
  311.                 generateStatements();
  312.             }
  313.             deleter = (com.mysql.jdbc.PreparedStatement) connection
  314.                 .prepareStatement(deleteSQL);
  315.             
  316.             if (deleter.getMaxRows() != 0) {
  317.              deleter.setMaxRows(0);
  318.             }
  319.         }
  320.         deleter.clearParameters();
  321.         String characterEncoding = null;
  322.         if (connection.useUnicode()) {
  323.             characterEncoding = connection.getEncoding();
  324.         }
  325.         //
  326.         // FIXME: Use internal routines where possible for character
  327.         //        conversion!
  328.         try {
  329.             int numKeys = primaryKeyIndicies.size();
  330.             if (numKeys == 1) {
  331.                 int index = ((Integer) primaryKeyIndicies.get(0)).intValue();
  332.                 String currentVal = ((characterEncoding == null)
  333.                     ? new String(thisRow[index])
  334.                     : new String(thisRow[index], characterEncoding));
  335.                 deleter.setString(1, currentVal);
  336.             } else {
  337.                 for (int i = 0; i < numKeys; i++) {
  338.                     int index = ((Integer) primaryKeyIndicies.get(i)).intValue();
  339.                     String currentVal = ((characterEncoding == null)
  340.                         ? new String(thisRow[index])
  341.                         : new String(thisRow[index], characterEncoding));
  342.                     deleter.setString(i + 1, currentVal);
  343.                 }
  344.             }
  345.             deleter.executeUpdate();
  346.             rowData.removeRow(rowData.getCurrentRowNumber());
  347.         } catch (java.io.UnsupportedEncodingException encodingEx) {
  348.             throw new SQLException("Unsupported character encoding '"
  349.                 + connection.getEncoding() + "'");
  350.         }
  351.     }
  352.     /**
  353.      * JDBC 2.0
  354.      * 
  355.      * <p>
  356.      * Moves to the first row in the result set.
  357.      * </p>
  358.      *
  359.      * @return true if on a valid row, false if no rows in the result set.
  360.      *
  361.      * @exception SQLException if a database-access error occurs, or result set
  362.      *            type is TYPE_FORWARD_ONLY.
  363.      */
  364.     public synchronized boolean first() throws SQLException {
  365.         return super.first();
  366.     }
  367.     /**
  368.      * JDBC 2.0 Insert the contents of the insert row into the result set and
  369.      * the database.  Must be on the insert row when this method is called.
  370.      *
  371.      * @exception SQLException if a database-access error occurs, if called
  372.      *            when not on the insert row, or if all non-nullable columns
  373.      *            in the insert row have not been given a value
  374.      */
  375.     public synchronized void insertRow() throws SQLException {
  376.         if (!onInsertRow) {
  377.             throw new SQLException("Not on insert row");
  378.         } else {
  379.             inserter.executeUpdate();
  380.             int numPrimaryKeys = 0;
  381.             if (primaryKeyIndicies != null) {
  382.                 numPrimaryKeys = primaryKeyIndicies.size();
  383.             }
  384.             long autoIncrementId = inserter.getLastInsertID();
  385.             int numFields = fields.length;
  386.             byte[][] newRow = new byte[numFields][];
  387.             for (int i = 0; i < numFields; i++) {
  388.                 if (inserter.isNull(i)) {
  389.                     newRow[i] = null;
  390.                 } else {
  391.                     newRow[i] = inserter.getBytes(i);
  392.                 }
  393.                 if ((numPrimaryKeys == 1) && fields[i].isPrimaryKey()
  394.                         && (autoIncrementId > 0)) {
  395.                     newRow[i] = String.valueOf(autoIncrementId).getBytes();
  396.                 }
  397.             }
  398.             rowData.addRow(newRow);
  399.             resetInserter();
  400.         }
  401.     }
  402.     /**
  403.      * JDBC 2.0
  404.      * 
  405.      * <p>
  406.      * Moves to the last row in the result set.
  407.      * </p>
  408.      *
  409.      * @return true if on a valid row, false if no rows in the result set.
  410.      *
  411.      * @exception SQLException if a database-access error occurs, or result set
  412.      *            type is TYPE_FORWARD_ONLY.
  413.      */
  414.     public synchronized boolean last() throws SQLException {
  415.         return super.last();
  416.     }
  417.     /**
  418.      * JDBC 2.0 Move the cursor to the remembered cursor position, usually the
  419.      * current row.  Has no effect unless the cursor is on the insert  row.
  420.      *
  421.      * @exception SQLException if a database-access error occurs, or the result
  422.      *            set is not updatable
  423.      * @throws SQLException if the ResultSet is not updatable or some other
  424.      *         error occurs
  425.      */
  426.     public synchronized void moveToCurrentRow() throws SQLException {
  427.         if (!isUpdatable) {
  428.             throw new NotUpdatable();
  429.         }
  430.         if (this.onInsertRow) {
  431.             onInsertRow = false;
  432.             this.thisRow = this.savedCurrentRow;
  433.         }
  434.     }
  435.     /**
  436.      * JDBC 2.0 Move to the insert row.  The current cursor position is
  437.      * remembered while the cursor is positioned on the insert row. The insert
  438.      * row is a special row associated with an updatable result set.  It is
  439.      * essentially a buffer where a new row may be constructed by calling the
  440.      * updateXXX() methods prior to  inserting the row into the result set.
  441.      * Only the updateXXX(), getXXX(), and insertRow() methods may be  called
  442.      * when the cursor is on the insert row.  All of the columns in  a result
  443.      * set must be given a value each time this method is called before
  444.      * calling insertRow().  UpdateXXX()must be called before getXXX() on a
  445.      * column.
  446.      *
  447.      * @exception SQLException if a database-access error occurs, or the result
  448.      *            set is not updatable
  449.      * @throws NotUpdatable DOCUMENT ME!
  450.      */
  451.     public synchronized void moveToInsertRow() throws SQLException {
  452.         if (!this.isUpdatable) {
  453.             throw new NotUpdatable();
  454.         }
  455.         if (this.inserter == null) {
  456.             generateStatements();
  457.             this.inserter = (com.mysql.jdbc.PreparedStatement) connection
  458.                 .prepareStatement(this.insertSQL);
  459.             
  460.             if (this.inserter.getMaxRows() != 0) {
  461.              this.inserter.setMaxRows(0);
  462.             }
  463.             
  464.             extractDefaultValues();
  465.             resetInserter();
  466.         } else {
  467.             resetInserter();
  468.         }
  469. int numFields = this.fields.length;
  470. this.onInsertRow = true;
  471. this.doingUpdates = false;
  472. this.savedCurrentRow = this.thisRow;
  473. this.thisRow = new byte[numFields][];
  474.    
  475.         for (int i = 0; i < numFields; i++) {
  476.             if (this.defaultColumnValue[i] != null) {
  477.                 this.inserter.setBytes(i + 1, this.defaultColumnValue[i]);
  478.                 
  479.                 // This value _could_ be changed from a getBytes(), so we
  480.                 // need a copy....
  481.                 byte[] defaultValueCopy = new byte[this.defaultColumnValue[i].length];
  482.                 System.arraycopy(defaultColumnValue[i], 0, defaultValueCopy, 0, defaultValueCopy.length);
  483.                 this.thisRow[i] = defaultValueCopy;
  484.             } else {
  485.                 this.inserter.setNull(i + 1, java.sql.Types.NULL);
  486.                 this.thisRow[i] = null;
  487.             }
  488.         }
  489.     }
  490.     /**
  491.      * A ResultSet is initially positioned before its first row, the first call
  492.      * to next makes the first row the current row; the second call makes the
  493.      * second row the current row, etc.
  494.      * 
  495.      * <p>
  496.      * If an input stream from the previous row is open, it is implicitly
  497.      * closed.  The ResultSet's warning chain is cleared when a new row is
  498.      * read
  499.      * </p>
  500.      *
  501.      * @return true if the new current is valid; false if there are no more
  502.      *         rows
  503.      *
  504.      * @exception java.sql.SQLException if a database access error occurs
  505.      */
  506.     public synchronized boolean next() throws java.sql.SQLException {
  507.         return super.next();
  508.     }
  509.     /**
  510.      * The prev method is not part of JDBC, but because of the architecture of
  511.      * this driver it is possible to move both forward and backward within the
  512.      * result set.
  513.      * 
  514.      * <p>
  515.      * If an input stream from the previous row is open, it is implicitly
  516.      * closed.  The ResultSet's warning chain is cleared when a new row is
  517.      * read
  518.      * </p>
  519.      *
  520.      * @return true if the new current is valid; false if there are no more
  521.      *         rows
  522.      *
  523.      * @exception java.sql.SQLException if a database access error occurs
  524.      */
  525.     public synchronized boolean prev() throws java.sql.SQLException {
  526.         return super.prev();
  527.     }
  528.     /**
  529.      * JDBC 2.0
  530.      * 
  531.      * <p>
  532.      * Moves to the previous row in the result set.
  533.      * </p>
  534.      * 
  535.      * <p>
  536.      * Note: previous() is not the same as relative(-1) since it makes sense to
  537.      * call previous() when there is no current row.
  538.      * </p>
  539.      *
  540.      * @return true if on a valid row, false if off the result set.
  541.      *
  542.      * @exception SQLException if a database-access error occurs, or result set
  543.      *            type is TYPE_FORWAR_DONLY.
  544.      */
  545.     public synchronized boolean previous() throws SQLException {
  546.         return super.previous();
  547.     }
  548.     /**
  549.      * JDBC 2.0 Refresh the value of the current row with its current value in
  550.      * the database.  Cannot be called when on the insert row. The
  551.      * refreshRow() method provides a way for an application to  explicitly
  552.      * tell the JDBC driver to refetch a row(s) from the database.  An
  553.      * application may want to call refreshRow() when  caching or prefetching
  554.      * is being done by the JDBC driver to fetch the latest value of a row
  555.      * from the database.  The JDBC driver  may actually refresh multiple rows
  556.      * at once if the fetch size is  greater than one.  All values are
  557.      * refetched subject to the transaction isolation  level and cursor
  558.      * sensitivity.  If refreshRow() is called after calling updateXXX(), but
  559.      * before calling updateRow() then the updates made to the row are lost.
  560.      * Calling refreshRow() frequently will likely slow performance.
  561.      *
  562.      * @exception SQLException if a database-access error occurs, or if called
  563.      *            when on the insert row.
  564.      * @throws NotUpdatable DOCUMENT ME!
  565.      */
  566.     public synchronized void refreshRow() throws SQLException {
  567.         if (!isUpdatable) {
  568.             throw new NotUpdatable();
  569.         }
  570.         if (onInsertRow) {
  571.             throw new SQLException(
  572.                 "Can not call refreshRow() when on insert row");
  573.         } else if (rowData.size() == 0) {
  574.             throw new SQLException("Can't refreshRow() on empty result set");
  575.         } else if (isBeforeFirst()) {
  576.             throw new SQLException(
  577.                 "Before start of result set. Can not call refreshRow().");
  578.         } else if (isAfterLast()) {
  579.             throw new SQLException(
  580.                 "After end of result set. Can not call refreshRow().");
  581.         }
  582.         if (refresher == null) {
  583.             if (refreshSQL == null) {
  584.                 generateStatements();
  585.             }
  586.             refresher = (com.mysql.jdbc.PreparedStatement) connection
  587.                 .prepareStatement(refreshSQL);
  588.             
  589.             if (refresher.getMaxRows() != 0) {
  590.              refresher.setMaxRows(0);
  591.             }
  592.         }
  593.         refresher.clearParameters();
  594.         int numKeys = primaryKeyIndicies.size();
  595.         if (numKeys == 1) {
  596.             byte[] dataFrom = null;
  597.             int index = ((Integer) primaryKeyIndicies.get(0)).intValue();
  598.             if (!doingUpdates) {
  599.                 dataFrom = thisRow[index];
  600.             } else {
  601.                 dataFrom = updater.getBytes(index);
  602.                 // Primary keys not set?
  603.                 if (updater.isNull(index) || (dataFrom.length == 0)) {
  604.                     dataFrom = thisRow[index];
  605.                 }
  606.             }
  607.             refresher.setBytesNoEscape(1, dataFrom);
  608.         } else {
  609.             for (int i = 0; i < numKeys; i++) {
  610.                 byte[] dataFrom = null;
  611.                 int index = ((Integer) primaryKeyIndicies.get(i)).intValue();
  612.                 if (!doingUpdates) {
  613.                     dataFrom = thisRow[index];
  614.                 } else {
  615.                     dataFrom = updater.getBytes(index);
  616.                     // Primary keys not set?
  617.                     if (updater.isNull(index) || (dataFrom.length == 0)) {
  618.                         dataFrom = thisRow[index];
  619.                     }
  620.                 }
  621.                 refresher.setBytesNoEscape(i + 1, dataFrom);
  622.             }
  623.         }
  624.         java.sql.ResultSet rs = null;
  625.         try {
  626.             rs = refresher.executeQuery();
  627.             int numCols = rs.getMetaData().getColumnCount();
  628.             if (rs.next()) {
  629.                 for (int i = 0; i < numCols; i++) {
  630.                     byte[] val = rs.getBytes(i + 1);
  631.                     if ((val == null) || rs.wasNull()) {
  632.                         thisRow[i] = null;
  633.                     } else {
  634.                         thisRow[i] = rs.getBytes(i + 1);
  635.                     }
  636.                 }
  637.             } else {
  638.                 throw new SQLException("refreshRow() called on row that has been deleted or had primary key changed",
  639.                     SQLError.SQL_STATE_GENERAL_ERROR);
  640.             }
  641.         } finally {
  642.             if (rs != null) {
  643.                 try {
  644.                     rs.close();
  645.                 } catch (SQLException ex) {
  646.                     ; // ignore
  647.                 }
  648.             }
  649.         }
  650.     }
  651.     /**
  652.      * JDBC 2.0
  653.      * 
  654.      * <p>
  655.      * Moves a relative number of rows, either positive or negative. Attempting
  656.      * to move beyond the first/last row in the result set positions the
  657.      * cursor before/after the the first/last row. Calling relative(0) is
  658.      * valid, but does not change the cursor position.
  659.      * </p>
  660.      * 
  661.      * <p>
  662.      * Note: Calling relative(1) is different than calling next() since is
  663.      * makes sense to call next() when there is no current row, for example,
  664.      * when the cursor is positioned before the first row or after the last
  665.      * row of the result set.
  666.      * </p>
  667.      *
  668.      * @param rows DOCUMENT ME!
  669.      *
  670.      * @return true if on a row, false otherwise.
  671.      *
  672.      * @exception SQLException if a database-access error occurs, or there is
  673.      *            no current row, or result set type is TYPE_FORWARD_ONLY.
  674.      */
  675.     public synchronized boolean relative(int rows) throws SQLException {
  676.         return super.relative(rows);
  677.     }
  678.     /**
  679.      * JDBC 2.0 Determine if this row has been deleted.  A deleted row may
  680.      * leave a visible "hole" in a result set.  This method can be used to
  681.      * detect holes in a result set.  The value returned depends on whether or
  682.      * not the result set can detect deletions.
  683.      *
  684.      * @return true if deleted and deletes are detected
  685.      *
  686.      * @exception SQLException if a database-access error occurs
  687.      * @throws NotImplemented DOCUMENT ME!
  688.      *
  689.      * @see DatabaseMetaData#deletesAreDetected
  690.      */
  691.     public synchronized boolean rowDeleted() throws SQLException {
  692.         throw new NotImplemented();
  693.     }
  694.     /**
  695.      * JDBC 2.0 Determine if the current row has been inserted.  The value
  696.      * returned  depends on whether or not the result set can detect visible
  697.      * inserts.
  698.      *
  699.      * @return true if inserted and inserts are detected
  700.      *
  701.      * @exception SQLException if a database-access error occurs
  702.      * @throws NotImplemented DOCUMENT ME!
  703.      *
  704.      * @see DatabaseMetaData#insertsAreDetected
  705.      */
  706.     public synchronized boolean rowInserted() throws SQLException {
  707.         throw new NotImplemented();
  708.     }
  709.     //---------------------------------------------------------------------
  710.     // Updates
  711.     //---------------------------------------------------------------------
  712.     /**
  713.      * JDBC 2.0 Determine if the current row has been updated.  The value
  714.      * returned  depends on whether or not the result set can detect updates.
  715.      *
  716.      * @return true if the row has been visibly updated by the owner or
  717.      *         another, and updates are detected
  718.      *
  719.      * @exception SQLException if a database-access error occurs
  720.      * @throws NotImplemented DOCUMENT ME!
  721.      *
  722.      * @see DatabaseMetaData#updatesAreDetected
  723.      */
  724.     public synchronized boolean rowUpdated() throws SQLException {
  725.         throw new NotImplemented();
  726.     }
  727.     /**
  728.      * JDBC 2.0  Update a column with an ascii stream value. The updateXXX()
  729.      * methods are used to update column values in the current row, or the
  730.      * insert row.  The updateXXX() methods do not  update the underlying
  731.      * database, instead the updateRow() or insertRow() methods are called to
  732.      * update the database.
  733.      *
  734.      * @param columnIndex the first column is 1, the second is 2, ...
  735.      * @param x the new column value
  736.      * @param length the length of the stream
  737.      *
  738.      * @exception SQLException if a database-access error occurs
  739.      */
  740.     public synchronized void updateAsciiStream(int columnIndex,
  741.         java.io.InputStream x, int length) throws SQLException {
  742.         if (!onInsertRow) {
  743.             if (!doingUpdates) {
  744.                 doingUpdates = true;
  745.                 syncUpdate();
  746.             }
  747.             updater.setAsciiStream(columnIndex, x, length);
  748.         } else {
  749.             inserter.setAsciiStream(columnIndex, x, length);
  750.             this.thisRow[columnIndex - 1] = STREAM_DATA_MARKER;
  751.         }
  752.     }
  753.     /**
  754.      * JDBC 2.0  Update a column with an ascii stream value. The updateXXX()
  755.      * methods are used to update column values in the current row, or the
  756.      * insert row.  The updateXXX() methods do not  update the underlying
  757.      * database, instead the updateRow() or insertRow() methods are called to
  758.      * update the database.
  759.      *
  760.      * @param columnName the name of the column
  761.      * @param x the new column value
  762.      * @param length of the stream
  763.      *
  764.      * @exception SQLException if a database-access error occurs
  765.      */
  766.     public synchronized void updateAsciiStream(String columnName,
  767.         java.io.InputStream x, int length) throws SQLException {
  768.         updateAsciiStream(findColumn(columnName), x, length);
  769.     }
  770.     /**
  771.      * JDBC 2.0  Update a column with a BigDecimal value. The updateXXX()
  772.      * methods are used to update column values in the current row, or the
  773.      * insert row.  The updateXXX() methods do not  update the underlying
  774.      * database, instead the updateRow() or insertRow() methods are called to
  775.      * update the database.
  776.      *
  777.      * @param columnIndex the first column is 1, the second is 2, ...
  778.      * @param x the new column value
  779.      *
  780.      * @exception SQLException if a database-access error occurs
  781.      */
  782.     public synchronized void updateBigDecimal(int columnIndex, BigDecimal x)
  783.         throws SQLException {
  784.         if (!onInsertRow) {
  785.             if (!doingUpdates) {
  786.                 doingUpdates = true;
  787.                 syncUpdate();
  788.             }
  789.             updater.setBigDecimal(columnIndex, x);
  790.         } else {
  791.             inserter.setBigDecimal(columnIndex, x);
  792.             if (x == null) {
  793.                 this.thisRow[columnIndex - 1] = null;
  794.             } else {
  795.                 this.thisRow[columnIndex - 1] = x.toString().getBytes();
  796.             }
  797.         }
  798.     }
  799.     /**
  800.      * JDBC 2.0  Update a column with a BigDecimal value. The updateXXX()
  801.      * methods are used to update column values in the current row, or the
  802.      * insert row.  The updateXXX() methods do not  update the underlying
  803.      * database, instead the updateRow() or insertRow() methods are called to
  804.      * update the database.
  805.      *
  806.      * @param columnName the name of the column
  807.      * @param x the new column value
  808.      *
  809.      * @exception SQLException if a database-access error occurs
  810.      */
  811.     public synchronized void updateBigDecimal(String columnName, BigDecimal x)
  812.         throws SQLException {
  813.         updateBigDecimal(findColumn(columnName), x);
  814.     }
  815.     /**
  816.      * JDBC 2.0  Update a column with a binary stream value. The updateXXX()
  817.      * methods are used to update column values in the current row, or the
  818.      * insert row.  The updateXXX() methods do not  update the underlying
  819.      * database, instead the updateRow() or insertRow() methods are called to
  820.      * update the database.
  821.      *
  822.      * @param columnIndex the first column is 1, the second is 2, ...
  823.      * @param x the new column value
  824.      * @param length the length of the stream
  825.      *
  826.      * @exception SQLException if a database-access error occurs
  827.      */
  828.     public synchronized void updateBinaryStream(int columnIndex,
  829.         java.io.InputStream x, int length) throws SQLException {
  830.         if (!onInsertRow) {
  831.             if (!doingUpdates) {
  832.                 doingUpdates = true;
  833.                 syncUpdate();
  834.             }
  835.             updater.setBinaryStream(columnIndex, x, length);
  836.         } else {
  837.             inserter.setBinaryStream(columnIndex, x, length);
  838.             if (x == null) {
  839.                 this.thisRow[columnIndex - 1] = null;
  840.             } else {
  841.                 this.thisRow[columnIndex - 1] = STREAM_DATA_MARKER;
  842.             }
  843.         }
  844.     }
  845.     /**
  846.      * JDBC 2.0  Update a column with a binary stream value. The updateXXX()
  847.      * methods are used to update column values in the current row, or the
  848.      * insert row.  The updateXXX() methods do not  update the underlying
  849.      * database, instead the updateRow() or insertRow() methods are called to
  850.      * update the database.
  851.      *
  852.      * @param columnName the name of the column
  853.      * @param x the new column value
  854.      * @param length of the stream
  855.      *
  856.      * @exception SQLException if a database-access error occurs
  857.      */
  858.     public synchronized void updateBinaryStream(String columnName,
  859.         java.io.InputStream x, int length) throws SQLException {
  860.         updateBinaryStream(findColumn(columnName), x, length);
  861.     }
  862.     /**
  863.      * @see ResultSet#updateBlob(int, Blob)
  864.      */
  865.     public void updateBlob(int columnIndex, java.sql.Blob blob)
  866.         throws SQLException {
  867.         if (!onInsertRow) {
  868.             if (!doingUpdates) {
  869.                 doingUpdates = true;
  870.                 syncUpdate();
  871.             }
  872.             updater.setBlob(columnIndex, blob);
  873.         } else {
  874.             inserter.setBlob(columnIndex, blob);
  875.             if (blob == null) {
  876.                 this.thisRow[columnIndex - 1] = null;
  877.             } else {
  878.                 this.thisRow[columnIndex - 1] = STREAM_DATA_MARKER;
  879.             }
  880.         }
  881.     }
  882.     /**
  883.      * @see ResultSet#updateBlob(String, Blob)
  884.      */
  885.     public void updateBlob(String columnName, java.sql.Blob blob)
  886.         throws SQLException {
  887.         updateBlob(findColumn(columnName), blob);
  888.     }
  889.     /**
  890.      * JDBC 2.0  Update a column with a boolean value. The updateXXX() methods
  891.      * are used to update column values in the current row, or the insert row.
  892.      * The updateXXX() methods do not  update the underlying database, instead
  893.      * the updateRow() or insertRow() methods are called to update the
  894.      * database.
  895.      *
  896.      * @param columnIndex the first column is 1, the second is 2, ...
  897.      * @param x the new column value
  898.      *
  899.      * @exception SQLException if a database-access error occurs
  900.      */
  901.     public synchronized void updateBoolean(int columnIndex, boolean x)
  902.         throws SQLException {
  903.         if (!onInsertRow) {
  904.             if (!doingUpdates) {
  905.                 doingUpdates = true;
  906.                 syncUpdate();
  907.             }
  908.             updater.setBoolean(columnIndex, x);
  909.         } else {
  910.             inserter.setBoolean(columnIndex, x);
  911.             this.thisRow[columnIndex - 1] = inserter.getBytes(1);
  912.         }
  913.     }
  914.     /**
  915.      * JDBC 2.0  Update a column with a boolean value. The updateXXX() methods
  916.      * are used to update column values in the current row, or the insert row.
  917.      * The updateXXX() methods do not  update the underlying database, instead
  918.      * the updateRow() or insertRow() methods are called to update the
  919.      * database.
  920.      *
  921.      * @param columnName the name of the column
  922.      * @param x the new column value
  923.      *
  924.      * @exception SQLException if a database-access error occurs
  925.      */
  926.     public synchronized void updateBoolean(String columnName, boolean x)
  927.         throws SQLException {
  928.         updateBoolean(findColumn(columnName), x);
  929.     }
  930.     /**
  931.      * JDBC 2.0  Update a column with a byte value. The updateXXX() methods are
  932.      * used to update column values in the current row, or the insert row. The
  933.      * updateXXX() methods do not  update the underlying database, instead the
  934.      * updateRow() or insertRow() methods are called to update the database.
  935.      *
  936.      * @param columnIndex the first column is 1, the second is 2, ...
  937.      * @param x the new column value
  938.      *
  939.      * @exception SQLException if a database-access error occurs
  940.      */
  941.     public synchronized void updateByte(int columnIndex, byte x)
  942.         throws SQLException {
  943.         if (!onInsertRow) {
  944.             if (!doingUpdates) {
  945.                 doingUpdates = true;
  946.                 syncUpdate();
  947.             }
  948.             updater.setByte(columnIndex, x);
  949.         } else {
  950.             inserter.setByte(columnIndex, x);
  951.             this.thisRow[columnIndex - 1] = inserter.getBytes(columnIndex);
  952.         }
  953.     }
  954.     /**
  955.      * JDBC 2.0  Update a column with a byte value. The updateXXX() methods are
  956.      * used to update column values in the current row, or the insert row. The
  957.      * updateXXX() methods do not  update the underlying database, instead the
  958.      * updateRow() or insertRow() methods are called to update the database.
  959.      *
  960.      * @param columnName the name of the column
  961.      * @param x the new column value
  962.      *
  963.      * @exception SQLException if a database-access error occurs
  964.      */
  965.     public synchronized void updateByte(String columnName, byte x)
  966.         throws SQLException {
  967.         updateByte(findColumn(columnName), x);
  968.     }
  969.     /**
  970.      * JDBC 2.0  Update a column with a byte array value. The updateXXX()
  971.      * methods are used to update column values in the current row, or the
  972.      * insert row.  The updateXXX() methods do not  update the underlying
  973.      * database, instead the updateRow() or insertRow() methods are called to
  974.      * update the database.
  975.      *
  976.      * @param columnIndex the first column is 1, the second is 2, ...
  977.      * @param x the new column value
  978.      *
  979.      * @exception SQLException if a database-access error occurs
  980.      */
  981.     public synchronized void updateBytes(int columnIndex, byte[] x)
  982.         throws SQLException {
  983.         if (!onInsertRow) {
  984.             if (!doingUpdates) {
  985.                 doingUpdates = true;
  986.                 syncUpdate();
  987.             }
  988.             updater.setBytes(columnIndex, x);
  989.         } else {
  990.             inserter.setBytes(columnIndex, x);
  991.             this.thisRow[columnIndex - 1] = x;
  992.         }
  993.     }
  994.     /**
  995.      * JDBC 2.0  Update a column with a byte array value. The updateXXX()
  996.      * methods are used to update column values in the current row, or the
  997.      * insert row.  The updateXXX() methods do not  update the underlying
  998.      * database, instead the updateRow() or insertRow() methods are called to
  999.      * update the database.
  1000.      *
  1001.      * @param columnName the name of the column
  1002.      * @param x the new column value
  1003.      *
  1004.      * @exception SQLException if a database-access error occurs
  1005.      */
  1006.     public synchronized void updateBytes(String columnName, byte[] x)
  1007.         throws SQLException {
  1008.         updateBytes(findColumn(columnName), x);
  1009.     }
  1010.     /**
  1011.      * JDBC 2.0  Update a column with a character stream value. The updateXXX()
  1012.      * methods are used to update column values in the current row, or the
  1013.      * insert row.  The updateXXX() methods do not  update the underlying
  1014.      * database, instead the updateRow() or insertRow() methods are called to
  1015.      * update the database.
  1016.      *
  1017.      * @param columnIndex the first column is 1, the second is 2, ...
  1018.      * @param x the new column value
  1019.      * @param length the length of the stream
  1020.      *
  1021.      * @exception SQLException if a database-access error occurs
  1022.      */
  1023.     public synchronized void updateCharacterStream(int columnIndex,
  1024.         java.io.Reader x, int length) throws SQLException {
  1025.         if (!onInsertRow) {
  1026.             if (!doingUpdates) {
  1027.                 doingUpdates = true;
  1028.                 syncUpdate();
  1029.             }
  1030.             updater.setCharacterStream(columnIndex, x, length);
  1031.         } else {
  1032.             inserter.setCharacterStream(columnIndex, x, length);
  1033.             if (x == null) {
  1034.                 this.thisRow[columnIndex - 1] = null;
  1035.             } else {
  1036.                 this.thisRow[columnIndex - 1] = STREAM_DATA_MARKER;
  1037.             }
  1038.         }
  1039.     }
  1040.     /**
  1041.      * JDBC 2.0  Update a column with a character stream value. The updateXXX()
  1042.      * methods are used to update column values in the current row, or the
  1043.      * insert row.  The updateXXX() methods do not  update the underlying
  1044.      * database, instead the updateRow() or insertRow() methods are called to
  1045.      * update the database.
  1046.      *
  1047.      * @param columnName the name of the column
  1048.      * @param reader the new column value
  1049.      * @param length of the stream
  1050.      *
  1051.      * @exception SQLException if a database-access error occurs
  1052.      */
  1053.     public synchronized void updateCharacterStream(String columnName,
  1054.         java.io.Reader reader, int length) throws SQLException {
  1055.         updateCharacterStream(findColumn(columnName), reader, length);
  1056.     }
  1057.     
  1058. /**
  1059.   * @see ResultSet#updateClob(int, Clob)
  1060.   */
  1061.  public void updateClob(int columnIndex, java.sql.Clob clob) throws SQLException {
  1062.    if (clob == null) {
  1063.     updateNull(columnIndex);
  1064.    } else {
  1065.     updateCharacterStream(columnIndex, clob.getCharacterStream(), (int) clob.length());
  1066.    }
  1067.  }
  1068.     /**
  1069.      * JDBC 2.0  Update a column with a Date value. The updateXXX() methods are
  1070.      * used to update column values in the current row, or the insert row. The
  1071.      * updateXXX() methods do not  update the underlying database, instead the
  1072.      * updateRow() or insertRow() methods are called to update the database.
  1073.      *
  1074.      * @param columnIndex the first column is 1, the second is 2, ...
  1075.      * @param x the new column value
  1076.      *
  1077.      * @exception SQLException if a database-access error occurs
  1078.      */
  1079.     public synchronized void updateDate(int columnIndex, java.sql.Date x)
  1080.         throws SQLException {
  1081.         if (!onInsertRow) {
  1082.             if (!doingUpdates) {
  1083.                 doingUpdates = true;
  1084.                 syncUpdate();
  1085.             }
  1086.             updater.setDate(columnIndex, x);
  1087.         } else {
  1088.             inserter.setDate(columnIndex, x);
  1089.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1090.                     - 1);
  1091.         }
  1092.     }
  1093.     /**
  1094.      * JDBC 2.0  Update a column with a Date value. The updateXXX() methods are
  1095.      * used to update column values in the current row, or the insert row. The
  1096.      * updateXXX() methods do not  update the underlying database, instead the
  1097.      * updateRow() or insertRow() methods are called to update the database.
  1098.      *
  1099.      * @param columnName the name of the column
  1100.      * @param x the new column value
  1101.      *
  1102.      * @exception SQLException if a database-access error occurs
  1103.      */
  1104.     public synchronized void updateDate(String columnName, java.sql.Date x)
  1105.         throws SQLException {
  1106.         updateDate(findColumn(columnName), x);
  1107.     }
  1108.     /**
  1109.      * JDBC 2.0  Update a column with a Double value. The updateXXX() methods
  1110.      * are used to update column values in the current row, or the insert row.
  1111.      * The updateXXX() methods do not  update the underlying database, instead
  1112.      * the updateRow() or insertRow() methods are called to update the
  1113.      * database.
  1114.      *
  1115.      * @param columnIndex the first column is 1, the second is 2, ...
  1116.      * @param x the new column value
  1117.      *
  1118.      * @exception SQLException if a database-access error occurs
  1119.      */
  1120.     public synchronized void updateDouble(int columnIndex, double x)
  1121.         throws SQLException {
  1122.         if (!onInsertRow) {
  1123.             if (!doingUpdates) {
  1124.                 doingUpdates = true;
  1125.                 syncUpdate();
  1126.             }
  1127.             updater.setDouble(columnIndex, x);
  1128.         } else {
  1129.             inserter.setDouble(columnIndex, x);
  1130.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1131.                     - 1);
  1132.         }
  1133.     }
  1134.     /**
  1135.      * JDBC 2.0  Update a column with a double value. The updateXXX() methods
  1136.      * are used to update column values in the current row, or the insert row.
  1137.      * The updateXXX() methods do not  update the underlying database, instead
  1138.      * the updateRow() or insertRow() methods are called to update the
  1139.      * database.
  1140.      *
  1141.      * @param columnName the name of the column
  1142.      * @param x the new column value
  1143.      *
  1144.      * @exception SQLException if a database-access error occurs
  1145.      */
  1146.     public synchronized void updateDouble(String columnName, double x)
  1147.         throws SQLException {
  1148.         updateDouble(findColumn(columnName), x);
  1149.     }
  1150.     /**
  1151.      * JDBC 2.0  Update a column with a float value. The updateXXX() methods
  1152.      * are used to update column values in the current row, or the insert row.
  1153.      * The updateXXX() methods do not  update the underlying database, instead
  1154.      * the updateRow() or insertRow() methods are called to update the
  1155.      * database.
  1156.      *
  1157.      * @param columnIndex the first column is 1, the second is 2, ...
  1158.      * @param x the new column value
  1159.      *
  1160.      * @exception SQLException if a database-access error occurs
  1161.      */
  1162.     public synchronized void updateFloat(int columnIndex, float x)
  1163.         throws SQLException {
  1164.         if (!onInsertRow) {
  1165.             if (!doingUpdates) {
  1166.                 doingUpdates = true;
  1167.                 syncUpdate();
  1168.             }
  1169.             updater.setFloat(columnIndex, x);
  1170.         } else {
  1171.             inserter.setFloat(columnIndex, x);
  1172.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1173.                     - 1);
  1174.         }
  1175.     }
  1176.     /**
  1177.      * JDBC 2.0  Update a column with a float value. The updateXXX() methods
  1178.      * are used to update column values in the current row, or the insert row.
  1179.      * The updateXXX() methods do not  update the underlying database, instead
  1180.      * the updateRow() or insertRow() methods are called to update the
  1181.      * database.
  1182.      *
  1183.      * @param columnName the name of the column
  1184.      * @param x the new column value
  1185.      *
  1186.      * @exception SQLException if a database-access error occurs
  1187.      */
  1188.     public synchronized void updateFloat(String columnName, float x)
  1189.         throws SQLException {
  1190.         updateFloat(findColumn(columnName), x);
  1191.     }
  1192.     /**
  1193.      * JDBC 2.0  Update a column with an integer value. The updateXXX() methods
  1194.      * are used to update column values in the current row, or the insert row.
  1195.      * The updateXXX() methods do not  update the underlying database, instead
  1196.      * the updateRow() or insertRow() methods are called to update the
  1197.      * database.
  1198.      *
  1199.      * @param columnIndex the first column is 1, the second is 2, ...
  1200.      * @param x the new column value
  1201.      *
  1202.      * @exception SQLException if a database-access error occurs
  1203.      */
  1204.     public synchronized void updateInt(int columnIndex, int x)
  1205.         throws SQLException {
  1206.         if (!onInsertRow) {
  1207.             if (!doingUpdates) {
  1208.                 doingUpdates = true;
  1209.                 syncUpdate();
  1210.             }
  1211.             updater.setInt(columnIndex, x);
  1212.         } else {
  1213.             inserter.setInt(columnIndex, x);
  1214.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1215.                     - 1);
  1216.         }
  1217.     }
  1218.     /**
  1219.      * JDBC 2.0  Update a column with an integer value. The updateXXX() methods
  1220.      * are used to update column values in the current row, or the insert row.
  1221.      * The updateXXX() methods do not  update the underlying database, instead
  1222.      * the updateRow() or insertRow() methods are called to update the
  1223.      * database.
  1224.      *
  1225.      * @param columnName the name of the column
  1226.      * @param x the new column value
  1227.      *
  1228.      * @exception SQLException if a database-access error occurs
  1229.      */
  1230.     public synchronized void updateInt(String columnName, int x)
  1231.         throws SQLException {
  1232.         updateInt(findColumn(columnName), x);
  1233.     }
  1234.     /**
  1235.      * JDBC 2.0  Update a column with a long value. The updateXXX() methods are
  1236.      * used to update column values in the current row, or the insert row. The
  1237.      * updateXXX() methods do not  update the underlying database, instead the
  1238.      * updateRow() or insertRow() methods are called to update the database.
  1239.      *
  1240.      * @param columnIndex the first column is 1, the second is 2, ...
  1241.      * @param x the new column value
  1242.      *
  1243.      * @exception SQLException if a database-access error occurs
  1244.      */
  1245.     public synchronized void updateLong(int columnIndex, long x)
  1246.         throws SQLException {
  1247.         if (!onInsertRow) {
  1248.             if (!doingUpdates) {
  1249.                 doingUpdates = true;
  1250.                 syncUpdate();
  1251.             }
  1252.             updater.setLong(columnIndex, x);
  1253.         } else {
  1254.             inserter.setLong(columnIndex, x);
  1255.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1256.                     - 1);
  1257.         }
  1258.     }
  1259.     /**
  1260.      * JDBC 2.0  Update a column with a long value. The updateXXX() methods are
  1261.      * used to update column values in the current row, or the insert row. The
  1262.      * updateXXX() methods do not  update the underlying database, instead the
  1263.      * updateRow() or insertRow() methods are called to update the database.
  1264.      *
  1265.      * @param columnName the name of the column
  1266.      * @param x the new column value
  1267.      *
  1268.      * @exception SQLException if a database-access error occurs
  1269.      */
  1270.     public synchronized void updateLong(String columnName, long x)
  1271.         throws SQLException {
  1272.         updateLong(findColumn(columnName), x);
  1273.     }
  1274.     /**
  1275.      * JDBC 2.0  Give a nullable column a null value.  The updateXXX() methods
  1276.      * are used to update column values in the current row, or the insert row.
  1277.      * The updateXXX() methods do not  update the underlying database, instead
  1278.      * the updateRow() or insertRow() methods are called to update the
  1279.      * database.
  1280.      *
  1281.      * @param columnIndex the first column is 1, the second is 2, ...
  1282.      *
  1283.      * @exception SQLException if a database-access error occurs
  1284.      */
  1285.     public synchronized void updateNull(int columnIndex)
  1286.         throws SQLException {
  1287.         if (!onInsertRow) {
  1288.             if (!doingUpdates) {
  1289.                 doingUpdates = true;
  1290.                 syncUpdate();
  1291.             }
  1292.             updater.setNull(columnIndex, 0);
  1293.         } else {
  1294.             inserter.setNull(columnIndex, 0);
  1295.             this.thisRow[columnIndex - 1] = null;
  1296.         }
  1297.     }
  1298.     /**
  1299.      * JDBC 2.0  Update a column with a null value. The updateXXX() methods are
  1300.      * used to update column values in the current row, or the insert row. The
  1301.      * updateXXX() methods do not  update the underlying database, instead the
  1302.      * updateRow() or insertRow() methods are called to update the database.
  1303.      *
  1304.      * @param columnName the name of the column
  1305.      *
  1306.      * @exception SQLException if a database-access error occurs
  1307.      */
  1308.     public synchronized void updateNull(String columnName)
  1309.         throws SQLException {
  1310.         updateNull(findColumn(columnName));
  1311.     }
  1312.     /**
  1313.      * JDBC 2.0  Update a column with an Object value. The updateXXX() methods
  1314.      * are used to update column values in the current row, or the insert row.
  1315.      * The updateXXX() methods do not  update the underlying database, instead
  1316.      * the updateRow() or insertRow() methods are called to update the
  1317.      * database.
  1318.      *
  1319.      * @param columnIndex the first column is 1, the second is 2, ...
  1320.      * @param x the new column value
  1321.      * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
  1322.      *        this is the number of digits after the decimal.  For all other
  1323.      *        types this value will be ignored.
  1324.      *
  1325.      * @exception SQLException if a database-access error occurs
  1326.      */
  1327.     public synchronized void updateObject(int columnIndex, Object x, int scale)
  1328.         throws SQLException {
  1329.         if (!onInsertRow) {
  1330.             if (!doingUpdates) {
  1331.                 doingUpdates = true;
  1332.                 syncUpdate();
  1333.             }
  1334.             updater.setObject(columnIndex, x);
  1335.         } else {
  1336.             inserter.setObject(columnIndex, x);
  1337.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1338.                     - 1);
  1339.         }
  1340.     }
  1341.     /**
  1342.      * JDBC 2.0  Update a column with an Object value. The updateXXX() methods
  1343.      * are used to update column values in the current row, or the insert row.
  1344.      * The updateXXX() methods do not  update the underlying database, instead
  1345.      * the updateRow() or insertRow() methods are called to update the
  1346.      * database.
  1347.      *
  1348.      * @param columnIndex the first column is 1, the second is 2, ...
  1349.      * @param x the new column value
  1350.      *
  1351.      * @exception SQLException if a database-access error occurs
  1352.      */
  1353.     public synchronized void updateObject(int columnIndex, Object x)
  1354.         throws SQLException {
  1355.         if (!onInsertRow) {
  1356.             if (!doingUpdates) {
  1357.                 doingUpdates = true;
  1358.                 syncUpdate();
  1359.             }
  1360.             updater.setObject(columnIndex, x);
  1361.         } else {
  1362.             inserter.setObject(columnIndex, x);
  1363.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1364.                     - 1);
  1365.         }
  1366.     }
  1367.     /**
  1368.      * JDBC 2.0  Update a column with an Object value. The updateXXX() methods
  1369.      * are used to update column values in the current row, or the insert row.
  1370.      * The updateXXX() methods do not  update the underlying database, instead
  1371.      * the updateRow() or insertRow() methods are called to update the
  1372.      * database.
  1373.      *
  1374.      * @param columnName the name of the column
  1375.      * @param x the new column value
  1376.      * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
  1377.      *        this is the number of digits after the decimal.  For all other
  1378.      *        types this value will be ignored.
  1379.      *
  1380.      * @exception SQLException if a database-access error occurs
  1381.      */
  1382.     public synchronized void updateObject(String columnName, Object x, int scale)
  1383.         throws SQLException {
  1384.         updateObject(findColumn(columnName), x);
  1385.     }
  1386.     /**
  1387.      * JDBC 2.0  Update a column with an Object value. The updateXXX() methods
  1388.      * are used to update column values in the current row, or the insert row.
  1389.      * The updateXXX() methods do not  update the underlying database, instead
  1390.      * the updateRow() or insertRow() methods are called to update the
  1391.      * database.
  1392.      *
  1393.      * @param columnName the name of the column
  1394.      * @param x the new column value
  1395.      *
  1396.      * @exception SQLException if a database-access error occurs
  1397.      */
  1398.     public synchronized void updateObject(String columnName, Object x)
  1399.         throws SQLException {
  1400.         updateObject(findColumn(columnName), x);
  1401.     }
  1402.     /**
  1403.      * JDBC 2.0 Update the underlying database with the new contents of the
  1404.      * current row.  Cannot be called when on the insert row.
  1405.      *
  1406.      * @exception SQLException if a database-access error occurs, or if called
  1407.      *            when on the insert row
  1408.      * @throws NotUpdatable DOCUMENT ME!
  1409.      */
  1410.     public synchronized void updateRow() throws SQLException {
  1411.         if (!isUpdatable) {
  1412.             throw new NotUpdatable();
  1413.         }
  1414.         if (doingUpdates) {
  1415.             updater.executeUpdate();
  1416.             refreshRow();
  1417.             doingUpdates = false;
  1418.         }
  1419.         //
  1420.         // fixes calling updateRow() and then doing more
  1421.         // updates on same row...
  1422.         syncUpdate();
  1423.     }
  1424.     /**
  1425.      * JDBC 2.0  Update a column with a short value. The updateXXX() methods
  1426.      * are used to update column values in the current row, or the insert row.
  1427.      * The updateXXX() methods do not  update the underlying database, instead
  1428.      * the updateRow() or insertRow() methods are called to update the
  1429.      * database.
  1430.      *
  1431.      * @param columnIndex the first column is 1, the second is 2, ...
  1432.      * @param x the new column value
  1433.      *
  1434.      * @exception SQLException if a database-access error occurs
  1435.      */
  1436.     public synchronized void updateShort(int columnIndex, short x)
  1437.         throws SQLException {
  1438.         if (!onInsertRow) {
  1439.             if (!doingUpdates) {
  1440.                 doingUpdates = true;
  1441.                 syncUpdate();
  1442.             }
  1443.             updater.setShort(columnIndex, x);
  1444.         } else {
  1445.             inserter.setShort(columnIndex, x);
  1446.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1447.                     - 1);
  1448.         }
  1449.     }
  1450.     /**
  1451.      * JDBC 2.0  Update a column with a short value. The updateXXX() methods
  1452.      * are used to update column values in the current row, or the insert row.
  1453.      * The updateXXX() methods do not  update the underlying database, instead
  1454.      * the updateRow() or insertRow() methods are called to update the
  1455.      * database.
  1456.      *
  1457.      * @param columnName the name of the column
  1458.      * @param x the new column value
  1459.      *
  1460.      * @exception SQLException if a database-access error occurs
  1461.      */
  1462.     public synchronized void updateShort(String columnName, short x)
  1463.         throws SQLException {
  1464.         updateShort(findColumn(columnName), x);
  1465.     }
  1466.     /**
  1467.      * JDBC 2.0  Update a column with a String value. The updateXXX() methods
  1468.      * are used to update column values in the current row, or the insert row.
  1469.      * The updateXXX() methods do not  update the underlying database, instead
  1470.      * the updateRow() or insertRow() methods are called to update the
  1471.      * database.
  1472.      *
  1473.      * @param columnIndex the first column is 1, the second is 2, ...
  1474.      * @param x the new column value
  1475.      *
  1476.      * @exception SQLException if a database-access error occurs
  1477.      */
  1478.     public synchronized void updateString(int columnIndex, String x)
  1479.         throws SQLException {
  1480.         if (!onInsertRow) {
  1481.             if (!doingUpdates) {
  1482.                 doingUpdates = true;
  1483.                 syncUpdate();
  1484.             }
  1485.             updater.setString(columnIndex, x);
  1486.         } else {
  1487.             inserter.setString(columnIndex, x);
  1488.             if (x == null) {
  1489.                 this.thisRow[columnIndex - 1] = null;
  1490.             } else {
  1491.                 if (getCharConverter() != null) {
  1492.                     try {
  1493.                         this.thisRow[columnIndex - 1] = StringUtils.getBytes(x,
  1494.                                 this.charConverter, this.charEncoding);
  1495.                     } catch (UnsupportedEncodingException uEE) {
  1496.                         throw new SQLException(
  1497.                             "Unsupported character encoding '"
  1498.                             + this.charEncoding + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
  1499.                     }
  1500.                 } else {
  1501.                     this.thisRow[columnIndex - 1] = x.getBytes();
  1502.                 }
  1503.             }
  1504.         }
  1505.     }
  1506.     /**
  1507.      * JDBC 2.0  Update a column with a String value. The updateXXX() methods
  1508.      * are used to update column values in the current row, or the insert row.
  1509.      * The updateXXX() methods do not  update the underlying database, instead
  1510.      * the updateRow() or insertRow() methods are called to update the
  1511.      * database.
  1512.      *
  1513.      * @param columnName the name of the column
  1514.      * @param x the new column value
  1515.      *
  1516.      * @exception SQLException if a database-access error occurs
  1517.      */
  1518.     public synchronized void updateString(String columnName, String x)
  1519.         throws SQLException {
  1520.         updateString(findColumn(columnName), x);
  1521.     }
  1522.     /**
  1523.      * JDBC 2.0  Update a column with a Time value. The updateXXX() methods are
  1524.      * used to update column values in the current row, or the insert row. The
  1525.      * updateXXX() methods do not  update the underlying database, instead the
  1526.      * updateRow() or insertRow() methods are called to update the database.
  1527.      *
  1528.      * @param columnIndex the first column is 1, the second is 2, ...
  1529.      * @param x the new column value
  1530.      *
  1531.      * @exception SQLException if a database-access error occurs
  1532.      */
  1533.     public synchronized void updateTime(int columnIndex, java.sql.Time x)
  1534.         throws SQLException {
  1535.         if (!onInsertRow) {
  1536.             if (!doingUpdates) {
  1537.                 doingUpdates = true;
  1538.                 syncUpdate();
  1539.             }
  1540.             updater.setTime(columnIndex, x);
  1541.         } else {
  1542.             inserter.setTime(columnIndex, x);
  1543.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1544.                     - 1);
  1545.         }
  1546.     }
  1547.     /**
  1548.      * JDBC 2.0  Update a column with a Time value. The updateXXX() methods are
  1549.      * used to update column values in the current row, or the insert row. The
  1550.      * updateXXX() methods do not  update the underlying database, instead the
  1551.      * updateRow() or insertRow() methods are called to update the database.
  1552.      *
  1553.      * @param columnName the name of the column
  1554.      * @param x the new column value
  1555.      *
  1556.      * @exception SQLException if a database-access error occurs
  1557.      */
  1558.     public synchronized void updateTime(String columnName, java.sql.Time x)
  1559.         throws SQLException {
  1560.         updateTime(findColumn(columnName), x);
  1561.     }
  1562.     /**
  1563.      * JDBC 2.0  Update a column with a Timestamp value. The updateXXX()
  1564.      * methods are used to update column values in the current row, or the
  1565.      * insert row.  The updateXXX() methods do not  update the underlying
  1566.      * database, instead the updateRow() or insertRow() methods are called to
  1567.      * update the database.
  1568.      *
  1569.      * @param columnIndex the first column is 1, the second is 2, ...
  1570.      * @param x the new column value
  1571.      *
  1572.      * @exception SQLException if a database-access error occurs
  1573.      */
  1574.     public synchronized void updateTimestamp(int columnIndex,
  1575.         java.sql.Timestamp x) throws SQLException {
  1576.         if (!onInsertRow) {
  1577.             if (!doingUpdates) {
  1578.                 doingUpdates = true;
  1579.                 syncUpdate();
  1580.             }
  1581.             updater.setTimestamp(columnIndex, x);
  1582.         } else {
  1583.             inserter.setTimestamp(columnIndex, x);
  1584.             this.thisRow[columnIndex - 1] = this.inserter.getBytes(columnIndex
  1585.                     - 1);
  1586.         }
  1587.     }
  1588.     /**
  1589.      * JDBC 2.0  Update a column with a Timestamp value. The updateXXX()
  1590.      * methods are used to update column values in the current row, or the
  1591.      * insert row.  The updateXXX() methods do not  update the underlying
  1592.      * database, instead the updateRow() or insertRow() methods are called to
  1593.      * update the database.
  1594.      *
  1595.      * @param columnName the name of the column
  1596.      * @param x the new column value
  1597.      *
  1598.      * @exception SQLException if a database-access error occurs
  1599.      */
  1600.     public synchronized void updateTimestamp(String columnName,
  1601.         java.sql.Timestamp x) throws SQLException {
  1602.         updateTimestamp(findColumn(columnName), x);
  1603.     }
  1604.     /**
  1605.      * Sets the concurrency type of this result set
  1606.      *
  1607.      * @param concurrencyFlag the type of concurrency that this ResultSet
  1608.      *        should support.
  1609.      */
  1610.     protected void setResultSetConcurrency(int concurrencyFlag) {
  1611.         super.setResultSetConcurrency(concurrencyFlag);
  1612.         //
  1613.         // FIXME: Issue warning when asked for updateable result set, but result set is not
  1614.         // updatable
  1615.         //
  1616.         //if ((concurrencyFlag == CONCUR_UPDATABLE) && !isUpdatable()) {
  1617.         //java.sql.SQLWarning warning = new java.sql.SQLWarning(
  1618.         //NotUpdatable.NOT_UPDATEABLE_MESSAGE);
  1619.         //}
  1620.     }
  1621.     protected void checkRowPos() throws SQLException {
  1622.         // don't use RowData's idea of
  1623.         // row bounds when we're doing
  1624.         // inserts...
  1625.         if (!this.onInsertRow) {
  1626.             super.checkRowPos();
  1627.         }
  1628.     }
  1629.     /**
  1630.      * Figure out whether or not this ResultSet is updateable, and if so,
  1631.      * generate the PreparedStatements to support updates.
  1632.      *
  1633.      * @throws SQLException DOCUMENT ME!
  1634.      * @throws NotUpdatable DOCUMENT ME!
  1635.      */
  1636.     protected void generateStatements() throws SQLException {
  1637.         if (!isUpdatable) {
  1638.          this.doingUpdates = false;
  1639.          this.onInsertRow = false;
  1640.         
  1641.             throw new NotUpdatable();
  1642.         }
  1643.         String quotedId = getQuotedIdChar();
  1644.         this.tableName = null;
  1645.         if (fields[0].getOriginalTableName() != null) {
  1646.             StringBuffer tableNameBuffer = new StringBuffer();
  1647.             String databaseName = fields[0].getDatabaseName();
  1648.             if ((databaseName != null) && (databaseName.length() > 0)) {
  1649.                 tableNameBuffer.append(quotedId);
  1650.                 tableNameBuffer.append(databaseName);
  1651.                 tableNameBuffer.append(quotedId);
  1652.                 tableNameBuffer.append('.');
  1653.             }
  1654.             tableNameBuffer.append(quotedId);
  1655.             tableNameBuffer.append(fields[0].getOriginalTableName());
  1656.             tableNameBuffer.append(quotedId);
  1657.             this.tableName = tableNameBuffer.toString();
  1658.         } else {
  1659.             StringBuffer tableNameBuffer = new StringBuffer();
  1660.             tableNameBuffer.append(quotedId);
  1661.             tableNameBuffer.append(fields[0].getTableName());
  1662.             tableNameBuffer.append(quotedId);
  1663.             this.tableName = tableNameBuffer.toString();
  1664.         }
  1665.         primaryKeyIndicies = new ArrayList();
  1666.         StringBuffer fieldValues = new StringBuffer();
  1667.         StringBuffer keyValues = new StringBuffer();
  1668.         StringBuffer columnNames = new StringBuffer();
  1669.         StringBuffer insertPlaceHolders = new StringBuffer();
  1670.         boolean firstTime = true;
  1671.         boolean keysFirstTime = true;
  1672.         for (int i = 0; i < fields.length; i++) {
  1673.             String originalColumnName = fields[i].getOriginalName();
  1674.             String columnName = null;
  1675.             if (this.connection.getIO().hasLongColumnInfo()
  1676.                     && (originalColumnName != null)
  1677.                     && (originalColumnName.length() > 0)) {
  1678.                 columnName = originalColumnName;
  1679.             } else {
  1680.                 columnName = fields[i].getName();
  1681.             }
  1682.             if (fields[i].isPrimaryKey()) {
  1683.                 primaryKeyIndicies.add(new Integer(i));
  1684.                 if (!keysFirstTime) {
  1685.                     keyValues.append(" AND ");
  1686.                 } else {
  1687.                     keysFirstTime = false;
  1688.                 }
  1689.                 keyValues.append(quotedId);
  1690.                 keyValues.append(columnName);
  1691.                 keyValues.append(quotedId);
  1692.                 keyValues.append("=?");
  1693.             }
  1694.             if (firstTime) {
  1695.                 firstTime = false;
  1696.                 fieldValues.append("SET ");
  1697.             } else {
  1698.                 fieldValues.append(",");
  1699.                 columnNames.append(",");
  1700.                 insertPlaceHolders.append(",");
  1701.             }
  1702.             insertPlaceHolders.append("?");
  1703.             columnNames.append(quotedId);
  1704.             columnNames.append(columnName);
  1705.             columnNames.append(quotedId);
  1706.             fieldValues.append(quotedId);
  1707.             fieldValues.append(columnName);
  1708.             fieldValues.append(quotedId);
  1709.             fieldValues.append("=?");
  1710.         }
  1711.         updateSQL = "UPDATE " + this.tableName + " " + fieldValues.toString()
  1712.             + " WHERE " + keyValues.toString();
  1713.         insertSQL = "INSERT INTO " + this.tableName + " ("
  1714.             + columnNames.toString() + ") VALUES ("
  1715.             + insertPlaceHolders.toString() + ")";
  1716.         refreshSQL = "SELECT " + columnNames.toString() + " FROM " + tableName
  1717.             + " WHERE " + keyValues.toString();
  1718.         deleteSQL = "DELETE FROM " + this.tableName + " WHERE "
  1719.             + keyValues.toString();
  1720.     }
  1721.     boolean isUpdatable() {
  1722.         return this.isUpdatable;
  1723.     }
  1724.     /**
  1725.      * Reset UPDATE prepared statement to value in current row.  This_Row MUST
  1726.      * point to current, valid row.
  1727.      *
  1728.      * @throws SQLException DOCUMENT ME!
  1729.      */
  1730.     void syncUpdate() throws SQLException {
  1731.         if (updater == null) {
  1732.             if (updateSQL == null) {
  1733.                 generateStatements();
  1734.             }
  1735.             updater = (com.mysql.jdbc.PreparedStatement) connection
  1736.                 .prepareStatement(updateSQL);
  1737.             
  1738.             if (updater.getMaxRows() != 0) {
  1739.              updater.setMaxRows(0);
  1740.             }
  1741.         }
  1742.         int numFields = fields.length;
  1743.         updater.clearParameters();
  1744.         for (int i = 0; i < numFields; i++) {
  1745.             if (thisRow[i] != null) {
  1746.                 updater.setBytes(i + 1, thisRow[i]);
  1747.             } else {
  1748.                 updater.setNull(i + 1, 0);
  1749.             }
  1750.         }
  1751.         int numKeys = primaryKeyIndicies.size();
  1752.         if (numKeys == 1) {
  1753.             int index = ((Integer) primaryKeyIndicies.get(0)).intValue();
  1754.             byte[] keyData = thisRow[index];
  1755.             updater.setBytes(numFields + 1, keyData);
  1756.         } else {
  1757.             for (int i = 0; i < numKeys; i++) {
  1758.                 byte[] currentVal = thisRow[((Integer) primaryKeyIndicies.get(i))
  1759.                     .intValue()];
  1760.                 if (currentVal != null) {
  1761.                     updater.setBytes(numFields + i + 1, currentVal);
  1762.                 } else {
  1763.                     updater.setNull(numFields + i + 1, 0);
  1764.                 }
  1765.             }
  1766.         }
  1767.     }
  1768.     private boolean initializedCharConverter = false;
  1769.     
  1770.     private synchronized SingleByteCharsetConverter getCharConverter()
  1771.         throws SQLException {
  1772.         if (!this.initializedCharConverter) {
  1773.          this.initializedCharConverter = true;
  1774.         
  1775.             if (this.connection.useUnicode()) {
  1776.                 this.charEncoding = connection.getEncoding();
  1777.                 this.charConverter = this.connection.getCharsetConverter(this.charEncoding);
  1778.             }
  1779.         }
  1780.         return this.charConverter;
  1781.     }
  1782.     private synchronized String getQuotedIdChar() throws SQLException {
  1783.         if (this.quotedIdChar == null) {
  1784.             boolean useQuotedIdentifiers = connection.supportsQuotedIdentifiers();
  1785.             if (useQuotedIdentifiers) {
  1786.                 java.sql.DatabaseMetaData dbmd = connection.getMetaData();
  1787.                 this.quotedIdChar = dbmd.getIdentifierQuoteString();
  1788.             } else {
  1789.                 this.quotedIdChar = "";
  1790.             }
  1791.         }
  1792.         return this.quotedIdChar;
  1793.     }
  1794.     /**
  1795.      * DOCUMENT ME!
  1796.      *
  1797.      * @param field
  1798.      *
  1799.      * @return String
  1800.      */
  1801.     private String getTableName(Field field) {
  1802.         String originalTableName = field.getOriginalTableName();
  1803.         if ((originalTableName != null) && (originalTableName.length() > 0)) {
  1804.             return originalTableName;
  1805.         } else {
  1806.             return field.getTableName();
  1807.         }
  1808.     }
  1809.     /**
  1810.      * Is this ResultSet updateable?
  1811.      *
  1812.      * @return DOCUMENT ME!
  1813.      *
  1814.      * @throws SQLException DOCUMENT ME!
  1815.      */
  1816. private boolean checkUpdatability() throws SQLException {
  1817. String tableName = null;
  1818. String catalogName = null;
  1819. int primaryKeyCount = 0;
  1820. if (fields.length > 0) {
  1821. tableName = fields[0].getOriginalTableName();
  1822.             catalogName = fields[0].getDatabaseName();
  1823.             
  1824. if (tableName == null) {
  1825. tableName = fields[0].getTableName();
  1826. catalogName = this.catalog;
  1827. }
  1828. if (fields[0].isPrimaryKey()) {
  1829. primaryKeyCount++;
  1830. }
  1831. //
  1832. // References only one table?
  1833. //
  1834. for (int i = 1; i < fields.length; i++) {
  1835. String otherTableName = fields[i].getOriginalTableName();
  1836.             
  1837. String otherCatalogName = fields[i].getDatabaseName();
  1838. if (otherTableName == null) {
  1839. otherTableName = fields[i].getTableName();
  1840. otherCatalogName = this.catalog;
  1841. }
  1842.             
  1843. // Can't have more than one table
  1844. if ((tableName == null)
  1845. || !otherTableName.equals(tableName)) {
  1846. return false;
  1847. }
  1848. // Can't reference more than one database
  1849. if ((catalogName == null) || !otherCatalogName.equals(catalogName)) {
  1850. return false;
  1851. }
  1852. if (fields[i].isPrimaryKey()) {
  1853. primaryKeyCount++;
  1854. }
  1855. }
  1856. if ((tableName == null) || (tableName.length() == 0)) {
  1857. return false;
  1858. }
  1859. } else {
  1860. return false;
  1861. }
  1862. // 
  1863. // Must have at least one primary key
  1864. //
  1865. if (primaryKeyCount == 0) {
  1866. return false;
  1867. }
  1868. // We can only do this if we know that there is a currently
  1869. // selected database, or if we're talking to a > 4.1 version
  1870. // of MySQL server (as it returns database names in field
  1871. // info)
  1872. //
  1873. if ((this.catalog == null) || (this.catalog.length() == 0)) {
  1874. this.catalog = fields[0].getDatabaseName();
  1875. if ((this.catalog == null) || (this.catalog.length() == 0)) {
  1876. throw new SQLException(
  1877. "Can not create updatable result sets when there is no currently selected database"
  1878. + " and MySQL server version < 4.1", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
  1879. }
  1880. }
  1881. if (this.connection.useStrictUpdates()) {
  1882. java.sql.DatabaseMetaData dbmd = this.connection.getMetaData();
  1883. java.sql.ResultSet rs = null;
  1884. HashMap primaryKeyNames = new HashMap();
  1885. try {
  1886. rs = dbmd.getPrimaryKeys(catalogName, null, tableName);
  1887. while (rs.next()) {
  1888. String keyName = rs.getString(4);
  1889. keyName = keyName.toUpperCase();
  1890. primaryKeyNames.put(keyName, keyName);
  1891. }
  1892. } finally {
  1893. if (rs != null) {
  1894. try {
  1895. rs.close();
  1896. } catch (Exception ex) {
  1897. AssertionFailedException.shouldNotHappen(ex);
  1898. }
  1899. rs = null;
  1900. }
  1901. }
  1902. if (primaryKeyNames.size() == 0) {
  1903. return false; // we can't update tables w/o keys
  1904. }
  1905. //
  1906. // Contains all primary keys?
  1907. //
  1908. for (int i = 0; i < fields.length; i++) {
  1909. if (fields[i].isPrimaryKey()) {
  1910. String columnNameUC = fields[i].getName().toUpperCase();
  1911. if (primaryKeyNames.remove(columnNameUC) == null) {
  1912. // try original name
  1913. String originalName = fields[i].getOriginalName();
  1914. if (originalName != null) {
  1915. if (primaryKeyNames.remove(
  1916. originalName.toUpperCase()) == null) {
  1917. // we don't know about this key, so give up :(
  1918. return false;
  1919. }
  1920. }
  1921. }
  1922. }
  1923. }
  1924. return primaryKeyNames.isEmpty();
  1925. }
  1926. return true;
  1927. }
  1928.     private synchronized void extractDefaultValues() throws SQLException {
  1929.         java.sql.DatabaseMetaData dbmd = this.connection.getMetaData();
  1930.         java.sql.ResultSet columnsResultSet = null;
  1931.         try {
  1932.             String unquotedTableName = this.tableName;
  1933.             if (unquotedTableName.startsWith(this.quotedIdChar)) {
  1934.                 unquotedTableName = unquotedTableName.substring(1);
  1935.             }
  1936.             if (unquotedTableName.endsWith(this.quotedIdChar)) {
  1937.                 unquotedTableName = unquotedTableName.substring(0,
  1938.                         unquotedTableName.length() - 1);
  1939.             }
  1940.             columnsResultSet = dbmd.getColumns(this.catalog, null,
  1941.                     unquotedTableName, "%");
  1942.             HashMap columnNameToDefaultValueMap = new HashMap(this.fields.length /* at least this big... */);
  1943.             while (columnsResultSet.next()) {
  1944.                 String columnName = columnsResultSet.getString("COLUMN_NAME");
  1945.                 byte[] defaultValue = columnsResultSet.getBytes("COLUMN_DEF");
  1946.                 columnNameToDefaultValueMap.put(columnName, defaultValue);
  1947.             }
  1948.             int numFields = this.fields.length;
  1949.             this.defaultColumnValue = new byte[numFields][];
  1950.             for (int i = 0; i < numFields; i++) {
  1951.                 String tableName = this.fields[i].getOriginalName();
  1952.                 if ((tableName == null) || (tableName.length() == 0)) {
  1953.                     tableName = this.fields[i].getName();
  1954.                 }
  1955.                 if (tableName != null) {
  1956.                     byte[] defaultVal = (byte[]) columnNameToDefaultValueMap
  1957.                         .get(tableName);
  1958.                     this.defaultColumnValue[i] = defaultVal;
  1959.                 }
  1960.             }
  1961.         } finally {
  1962.             if (columnsResultSet != null) {
  1963.                 columnsResultSet.close();
  1964.                 columnsResultSet = null;
  1965.             }
  1966.         }
  1967.     }
  1968.     private void resetInserter() throws SQLException {
  1969.         inserter.clearParameters();
  1970.         for (int i = 0; i < fields.length; i++) {
  1971.             inserter.setNull(i + 1, 0);
  1972.         }
  1973.     }
  1974. }