EMMA Coverage Report (generated Fri May 26 15:35:26 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [UpdatableResultSet.java]

nameclass, %method, %block, %line, %
UpdatableResultSet.java100% (1/1)49%  (39/80)63%  (1790/2845)63%  (403.4/642)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class UpdatableResultSet100% (1/1)49%  (39/80)63%  (1790/2845)63%  (403.4/642)
UpdatableResultSet (long, long, Connection, Statement): void 0%   (0/1)0%   (0/42)0%   (0/14)
afterLast (): void 0%   (0/1)0%   (0/3)0%   (0/2)
isFirst (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
isLast (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
isUpdatable (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
prev (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
previous (): boolean 0%   (0/1)0%   (0/3)0%   (0/1)
relative (int): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
rowDeleted (): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
rowInserted (): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
rowUpdated (): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
updateAsciiStream (String, InputStream, int): void 0%   (0/1)0%   (0/8)0%   (0/2)
updateAsciiStream (int, InputStream, int): void 0%   (0/1)0%   (0/32)0%   (0/8)
updateBigDecimal (String, BigDecimal): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateBigDecimal (int, BigDecimal): void 0%   (0/1)0%   (0/42)0%   (0/10)
updateBlob (String, Blob): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateBlob (int, Blob): void 0%   (0/1)0%   (0/40)0%   (0/10)
updateBoolean (String, boolean): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateBoolean (int, boolean): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateByte (String, byte): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateBytes (String, byte []): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateBytes (int, byte []): void 0%   (0/1)0%   (0/30)0%   (0/8)
updateCharacterStream (String, Reader, int): void 0%   (0/1)0%   (0/8)0%   (0/2)
updateDate (String, Date): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateDate (int, Date): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateDouble (String, double): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateDouble (int, double): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateFloat (String, float): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateFloat (int, float): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateLong (String, long): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateLong (int, long): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateNull (String): void 0%   (0/1)0%   (0/6)0%   (0/2)
updateNull (int): void 0%   (0/1)0%   (0/30)0%   (0/8)
updateObject (String, Object, int): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateObject (int, Object, int): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateShort (String, short): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateShort (int, short): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateTime (String, Time): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateTime (int, Time): void 0%   (0/1)0%   (0/35)0%   (0/8)
updateTimestamp (String, Timestamp): void 0%   (0/1)0%   (0/7)0%   (0/2)
updateTimestamp (int, Timestamp): void 0%   (0/1)0%   (0/35)0%   (0/8)
realClose (boolean): void 100% (1/1)36%  (39/108)57%  (17/30)
updateObject (int, Object): void 100% (1/1)51%  (18/35)75%  (6/8)
deleteRow (): void 100% (1/1)52%  (96/184)67%  (22.8/34)
updateByte (int, byte): void 100% (1/1)60%  (21/35)50%  (4/8)
refreshRow (): void 100% (1/1)72%  (177/246)77%  (41.4/54)
updateClob (int, Clob): void 100% (1/1)73%  (11/15)75%  (3/4)
updateString (int, String): void 100% (1/1)75%  (47/63)83%  (10/12)
checkUpdatability (): void 100% (1/1)80%  (207/259)75%  (52.4/70)
moveToCurrentRow (): void 100% (1/1)80%  (16/20)86%  (6/7)
updateBinaryStream (int, InputStream, int): void 100% (1/1)81%  (34/42)90%  (9/10)
updateCharacterStream (int, Reader, int): void 100% (1/1)81%  (34/42)90%  (9/10)
updateRow (): void 100% (1/1)82%  (18/22)88%  (7/8)
getConcurrency (): int 100% (1/1)86%  (6/7)86%  (0.9/1)
getQuotedIdChar (): String 100% (1/1)88%  (21/24)86%  (6/7)
insertRow (): void 100% (1/1)92%  (67/73)94%  (15/16)
syncUpdate (): void 100% (1/1)93%  (122/131)95%  (20/21)
extractDefaultValues (): void 100% (1/1)96%  (94/98)98%  (22.4/23)
generateStatements (): void 100% (1/1)100% (355/356)100% (67/67)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
UpdatableResultSet (String, Field [], RowData, Connection, Statement): void 100% (1/1)100% (43/43)100% (14/14)
absolute (int): boolean 100% (1/1)100% (4/4)100% (1/1)
beforeFirst (): void 100% (1/1)100% (3/3)100% (2/2)
cancelRowUpdates (): void 100% (1/1)100% (12/12)100% (5/5)
checkRowPos (): void 100% (1/1)100% (8/8)100% (4/4)
first (): boolean 100% (1/1)100% (3/3)100% (1/1)
getCharConverter (): SingleByteCharsetConverter 100% (1/1)100% (25/25)100% (6/6)
isAfterLast (): boolean 100% (1/1)100% (3/3)100% (1/1)
isBeforeFirst (): boolean 100% (1/1)100% (3/3)100% (1/1)
last (): boolean 100% (1/1)100% (3/3)100% (1/1)
moveToInsertRow (): void 100% (1/1)100% (200/200)100% (29/29)
next (): boolean 100% (1/1)100% (3/3)100% (1/1)
resetInserter (): void 100% (1/1)100% (20/20)100% (4/4)
setResultSetConcurrency (int): void 100% (1/1)100% (4/4)100% (2/2)
stripBinaryPrefix (byte []): byte [] 100% (1/1)100% (5/5)100% (1/1)
updateBinaryStream (String, InputStream, int): void 100% (1/1)100% (8/8)100% (2/2)
updateInt (String, int): void 100% (1/1)100% (7/7)100% (2/2)
updateInt (int, int): void 100% (1/1)100% (35/35)100% (8/8)
updateObject (String, Object): void 100% (1/1)100% (7/7)100% (2/2)
updateString (String, String): void 100% (1/1)100% (7/7)100% (2/2)

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

[all classes][com.mysql.jdbc]
EMMA 2.0.4217 (C) Vladimir Roubtsov