0001: /*
0002: Copyright (C) 2002-2007 MySQL AB
0003:
0004: This program is free software; you can redistribute it and/or modify
0005: it under the terms of version 2 of the GNU General Public License as
0006: published by the Free Software Foundation.
0007:
0008: There are special exceptions to the terms and conditions of the GPL
0009: as it is applied to this software. View the full text of the
0010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
0011: software distribution.
0012:
0013: This program is distributed in the hope that it will be useful,
0014: but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: GNU General Public License for more details.
0017:
0018: You should have received a copy of the GNU General Public License
0019: along with this program; if not, write to the Free Software
0020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0021:
0022:
0023:
0024: */
0025: package com.mysql.jdbc;
0026:
0027: import com.mysql.jdbc.profiler.ProfileEventSink;
0028: import com.mysql.jdbc.profiler.ProfilerEvent;
0029:
0030: import java.io.InputStream;
0031: import java.io.Reader;
0032: import java.math.BigDecimal;
0033:
0034: import java.sql.SQLException;
0035:
0036: import java.util.ArrayList;
0037: import java.util.HashMap;
0038: import java.util.Iterator;
0039: import java.util.List;
0040: import java.util.Map;
0041: import java.util.TreeMap;
0042:
0043: /**
0044: * A result set that is updatable.
0045: *
0046: * @author Mark Matthews
0047: */
0048: public class UpdatableResultSet extends ResultSetImpl {
0049: /** Marker for 'stream' data when doing INSERT rows */
0050: protected final static byte[] STREAM_DATA_MARKER = "** STREAM DATA **" //$NON-NLS-1$
0051: .getBytes();
0052:
0053: protected SingleByteCharsetConverter charConverter;
0054:
0055: private String charEncoding;
0056:
0057: /** What is the default value for the column? */
0058: private byte[][] defaultColumnValue;
0059:
0060: /** PreparedStatement used to delete data */
0061: private com.mysql.jdbc.PreparedStatement deleter = null;
0062:
0063: private String deleteSQL = null;
0064:
0065: private boolean initializedCharConverter = false;
0066:
0067: /** PreparedStatement used to insert data */
0068: protected com.mysql.jdbc.PreparedStatement inserter = null;
0069:
0070: private String insertSQL = null;
0071:
0072: /** Is this result set updateable? */
0073: private boolean isUpdatable = false;
0074:
0075: /** Reason the result set is not updatable */
0076: private String notUpdatableReason = null;
0077:
0078: /** List of primary keys */
0079: private List primaryKeyIndicies = null;
0080:
0081: private String qualifiedAndQuotedTableName;
0082:
0083: private String quotedIdChar = null;
0084:
0085: /** PreparedStatement used to refresh data */
0086: private com.mysql.jdbc.PreparedStatement refresher;
0087:
0088: private String refreshSQL = null;
0089:
0090: /** The binary data for the 'current' row */
0091: private ResultSetRow savedCurrentRow;
0092:
0093: /** PreparedStatement used to delete data */
0094: protected com.mysql.jdbc.PreparedStatement updater = null;
0095:
0096: /** SQL for in-place modifcation */
0097: private String updateSQL = null;
0098:
0099: private boolean populateInserterWithDefaultValues = false;
0100:
0101: private Map databasesUsedToTablesUsed = null;
0102:
0103: /**
0104: * Creates a new ResultSet object.
0105: *
0106: * @param catalog
0107: * the database in use when we were created
0108: * @param fields
0109: * an array of Field objects (basically, the ResultSet MetaData)
0110: * @param tuples
0111: * actual row data
0112: * @param conn
0113: * the Connection that created us.
0114: * @param creatorStmt
0115: * DOCUMENT ME!
0116: *
0117: * @throws SQLException
0118: * DOCUMENT ME!
0119: */
0120: protected UpdatableResultSet(String catalog, Field[] fields,
0121: RowData tuples, ConnectionImpl conn,
0122: StatementImpl creatorStmt) throws SQLException {
0123: super (catalog, fields, tuples, conn, creatorStmt);
0124: checkUpdatability();
0125: this .populateInserterWithDefaultValues = this .connection
0126: .getPopulateInsertRowWithDefaultValues();
0127: }
0128:
0129: /**
0130: * JDBC 2.0
0131: *
0132: * <p>
0133: * Move to an absolute row number in the result set.
0134: * </p>
0135: *
0136: * <p>
0137: * If row is positive, moves to an absolute row with respect to the
0138: * beginning of the result set. The first row is row 1, the second is row 2,
0139: * etc.
0140: * </p>
0141: *
0142: * <p>
0143: * If row is negative, moves to an absolute row position with respect to the
0144: * end of result set. For example, calling absolute(-1) positions the cursor
0145: * on the last row, absolute(-2) indicates the next-to-last row, etc.
0146: * </p>
0147: *
0148: * <p>
0149: * An attempt to position the cursor beyond the first/last row in the result
0150: * set, leaves the cursor before/after the first/last row, respectively.
0151: * </p>
0152: *
0153: * <p>
0154: * Note: Calling absolute(1) is the same as calling first(). Calling
0155: * absolute(-1) is the same as calling last().
0156: * </p>
0157: *
0158: * @param row
0159: * DOCUMENT ME!
0160: *
0161: * @return true if on the result set, false if off.
0162: *
0163: * @exception SQLException
0164: * if a database-access error occurs, or row is 0, or result
0165: * set type is TYPE_FORWARD_ONLY.
0166: */
0167: public synchronized boolean absolute(int row) throws SQLException {
0168: return super .absolute(row);
0169: }
0170:
0171: /**
0172: * JDBC 2.0
0173: *
0174: * <p>
0175: * Moves to the end of the result set, just after the last row. Has no
0176: * effect if the result set contains no rows.
0177: * </p>
0178: *
0179: * @exception SQLException
0180: * if a database-access error occurs, or result set type is
0181: * TYPE_FORWARD_ONLY.
0182: */
0183: public synchronized void afterLast() throws SQLException {
0184: super .afterLast();
0185: }
0186:
0187: /**
0188: * JDBC 2.0
0189: *
0190: * <p>
0191: * Moves to the front of the result set, just before the first row. Has no
0192: * effect if the result set contains no rows.
0193: * </p>
0194: *
0195: * @exception SQLException
0196: * if a database-access error occurs, or result set type is
0197: * TYPE_FORWARD_ONLY
0198: */
0199: public synchronized void beforeFirst() throws SQLException {
0200: super .beforeFirst();
0201: }
0202:
0203: /**
0204: * JDBC 2.0 The cancelRowUpdates() method may be called after calling an
0205: * updateXXX() method(s) and before calling updateRow() to rollback the
0206: * updates made to a row. If no updates have been made or updateRow() has
0207: * already been called, then this method has no effect.
0208: *
0209: * @exception SQLException
0210: * if a database-access error occurs, or if called when on
0211: * the insert row.
0212: */
0213: public synchronized void cancelRowUpdates() throws SQLException {
0214: checkClosed();
0215:
0216: if (this .doingUpdates) {
0217: this .doingUpdates = false;
0218: this .updater.clearParameters();
0219: }
0220: }
0221:
0222: /*
0223: * (non-Javadoc)
0224: *
0225: * @see com.mysql.jdbc.ResultSet#checkRowPos()
0226: */
0227: protected void checkRowPos() throws SQLException {
0228: checkClosed();
0229:
0230: if (!this .onInsertRow) {
0231: super .checkRowPos();
0232: }
0233: }
0234:
0235: /**
0236: * Is this ResultSet updateable?
0237: *
0238: * @throws SQLException
0239: * DOCUMENT ME!
0240: */
0241: protected void checkUpdatability() throws SQLException {
0242: if (this .fields == null) {
0243: // we've been created to be populated with cached
0244: // metadata, and we don't have the metadata yet,
0245: // we'll be called again by
0246: // Connection.initializeResultsMetadataFromCache()
0247: // when the metadata has been made available
0248:
0249: return;
0250: }
0251:
0252: String singleTableName = null;
0253: String catalogName = null;
0254:
0255: int primaryKeyCount = 0;
0256:
0257: // We can only do this if we know that there is a currently
0258: // selected database, or if we're talking to a > 4.1 version
0259: // of MySQL server (as it returns database names in field
0260: // info)
0261: //
0262: if ((this .catalog == null) || (this .catalog.length() == 0)) {
0263: this .catalog = this .fields[0].getDatabaseName();
0264:
0265: if ((this .catalog == null) || (this .catalog.length() == 0)) {
0266: throw SQLError.createSQLException(Messages
0267: .getString("UpdatableResultSet.43") //$NON-NLS-1$
0268: , SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
0269: }
0270: }
0271:
0272: if (this .fields.length > 0) {
0273: singleTableName = this .fields[0].getOriginalTableName();
0274: catalogName = this .fields[0].getDatabaseName();
0275:
0276: if (singleTableName == null) {
0277: singleTableName = this .fields[0].getTableName();
0278: catalogName = this .catalog;
0279: }
0280:
0281: if (singleTableName != null
0282: && singleTableName.length() == 0) {
0283: this .isUpdatable = false;
0284: this .notUpdatableReason = Messages
0285: .getString("NotUpdatableReason.3");
0286:
0287: return;
0288: }
0289:
0290: if (this .fields[0].isPrimaryKey()) {
0291: primaryKeyCount++;
0292: }
0293:
0294: //
0295: // References only one table?
0296: //
0297: for (int i = 1; i < this .fields.length; i++) {
0298: String otherTableName = this .fields[i]
0299: .getOriginalTableName();
0300: String otherCatalogName = this .fields[i]
0301: .getDatabaseName();
0302:
0303: if (otherTableName == null) {
0304: otherTableName = this .fields[i].getTableName();
0305: otherCatalogName = this .catalog;
0306: }
0307:
0308: if (otherTableName != null
0309: && otherTableName.length() == 0) {
0310: this .isUpdatable = false;
0311: this .notUpdatableReason = Messages
0312: .getString("NotUpdatableReason.3");
0313:
0314: return;
0315: }
0316:
0317: if ((singleTableName == null)
0318: || !otherTableName.equals(singleTableName)) {
0319: this .isUpdatable = false;
0320: this .notUpdatableReason = Messages
0321: .getString("NotUpdatableReason.0");
0322:
0323: return;
0324: }
0325:
0326: // Can't reference more than one database
0327: if ((catalogName == null)
0328: || !otherCatalogName.equals(catalogName)) {
0329: this .isUpdatable = false;
0330: this .notUpdatableReason = Messages
0331: .getString("NotUpdatableReason.1");
0332:
0333: return;
0334: }
0335:
0336: if (this .fields[i].isPrimaryKey()) {
0337: primaryKeyCount++;
0338: }
0339: }
0340:
0341: if ((singleTableName == null)
0342: || (singleTableName.length() == 0)) {
0343: this .isUpdatable = false;
0344: this .notUpdatableReason = Messages
0345: .getString("NotUpdatableReason.2");
0346:
0347: return;
0348: }
0349: } else {
0350: this .isUpdatable = false;
0351: this .notUpdatableReason = Messages
0352: .getString("NotUpdatableReason.3");
0353:
0354: return;
0355: }
0356:
0357: if (this .connection.getStrictUpdates()) {
0358: java.sql.DatabaseMetaData dbmd = this .connection
0359: .getMetaData();
0360:
0361: java.sql.ResultSet rs = null;
0362: HashMap primaryKeyNames = new HashMap();
0363:
0364: try {
0365: rs = dbmd.getPrimaryKeys(catalogName, null,
0366: singleTableName);
0367:
0368: while (rs.next()) {
0369: String keyName = rs.getString(4);
0370: keyName = keyName.toUpperCase();
0371: primaryKeyNames.put(keyName, keyName);
0372: }
0373: } finally {
0374: if (rs != null) {
0375: try {
0376: rs.close();
0377: } catch (Exception ex) {
0378: AssertionFailedException.shouldNotHappen(ex);
0379: }
0380:
0381: rs = null;
0382: }
0383: }
0384:
0385: int existingPrimaryKeysCount = primaryKeyNames.size();
0386:
0387: if (existingPrimaryKeysCount == 0) {
0388: this .isUpdatable = false;
0389: this .notUpdatableReason = Messages
0390: .getString("NotUpdatableReason.5");
0391:
0392: return; // we can't update tables w/o keys
0393: }
0394:
0395: //
0396: // Contains all primary keys?
0397: //
0398: for (int i = 0; i < this .fields.length; i++) {
0399: if (this .fields[i].isPrimaryKey()) {
0400: String columnNameUC = this .fields[i].getName()
0401: .toUpperCase();
0402:
0403: if (primaryKeyNames.remove(columnNameUC) == null) {
0404: // try original name
0405: String originalName = this .fields[i]
0406: .getOriginalName();
0407:
0408: if (originalName != null) {
0409: if (primaryKeyNames.remove(originalName
0410: .toUpperCase()) == null) {
0411: // we don't know about this key, so give up :(
0412: this .isUpdatable = false;
0413: this .notUpdatableReason = Messages
0414: .getString(
0415: "NotUpdatableReason.6",
0416: new Object[] { originalName });
0417:
0418: return;
0419: }
0420: }
0421: }
0422: }
0423: }
0424:
0425: this .isUpdatable = primaryKeyNames.isEmpty();
0426:
0427: if (!this .isUpdatable) {
0428: if (existingPrimaryKeysCount > 1) {
0429: this .notUpdatableReason = Messages
0430: .getString("NotUpdatableReason.7");
0431: } else {
0432: this .notUpdatableReason = Messages
0433: .getString("NotUpdatableReason.4");
0434: }
0435:
0436: return;
0437: }
0438: }
0439:
0440: //
0441: // Must have at least one primary key
0442: //
0443: if (primaryKeyCount == 0) {
0444: this .isUpdatable = false;
0445: this .notUpdatableReason = Messages
0446: .getString("NotUpdatableReason.4");
0447:
0448: return;
0449: }
0450:
0451: this .isUpdatable = true;
0452: this .notUpdatableReason = null;
0453:
0454: return;
0455: }
0456:
0457: /**
0458: * JDBC 2.0 Delete the current row from the result set and the underlying
0459: * database. Cannot be called when on the insert row.
0460: *
0461: * @exception SQLException
0462: * if a database-access error occurs, or if called when on
0463: * the insert row.
0464: * @throws SQLException
0465: * if the ResultSet is not updatable or some other error occurs
0466: */
0467: public synchronized void deleteRow() throws SQLException {
0468: checkClosed();
0469:
0470: if (!this .isUpdatable) {
0471: throw new NotUpdatable(this .notUpdatableReason);
0472: }
0473:
0474: if (this .onInsertRow) {
0475: throw SQLError.createSQLException(Messages
0476: .getString("UpdatableResultSet.1")); //$NON-NLS-1$
0477: } else if (this .rowData.size() == 0) {
0478: throw SQLError.createSQLException(Messages
0479: .getString("UpdatableResultSet.2")); //$NON-NLS-1$
0480: } else if (isBeforeFirst()) {
0481: throw SQLError.createSQLException(Messages
0482: .getString("UpdatableResultSet.3")); //$NON-NLS-1$
0483: } else if (isAfterLast()) {
0484: throw SQLError.createSQLException(Messages
0485: .getString("UpdatableResultSet.4")); //$NON-NLS-1$
0486: }
0487:
0488: if (this .deleter == null) {
0489: if (this .deleteSQL == null) {
0490: generateStatements();
0491: }
0492:
0493: this .deleter = this .connection
0494: .clientPrepareStatement(this .deleteSQL);
0495: }
0496:
0497: this .deleter.clearParameters();
0498:
0499: String characterEncoding = null;
0500:
0501: if (this .connection.getUseUnicode()) {
0502: characterEncoding = this .connection.getEncoding();
0503: }
0504:
0505: //
0506: // FIXME: Use internal routines where possible for character
0507: // conversion!
0508: try {
0509: int numKeys = this .primaryKeyIndicies.size();
0510:
0511: if (numKeys == 1) {
0512: int index = ((Integer) this .primaryKeyIndicies.get(0))
0513: .intValue();
0514: String currentVal = ((characterEncoding == null) ? new String(
0515: (byte[]) this .this Row.getColumnValue(index))
0516: : new String((byte[]) this .this Row
0517: .getColumnValue(index),
0518: characterEncoding));
0519: this .deleter.setString(1, currentVal);
0520: } else {
0521: for (int i = 0; i < numKeys; i++) {
0522: int index = ((Integer) this .primaryKeyIndicies
0523: .get(i)).intValue();
0524: String currentVal = ((characterEncoding == null) ? new String(
0525: (byte[]) this .this Row.getColumnValue(index))
0526: : new String((byte[]) this .this Row
0527: .getColumnValue(index),
0528: characterEncoding));
0529: this .deleter.setString(i + 1, currentVal);
0530: }
0531: }
0532:
0533: this .deleter.executeUpdate();
0534: this .rowData.removeRow(this .rowData.getCurrentRowNumber());
0535: } catch (java.io.UnsupportedEncodingException encodingEx) {
0536: throw SQLError.createSQLException(Messages.getString(
0537: "UpdatableResultSet.39", //$NON-NLS-1$
0538: new Object[] { this .charEncoding }) //$NON-NLS-1$
0539: , SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$ //$NON-NLS-2$
0540: }
0541: }
0542:
0543: private synchronized void extractDefaultValues()
0544: throws SQLException {
0545: java.sql.DatabaseMetaData dbmd = this .connection.getMetaData();
0546: this .defaultColumnValue = new byte[this .fields.length][];
0547:
0548: java.sql.ResultSet columnsResultSet = null;
0549: Iterator referencedDbs = this .databasesUsedToTablesUsed
0550: .entrySet().iterator();
0551:
0552: while (referencedDbs.hasNext()) {
0553: Map.Entry dbEntry = (Map.Entry) referencedDbs.next();
0554: String databaseName = dbEntry.getKey().toString();
0555:
0556: Iterator referencedTables = ((Map) dbEntry.getValue())
0557: .entrySet().iterator();
0558:
0559: while (referencedTables.hasNext()) {
0560: Map.Entry tableEntry = (Map.Entry) referencedTables
0561: .next();
0562: String tableName = tableEntry.getKey().toString();
0563: Map columnNamesToIndices = (Map) tableEntry.getValue();
0564:
0565: try {
0566: columnsResultSet = dbmd.getColumns(this .catalog,
0567: null, tableName, "%"); //$NON-NLS-1$
0568:
0569: while (columnsResultSet.next()) {
0570: String columnName = columnsResultSet
0571: .getString("COLUMN_NAME"); //$NON-NLS-1$
0572: byte[] defaultValue = columnsResultSet
0573: .getBytes("COLUMN_DEF"); //$NON-NLS-1$
0574:
0575: if (columnNamesToIndices
0576: .containsKey(columnName)) {
0577: int localColumnIndex = ((Integer) columnNamesToIndices
0578: .get(columnName)).intValue();
0579:
0580: this .defaultColumnValue[localColumnIndex] = defaultValue;
0581: } // else assert?
0582: }
0583: } finally {
0584: if (columnsResultSet != null) {
0585: columnsResultSet.close();
0586:
0587: columnsResultSet = null;
0588: }
0589: }
0590: }
0591: }
0592: }
0593:
0594: /**
0595: * JDBC 2.0
0596: *
0597: * <p>
0598: * Moves to the first row in the result set.
0599: * </p>
0600: *
0601: * @return true if on a valid row, false if no rows in the result set.
0602: *
0603: * @exception SQLException
0604: * if a database-access error occurs, or result set type is
0605: * TYPE_FORWARD_ONLY.
0606: */
0607: public synchronized boolean first() throws SQLException {
0608: return super .first();
0609: }
0610:
0611: /**
0612: * Figure out whether or not this ResultSet is updateable, and if so,
0613: * generate the PreparedStatements to support updates.
0614: *
0615: * @throws SQLException
0616: * DOCUMENT ME!
0617: * @throws NotUpdatable
0618: * DOCUMENT ME!
0619: */
0620: protected synchronized void generateStatements()
0621: throws SQLException {
0622: if (!this .isUpdatable) {
0623: this .doingUpdates = false;
0624: this .onInsertRow = false;
0625:
0626: throw new NotUpdatable(this .notUpdatableReason);
0627: }
0628:
0629: String quotedId = getQuotedIdChar();
0630:
0631: Map tableNamesSoFar = null;
0632:
0633: if (this .connection.lowerCaseTableNames()) {
0634: tableNamesSoFar = new TreeMap(String.CASE_INSENSITIVE_ORDER);
0635: this .databasesUsedToTablesUsed = new TreeMap(
0636: String.CASE_INSENSITIVE_ORDER);
0637: } else {
0638: tableNamesSoFar = new TreeMap();
0639: this .databasesUsedToTablesUsed = new TreeMap();
0640: }
0641:
0642: this .primaryKeyIndicies = new ArrayList();
0643:
0644: StringBuffer fieldValues = new StringBuffer();
0645: StringBuffer keyValues = new StringBuffer();
0646: StringBuffer columnNames = new StringBuffer();
0647: StringBuffer insertPlaceHolders = new StringBuffer();
0648: StringBuffer allTablesBuf = new StringBuffer();
0649: Map columnIndicesToTable = new HashMap();
0650:
0651: boolean firstTime = true;
0652: boolean keysFirstTime = true;
0653:
0654: String equalsStr = this .connection
0655: .versionMeetsMinimum(3, 23, 0) ? "<=>" : "=";
0656:
0657: for (int i = 0; i < this .fields.length; i++) {
0658: StringBuffer tableNameBuffer = new StringBuffer();
0659: Map columnNameToIndex = null;
0660:
0661: // FIXME: What about no table?
0662: if (this .fields[i].getOriginalTableName() != null) {
0663:
0664: String databaseName = this .fields[i].getDatabaseName();
0665:
0666: if ((databaseName != null)
0667: && (databaseName.length() > 0)) {
0668: tableNameBuffer.append(quotedId);
0669: tableNameBuffer.append(databaseName);
0670: tableNameBuffer.append(quotedId);
0671: tableNameBuffer.append('.');
0672: }
0673:
0674: String tableOnlyName = this .fields[i]
0675: .getOriginalTableName();
0676:
0677: tableNameBuffer.append(quotedId);
0678: tableNameBuffer.append(tableOnlyName);
0679: tableNameBuffer.append(quotedId);
0680:
0681: String fqTableName = tableNameBuffer.toString();
0682:
0683: if (!tableNamesSoFar.containsKey(fqTableName)) {
0684: if (!tableNamesSoFar.isEmpty()) {
0685: allTablesBuf.append(',');
0686: }
0687:
0688: allTablesBuf.append(fqTableName);
0689: tableNamesSoFar.put(fqTableName, fqTableName);
0690: }
0691:
0692: columnIndicesToTable.put(new Integer(i), fqTableName);
0693:
0694: columnNameToIndex = getColumnsToIndexMapForTableAndDB(
0695: databaseName, tableOnlyName);
0696: } else {
0697: String tableOnlyName = this .fields[i].getTableName();
0698:
0699: if (tableOnlyName != null) {
0700: tableNameBuffer.append(quotedId);
0701: tableNameBuffer.append(tableOnlyName);
0702: tableNameBuffer.append(quotedId);
0703:
0704: String fqTableName = tableNameBuffer.toString();
0705:
0706: if (!tableNamesSoFar.containsKey(fqTableName)) {
0707: if (!tableNamesSoFar.isEmpty()) {
0708: allTablesBuf.append(',');
0709: }
0710:
0711: allTablesBuf.append(fqTableName);
0712: tableNamesSoFar.put(fqTableName, fqTableName);
0713: }
0714:
0715: columnIndicesToTable.put(new Integer(i),
0716: fqTableName);
0717:
0718: columnNameToIndex = getColumnsToIndexMapForTableAndDB(
0719: this .catalog, tableOnlyName);
0720: }
0721: }
0722:
0723: String originalColumnName = this .fields[i]
0724: .getOriginalName();
0725: String columnName = null;
0726:
0727: if (this .connection.getIO().hasLongColumnInfo()
0728: && (originalColumnName != null)
0729: && (originalColumnName.length() > 0)) {
0730: columnName = originalColumnName;
0731: } else {
0732: columnName = this .fields[i].getName();
0733: }
0734:
0735: if (columnNameToIndex != null && columnName != null) {
0736: columnNameToIndex.put(columnName, new Integer(i));
0737: }
0738:
0739: String originalTableName = this .fields[i]
0740: .getOriginalTableName();
0741: String tableName = null;
0742:
0743: if (this .connection.getIO().hasLongColumnInfo()
0744: && (originalTableName != null)
0745: && (originalTableName.length() > 0)) {
0746: tableName = originalTableName;
0747: } else {
0748: tableName = this .fields[i].getTableName();
0749: }
0750:
0751: StringBuffer fqcnBuf = new StringBuffer();
0752: String databaseName = this .fields[i].getDatabaseName();
0753:
0754: if (databaseName != null && databaseName.length() > 0) {
0755: fqcnBuf.append(quotedId);
0756: fqcnBuf.append(databaseName);
0757: fqcnBuf.append(quotedId);
0758: fqcnBuf.append('.');
0759: }
0760:
0761: fqcnBuf.append(quotedId);
0762: fqcnBuf.append(tableName);
0763: fqcnBuf.append(quotedId);
0764: fqcnBuf.append('.');
0765: fqcnBuf.append(quotedId);
0766: fqcnBuf.append(columnName);
0767: fqcnBuf.append(quotedId);
0768:
0769: String qualifiedColumnName = fqcnBuf.toString();
0770:
0771: if (this .fields[i].isPrimaryKey()) {
0772: this .primaryKeyIndicies
0773: .add(Constants.integerValueOf(i));
0774:
0775: if (!keysFirstTime) {
0776: keyValues.append(" AND "); //$NON-NLS-1$
0777: } else {
0778: keysFirstTime = false;
0779: }
0780:
0781: keyValues.append(qualifiedColumnName);
0782: keyValues.append(equalsStr);
0783: keyValues.append("?"); //$NON-NLS-1$
0784: }
0785:
0786: if (firstTime) {
0787: firstTime = false;
0788: fieldValues.append("SET "); //$NON-NLS-1$
0789: } else {
0790: fieldValues.append(","); //$NON-NLS-1$
0791: columnNames.append(","); //$NON-NLS-1$
0792: insertPlaceHolders.append(","); //$NON-NLS-1$
0793: }
0794:
0795: insertPlaceHolders.append("?"); //$NON-NLS-1$
0796:
0797: columnNames.append(qualifiedColumnName);
0798:
0799: fieldValues.append(qualifiedColumnName);
0800: fieldValues.append("=?"); //$NON-NLS-1$
0801: }
0802:
0803: this .qualifiedAndQuotedTableName = allTablesBuf.toString();
0804:
0805: this .updateSQL = "UPDATE " + this .qualifiedAndQuotedTableName + " " //$NON-NLS-1$ //$NON-NLS-2$
0806: + fieldValues.toString() //$NON-NLS-1$ //$NON-NLS-2$
0807: + " WHERE " + keyValues.toString(); //$NON-NLS-1$
0808: this .insertSQL = "INSERT INTO " + this .qualifiedAndQuotedTableName //$NON-NLS-1$
0809: + " (" + columnNames.toString() //$NON-NLS-1$ //$NON-NLS-2$
0810: + ") VALUES (" + insertPlaceHolders.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
0811: this .refreshSQL = "SELECT " + columnNames.toString() + " FROM " //$NON-NLS-1$ //$NON-NLS-2$
0812: + this .qualifiedAndQuotedTableName //$NON-NLS-1$ //$NON-NLS-2$
0813: + " WHERE " + keyValues.toString(); //$NON-NLS-1$
0814: this .deleteSQL = "DELETE FROM " + this .qualifiedAndQuotedTableName //$NON-NLS-1$
0815: + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$
0816: + keyValues.toString();
0817: }
0818:
0819: private Map getColumnsToIndexMapForTableAndDB(String databaseName,
0820: String tableName) {
0821: Map nameToIndex;
0822: Map tablesUsedToColumnsMap = (Map) this .databasesUsedToTablesUsed
0823: .get(databaseName);
0824:
0825: if (tablesUsedToColumnsMap == null) {
0826: if (this .connection.lowerCaseTableNames()) {
0827: tablesUsedToColumnsMap = new TreeMap(
0828: String.CASE_INSENSITIVE_ORDER);
0829: } else {
0830: tablesUsedToColumnsMap = new TreeMap();
0831: }
0832:
0833: this .databasesUsedToTablesUsed.put(databaseName,
0834: tablesUsedToColumnsMap);
0835: }
0836:
0837: nameToIndex = (Map) tablesUsedToColumnsMap.get(tableName);
0838:
0839: if (nameToIndex == null) {
0840: nameToIndex = new HashMap();
0841: tablesUsedToColumnsMap.put(tableName, nameToIndex);
0842: }
0843:
0844: return nameToIndex;
0845: }
0846:
0847: private synchronized SingleByteCharsetConverter getCharConverter()
0848: throws SQLException {
0849: if (!this .initializedCharConverter) {
0850: this .initializedCharConverter = true;
0851:
0852: if (this .connection.getUseUnicode()) {
0853: this .charEncoding = connection.getEncoding();
0854: this .charConverter = this .connection
0855: .getCharsetConverter(this .charEncoding);
0856: }
0857: }
0858:
0859: return this .charConverter;
0860: }
0861:
0862: /**
0863: * JDBC 2.0 Return the concurrency of this result set. The concurrency used
0864: * is determined by the statement that created the result set.
0865: *
0866: * @return the concurrency type, CONCUR_READ_ONLY, etc.
0867: *
0868: * @exception SQLException
0869: * if a database-access error occurs
0870: */
0871: public int getConcurrency() throws SQLException {
0872: return (this .isUpdatable ? CONCUR_UPDATABLE : CONCUR_READ_ONLY);
0873: }
0874:
0875: private synchronized String getQuotedIdChar() throws SQLException {
0876: if (this .quotedIdChar == null) {
0877: boolean useQuotedIdentifiers = this .connection
0878: .supportsQuotedIdentifiers();
0879:
0880: if (useQuotedIdentifiers) {
0881: java.sql.DatabaseMetaData dbmd = this .connection
0882: .getMetaData();
0883: this .quotedIdChar = dbmd.getIdentifierQuoteString();
0884: } else {
0885: this .quotedIdChar = ""; //$NON-NLS-1$
0886: }
0887: }
0888:
0889: return this .quotedIdChar;
0890: }
0891:
0892: /**
0893: * JDBC 2.0 Insert the contents of the insert row into the result set and
0894: * the database. Must be on the insert row when this method is called.
0895: *
0896: * @exception SQLException
0897: * if a database-access error occurs, if called when not on
0898: * the insert row, or if all non-nullable columns in the
0899: * insert row have not been given a value
0900: */
0901: public synchronized void insertRow() throws SQLException {
0902: checkClosed();
0903:
0904: if (!this .onInsertRow) {
0905: throw SQLError.createSQLException(Messages
0906: .getString("UpdatableResultSet.7")); //$NON-NLS-1$
0907: }
0908:
0909: this .inserter.executeUpdate();
0910:
0911: long autoIncrementId = this .inserter.getLastInsertID();
0912: int numFields = this .fields.length;
0913: byte[][] newRow = new byte[numFields][];
0914:
0915: for (int i = 0; i < numFields; i++) {
0916: if (this .inserter.isNull(i)) {
0917: newRow[i] = null;
0918: } else {
0919: newRow[i] = this .inserter.getBytesRepresentation(i);
0920: }
0921:
0922: //
0923: // WARN: This non-variant only holds if MySQL never allows more
0924: // than one auto-increment key (which is the way it is _today_)
0925: //
0926: if (this .fields[i].isAutoIncrement() && autoIncrementId > 0) {
0927: newRow[i] = String.valueOf(autoIncrementId).getBytes();
0928: this .inserter
0929: .setBytesNoEscapeNoQuotes(i + 1, newRow[i]);
0930: }
0931: }
0932:
0933: ResultSetRow resultSetRow = new ByteArrayRow(newRow);
0934:
0935: refreshRow(this .inserter, resultSetRow);
0936:
0937: this .rowData.addRow(resultSetRow);
0938: resetInserter();
0939: }
0940:
0941: /**
0942: * JDBC 2.0
0943: *
0944: * <p>
0945: * Determine if the cursor is after the last row in the result set.
0946: * </p>
0947: *
0948: * @return true if after the last row, false otherwise. Returns false when
0949: * the result set contains no rows.
0950: *
0951: * @exception SQLException
0952: * if a database-access error occurs.
0953: */
0954: public synchronized boolean isAfterLast() throws SQLException {
0955: return super .isAfterLast();
0956: }
0957:
0958: /**
0959: * JDBC 2.0
0960: *
0961: * <p>
0962: * Determine if the cursor is before the first row in the result set.
0963: * </p>
0964: *
0965: * @return true if before the first row, false otherwise. Returns false when
0966: * the result set contains no rows.
0967: *
0968: * @exception SQLException
0969: * if a database-access error occurs.
0970: */
0971: public synchronized boolean isBeforeFirst() throws SQLException {
0972: return super .isBeforeFirst();
0973: }
0974:
0975: /**
0976: * JDBC 2.0
0977: *
0978: * <p>
0979: * Determine if the cursor is on the first row of the result set.
0980: * </p>
0981: *
0982: * @return true if on the first row, false otherwise.
0983: *
0984: * @exception SQLException
0985: * if a database-access error occurs.
0986: */
0987: public synchronized boolean isFirst() throws SQLException {
0988: return super .isFirst();
0989: }
0990:
0991: /**
0992: * JDBC 2.0
0993: *
0994: * <p>
0995: * Determine if the cursor is on the last row of the result set. Note:
0996: * Calling isLast() may be expensive since the JDBC driver might need to
0997: * fetch ahead one row in order to determine whether the current row is the
0998: * last row in the result set.
0999: * </p>
1000: *
1001: * @return true if on the last row, false otherwise.
1002: *
1003: * @exception SQLException
1004: * if a database-access error occurs.
1005: */
1006: public synchronized boolean isLast() throws SQLException {
1007: return super .isLast();
1008: }
1009:
1010: boolean isUpdatable() {
1011: return this .isUpdatable;
1012: }
1013:
1014: /**
1015: * JDBC 2.0
1016: *
1017: * <p>
1018: * Moves to the last row in the result set.
1019: * </p>
1020: *
1021: * @return true if on a valid row, false if no rows in the result set.
1022: *
1023: * @exception SQLException
1024: * if a database-access error occurs, or result set type is
1025: * TYPE_FORWARD_ONLY.
1026: */
1027: public synchronized boolean last() throws SQLException {
1028: return super .last();
1029: }
1030:
1031: /**
1032: * JDBC 2.0 Move the cursor to the remembered cursor position, usually the
1033: * current row. Has no effect unless the cursor is on the insert row.
1034: *
1035: * @exception SQLException
1036: * if a database-access error occurs, or the result set is
1037: * not updatable
1038: * @throws SQLException
1039: * if the ResultSet is not updatable or some other error occurs
1040: */
1041: public synchronized void moveToCurrentRow() throws SQLException {
1042: checkClosed();
1043:
1044: if (!this .isUpdatable) {
1045: throw new NotUpdatable(this .notUpdatableReason);
1046: }
1047:
1048: if (this .onInsertRow) {
1049: this .onInsertRow = false;
1050: this .this Row = this .savedCurrentRow;
1051: }
1052: }
1053:
1054: /**
1055: * JDBC 2.0 Move to the insert row. The current cursor position is
1056: * remembered while the cursor is positioned on the insert row. The insert
1057: * row is a special row associated with an updatable result set. It is
1058: * essentially a buffer where a new row may be constructed by calling the
1059: * updateXXX() methods prior to inserting the row into the result set. Only
1060: * the updateXXX(), getXXX(), and insertRow() methods may be called when the
1061: * cursor is on the insert row. All of the columns in a result set must be
1062: * given a value each time this method is called before calling insertRow().
1063: * UpdateXXX()must be called before getXXX() on a column.
1064: *
1065: * @exception SQLException
1066: * if a database-access error occurs, or the result set is
1067: * not updatable
1068: * @throws NotUpdatable
1069: * DOCUMENT ME!
1070: */
1071: public synchronized void moveToInsertRow() throws SQLException {
1072: checkClosed();
1073:
1074: if (!this .isUpdatable) {
1075: throw new NotUpdatable(this .notUpdatableReason);
1076: }
1077:
1078: if (this .inserter == null) {
1079: if (this .insertSQL == null) {
1080: generateStatements();
1081: }
1082:
1083: this .inserter = this .connection
1084: .clientPrepareStatement(this .insertSQL);
1085: if (this .populateInserterWithDefaultValues) {
1086: extractDefaultValues();
1087: }
1088:
1089: resetInserter();
1090: } else {
1091: resetInserter();
1092: }
1093:
1094: int numFields = this .fields.length;
1095:
1096: this .onInsertRow = true;
1097: this .doingUpdates = false;
1098: this .savedCurrentRow = this .this Row;
1099: byte[][] newRowData = new byte[numFields][];
1100: this .this Row = new ByteArrayRow(newRowData);
1101:
1102: for (int i = 0; i < numFields; i++) {
1103: if (!this .populateInserterWithDefaultValues) {
1104: this .inserter.setBytesNoEscapeNoQuotes(i + 1, "DEFAULT"
1105: .getBytes());
1106: newRowData = null;
1107: } else {
1108: if (this .defaultColumnValue[i] != null) {
1109: Field f = this .fields[i];
1110:
1111: switch (f.getMysqlType()) {
1112: case MysqlDefs.FIELD_TYPE_DATE:
1113: case MysqlDefs.FIELD_TYPE_DATETIME:
1114: case MysqlDefs.FIELD_TYPE_NEWDATE:
1115: case MysqlDefs.FIELD_TYPE_TIME:
1116: case MysqlDefs.FIELD_TYPE_TIMESTAMP:
1117:
1118: if (this .defaultColumnValue[i].length > 7
1119: && this .defaultColumnValue[i][0] == (byte) 'C'
1120: && this .defaultColumnValue[i][1] == (byte) 'U'
1121: && this .defaultColumnValue[i][2] == (byte) 'R'
1122: && this .defaultColumnValue[i][3] == (byte) 'R'
1123: && this .defaultColumnValue[i][4] == (byte) 'E'
1124: && this .defaultColumnValue[i][5] == (byte) 'N'
1125: && this .defaultColumnValue[i][6] == (byte) 'T'
1126: && this .defaultColumnValue[i][7] == (byte) '_') {
1127: this .inserter.setBytesNoEscapeNoQuotes(
1128: i + 1, this .defaultColumnValue[i]);
1129:
1130: break;
1131: }
1132: default:
1133: this .inserter.setBytes(i + 1,
1134: this .defaultColumnValue[i], false,
1135: false);
1136: }
1137:
1138: // This value _could_ be changed from a getBytes(), so we
1139: // need a copy....
1140: byte[] defaultValueCopy = new byte[this .defaultColumnValue[i].length];
1141: System.arraycopy(defaultColumnValue[i], 0,
1142: defaultValueCopy, 0,
1143: defaultValueCopy.length);
1144: newRowData[i] = defaultValueCopy;
1145: } else {
1146: this .inserter.setNull(i + 1, java.sql.Types.NULL);
1147: newRowData[i] = null;
1148: }
1149: }
1150: }
1151: }
1152:
1153: // ---------------------------------------------------------------------
1154: // Updates
1155: // ---------------------------------------------------------------------
1156:
1157: /**
1158: * A ResultSet is initially positioned before its first row, the first call
1159: * to next makes the first row the current row; the second call makes the
1160: * second row the current row, etc.
1161: *
1162: * <p>
1163: * If an input stream from the previous row is open, it is implicitly
1164: * closed. The ResultSet's warning chain is cleared when a new row is read
1165: * </p>
1166: *
1167: * @return true if the new current is valid; false if there are no more rows
1168: *
1169: * @exception SQLException
1170: * if a database access error occurs
1171: */
1172: public synchronized boolean next() throws SQLException {
1173: return super .next();
1174: }
1175:
1176: /**
1177: * The prev method is not part of JDBC, but because of the architecture of
1178: * this driver it is possible to move both forward and backward within the
1179: * result set.
1180: *
1181: * <p>
1182: * If an input stream from the previous row is open, it is implicitly
1183: * closed. The ResultSet's warning chain is cleared when a new row is read
1184: * </p>
1185: *
1186: * @return true if the new current is valid; false if there are no more rows
1187: *
1188: * @exception SQLException
1189: * if a database access error occurs
1190: */
1191: public synchronized boolean prev() throws SQLException {
1192: return super .prev();
1193: }
1194:
1195: /**
1196: * JDBC 2.0
1197: *
1198: * <p>
1199: * Moves to the previous row in the result set.
1200: * </p>
1201: *
1202: * <p>
1203: * Note: previous() is not the same as relative(-1) since it makes sense to
1204: * call previous() when there is no current row.
1205: * </p>
1206: *
1207: * @return true if on a valid row, false if off the result set.
1208: *
1209: * @exception SQLException
1210: * if a database-access error occurs, or result set type is
1211: * TYPE_FORWAR_DONLY.
1212: */
1213: public synchronized boolean previous() throws SQLException {
1214: return super .previous();
1215: }
1216:
1217: /**
1218: * Closes this ResultSet, releasing all resources.
1219: *
1220: * @param calledExplicitly
1221: * was this called from close()?
1222: *
1223: * @throws SQLException
1224: * if an error occurs.
1225: */
1226: public void realClose(boolean calledExplicitly) throws SQLException {
1227: if (this .isClosed) {
1228: return;
1229: }
1230:
1231: SQLException sqlEx = null;
1232:
1233: if (this .useUsageAdvisor) {
1234: if ((this .deleter == null) && (this .inserter == null)
1235: && (this .refresher == null)
1236: && (this .updater == null)) {
1237: this .eventSink = ProfileEventSink
1238: .getInstance(this .connection);
1239:
1240: String message = Messages
1241: .getString("UpdatableResultSet.34"); //$NON-NLS-1$
1242:
1243: this .eventSink.consumeEvent(new ProfilerEvent(
1244: ProfilerEvent.TYPE_WARN,
1245: "", //$NON-NLS-1$
1246: (this .owningStatement == null) ? "N/A" //$NON-NLS-1$
1247: : this .owningStatement.currentCatalog, //$NON-NLS-1$
1248: this .connectionId,
1249: (this .owningStatement == null) ? (-1)
1250: : this .owningStatement.getId(),
1251: this .resultId, System.currentTimeMillis(), 0,
1252: Constants.MILLIS_I18N, null,
1253: this .pointOfOrigin, message));
1254: }
1255: }
1256:
1257: try {
1258: if (this .deleter != null) {
1259: this .deleter.close();
1260: }
1261: } catch (SQLException ex) {
1262: sqlEx = ex;
1263: }
1264:
1265: try {
1266: if (this .inserter != null) {
1267: this .inserter.close();
1268: }
1269: } catch (SQLException ex) {
1270: sqlEx = ex;
1271: }
1272:
1273: try {
1274: if (this .refresher != null) {
1275: this .refresher.close();
1276: }
1277: } catch (SQLException ex) {
1278: sqlEx = ex;
1279: }
1280:
1281: try {
1282: if (this .updater != null) {
1283: this .updater.close();
1284: }
1285: } catch (SQLException ex) {
1286: sqlEx = ex;
1287: }
1288:
1289: super .realClose(calledExplicitly);
1290:
1291: if (sqlEx != null) {
1292: throw sqlEx;
1293: }
1294: }
1295:
1296: /**
1297: * JDBC 2.0 Refresh the value of the current row with its current value in
1298: * the database. Cannot be called when on the insert row. The refreshRow()
1299: * method provides a way for an application to explicitly tell the JDBC
1300: * driver to refetch a row(s) from the database. An application may want to
1301: * call refreshRow() when caching or prefetching is being done by the JDBC
1302: * driver to fetch the latest value of a row from the database. The JDBC
1303: * driver may actually refresh multiple rows at once if the fetch size is
1304: * greater than one. All values are refetched subject to the transaction
1305: * isolation level and cursor sensitivity. If refreshRow() is called after
1306: * calling updateXXX(), but before calling updateRow() then the updates made
1307: * to the row are lost. Calling refreshRow() frequently will likely slow
1308: * performance.
1309: *
1310: * @exception SQLException
1311: * if a database-access error occurs, or if called when on
1312: * the insert row.
1313: * @throws NotUpdatable
1314: * DOCUMENT ME!
1315: */
1316: public synchronized void refreshRow() throws SQLException {
1317: checkClosed();
1318:
1319: if (!this .isUpdatable) {
1320: throw new NotUpdatable();
1321: }
1322:
1323: if (this .onInsertRow) {
1324: throw SQLError.createSQLException(Messages
1325: .getString("UpdatableResultSet.8")); //$NON-NLS-1$
1326: } else if (this .rowData.size() == 0) {
1327: throw SQLError.createSQLException(Messages
1328: .getString("UpdatableResultSet.9")); //$NON-NLS-1$
1329: } else if (isBeforeFirst()) {
1330: throw SQLError.createSQLException(Messages
1331: .getString("UpdatableResultSet.10")); //$NON-NLS-1$
1332: } else if (isAfterLast()) {
1333: throw SQLError.createSQLException(Messages
1334: .getString("UpdatableResultSet.11")); //$NON-NLS-1$
1335: }
1336:
1337: refreshRow(this .updater, this .this Row);
1338: }
1339:
1340: private synchronized void refreshRow(
1341: PreparedStatement updateInsertStmt,
1342: ResultSetRow rowToRefresh) throws SQLException {
1343: if (this .refresher == null) {
1344: if (this .refreshSQL == null) {
1345: generateStatements();
1346: }
1347:
1348: this .refresher = this .connection
1349: .clientPrepareStatement(this .refreshSQL);
1350: }
1351:
1352: this .refresher.clearParameters();
1353:
1354: int numKeys = this .primaryKeyIndicies.size();
1355:
1356: if (numKeys == 1) {
1357: byte[] dataFrom = null;
1358: int index = ((Integer) this .primaryKeyIndicies.get(0))
1359: .intValue();
1360:
1361: if (!this .doingUpdates && !this .onInsertRow) {
1362: dataFrom = (byte[]) rowToRefresh.getColumnValue(index);
1363: } else {
1364: dataFrom = updateInsertStmt
1365: .getBytesRepresentation(index);
1366:
1367: // Primary keys not set?
1368: if (updateInsertStmt.isNull(index)
1369: || (dataFrom.length == 0)) {
1370: dataFrom = (byte[]) rowToRefresh
1371: .getColumnValue(index);
1372: } else {
1373: dataFrom = stripBinaryPrefix(dataFrom);
1374: }
1375: }
1376:
1377: this .refresher.setBytesNoEscape(1, dataFrom);
1378: } else {
1379: for (int i = 0; i < numKeys; i++) {
1380: byte[] dataFrom = null;
1381: int index = ((Integer) this .primaryKeyIndicies.get(i))
1382: .intValue();
1383:
1384: if (!this .doingUpdates && !this .onInsertRow) {
1385: dataFrom = (byte[]) rowToRefresh
1386: .getColumnValue(index);
1387: } else {
1388: dataFrom = updateInsertStmt
1389: .getBytesRepresentation(index);
1390:
1391: // Primary keys not set?
1392: if (updateInsertStmt.isNull(index)
1393: || (dataFrom.length == 0)) {
1394: dataFrom = (byte[]) rowToRefresh
1395: .getColumnValue(index);
1396: } else {
1397: dataFrom = stripBinaryPrefix(dataFrom);
1398: }
1399: }
1400:
1401: this .refresher.setBytesNoEscape(i + 1, dataFrom);
1402: }
1403: }
1404:
1405: java.sql.ResultSet rs = null;
1406:
1407: try {
1408: rs = this .refresher.executeQuery();
1409:
1410: int numCols = rs.getMetaData().getColumnCount();
1411:
1412: if (rs.next()) {
1413: for (int i = 0; i < numCols; i++) {
1414: byte[] val = rs.getBytes(i + 1);
1415:
1416: if ((val == null) || rs.wasNull()) {
1417: rowToRefresh.setColumnValue(i, null);
1418: } else {
1419: rowToRefresh.setColumnValue(i, rs
1420: .getBytes(i + 1));
1421: }
1422: }
1423: } else {
1424: throw SQLError.createSQLException(Messages
1425: .getString("UpdatableResultSet.12"), //$NON-NLS-1$
1426: SQLError.SQL_STATE_GENERAL_ERROR); //$NON-NLS-1$
1427: }
1428: } finally {
1429: if (rs != null) {
1430: try {
1431: rs.close();
1432: } catch (SQLException ex) {
1433: ; // ignore
1434: }
1435: }
1436: }
1437: }
1438:
1439: /**
1440: * JDBC 2.0
1441: *
1442: * <p>
1443: * Moves a relative number of rows, either positive or negative. Attempting
1444: * to move beyond the first/last row in the result set positions the cursor
1445: * before/after the the first/last row. Calling relative(0) is valid, but
1446: * does not change the cursor position.
1447: * </p>
1448: *
1449: * <p>
1450: * Note: Calling relative(1) is different than calling next() since is makes
1451: * sense to call next() when there is no current row, for example, when the
1452: * cursor is positioned before the first row or after the last row of the
1453: * result set.
1454: * </p>
1455: *
1456: * @param rows
1457: * DOCUMENT ME!
1458: *
1459: * @return true if on a row, false otherwise.
1460: *
1461: * @exception SQLException
1462: * if a database-access error occurs, or there is no current
1463: * row, or result set type is TYPE_FORWARD_ONLY.
1464: */
1465: public synchronized boolean relative(int rows) throws SQLException {
1466: return super .relative(rows);
1467: }
1468:
1469: private void resetInserter() throws SQLException {
1470: this .inserter.clearParameters();
1471:
1472: for (int i = 0; i < this .fields.length; i++) {
1473: this .inserter.setNull(i + 1, 0);
1474: }
1475: }
1476:
1477: /**
1478: * JDBC 2.0 Determine if this row has been deleted. A deleted row may leave
1479: * a visible "hole" in a result set. This method can be used to detect holes
1480: * in a result set. The value returned depends on whether or not the result
1481: * set can detect deletions.
1482: *
1483: * @return true if deleted and deletes are detected
1484: *
1485: * @exception SQLException
1486: * if a database-access error occurs
1487: * @throws NotImplemented
1488: * DOCUMENT ME!
1489: *
1490: * @see DatabaseMetaData#deletesAreDetected
1491: */
1492: public synchronized boolean rowDeleted() throws SQLException {
1493: throw new NotImplemented();
1494: }
1495:
1496: /**
1497: * JDBC 2.0 Determine if the current row has been inserted. The value
1498: * returned depends on whether or not the result set can detect visible
1499: * inserts.
1500: *
1501: * @return true if inserted and inserts are detected
1502: *
1503: * @exception SQLException
1504: * if a database-access error occurs
1505: * @throws NotImplemented
1506: * DOCUMENT ME!
1507: *
1508: * @see DatabaseMetaData#insertsAreDetected
1509: */
1510: public synchronized boolean rowInserted() throws SQLException {
1511: throw new NotImplemented();
1512: }
1513:
1514: /**
1515: * JDBC 2.0 Determine if the current row has been updated. The value
1516: * returned depends on whether or not the result set can detect updates.
1517: *
1518: * @return true if the row has been visibly updated by the owner or another,
1519: * and updates are detected
1520: *
1521: * @exception SQLException
1522: * if a database-access error occurs
1523: * @throws NotImplemented
1524: * DOCUMENT ME!
1525: *
1526: * @see DatabaseMetaData#updatesAreDetected
1527: */
1528: public synchronized boolean rowUpdated() throws SQLException {
1529: throw new NotImplemented();
1530: }
1531:
1532: /**
1533: * Sets the concurrency type of this result set
1534: *
1535: * @param concurrencyFlag
1536: * the type of concurrency that this ResultSet should support.
1537: */
1538: protected void setResultSetConcurrency(int concurrencyFlag) {
1539: super .setResultSetConcurrency(concurrencyFlag);
1540:
1541: //
1542: // FIXME: Issue warning when asked for updateable result set, but result
1543: // set is not
1544: // updatable
1545: //
1546: // if ((concurrencyFlag == CONCUR_UPDATABLE) && !isUpdatable()) {
1547: // java.sql.SQLWarning warning = new java.sql.SQLWarning(
1548: // NotUpdatable.NOT_UPDATEABLE_MESSAGE);
1549: // }
1550: }
1551:
1552: private byte[] stripBinaryPrefix(byte[] dataFrom) {
1553: return StringUtils.stripEnclosure(dataFrom, "_binary'", "'");
1554: }
1555:
1556: /**
1557: * Reset UPDATE prepared statement to value in current row. This_Row MUST
1558: * point to current, valid row.
1559: *
1560: * @throws SQLException
1561: * DOCUMENT ME!
1562: */
1563: protected synchronized void syncUpdate() throws SQLException {
1564: if (this .updater == null) {
1565: if (this .updateSQL == null) {
1566: generateStatements();
1567: }
1568:
1569: this .updater = this .connection
1570: .clientPrepareStatement(this .updateSQL);
1571: }
1572:
1573: int numFields = this .fields.length;
1574: this .updater.clearParameters();
1575:
1576: for (int i = 0; i < numFields; i++) {
1577: if (this .this Row.getColumnValue(i) != null) {
1578: this .updater.setBytes(i + 1, (byte[]) this .this Row
1579: .getColumnValue(i), this .fields[i].isBinary(),
1580: false);
1581: } else {
1582: this .updater.setNull(i + 1, 0);
1583: }
1584: }
1585:
1586: int numKeys = this .primaryKeyIndicies.size();
1587:
1588: if (numKeys == 1) {
1589: int index = ((Integer) this .primaryKeyIndicies.get(0))
1590: .intValue();
1591: byte[] keyData = (byte[]) this .this Row
1592: .getColumnValue(index);
1593: this .updater.setBytes(numFields + 1, keyData, false, false);
1594: } else {
1595: for (int i = 0; i < numKeys; i++) {
1596: byte[] currentVal = (byte[]) this .this Row
1597: .getColumnValue(((Integer) this .primaryKeyIndicies
1598: .get(i)).intValue());
1599:
1600: if (currentVal != null) {
1601: this .updater.setBytes(numFields + i + 1,
1602: currentVal, false, false);
1603: } else {
1604: this .updater.setNull(numFields + i + 1, 0);
1605: }
1606: }
1607: }
1608: }
1609:
1610: /**
1611: * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
1612: * methods are used to update column values in the current row, or the
1613: * insert row. The updateXXX() methods do not update the underlying
1614: * database, instead the updateRow() or insertRow() methods are called to
1615: * update the database.
1616: *
1617: * @param columnIndex
1618: * the first column is 1, the second is 2, ...
1619: * @param x
1620: * the new column value
1621: * @param length
1622: * the length of the stream
1623: *
1624: * @exception SQLException
1625: * if a database-access error occurs
1626: */
1627: public synchronized void updateAsciiStream(int columnIndex,
1628: java.io.InputStream x, int length) throws SQLException {
1629: if (!this .onInsertRow) {
1630: if (!this .doingUpdates) {
1631: this .doingUpdates = true;
1632: syncUpdate();
1633: }
1634:
1635: this .updater.setAsciiStream(columnIndex, x, length);
1636: } else {
1637: this .inserter.setAsciiStream(columnIndex, x, length);
1638: this .this Row.setColumnValue(columnIndex - 1,
1639: STREAM_DATA_MARKER);
1640: }
1641: }
1642:
1643: /**
1644: * JDBC 2.0 Update a column with an ascii stream value. The updateXXX()
1645: * methods are used to update column values in the current row, or the
1646: * insert row. The updateXXX() methods do not update the underlying
1647: * database, instead the updateRow() or insertRow() methods are called to
1648: * update the database.
1649: *
1650: * @param columnName
1651: * the name of the column
1652: * @param x
1653: * the new column value
1654: * @param length
1655: * of the stream
1656: *
1657: * @exception SQLException
1658: * if a database-access error occurs
1659: */
1660: public synchronized void updateAsciiStream(String columnName,
1661: java.io.InputStream x, int length) throws SQLException {
1662: updateAsciiStream(findColumn(columnName), x, length);
1663: }
1664:
1665: /**
1666: * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
1667: * are used to update column values in the current row, or the insert row.
1668: * The updateXXX() methods do not update the underlying database, instead
1669: * the updateRow() or insertRow() methods are called to update the database.
1670: *
1671: * @param columnIndex
1672: * the first column is 1, the second is 2, ...
1673: * @param x
1674: * the new column value
1675: *
1676: * @exception SQLException
1677: * if a database-access error occurs
1678: */
1679: public synchronized void updateBigDecimal(int columnIndex,
1680: BigDecimal x) throws SQLException {
1681: if (!this .onInsertRow) {
1682: if (!this .doingUpdates) {
1683: this .doingUpdates = true;
1684: syncUpdate();
1685: }
1686:
1687: this .updater.setBigDecimal(columnIndex, x);
1688: } else {
1689: this .inserter.setBigDecimal(columnIndex, x);
1690:
1691: if (x == null) {
1692: this .this Row.setColumnValue(columnIndex - 1, null);
1693: } else {
1694: this .this Row.setColumnValue(columnIndex - 1, x
1695: .toString().getBytes());
1696: }
1697: }
1698: }
1699:
1700: /**
1701: * JDBC 2.0 Update a column with a BigDecimal value. The updateXXX() methods
1702: * are used to update column values in the current row, or the insert row.
1703: * The updateXXX() methods do not update the underlying database, instead
1704: * the updateRow() or insertRow() methods are called to update the database.
1705: *
1706: * @param columnName
1707: * the name of the column
1708: * @param x
1709: * the new column value
1710: *
1711: * @exception SQLException
1712: * if a database-access error occurs
1713: */
1714: public synchronized void updateBigDecimal(String columnName,
1715: BigDecimal x) throws SQLException {
1716: updateBigDecimal(findColumn(columnName), x);
1717: }
1718:
1719: /**
1720: * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
1721: * methods are used to update column values in the current row, or the
1722: * insert row. The updateXXX() methods do not update the underlying
1723: * database, instead the updateRow() or insertRow() methods are called to
1724: * update the database.
1725: *
1726: * @param columnIndex
1727: * the first column is 1, the second is 2, ...
1728: * @param x
1729: * the new column value
1730: * @param length
1731: * the length of the stream
1732: *
1733: * @exception SQLException
1734: * if a database-access error occurs
1735: */
1736: public synchronized void updateBinaryStream(int columnIndex,
1737: java.io.InputStream x, int length) throws SQLException {
1738: if (!this .onInsertRow) {
1739: if (!this .doingUpdates) {
1740: this .doingUpdates = true;
1741: syncUpdate();
1742: }
1743:
1744: this .updater.setBinaryStream(columnIndex, x, length);
1745: } else {
1746: this .inserter.setBinaryStream(columnIndex, x, length);
1747:
1748: if (x == null) {
1749: this .this Row.setColumnValue(columnIndex - 1, null);
1750: } else {
1751: this .this Row.setColumnValue(columnIndex - 1,
1752: STREAM_DATA_MARKER);
1753: }
1754: }
1755: }
1756:
1757: /**
1758: * JDBC 2.0 Update a column with a binary stream value. The updateXXX()
1759: * methods are used to update column values in the current row, or the
1760: * insert row. The updateXXX() methods do not update the underlying
1761: * database, instead the updateRow() or insertRow() methods are called to
1762: * update the database.
1763: *
1764: * @param columnName
1765: * the name of the column
1766: * @param x
1767: * the new column value
1768: * @param length
1769: * of the stream
1770: *
1771: * @exception SQLException
1772: * if a database-access error occurs
1773: */
1774: public synchronized void updateBinaryStream(String columnName,
1775: java.io.InputStream x, int length) throws SQLException {
1776: updateBinaryStream(findColumn(columnName), x, length);
1777: }
1778:
1779: /**
1780: * @see ResultSetInternalMethods#updateBlob(int, Blob)
1781: */
1782: public synchronized void updateBlob(int columnIndex,
1783: java.sql.Blob blob) throws SQLException {
1784: if (!this .onInsertRow) {
1785: if (!this .doingUpdates) {
1786: this .doingUpdates = true;
1787: syncUpdate();
1788: }
1789:
1790: this .updater.setBlob(columnIndex, blob);
1791: } else {
1792: this .inserter.setBlob(columnIndex, blob);
1793:
1794: if (blob == null) {
1795: this .this Row.setColumnValue(columnIndex - 1, null);
1796: } else {
1797: this .this Row.setColumnValue(columnIndex - 1,
1798: STREAM_DATA_MARKER);
1799: }
1800: }
1801: }
1802:
1803: /**
1804: * @see ResultSetInternalMethods#updateBlob(String, Blob)
1805: */
1806: public synchronized void updateBlob(String columnName,
1807: java.sql.Blob blob) throws SQLException {
1808: updateBlob(findColumn(columnName), blob);
1809: }
1810:
1811: /**
1812: * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods
1813: * are used to update column values in the current row, or the insert row.
1814: * The updateXXX() methods do not update the underlying database, instead
1815: * the updateRow() or insertRow() methods are called to update the database.
1816: *
1817: * @param columnIndex
1818: * the first column is 1, the second is 2, ...
1819: * @param x
1820: * the new column value
1821: *
1822: * @exception SQLException
1823: * if a database-access error occurs
1824: */
1825: public synchronized void updateBoolean(int columnIndex, boolean x)
1826: throws SQLException {
1827: if (!this .onInsertRow) {
1828: if (!this .doingUpdates) {
1829: this .doingUpdates = true;
1830: syncUpdate();
1831: }
1832:
1833: this .updater.setBoolean(columnIndex, x);
1834: } else {
1835: this .inserter.setBoolean(columnIndex, x);
1836:
1837: this .this Row.setColumnValue(columnIndex - 1, this .inserter
1838: .getBytesRepresentation(columnIndex - 1));
1839: }
1840: }
1841:
1842: /**
1843: * JDBC 2.0 Update a column with a boolean value. The updateXXX() methods
1844: * are used to update column values in the current row, or the insert row.
1845: * The updateXXX() methods do not update the underlying database, instead
1846: * the updateRow() or insertRow() methods are called to update the database.
1847: *
1848: * @param columnName
1849: * the name of the column
1850: * @param x
1851: * the new column value
1852: *
1853: * @exception SQLException
1854: * if a database-access error occurs
1855: */
1856: public synchronized void updateBoolean(String columnName, boolean x)
1857: throws SQLException {
1858: updateBoolean(findColumn(columnName), x);
1859: }
1860:
1861: /**
1862: * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
1863: * used to update column values in the current row, or the insert row. The
1864: * updateXXX() methods do not update the underlying database, instead the
1865: * updateRow() or insertRow() methods are called to update the database.
1866: *
1867: * @param columnIndex
1868: * the first column is 1, the second is 2, ...
1869: * @param x
1870: * the new column value
1871: *
1872: * @exception SQLException
1873: * if a database-access error occurs
1874: */
1875: public synchronized void updateByte(int columnIndex, byte x)
1876: throws SQLException {
1877: if (!this .onInsertRow) {
1878: if (!this .doingUpdates) {
1879: this .doingUpdates = true;
1880: syncUpdate();
1881: }
1882:
1883: this .updater.setByte(columnIndex, x);
1884: } else {
1885: this .inserter.setByte(columnIndex, x);
1886:
1887: this .this Row.setColumnValue(columnIndex - 1, this .inserter
1888: .getBytesRepresentation(columnIndex - 1));
1889: }
1890: }
1891:
1892: /**
1893: * JDBC 2.0 Update a column with a byte value. The updateXXX() methods are
1894: * used to update column values in the current row, or the insert row. The
1895: * updateXXX() methods do not update the underlying database, instead the
1896: * updateRow() or insertRow() methods are called to update the database.
1897: *
1898: * @param columnName
1899: * the name of the column
1900: * @param x
1901: * the new column value
1902: *
1903: * @exception SQLException
1904: * if a database-access error occurs
1905: */
1906: public synchronized void updateByte(String columnName, byte x)
1907: throws SQLException {
1908: updateByte(findColumn(columnName), x);
1909: }
1910:
1911: /**
1912: * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
1913: * are used to update column values in the current row, or the insert row.
1914: * The updateXXX() methods do not update the underlying database, instead
1915: * the updateRow() or insertRow() methods are called to update the database.
1916: *
1917: * @param columnIndex
1918: * the first column is 1, the second is 2, ...
1919: * @param x
1920: * the new column value
1921: *
1922: * @exception SQLException
1923: * if a database-access error occurs
1924: */
1925: public synchronized void updateBytes(int columnIndex, byte[] x)
1926: throws SQLException {
1927: if (!this .onInsertRow) {
1928: if (!this .doingUpdates) {
1929: this .doingUpdates = true;
1930: syncUpdate();
1931: }
1932:
1933: this .updater.setBytes(columnIndex, x);
1934: } else {
1935: this .inserter.setBytes(columnIndex, x);
1936:
1937: this .this Row.setColumnValue(columnIndex - 1, x);
1938: }
1939: }
1940:
1941: /**
1942: * JDBC 2.0 Update a column with a byte array value. The updateXXX() methods
1943: * are used to update column values in the current row, or the insert row.
1944: * The updateXXX() methods do not update the underlying database, instead
1945: * the updateRow() or insertRow() methods are called to update the database.
1946: *
1947: * @param columnName
1948: * the name of the column
1949: * @param x
1950: * the new column value
1951: *
1952: * @exception SQLException
1953: * if a database-access error occurs
1954: */
1955: public synchronized void updateBytes(String columnName, byte[] x)
1956: throws SQLException {
1957: updateBytes(findColumn(columnName), x);
1958: }
1959:
1960: /**
1961: * JDBC 2.0 Update a column with a character stream value. The updateXXX()
1962: * methods are used to update column values in the current row, or the
1963: * insert row. The updateXXX() methods do not update the underlying
1964: * database, instead the updateRow() or insertRow() methods are called to
1965: * update the database.
1966: *
1967: * @param columnIndex
1968: * the first column is 1, the second is 2, ...
1969: * @param x
1970: * the new column value
1971: * @param length
1972: * the length of the stream
1973: *
1974: * @exception SQLException
1975: * if a database-access error occurs
1976: */
1977: public synchronized void updateCharacterStream(int columnIndex,
1978: java.io.Reader x, int length) throws SQLException {
1979: if (!this .onInsertRow) {
1980: if (!this .doingUpdates) {
1981: this .doingUpdates = true;
1982: syncUpdate();
1983: }
1984:
1985: this .updater.setCharacterStream(columnIndex, x, length);
1986: } else {
1987: this .inserter.setCharacterStream(columnIndex, x, length);
1988:
1989: if (x == null) {
1990: this .this Row.setColumnValue(columnIndex - 1, null);
1991: } else {
1992: this .this Row.setColumnValue(columnIndex - 1,
1993: STREAM_DATA_MARKER);
1994: }
1995: }
1996: }
1997:
1998: /**
1999: * JDBC 2.0 Update a column with a character stream value. The updateXXX()
2000: * methods are used to update column values in the current row, or the
2001: * insert row. The updateXXX() methods do not update the underlying
2002: * database, instead the updateRow() or insertRow() methods are called to
2003: * update the database.
2004: *
2005: * @param columnName
2006: * the name of the column
2007: * @param reader
2008: * the new column value
2009: * @param length
2010: * of the stream
2011: *
2012: * @exception SQLException
2013: * if a database-access error occurs
2014: */
2015: public synchronized void updateCharacterStream(String columnName,
2016: java.io.Reader reader, int length) throws SQLException {
2017: updateCharacterStream(findColumn(columnName), reader, length);
2018: }
2019:
2020: /**
2021: * @see ResultSetInternalMethods#updateClob(int, Clob)
2022: */
2023: public void updateClob(int columnIndex, java.sql.Clob clob)
2024: throws SQLException {
2025: if (clob == null) {
2026: updateNull(columnIndex);
2027: } else {
2028: updateCharacterStream(columnIndex, clob
2029: .getCharacterStream(), (int) clob.length());
2030: }
2031: }
2032:
2033: /**
2034: * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2035: * used to update column values in the current row, or the insert row. The
2036: * updateXXX() methods do not update the underlying database, instead the
2037: * updateRow() or insertRow() methods are called to update the database.
2038: *
2039: * @param columnIndex
2040: * the first column is 1, the second is 2, ...
2041: * @param x
2042: * the new column value
2043: *
2044: * @exception SQLException
2045: * if a database-access error occurs
2046: */
2047: public synchronized void updateDate(int columnIndex, java.sql.Date x)
2048: throws SQLException {
2049: if (!this .onInsertRow) {
2050: if (!this .doingUpdates) {
2051: this .doingUpdates = true;
2052: syncUpdate();
2053: }
2054:
2055: this .updater.setDate(columnIndex, x);
2056: } else {
2057: this .inserter.setDate(columnIndex, x);
2058:
2059: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2060: .getBytesRepresentation(columnIndex - 1));
2061: }
2062: }
2063:
2064: /**
2065: * JDBC 2.0 Update a column with a Date value. The updateXXX() methods are
2066: * used to update column values in the current row, or the insert row. The
2067: * updateXXX() methods do not update the underlying database, instead the
2068: * updateRow() or insertRow() methods are called to update the database.
2069: *
2070: * @param columnName
2071: * the name of the column
2072: * @param x
2073: * the new column value
2074: *
2075: * @exception SQLException
2076: * if a database-access error occurs
2077: */
2078: public synchronized void updateDate(String columnName,
2079: java.sql.Date x) throws SQLException {
2080: updateDate(findColumn(columnName), x);
2081: }
2082:
2083: /**
2084: * JDBC 2.0 Update a column with a Double value. The updateXXX() methods are
2085: * used to update column values in the current row, or the insert row. The
2086: * updateXXX() methods do not update the underlying database, instead the
2087: * updateRow() or insertRow() methods are called to update the database.
2088: *
2089: * @param columnIndex
2090: * the first column is 1, the second is 2, ...
2091: * @param x
2092: * the new column value
2093: *
2094: * @exception SQLException
2095: * if a database-access error occurs
2096: */
2097: public synchronized void updateDouble(int columnIndex, double x)
2098: throws SQLException {
2099: if (!this .onInsertRow) {
2100: if (!this .doingUpdates) {
2101: this .doingUpdates = true;
2102: syncUpdate();
2103: }
2104:
2105: this .updater.setDouble(columnIndex, x);
2106: } else {
2107: this .inserter.setDouble(columnIndex, x);
2108:
2109: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2110: .getBytesRepresentation(columnIndex - 1));
2111: }
2112: }
2113:
2114: /**
2115: * JDBC 2.0 Update a column with a double value. The updateXXX() methods are
2116: * used to update column values in the current row, or the insert row. The
2117: * updateXXX() methods do not update the underlying database, instead the
2118: * updateRow() or insertRow() methods are called to update the database.
2119: *
2120: * @param columnName
2121: * the name of the column
2122: * @param x
2123: * the new column value
2124: *
2125: * @exception SQLException
2126: * if a database-access error occurs
2127: */
2128: public synchronized void updateDouble(String columnName, double x)
2129: throws SQLException {
2130: updateDouble(findColumn(columnName), x);
2131: }
2132:
2133: /**
2134: * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
2135: * used to update column values in the current row, or the insert row. The
2136: * updateXXX() methods do not update the underlying database, instead the
2137: * updateRow() or insertRow() methods are called to update the database.
2138: *
2139: * @param columnIndex
2140: * the first column is 1, the second is 2, ...
2141: * @param x
2142: * the new column value
2143: *
2144: * @exception SQLException
2145: * if a database-access error occurs
2146: */
2147: public synchronized void updateFloat(int columnIndex, float x)
2148: throws SQLException {
2149: if (!this .onInsertRow) {
2150: if (!this .doingUpdates) {
2151: this .doingUpdates = true;
2152: syncUpdate();
2153: }
2154:
2155: this .updater.setFloat(columnIndex, x);
2156: } else {
2157: this .inserter.setFloat(columnIndex, x);
2158:
2159: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2160: .getBytesRepresentation(columnIndex - 1));
2161: }
2162: }
2163:
2164: /**
2165: * JDBC 2.0 Update a column with a float value. The updateXXX() methods are
2166: * used to update column values in the current row, or the insert row. The
2167: * updateXXX() methods do not update the underlying database, instead the
2168: * updateRow() or insertRow() methods are called to update the database.
2169: *
2170: * @param columnName
2171: * the name of the column
2172: * @param x
2173: * the new column value
2174: *
2175: * @exception SQLException
2176: * if a database-access error occurs
2177: */
2178: public synchronized void updateFloat(String columnName, float x)
2179: throws SQLException {
2180: updateFloat(findColumn(columnName), x);
2181: }
2182:
2183: /**
2184: * JDBC 2.0 Update a column with an integer value. The updateXXX() methods
2185: * are used to update column values in the current row, or the insert row.
2186: * The updateXXX() methods do not update the underlying database, instead
2187: * the updateRow() or insertRow() methods are called to update the database.
2188: *
2189: * @param columnIndex
2190: * the first column is 1, the second is 2, ...
2191: * @param x
2192: * the new column value
2193: *
2194: * @exception SQLException
2195: * if a database-access error occurs
2196: */
2197: public synchronized void updateInt(int columnIndex, int x)
2198: throws SQLException {
2199: if (!this .onInsertRow) {
2200: if (!this .doingUpdates) {
2201: this .doingUpdates = true;
2202: syncUpdate();
2203: }
2204:
2205: this .updater.setInt(columnIndex, x);
2206: } else {
2207: this .inserter.setInt(columnIndex, x);
2208:
2209: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2210: .getBytesRepresentation(columnIndex - 1));
2211: }
2212: }
2213:
2214: /**
2215: * JDBC 2.0 Update a column with an integer value. The updateXXX() methods
2216: * are used to update column values in the current row, or the insert row.
2217: * The updateXXX() methods do not update the underlying database, instead
2218: * the updateRow() or insertRow() methods are called to update the database.
2219: *
2220: * @param columnName
2221: * the name of the column
2222: * @param x
2223: * the new column value
2224: *
2225: * @exception SQLException
2226: * if a database-access error occurs
2227: */
2228: public synchronized void updateInt(String columnName, int x)
2229: throws SQLException {
2230: updateInt(findColumn(columnName), x);
2231: }
2232:
2233: /**
2234: * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
2235: * used to update column values in the current row, or the insert row. The
2236: * updateXXX() methods do not update the underlying database, instead the
2237: * updateRow() or insertRow() methods are called to update the database.
2238: *
2239: * @param columnIndex
2240: * the first column is 1, the second is 2, ...
2241: * @param x
2242: * the new column value
2243: *
2244: * @exception SQLException
2245: * if a database-access error occurs
2246: */
2247: public synchronized void updateLong(int columnIndex, long x)
2248: throws SQLException {
2249: if (!this .onInsertRow) {
2250: if (!this .doingUpdates) {
2251: this .doingUpdates = true;
2252: syncUpdate();
2253: }
2254:
2255: this .updater.setLong(columnIndex, x);
2256: } else {
2257: this .inserter.setLong(columnIndex, x);
2258:
2259: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2260: .getBytesRepresentation(columnIndex - 1));
2261: }
2262: }
2263:
2264: /**
2265: * JDBC 2.0 Update a column with a long value. The updateXXX() methods are
2266: * used to update column values in the current row, or the insert row. The
2267: * updateXXX() methods do not update the underlying database, instead the
2268: * updateRow() or insertRow() methods are called to update the database.
2269: *
2270: * @param columnName
2271: * the name of the column
2272: * @param x
2273: * the new column value
2274: *
2275: * @exception SQLException
2276: * if a database-access error occurs
2277: */
2278: public synchronized void updateLong(String columnName, long x)
2279: throws SQLException {
2280: updateLong(findColumn(columnName), x);
2281: }
2282:
2283: /**
2284: * JDBC 2.0 Give a nullable column a null value. The updateXXX() methods are
2285: * used to update column values in the current row, or the insert row. The
2286: * updateXXX() methods do not update the underlying database, instead the
2287: * updateRow() or insertRow() methods are called to update the database.
2288: *
2289: * @param columnIndex
2290: * the first column is 1, the second is 2, ...
2291: *
2292: * @exception SQLException
2293: * if a database-access error occurs
2294: */
2295: public synchronized void updateNull(int columnIndex)
2296: throws SQLException {
2297: if (!this .onInsertRow) {
2298: if (!this .doingUpdates) {
2299: this .doingUpdates = true;
2300: syncUpdate();
2301: }
2302:
2303: this .updater.setNull(columnIndex, 0);
2304: } else {
2305: this .inserter.setNull(columnIndex, 0);
2306:
2307: this .this Row.setColumnValue(columnIndex - 1, null);
2308: }
2309: }
2310:
2311: /**
2312: * JDBC 2.0 Update a column with a null value. The updateXXX() methods are
2313: * used to update column values in the current row, or the insert row. The
2314: * updateXXX() methods do not update the underlying database, instead the
2315: * updateRow() or insertRow() methods are called to update the database.
2316: *
2317: * @param columnName
2318: * the name of the column
2319: *
2320: * @exception SQLException
2321: * if a database-access error occurs
2322: */
2323: public synchronized void updateNull(String columnName)
2324: throws SQLException {
2325: updateNull(findColumn(columnName));
2326: }
2327:
2328: /**
2329: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
2330: * are used to update column values in the current row, or the insert row.
2331: * The updateXXX() methods do not update the underlying database, instead
2332: * the updateRow() or insertRow() methods are called to update the database.
2333: *
2334: * @param columnIndex
2335: * the first column is 1, the second is 2, ...
2336: * @param x
2337: * the new column value
2338: *
2339: * @exception SQLException
2340: * if a database-access error occurs
2341: */
2342: public synchronized void updateObject(int columnIndex, Object x)
2343: throws SQLException {
2344: if (!this .onInsertRow) {
2345: if (!this .doingUpdates) {
2346: this .doingUpdates = true;
2347: syncUpdate();
2348: }
2349:
2350: this .updater.setObject(columnIndex, x);
2351: } else {
2352: this .inserter.setObject(columnIndex, x);
2353:
2354: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2355: .getBytesRepresentation(columnIndex - 1));
2356: }
2357: }
2358:
2359: /**
2360: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
2361: * are used to update column values in the current row, or the insert row.
2362: * The updateXXX() methods do not update the underlying database, instead
2363: * the updateRow() or insertRow() methods are called to update the database.
2364: *
2365: * @param columnIndex
2366: * the first column is 1, the second is 2, ...
2367: * @param x
2368: * the new column value
2369: * @param scale
2370: * For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2371: * this is the number of digits after the decimal. For all other
2372: * types this value will be ignored.
2373: *
2374: * @exception SQLException
2375: * if a database-access error occurs
2376: */
2377: public synchronized void updateObject(int columnIndex, Object x,
2378: int scale) throws SQLException {
2379: if (!this .onInsertRow) {
2380: if (!this .doingUpdates) {
2381: this .doingUpdates = true;
2382: syncUpdate();
2383: }
2384:
2385: this .updater.setObject(columnIndex, x);
2386: } else {
2387: this .inserter.setObject(columnIndex, x);
2388:
2389: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2390: .getBytesRepresentation(columnIndex - 1));
2391: }
2392: }
2393:
2394: /**
2395: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
2396: * are used to update column values in the current row, or the insert row.
2397: * The updateXXX() methods do not update the underlying database, instead
2398: * the updateRow() or insertRow() methods are called to update the database.
2399: *
2400: * @param columnName
2401: * the name of the column
2402: * @param x
2403: * the new column value
2404: *
2405: * @exception SQLException
2406: * if a database-access error occurs
2407: */
2408: public synchronized void updateObject(String columnName, Object x)
2409: throws SQLException {
2410: updateObject(findColumn(columnName), x);
2411: }
2412:
2413: /**
2414: * JDBC 2.0 Update a column with an Object value. The updateXXX() methods
2415: * are used to update column values in the current row, or the insert row.
2416: * The updateXXX() methods do not update the underlying database, instead
2417: * the updateRow() or insertRow() methods are called to update the database.
2418: *
2419: * @param columnName
2420: * the name of the column
2421: * @param x
2422: * the new column value
2423: * @param scale
2424: * For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
2425: * this is the number of digits after the decimal. For all other
2426: * types this value will be ignored.
2427: *
2428: * @exception SQLException
2429: * if a database-access error occurs
2430: */
2431: public synchronized void updateObject(String columnName, Object x,
2432: int scale) throws SQLException {
2433: updateObject(findColumn(columnName), x);
2434: }
2435:
2436: /**
2437: * JDBC 2.0 Update the underlying database with the new contents of the
2438: * current row. Cannot be called when on the insert row.
2439: *
2440: * @exception SQLException
2441: * if a database-access error occurs, or if called when on
2442: * the insert row
2443: * @throws NotUpdatable
2444: * DOCUMENT ME!
2445: */
2446: public synchronized void updateRow() throws SQLException {
2447: if (!this .isUpdatable) {
2448: throw new NotUpdatable(this .notUpdatableReason);
2449: }
2450:
2451: if (this .doingUpdates) {
2452: this .updater.executeUpdate();
2453: refreshRow();
2454: this .doingUpdates = false;
2455: }
2456:
2457: //
2458: // fixes calling updateRow() and then doing more
2459: // updates on same row...
2460: syncUpdate();
2461: }
2462:
2463: /**
2464: * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
2465: * used to update column values in the current row, or the insert row. The
2466: * updateXXX() methods do not update the underlying database, instead the
2467: * updateRow() or insertRow() methods are called to update the database.
2468: *
2469: * @param columnIndex
2470: * the first column is 1, the second is 2, ...
2471: * @param x
2472: * the new column value
2473: *
2474: * @exception SQLException
2475: * if a database-access error occurs
2476: */
2477: public synchronized void updateShort(int columnIndex, short x)
2478: throws SQLException {
2479: if (!this .onInsertRow) {
2480: if (!this .doingUpdates) {
2481: this .doingUpdates = true;
2482: syncUpdate();
2483: }
2484:
2485: this .updater.setShort(columnIndex, x);
2486: } else {
2487: this .inserter.setShort(columnIndex, x);
2488:
2489: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2490: .getBytesRepresentation(columnIndex - 1));
2491: }
2492: }
2493:
2494: /**
2495: * JDBC 2.0 Update a column with a short value. The updateXXX() methods are
2496: * used to update column values in the current row, or the insert row. The
2497: * updateXXX() methods do not update the underlying database, instead the
2498: * updateRow() or insertRow() methods are called to update the database.
2499: *
2500: * @param columnName
2501: * the name of the column
2502: * @param x
2503: * the new column value
2504: *
2505: * @exception SQLException
2506: * if a database-access error occurs
2507: */
2508: public synchronized void updateShort(String columnName, short x)
2509: throws SQLException {
2510: updateShort(findColumn(columnName), x);
2511: }
2512:
2513: /**
2514: * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2515: * used to update column values in the current row, or the insert row. The
2516: * updateXXX() methods do not update the underlying database, instead the
2517: * updateRow() or insertRow() methods are called to update the database.
2518: *
2519: * @param columnIndex
2520: * the first column is 1, the second is 2, ...
2521: * @param x
2522: * the new column value
2523: *
2524: * @exception SQLException
2525: * if a database-access error occurs
2526: */
2527: public synchronized void updateString(int columnIndex, String x)
2528: throws SQLException {
2529: checkClosed();
2530:
2531: if (!this .onInsertRow) {
2532: if (!this .doingUpdates) {
2533: this .doingUpdates = true;
2534: syncUpdate();
2535: }
2536:
2537: this .updater.setString(columnIndex, x);
2538: } else {
2539: this .inserter.setString(columnIndex, x);
2540:
2541: if (x == null) {
2542: this .this Row.setColumnValue(columnIndex - 1, null);
2543: } else {
2544: if (getCharConverter() != null) {
2545: this .this Row
2546: .setColumnValue(
2547: columnIndex - 1,
2548: StringUtils
2549: .getBytes(
2550: x,
2551: this .charConverter,
2552: this .charEncoding,
2553: this .connection
2554: .getServerCharacterEncoding(),
2555: this .connection
2556: .parserKnowsUnicode()));
2557: } else {
2558: this .this Row.setColumnValue(columnIndex - 1, x
2559: .getBytes());
2560: }
2561: }
2562: }
2563: }
2564:
2565: /**
2566: * JDBC 2.0 Update a column with a String value. The updateXXX() methods are
2567: * used to update column values in the current row, or the insert row. The
2568: * updateXXX() methods do not update the underlying database, instead the
2569: * updateRow() or insertRow() methods are called to update the database.
2570: *
2571: * @param columnName
2572: * the name of the column
2573: * @param x
2574: * the new column value
2575: *
2576: * @exception SQLException
2577: * if a database-access error occurs
2578: */
2579: public synchronized void updateString(String columnName, String x)
2580: throws SQLException {
2581: updateString(findColumn(columnName), x);
2582: }
2583:
2584: /**
2585: * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2586: * used to update column values in the current row, or the insert row. The
2587: * updateXXX() methods do not update the underlying database, instead the
2588: * updateRow() or insertRow() methods are called to update the database.
2589: *
2590: * @param columnIndex
2591: * the first column is 1, the second is 2, ...
2592: * @param x
2593: * the new column value
2594: *
2595: * @exception SQLException
2596: * if a database-access error occurs
2597: */
2598: public synchronized void updateTime(int columnIndex, java.sql.Time x)
2599: throws SQLException {
2600: if (!this .onInsertRow) {
2601: if (!this .doingUpdates) {
2602: this .doingUpdates = true;
2603: syncUpdate();
2604: }
2605:
2606: this .updater.setTime(columnIndex, x);
2607: } else {
2608: this .inserter.setTime(columnIndex, x);
2609:
2610: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2611: .getBytesRepresentation(columnIndex - 1));
2612: }
2613: }
2614:
2615: /**
2616: * JDBC 2.0 Update a column with a Time value. The updateXXX() methods are
2617: * used to update column values in the current row, or the insert row. The
2618: * updateXXX() methods do not update the underlying database, instead the
2619: * updateRow() or insertRow() methods are called to update the database.
2620: *
2621: * @param columnName
2622: * the name of the column
2623: * @param x
2624: * the new column value
2625: *
2626: * @exception SQLException
2627: * if a database-access error occurs
2628: */
2629: public synchronized void updateTime(String columnName,
2630: java.sql.Time x) throws SQLException {
2631: updateTime(findColumn(columnName), x);
2632: }
2633:
2634: /**
2635: * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2636: * are used to update column values in the current row, or the insert row.
2637: * The updateXXX() methods do not update the underlying database, instead
2638: * the updateRow() or insertRow() methods are called to update the database.
2639: *
2640: * @param columnIndex
2641: * the first column is 1, the second is 2, ...
2642: * @param x
2643: * the new column value
2644: *
2645: * @exception SQLException
2646: * if a database-access error occurs
2647: */
2648: public synchronized void updateTimestamp(int columnIndex,
2649: java.sql.Timestamp x) throws SQLException {
2650: if (!this .onInsertRow) {
2651: if (!this .doingUpdates) {
2652: this .doingUpdates = true;
2653: syncUpdate();
2654: }
2655:
2656: this .updater.setTimestamp(columnIndex, x);
2657: } else {
2658: this .inserter.setTimestamp(columnIndex, x);
2659:
2660: this .this Row.setColumnValue(columnIndex - 1, this .inserter
2661: .getBytesRepresentation(columnIndex - 1));
2662: }
2663: }
2664:
2665: /**
2666: * JDBC 2.0 Update a column with a Timestamp value. The updateXXX() methods
2667: * are used to update column values in the current row, or the insert row.
2668: * The updateXXX() methods do not update the underlying database, instead
2669: * the updateRow() or insertRow() methods are called to update the database.
2670: *
2671: * @param columnName
2672: * the name of the column
2673: * @param x
2674: * the new column value
2675: *
2676: * @exception SQLException
2677: * if a database-access error occurs
2678: */
2679: public synchronized void updateTimestamp(String columnName,
2680: java.sql.Timestamp x) throws SQLException {
2681: updateTimestamp(findColumn(columnName), x);
2682: }
2683: }
|