001: /*
002: Copyright (C) 2002-2007 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022: */
023:
024: package com.mysql.jdbc;
025:
026: import java.io.InputStream;
027: import java.io.Reader;
028: import java.io.UnsupportedEncodingException;
029: import java.sql.NClob;
030: import java.sql.RowId;
031: import java.sql.SQLException;
032: import java.sql.SQLXML;
033:
034: import com.mysql.jdbc.Connection;
035: import com.mysql.jdbc.Field;
036: import com.mysql.jdbc.NotUpdatable;
037: import com.mysql.jdbc.RowData;
038: import com.mysql.jdbc.Statement;
039: import com.mysql.jdbc.StringUtils;
040: import com.mysql.jdbc.UpdatableResultSet;
041:
042: import com.mysql.jdbc.exceptions.NotYetImplementedException;
043:
044: public class JDBC4UpdatableResultSet extends UpdatableResultSet {
045: public JDBC4UpdatableResultSet(String catalog, Field[] fields,
046: RowData tuples, ConnectionImpl conn,
047: StatementImpl creatorStmt) throws SQLException {
048: super (catalog, fields, tuples, conn, creatorStmt);
049: }
050:
051: public void updateAsciiStream(int columnIndex, InputStream x)
052: throws SQLException {
053: throw new NotUpdatable();
054:
055: }
056:
057: public void updateAsciiStream(int columnIndex, InputStream x,
058: long length) throws SQLException {
059: throw new NotUpdatable();
060:
061: }
062:
063: public void updateBinaryStream(int columnIndex, InputStream x)
064: throws SQLException {
065: throw new NotUpdatable();
066:
067: }
068:
069: public void updateBinaryStream(int columnIndex, InputStream x,
070: long length) throws SQLException {
071: throw new NotUpdatable();
072:
073: }
074:
075: public void updateBlob(int columnIndex, InputStream inputStream)
076: throws SQLException {
077: throw new NotUpdatable();
078: }
079:
080: public void updateBlob(int columnIndex, InputStream inputStream,
081: long length) throws SQLException {
082: throw new NotUpdatable();
083:
084: }
085:
086: public void updateCharacterStream(int columnIndex, Reader x)
087: throws SQLException {
088: throw new NotUpdatable();
089:
090: }
091:
092: public void updateCharacterStream(int columnIndex, Reader x,
093: long length) throws SQLException {
094: throw new NotUpdatable();
095:
096: }
097:
098: public void updateClob(int columnIndex, Reader reader)
099: throws SQLException {
100: throw new NotUpdatable();
101:
102: }
103:
104: public void updateClob(int columnIndex, Reader reader, long length)
105: throws SQLException {
106: throw new NotUpdatable();
107:
108: }
109:
110: public void updateNCharacterStream(int columnIndex, Reader x)
111: throws SQLException {
112: throw new NotUpdatable();
113:
114: }
115:
116: public void updateNCharacterStream(int columnIndex, Reader x,
117: long length) throws SQLException {
118: updateNCharacterStream(columnIndex, x, (int) length);
119:
120: }
121:
122: public void updateNClob(int columnIndex, Reader reader)
123: throws SQLException {
124: throw new NotUpdatable();
125:
126: }
127:
128: public void updateNClob(int columnIndex, Reader reader, long length)
129: throws SQLException {
130: throw new NotUpdatable();
131: }
132:
133: public void updateSQLXML(int columnIndex, SQLXML xmlObject)
134: throws SQLException {
135: throw new NotUpdatable();
136:
137: }
138:
139: public void updateRowId(int columnIndex, RowId x)
140: throws SQLException {
141: throw new NotUpdatable();
142: }
143:
144: public void updateAsciiStream(String columnLabel, InputStream x)
145: throws SQLException {
146: updateAsciiStream(findColumn(columnLabel), x);
147: }
148:
149: public void updateAsciiStream(String columnLabel, InputStream x,
150: long length) throws SQLException {
151: updateAsciiStream(findColumn(columnLabel), x, length);
152: }
153:
154: public void updateBinaryStream(String columnLabel, InputStream x)
155: throws SQLException {
156: updateBinaryStream(findColumn(columnLabel), x);
157: }
158:
159: public void updateBinaryStream(String columnLabel, InputStream x,
160: long length) throws SQLException {
161: updateBinaryStream(findColumn(columnLabel), x, length);
162: }
163:
164: public void updateBlob(String columnLabel, InputStream inputStream)
165: throws SQLException {
166: updateBlob(findColumn(columnLabel), inputStream);
167: }
168:
169: public void updateBlob(String columnLabel, InputStream inputStream,
170: long length) throws SQLException {
171: updateBlob(findColumn(columnLabel), inputStream, length);
172: }
173:
174: public void updateCharacterStream(String columnLabel, Reader reader)
175: throws SQLException {
176: updateCharacterStream(findColumn(columnLabel), reader);
177: }
178:
179: public void updateCharacterStream(String columnLabel,
180: Reader reader, long length) throws SQLException {
181: updateCharacterStream(findColumn(columnLabel), reader, length);
182: }
183:
184: public void updateClob(String columnLabel, Reader reader)
185: throws SQLException {
186: updateClob(findColumn(columnLabel), reader);
187: }
188:
189: public void updateClob(String columnLabel, Reader reader,
190: long length) throws SQLException {
191: updateClob(findColumn(columnLabel), reader, length);
192: }
193:
194: public void updateNCharacterStream(String columnLabel, Reader reader)
195: throws SQLException {
196: updateNCharacterStream(findColumn(columnLabel), reader);
197:
198: }
199:
200: public void updateNCharacterStream(String columnLabel,
201: Reader reader, long length) throws SQLException {
202: updateNCharacterStream(findColumn(columnLabel), reader, length);
203: }
204:
205: public void updateNClob(String columnLabel, Reader reader)
206: throws SQLException {
207: updateNClob(findColumn(columnLabel), reader);
208:
209: }
210:
211: public void updateNClob(String columnLabel, Reader reader,
212: long length) throws SQLException {
213: updateNClob(findColumn(columnLabel), reader, length);
214: }
215:
216: public void updateSQLXML(String columnLabel, SQLXML xmlObject)
217: throws SQLException {
218: updateSQLXML(findColumn(columnLabel), xmlObject);
219:
220: }
221:
222: /**
223: * JDBC 4.0 Update a column with a character stream value. The updateXXX()
224: * methods are used to update column values in the current row, or the
225: * insert row. The updateXXX() methods do not update the underlying
226: * database, instead the updateRow() or insertRow() methods are called to
227: * update the database.
228: *
229: * @param columnIndex
230: * the first column is 1, the second is 2, ...
231: * @param x
232: * the new column value
233: * @param length
234: * the length of the stream
235: *
236: * @exception SQLException
237: * if a database-access error occurs
238: */
239: public synchronized void updateNCharacterStream(int columnIndex,
240: java.io.Reader x, int length) throws SQLException {
241: String fieldEncoding = this .fields[columnIndex - 1]
242: .getCharacterSet();
243: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
244: throw new SQLException(
245: "Can not call updateNCharacterStream() when field's character set isn't UTF-8");
246: }
247:
248: if (!this .onInsertRow) {
249: if (!this .doingUpdates) {
250: this .doingUpdates = true;
251: syncUpdate();
252: }
253:
254: ((com.mysql.jdbc.JDBC4PreparedStatement) this .updater)
255: .setNCharacterStream(columnIndex, x, length);
256: } else {
257: ((com.mysql.jdbc.JDBC4PreparedStatement) this .inserter)
258: .setNCharacterStream(columnIndex, x, length);
259:
260: if (x == null) {
261: this .this Row.setColumnValue(columnIndex, null);
262: } else {
263: this .this Row.setColumnValue(columnIndex,
264: STREAM_DATA_MARKER);
265: }
266: }
267: }
268:
269: /**
270: * JDBC 4.0 Update a column with a character stream value. The updateXXX()
271: * methods are used to update column values in the current row, or the
272: * insert row. The updateXXX() methods do not update the underlying
273: * database, instead the updateRow() or insertRow() methods are called to
274: * update the database.
275: *
276: * @param columnName
277: * the name of the column
278: * @param reader
279: * the new column value
280: * @param length
281: * of the stream
282: *
283: * @exception SQLException
284: * if a database-access error occurs
285: */
286: public synchronized void updateNCharacterStream(String columnName,
287: java.io.Reader reader, int length) throws SQLException {
288: updateNCharacterStream(findColumn(columnName), reader, length);
289: }
290:
291: /**
292: * @see ResultSet#updateNClob(int, NClob)
293: */
294: public void updateNClob(int columnIndex, java.sql.NClob nClob)
295: throws SQLException {
296: String fieldEncoding = this .fields[columnIndex - 1]
297: .getCharacterSet();
298: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
299: throw new SQLException(
300: "Can not call updateNClob() when field's character set isn't UTF-8");
301: }
302:
303: if (nClob == null) {
304: updateNull(columnIndex);
305: } else {
306: updateNCharacterStream(columnIndex, nClob
307: .getCharacterStream(), (int) nClob.length());
308: }
309: }
310:
311: /**
312: * @see ResultSet#updateClob(int, Clob)
313: */
314: public void updateNClob(String columnName, java.sql.NClob nClob)
315: throws SQLException {
316: updateNClob(findColumn(columnName), nClob);
317: }
318:
319: /**
320: * JDBC 4.0 Update a column with NATIONAL CHARACTER. The updateXXX() methods
321: * are used to update column values in the current row, or the insert row.
322: * The updateXXX() methods do not update the underlying database, instead
323: * the updateRow() or insertRow() methods are called to update the database.
324: *
325: * @param columnIndex
326: * the first column is 1, the second is 2, ...
327: * @param x
328: * the new column value
329: *
330: * @exception SQLException
331: * if a database-access error occurs
332: */
333: public synchronized void updateNString(int columnIndex, String x)
334: throws SQLException {
335: String fieldEncoding = this .fields[columnIndex - 1]
336: .getCharacterSet();
337: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
338: throw new SQLException(
339: "Can not call updateNString() when field's character set isn't UTF-8");
340: }
341:
342: if (!this .onInsertRow) {
343: if (!this .doingUpdates) {
344: this .doingUpdates = true;
345: syncUpdate();
346: }
347:
348: ((com.mysql.jdbc.JDBC4PreparedStatement) this .updater)
349: .setNString(columnIndex, x);
350: } else {
351: ((com.mysql.jdbc.JDBC4PreparedStatement) this .inserter)
352: .setNString(columnIndex, x);
353:
354: if (x == null) {
355: this .this Row.setColumnValue(columnIndex, null);
356: } else {
357: this .this Row.setColumnValue(columnIndex, StringUtils
358: .getBytes(x, this .charConverter, fieldEncoding,
359: this .connection
360: .getServerCharacterEncoding(),
361: this .connection.parserKnowsUnicode()));
362: }
363: }
364: }
365:
366: /**
367: * JDBC 4.0 Update a column with NATIONAL CHARACTER. The updateXXX() methods
368: * are used to update column values in the current row, or the insert row.
369: * The updateXXX() methods do not update the underlying database, instead
370: * the updateRow() or insertRow() methods are called to update the database.
371: *
372: * @param columnName
373: * the name of the column
374: * @param x
375: * the new column value
376: *
377: * @exception SQLException
378: * if a database-access error occurs
379: */
380: public synchronized void updateNString(String columnName, String x)
381: throws SQLException {
382: updateNString(findColumn(columnName), x);
383: }
384:
385: public int getHoldability() throws SQLException {
386: throw new NotYetImplementedException();
387: }
388:
389: /**
390: * JDBC 4.0 Get a NCLOB column.
391: *
392: * @param columnIndex
393: * the first column is 1, the second is 2, ...
394: *
395: * @return an object representing a NCLOB
396: *
397: * @throws SQLException
398: * if an error occurs
399: */
400: protected java.sql.NClob getNativeNClob(int columnIndex)
401: throws SQLException {
402: String stringVal = getStringForNClob(columnIndex);
403:
404: if (stringVal == null) {
405: return null;
406: }
407:
408: return getNClobFromString(stringVal, columnIndex);
409: }
410:
411: /**
412: * JDBC 4.0
413: *
414: * <p>
415: * Get the value of a column in the current row as a java.io.Reader.
416: * </p>
417: *
418: * @param columnIndex
419: * the column to get the value from
420: *
421: * @return the value in the column as a java.io.Reader.
422: *
423: * @throws SQLException
424: * if an error occurs
425: */
426: public Reader getNCharacterStream(int columnIndex)
427: throws SQLException {
428: String fieldEncoding = this .fields[columnIndex - 1]
429: .getCharacterSet();
430: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
431: throw new SQLException(
432: "Can not call getNCharacterStream() when field's charset isn't UTF-8");
433: }
434:
435: return getCharacterStream(columnIndex);
436: }
437:
438: /**
439: * JDBC 4.0
440: *
441: * <p>
442: * Get the value of a column in the current row as a java.io.Reader.
443: * </p>
444: *
445: * @param columnName
446: * the column name to retrieve the value from
447: *
448: * @return the value as a java.io.Reader
449: *
450: * @throws SQLException
451: * if an error occurs
452: */
453: public Reader getNCharacterStream(String columnName)
454: throws SQLException {
455: return getNCharacterStream(findColumn(columnName));
456: }
457:
458: /**
459: * JDBC 4.0 Get a NCLOB column.
460: *
461: * @param i
462: * the first column is 1, the second is 2, ...
463: *
464: * @return an object representing a NCLOB
465: *
466: * @throws SQLException
467: * if an error occurs
468: */
469: public NClob getNClob(int columnIndex) throws SQLException {
470: String fieldEncoding = this .fields[columnIndex - 1]
471: .getCharacterSet();
472:
473: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
474: throw new SQLException(
475: "Can not call getNClob() when field's charset isn't UTF-8");
476: }
477:
478: if (!this .isBinaryEncoded) {
479: String asString = getStringForNClob(columnIndex);
480:
481: if (asString == null) {
482: return null;
483: }
484:
485: return new com.mysql.jdbc.JDBC4NClob(asString);
486: }
487:
488: return getNativeNClob(columnIndex);
489: }
490:
491: /**
492: * JDBC 4.0 Get a NCLOB column.
493: *
494: * @param colName
495: * the column name
496: *
497: * @return an object representing a NCLOB
498: *
499: * @throws SQLException
500: * if an error occurs
501: */
502: public NClob getNClob(String columnName) throws SQLException {
503: return getNClob(findColumn(columnName));
504: }
505:
506: private final java.sql.NClob getNClobFromString(String stringVal,
507: int columnIndex) throws SQLException {
508: return new com.mysql.jdbc.JDBC4NClob(stringVal);
509: }
510:
511: /**
512: * JDBC 4.0
513: *
514: * Get the value of a column in the current row as a Java String
515: *
516: * @param columnIndex
517: * the first column is 1, the second is 2...
518: *
519: * @return the column value, null for SQL NULL
520: *
521: * @exception SQLException
522: * if a database access error occurs
523: */
524: public String getNString(int columnIndex) throws SQLException {
525: String fieldEncoding = this .fields[columnIndex - 1]
526: .getCharacterSet();
527:
528: if (fieldEncoding == null || !fieldEncoding.equals("UTF-8")) {
529: throw new SQLException(
530: "Can not call getNString() when field's charset isn't UTF-8");
531: }
532:
533: return getString(columnIndex);
534: }
535:
536: /**
537: * JDBC 4.0
538: *
539: * The following routines simply convert the columnName into a columnIndex
540: * and then call the appropriate routine above.
541: *
542: * @param columnName
543: * is the SQL name of the column
544: *
545: * @return the column value
546: *
547: * @exception SQLException
548: * if a database access error occurs
549: */
550: public String getNString(String columnName) throws SQLException {
551: return getNString(findColumn(columnName));
552: }
553:
554: public RowId getRowId(int columnIndex) throws SQLException {
555: throw new NotYetImplementedException();
556: }
557:
558: public RowId getRowId(String columnLabel) throws SQLException {
559: return getRowId(findColumn(columnLabel));
560: }
561:
562: public SQLXML getSQLXML(int columnIndex) throws SQLException {
563: return new JDBC4MysqlSQLXML(this , columnIndex);
564: }
565:
566: public SQLXML getSQLXML(String columnLabel) throws SQLException {
567: return getSQLXML(findColumn(columnLabel));
568: }
569:
570: private String getStringForNClob(int columnIndex)
571: throws SQLException {
572: String asString = null;
573:
574: String forcedEncoding = "UTF-8";
575:
576: try {
577: byte[] asBytes = null;
578:
579: if (!this .isBinaryEncoded) {
580: asBytes = getBytes(columnIndex);
581: } else {
582: asBytes = getNativeBytes(columnIndex, true);
583: }
584:
585: if (asBytes != null) {
586: asString = new String(asBytes, forcedEncoding);
587: }
588: } catch (UnsupportedEncodingException uee) {
589: throw SQLError.createSQLException(
590: "Unsupported character encoding " + forcedEncoding,
591: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
592: }
593:
594: return asString;
595: }
596:
597: public synchronized boolean isClosed() throws SQLException {
598: return this .isClosed;
599: }
600:
601: /**
602: * Returns true if this either implements the interface argument or is
603: * directly or indirectly a wrapper for an object that does. Returns false
604: * otherwise. If this implements the interface then return true, else if
605: * this is a wrapper then return the result of recursively calling
606: * <code>isWrapperFor</code> on the wrapped object. If this does not
607: * implement the interface and is not a wrapper, return false. This method
608: * should be implemented as a low-cost operation compared to
609: * <code>unwrap</code> so that callers can use this method to avoid
610: * expensive <code>unwrap</code> calls that may fail. If this method
611: * returns true then calling <code>unwrap</code> with the same argument
612: * should succeed.
613: *
614: * @param interfaces
615: * a Class defining an interface.
616: * @return true if this implements the interface or directly or indirectly
617: * wraps an object that does.
618: * @throws java.sql.SQLException
619: * if an error occurs while determining whether this is a
620: * wrapper for an object with the given interface.
621: * @since 1.6
622: */
623: public boolean isWrapperFor(Class<?> iface) throws SQLException {
624: checkClosed();
625:
626: // This works for classes that aren't actually wrapping
627: // anything
628: return iface.isInstance(this );
629: }
630:
631: /**
632: * Returns an object that implements the given interface to allow access to
633: * non-standard methods, or standard methods not exposed by the proxy. The
634: * result may be either the object found to implement the interface or a
635: * proxy for that object. If the receiver implements the interface then that
636: * is the object. If the receiver is a wrapper and the wrapped object
637: * implements the interface then that is the object. Otherwise the object is
638: * the result of calling <code>unwrap</code> recursively on the wrapped
639: * object. If the receiver is not a wrapper and does not implement the
640: * interface, then an <code>SQLException</code> is thrown.
641: *
642: * @param iface
643: * A Class defining an interface that the result must implement.
644: * @return an object that implements the interface. May be a proxy for the
645: * actual implementing object.
646: * @throws java.sql.SQLException
647: * If no object found that implements the interface
648: * @since 1.6
649: */
650: public <T> T unwrap(java.lang.Class<T> iface)
651: throws java.sql.SQLException {
652: try {
653: // This works for classes that aren't actually wrapping
654: // anything
655: return iface.cast(this );
656: } catch (ClassCastException cce) {
657: throw SQLError.createSQLException("Unable to unwrap to "
658: + iface.toString(),
659: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
660: }
661: }
662: }
|