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 | */ |
25 | package com.mysql.jdbc; |
26 | |
27 | import com.mysql.jdbc.profiler.ProfileEventSink; |
28 | import com.mysql.jdbc.profiler.ProfilerEvent; |
29 | |
30 | import java.math.BigDecimal; |
31 | |
32 | import java.sql.SQLException; |
33 | |
34 | import java.util.ArrayList; |
35 | import java.util.HashMap; |
36 | import java.util.List; |
37 | |
38 | /** |
39 | * A result set that is updatable. |
40 | * |
41 | * @author Mark Matthews |
42 | */ |
43 | public 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 | } |