File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\jdbc\JdbcConnection.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.jdbc;
8
9 import java.io.ByteArrayInputStream;
10 import java.io.InputStream;
11 import java.io.InputStreamReader;
12 import java.io.Reader;
13 import java.sql.Blob;
14 import java.sql.CallableStatement;
15 import java.sql.Clob;
16 import java.sql.Connection;
17 import java.sql.DatabaseMetaData;
18 import java.sql.PreparedStatement;
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.sql.SQLWarning;
22 import java.sql.Savepoint;
23 import java.sql.Statement;
24 import java.util.Map;
25 import java.util.Properties;
26 import org.h2.command.CommandInterface;
27 import org.h2.constant.ErrorCode;
28 import org.h2.constant.SysProperties;
29 import org.h2.engine.ConnectionInfo;
30 import org.h2.engine.Constants;
31 import org.h2.engine.SessionInterface;
32 import org.h2.engine.SessionRemote;
33 import org.h2.message.DbException;
34 import org.h2.message.TraceObject;
35 import org.h2.result.ResultInterface;
36 import org.h2.util.CloseWatcher;
37 import org.h2.util.Utils;
38 import org.h2.value.CompareMode;
39 import org.h2.value.Value;
40 import org.h2.value.ValueInt;
41 import org.h2.value.ValueNull;
42 import org.h2.value.ValueString;
43
44 //## Java 1.6 ##
45 import java.sql.Array;
46 import java.sql.NClob;
47 import java.sql.Struct;
48 import java.sql.SQLXML;
49 import java.sql.SQLClientInfoException;
50 //*/
51
52 /*## Java 1.7 ##
53 import java.util.concurrent.Executor;
54 //*/
55
56 /**
57 * <p>
58 * Represents a connection (session) to a database.
59 * </p>
60 * <p>
61 * Thread safety: the connection is thread-safe, because access
62 * is synchronized. However, for compatibility with other databases, a
63 * connection should only be used in one thread at any time.
64 * </p>
65 */
66 public class JdbcConnection extends TraceObject implements Connection {
67
68 private static boolean keepOpenStackTrace;
69
70 private final String url;
71 private final String user;
72
73 // ResultSet.HOLD_CURSORS_OVER_COMMIT
74 private int holdability = 1;
75
76 private SessionInterface session;
77 private CommandInterface commit, rollback;
78 private CommandInterface getReadOnly, getGeneratedKeys;
79 private CommandInterface setLockMode, getLockMode;
80 private CommandInterface setQueryTimeout, getQueryTimeout;
81
82 private int savepointId;
83 private String catalog;
84 private Statement executingStatement;
85 private final CompareMode compareMode = CompareMode.getInstance(null, 0);
86 private final CloseWatcher watcher;
87 private int queryTimeoutCache = -1;
88
89 /**
90 * INTERNAL
91 */
92 public JdbcConnection(String url, Properties info) throws SQLException {
93 this(new ConnectionInfo(url, info), true);
94 }
95
96 /**
97 * INTERNAL
98 */
99 public JdbcConnection(ConnectionInfo ci, boolean useBaseDir) throws SQLException {
100 try {
101 if (useBaseDir) {
102 String baseDir = SysProperties.getBaseDir();
103 if (baseDir != null) {
104 ci.setBaseDir(baseDir);
105 }
106 }
107 checkJavaVersion();
108 // this will return an embedded or server connection
109 session = new SessionRemote(ci).connectEmbeddedOrServer(false);
110 trace = session.getTrace();
111 int id = getNextId(TraceObject.CONNECTION);
112 setTrace(trace, TraceObject.CONNECTION, id);
113 this.user = ci.getUserName();
114 if (isInfoEnabled()) {
115 trace.infoCode("Connection " + getTraceObjectName()
116 + " = DriverManager.getConnection(" + quote(ci.getOriginalURL())
117 + ", " + quote(user) + ", \"\");");
118 }
119 this.url = ci.getURL();
120 closeOld();
121 watcher = CloseWatcher.register(this, session, keepOpenStackTrace);
122 } catch (Exception e) {
123 throw logAndConvert(e);
124 }
125 }
126
127 /**
128 * INTERNAL
129 */
130 public JdbcConnection(JdbcConnection clone) {
131 this.session = clone.session;
132 trace = session.getTrace();
133 int id = getNextId(TraceObject.CONNECTION);
134 setTrace(trace, TraceObject.CONNECTION, id);
135 this.user = clone.user;
136 this.url = clone.url;
137 this.catalog = clone.catalog;
138 this.commit = clone.commit;
139 this.getGeneratedKeys = clone.getGeneratedKeys;
140 this.getLockMode = clone.getLockMode;
141 this.getQueryTimeout = clone.getQueryTimeout;
142 this.getReadOnly = clone.getReadOnly;
143 this.rollback = clone.rollback;
144 this.watcher = null;
145 }
146
147 /**
148 * INTERNAL
149 */
150 public JdbcConnection(SessionInterface session, String user, String url) {
151 this.session = session;
152 trace = session.getTrace();
153 int id = getNextId(TraceObject.CONNECTION);
154 setTrace(trace, TraceObject.CONNECTION, id);
155 this.user = user;
156 this.url = url;
157 this.watcher = null;
158 }
159
160 private void closeOld() {
161 while (true) {
162 CloseWatcher w = CloseWatcher.pollUnclosed();
163 if (w == null) {
164 break;
165 }
166 try {
167 w.getCloseable().close();
168 } catch (Exception e) {
169 trace.error(e, "closing session");
170 }
171 // there was an unclosed object -
172 // keep the stack trace from now on
173 keepOpenStackTrace = true;
174 String s = w.getOpenStackTrace();
175 Exception ex = DbException.get(ErrorCode.TRACE_CONNECTION_NOT_CLOSED);
176 trace.error(ex, s);
177 }
178 }
179
180 /**
181 * Creates a new statement.
182 *
183 * @return the new statement
184 * @throws SQLException if the connection is closed
185 */
186 public Statement createStatement() throws SQLException {
187 try {
188 int id = getNextId(TraceObject.STATEMENT);
189 if (isDebugEnabled()) {
190 debugCodeAssign("Statement", TraceObject.STATEMENT, id, "createStatement()");
191 }
192 checkClosed();
193 return new JdbcStatement(this, id, ResultSet.TYPE_FORWARD_ONLY, Constants.DEFAULT_RESULT_SET_CONCURRENCY, false);
194 } catch (Exception e) {
195 throw logAndConvert(e);
196 }
197 }
198
199 /**
200 * Creates a statement with the specified result set type and concurrency.
201 *
202 * @param resultSetType the result set type (ResultSet.TYPE_*)
203 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
204 * @return the statement
205 * @throws SQLException
206 * if the connection is closed or the result set type or
207 * concurrency are not supported
208 */
209 public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
210 try {
211 int id = getNextId(TraceObject.STATEMENT);
212 if (isDebugEnabled()) {
213 debugCodeAssign("Statement", TraceObject.STATEMENT, id,
214 "createStatement(" + resultSetType + ", " + resultSetConcurrency + ")");
215 }
216 checkTypeConcurrency(resultSetType, resultSetConcurrency);
217 checkClosed();
218 return new JdbcStatement(this, id, resultSetType, resultSetConcurrency, false);
219 } catch (Exception e) {
220 throw logAndConvert(e);
221 }
222 }
223
224 /**
225 * Creates a statement with the specified result set type, concurrency, and
226 * holdability.
227 *
228 * @param resultSetType the result set type (ResultSet.TYPE_*)
229 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
230 * @param resultSetHoldability the holdability (ResultSet.HOLD* / CLOSE*)
231 * @return the statement
232 * @throws SQLException if the connection is closed or the result set type,
233 * concurrency, or holdability are not supported
234 */
235 public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
236 throws SQLException {
237 try {
238 int id = getNextId(TraceObject.STATEMENT);
239 if (isDebugEnabled()) {
240 debugCodeAssign("Statement", TraceObject.STATEMENT, id,
241 "createStatement(" + resultSetType + ", " + resultSetConcurrency + ", " + resultSetHoldability + ")");
242 }
243 checkTypeConcurrency(resultSetType, resultSetConcurrency);
244 checkHoldability(resultSetHoldability);
245 checkClosed();
246 return new JdbcStatement(this, id, resultSetType, resultSetConcurrency, false);
247 } catch (Exception e) {
248 throw logAndConvert(e);
249 }
250 }
251
252 /**
253 * Creates a new prepared statement.
254 *
255 * @param sql the SQL statement
256 * @return the prepared statement
257 * @throws SQLException if the connection is closed
258 */
259 public PreparedStatement prepareStatement(String sql) throws SQLException {
260 try {
261 int id = getNextId(TraceObject.PREPARED_STATEMENT);
262 if (isDebugEnabled()) {
263 debugCodeAssign("PreparedStatement", TraceObject.PREPARED_STATEMENT, id, "prepareStatement(" + quote(sql) + ")");
264 }
265 checkClosed();
266 sql = translateSQL(sql);
267 return new JdbcPreparedStatement(this, sql, id,
268 ResultSet.TYPE_FORWARD_ONLY, Constants.DEFAULT_RESULT_SET_CONCURRENCY, false);
269 } catch (Exception e) {
270 throw logAndConvert(e);
271 }
272 }
273
274 /**
275 * Prepare a statement that will automatically close when the result set is
276 * closed. This method is used to retrieve database meta data.
277 *
278 * @param sql the SQL statement
279 * @return the prepared statement
280 */
281 PreparedStatement prepareAutoCloseStatement(String sql) throws SQLException {
282 try {
283 int id = getNextId(TraceObject.PREPARED_STATEMENT);
284 if (isDebugEnabled()) {
285 debugCodeAssign("PreparedStatement", TraceObject.PREPARED_STATEMENT, id, "prepareStatement(" + quote(sql) + ")");
286 }
287 checkClosed();
288 sql = translateSQL(sql);
289 return new JdbcPreparedStatement(this, sql, id,
290 ResultSet.TYPE_FORWARD_ONLY, Constants.DEFAULT_RESULT_SET_CONCURRENCY, true);
291 } catch (Exception e) {
292 throw logAndConvert(e);
293 }
294 }
295
296 /**
297 * Gets the database meta data for this database.
298 *
299 * @return the database meta data
300 * @throws SQLException if the connection is closed
301 */
302 public DatabaseMetaData getMetaData() throws SQLException {
303 try {
304 int id = getNextId(TraceObject.DATABASE_META_DATA);
305 if (isDebugEnabled()) {
306 debugCodeAssign("DatabaseMetaData", TraceObject.DATABASE_META_DATA, id, "getMetaData()");
307 }
308 checkClosed();
309 return new JdbcDatabaseMetaData(this, trace, id);
310 } catch (Exception e) {
311 throw logAndConvert(e);
312 }
313 }
314
315 /**
316 * INTERNAL
317 */
318 public SessionInterface getSession() {
319 return session;
320 }
321
322 /**
323 * Closes this connection. All open statements, prepared statements and
324 * result sets that where created by this connection become invalid after
325 * calling this method. If there is an uncommitted transaction, it will be
326 * rolled back.
327 */
328 public synchronized void close() throws SQLException {
329 try {
330 debugCodeCall("close");
331 if (session == null) {
332 return;
333 }
334 CloseWatcher.unregister(watcher);
335 session.cancel();
336 if (executingStatement != null) {
337 try {
338 executingStatement.cancel();
339 } catch (NullPointerException e) {
340 // ignore
341 }
342 }
343 synchronized (session) {
344 try {
345 if (!session.isClosed()) {
346 try {
347 if (session.getUndoLogPos() != 0) {
348 // roll back unless that would require to re-connect
349 // (the transaction can't be rolled back after re-connecting)
350 if (!session.isReconnectNeeded(true)) {
351 try {
352 rollbackInternal();
353 } catch (DbException e) {
354 // ignore if the connection is broken right now
355 if (e.getErrorCode() != ErrorCode.CONNECTION_BROKEN_1) {
356 throw e;
357 }
358 }
359 }
360 session.afterWriting();
361 }
362 closePreparedCommands();
363 } finally {
364 session.close();
365 }
366 }
367 } finally {
368 session = null;
369 }
370 }
371 } catch (Exception e) {
372 throw logAndConvert(e);
373 }
374 }
375
376 private void closePreparedCommands() {
377 commit = closeAndSetNull(commit);
378 rollback = closeAndSetNull(rollback);
379 getReadOnly = closeAndSetNull(getReadOnly);
380 getGeneratedKeys = closeAndSetNull(getGeneratedKeys);
381 getLockMode = closeAndSetNull(getLockMode);
382 setLockMode = closeAndSetNull(setLockMode);
383 getQueryTimeout = closeAndSetNull(getQueryTimeout);
384 setQueryTimeout = closeAndSetNull(setQueryTimeout);
385 }
386
387 private static CommandInterface closeAndSetNull(CommandInterface command) {
388 if (command != null) {
389 command.close();
390 }
391 return null;
392 }
393
394 /**
395 * Switches auto commit on or off. Enabling it commits an uncommitted
396 * transaction, if there is one.
397 *
398 * @param autoCommit true for auto commit on, false for off
399 * @throws SQLException if the connection is closed
400 */
401 public synchronized void setAutoCommit(boolean autoCommit) throws SQLException {
402 try {
403 if (isDebugEnabled()) {
404 debugCode("setAutoCommit(" + autoCommit + ");");
405 }
406 checkClosed();
407 if (autoCommit && !session.getAutoCommit()) {
408 commit();
409 }
410 session.setAutoCommit(autoCommit);
411 } catch (Exception e) {
412 throw logAndConvert(e);
413 }
414 }
415
416 /**
417 * Gets the current setting for auto commit.
418 *
419 * @return true for on, false for off
420 * @throws SQLException if the connection is closed
421 */
422 public synchronized boolean getAutoCommit() throws SQLException {
423 try {
424 checkClosed();
425 debugCodeCall("getAutoCommit");
426 return session.getAutoCommit();
427 } catch (Exception e) {
428 throw logAndConvert(e);
429 }
430 }
431
432 /**
433 * Commits the current transaction. This call has only an effect if auto
434 * commit is switched off.
435 *
436 * @throws SQLException if the connection is closed
437 */
438 public synchronized void commit() throws SQLException {
439 try {
440 debugCodeCall("commit");
441 checkClosedForWrite();
442 try {
443 commit = prepareCommand("COMMIT", commit);
444 commit.executeUpdate();
445 } finally {
446 afterWriting();
447 }
448 } catch (Exception e) {
449 throw logAndConvert(e);
450 }
451 }
452
453 /**
454 * Rolls back the current transaction. This call has only an effect if auto
455 * commit is switched off.
456 *
457 * @throws SQLException if the connection is closed
458 */
459 public synchronized void rollback() throws SQLException {
460 try {
461 debugCodeCall("rollback");
462 checkClosedForWrite();
463 try {
464 rollbackInternal();
465 } finally {
466 afterWriting();
467 }
468 } catch (Exception e) {
469 throw logAndConvert(e);
470 }
471 }
472
473 /**
474 * Returns true if this connection has been closed.
475 *
476 * @return true if close was called
477 */
478 public boolean isClosed() throws SQLException {
479 try {
480 debugCodeCall("isClosed");
481 return session == null || session.isClosed();
482 } catch (Exception e) {
483 throw logAndConvert(e);
484 }
485 }
486
487 /**
488 * Translates a SQL statement into the database grammar.
489 *
490 * @param sql the SQL statement with or without JDBC escape sequences
491 * @return the translated statement
492 * @throws SQLException if the connection is closed
493 */
494 public String nativeSQL(String sql) throws SQLException {
495 try {
496 debugCodeCall("nativeSQL", sql);
497 checkClosed();
498 return translateSQL(sql);
499 } catch (Exception e) {
500 throw logAndConvert(e);
501 }
502 }
503
504 /**
505 * According to the JDBC specs, this setting is only a hint to the database
506 * to enable optimizations - it does not cause writes to be prohibited.
507 *
508 * @param readOnly ignored
509 * @throws SQLException if the connection is closed
510 */
511 public void setReadOnly(boolean readOnly) throws SQLException {
512 try {
513 if (isDebugEnabled()) {
514 debugCode("setReadOnly(" + readOnly + ");");
515 }
516 checkClosed();
517 } catch (Exception e) {
518 throw logAndConvert(e);
519 }
520 }
521
522 /**
523 * Returns true if the database is read-only.
524 *
525 * @return if the database is read-only
526 * @throws SQLException if the connection is closed
527 */
528 public boolean isReadOnly() throws SQLException {
529 try {
530 debugCodeCall("isReadOnly");
531 checkClosed();
532 getReadOnly = prepareCommand("CALL READONLY()", getReadOnly);
533 ResultInterface result = getReadOnly.executeQuery(0, false);
534 result.next();
535 boolean readOnly = result.currentRow()[0].getBoolean().booleanValue();
536 return readOnly;
537 } catch (Exception e) {
538 throw logAndConvert(e);
539 }
540 }
541
542 /**
543 * Set the default catalog name. This call is ignored.
544 *
545 * @param catalog ignored
546 * @throws SQLException if the connection is closed
547 */
548 public void setCatalog(String catalog) throws SQLException {
549 try {
550 debugCodeCall("setCatalog", catalog);
551 checkClosed();
552 } catch (Exception e) {
553 throw logAndConvert(e);
554 }
555 }
556
557 /**
558 * Gets the current catalog name.
559 *
560 * @return the catalog name
561 * @throws SQLException if the connection is closed
562 */
563 public String getCatalog() throws SQLException {
564 try {
565 debugCodeCall("getCatalog");
566 checkClosed();
567 if (catalog == null) {
568 CommandInterface cat = prepareCommand("CALL DATABASE()", Integer.MAX_VALUE);
569 ResultInterface result = cat.executeQuery(0, false);
570 result.next();
571 catalog = result.currentRow()[0].getString();
572 cat.close();
573 }
574 return catalog;
575 } catch (Exception e) {
576 throw logAndConvert(e);
577 }
578 }
579
580 /**
581 * Gets the first warning reported by calls on this object.
582 *
583 * @return null
584 */
585 public SQLWarning getWarnings() throws SQLException {
586 try {
587 debugCodeCall("getWarnings");
588 checkClosed();
589 return null;
590 } catch (Exception e) {
591 throw logAndConvert(e);
592 }
593 }
594
595 /**
596 * Clears all warnings.
597 */
598 public void clearWarnings() throws SQLException {
599 try {
600 debugCodeCall("clearWarnings");
601 checkClosed();
602 } catch (Exception e) {
603 throw logAndConvert(e);
604 }
605 }
606
607 /**
608 * Creates a prepared statement with the specified result set type and
609 * concurrency.
610 *
611 * @param sql the SQL statement
612 * @param resultSetType the result set type (ResultSet.TYPE_*)
613 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
614 * @return the prepared statement
615 * @throws SQLException
616 * if the connection is closed or the result set type or
617 * concurrency are not supported
618 */
619 public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
620 try {
621 int id = getNextId(TraceObject.PREPARED_STATEMENT);
622 if (isDebugEnabled()) {
623 debugCodeAssign("PreparedStatement", TraceObject.PREPARED_STATEMENT, id,
624 "prepareStatement(" + quote(sql) + ", " + resultSetType + ", " + resultSetConcurrency + ")");
625 }
626 checkTypeConcurrency(resultSetType, resultSetConcurrency);
627 checkClosed();
628 sql = translateSQL(sql);
629 return new JdbcPreparedStatement(this, sql, id, resultSetType, resultSetConcurrency, false);
630 } catch (Exception e) {
631 throw logAndConvert(e);
632 }
633 }
634
635 /**
636 * Changes the current transaction isolation level. Calling this method will
637 * commit an open transaction, even if the new level is the same as the old
638 * one, except if the level is not supported. Internally, this method calls
639 * SET LOCK_MODE. The following isolation levels are supported:
640 * <ul>
641 * <li> Connection.TRANSACTION_READ_UNCOMMITTED = SET LOCK_MODE 0: no
642 * locking (should only be used for testing). </li>
643 * <li>Connection.TRANSACTION_SERIALIZABLE = SET LOCK_MODE 1: table level
644 * locking. </li>
645 * <li>Connection.TRANSACTION_READ_COMMITTED = SET LOCK_MODE 3: table
646 * level locking, but read locks are released immediately (default). </li>
647 * </ul>
648 * This setting is not persistent. Please note that using
649 * TRANSACTION_READ_UNCOMMITTED while at the same time using multiple
650 * connections may result in inconsistent transactions.
651 *
652 * @param level the new transaction isolation level:
653 * Connection.TRANSACTION_READ_UNCOMMITTED,
654 * Connection.TRANSACTION_READ_COMMITTED, or
655 * Connection.TRANSACTION_SERIALIZABLE
656 * @throws SQLException if the connection is closed or the isolation level
657 * is not supported
658 */
659 public void setTransactionIsolation(int level) throws SQLException {
660 try {
661 debugCodeCall("setTransactionIsolation", level);
662 checkClosed();
663 int lockMode;
664 switch(level) {
665 case Connection.TRANSACTION_READ_UNCOMMITTED:
666 lockMode = Constants.LOCK_MODE_OFF;
667 break;
668 case Connection.TRANSACTION_READ_COMMITTED:
669 lockMode = Constants.LOCK_MODE_READ_COMMITTED;
670 break;
671 case Connection.TRANSACTION_REPEATABLE_READ:
672 case Connection.TRANSACTION_SERIALIZABLE:
673 lockMode = Constants.LOCK_MODE_TABLE;
674 break;
675 default:
676 throw DbException.getInvalidValueException("level", level);
677 }
678 commit();
679 setLockMode = prepareCommand("SET LOCK_MODE ?", setLockMode);
680 setLockMode.getParameters().get(0).setValue(ValueInt.get(lockMode), false);
681 setLockMode.executeUpdate();
682 } catch (Exception e) {
683 throw logAndConvert(e);
684 }
685 }
686
687 /**
688 * INTERNAL
689 */
690 public void setQueryTimeout(int seconds) throws SQLException {
691 try {
692 debugCodeCall("setQueryTimeout", seconds);
693 checkClosed();
694 setQueryTimeout = prepareCommand("SET QUERY_TIMEOUT ?", setQueryTimeout);
695 setQueryTimeout.getParameters().get(0).setValue(ValueInt.get(seconds * 1000), false);
696 setQueryTimeout.executeUpdate();
697 queryTimeoutCache = seconds;
698 } catch (Exception e) {
699 throw logAndConvert(e);
700 }
701 }
702
703 /**
704 * INTERNAL
705 */
706 public int getQueryTimeout() throws SQLException {
707 try {
708 debugCodeCall("getQueryTimeout");
709 if (queryTimeoutCache == -1) {
710 checkClosed();
711 getQueryTimeout = prepareCommand("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?", getQueryTimeout);
712 getQueryTimeout.getParameters().get(0).setValue(ValueString.get("QUERY_TIMEOUT"), false);
713 ResultInterface result = getQueryTimeout.executeQuery(0, false);
714 result.next();
715 int queryTimeout = result.currentRow()[0].getInt();
716 result.close();
717 if (queryTimeout != 0) {
718 // round to the next second, otherwise 999 millis would return 0 seconds
719 queryTimeout = (queryTimeout + 999) / 1000;
720 }
721 queryTimeoutCache = queryTimeout;
722 }
723 return queryTimeoutCache;
724 } catch (Exception e) {
725 throw logAndConvert(e);
726 }
727 }
728
729 /**
730 * Returns the current transaction isolation level.
731 *
732 * @return the isolation level.
733 * @throws SQLException if the connection is closed
734 */
735 public int getTransactionIsolation() throws SQLException {
736 try {
737 debugCodeCall("getTransactionIsolation");
738 checkClosed();
739 getLockMode = prepareCommand("CALL LOCK_MODE()", getLockMode);
740 ResultInterface result = getLockMode.executeQuery(0, false);
741 result.next();
742 int lockMode = result.currentRow()[0].getInt();
743 result.close();
744 int transactionIsolationLevel;
745 switch(lockMode) {
746 case Constants.LOCK_MODE_OFF:
747 transactionIsolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
748 break;
749 case Constants.LOCK_MODE_READ_COMMITTED:
750 transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED;
751 break;
752 case Constants.LOCK_MODE_TABLE:
753 case Constants.LOCK_MODE_TABLE_GC:
754 transactionIsolationLevel = Connection.TRANSACTION_SERIALIZABLE;
755 break;
756 default:
757 throw DbException.throwInternalError("lockMode:" + lockMode);
758 }
759 return transactionIsolationLevel;
760 } catch (Exception e) {
761 throw logAndConvert(e);
762 }
763 }
764
765 /**
766 * Changes the current result set holdability.
767 *
768 * @param holdability
769 * ResultSet.HOLD_CURSORS_OVER_COMMIT or
770 * ResultSet.CLOSE_CURSORS_AT_COMMIT;
771 * @throws SQLException
772 * if the connection is closed or the holdability is not
773 * supported
774 */
775 public void setHoldability(int holdability) throws SQLException {
776 try {
777 debugCodeCall("setHoldability", holdability);
778 checkClosed();
779 checkHoldability(holdability);
780 this.holdability = holdability;
781 } catch (Exception e) {
782 throw logAndConvert(e);
783 }
784 }
785
786 /**
787 * Returns the current result set holdability.
788 *
789 * @return the holdability
790 * @throws SQLException if the connection is closed
791 */
792 public int getHoldability() throws SQLException {
793 try {
794 debugCodeCall("getHoldability");
795 checkClosed();
796 return holdability;
797 } catch (Exception e) {
798 throw logAndConvert(e);
799 }
800 }
801
802 /**
803 * Gets the type map.
804 *
805 * @return null
806 * @throws SQLException if the connection is closed
807 */
808 public Map<String, Class<?>> getTypeMap() throws SQLException {
809 try {
810 debugCodeCall("getTypeMap");
811 checkClosed();
812 return null;
813 } catch (Exception e) {
814 throw logAndConvert(e);
815 }
816 }
817
818 /**
819 * [Partially supported] Sets the type map. This is only supported if the
820 * map is empty or null.
821 */
822 public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
823 try {
824 debugCode("setTypeMap(" + quoteMap(map) + ");");
825 checkMap(map);
826 } catch (Exception e) {
827 throw logAndConvert(e);
828 }
829 }
830
831 /**
832 * Creates a new callable statement.
833 *
834 * @param sql the SQL statement
835 * @return the callable statement
836 * @throws SQLException
837 * if the connection is closed or the statement is not valid
838 */
839 public CallableStatement prepareCall(String sql) throws SQLException {
840 try {
841 int id = getNextId(TraceObject.CALLABLE_STATEMENT);
842 if (isDebugEnabled()) {
843 debugCodeAssign("CallableStatement", TraceObject.CALLABLE_STATEMENT, id, "prepareCall(" + quote(sql) + ")");
844 }
845 checkClosed();
846 sql = translateSQL(sql);
847 return new JdbcCallableStatement(this, sql, id, ResultSet.TYPE_FORWARD_ONLY, Constants.DEFAULT_RESULT_SET_CONCURRENCY);
848 } catch (Exception e) {
849 throw logAndConvert(e);
850 }
851 }
852
853 /**
854 * Creates a callable statement with the specified result set type and
855 * concurrency.
856 *
857 * @param sql the SQL statement
858 * @param resultSetType the result set type (ResultSet.TYPE_*)
859 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
860 * @return the callable statement
861 * @throws SQLException
862 * if the connection is closed or the result set type or
863 * concurrency are not supported
864 */
865 public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
866 try {
867 int id = getNextId(TraceObject.CALLABLE_STATEMENT);
868 if (isDebugEnabled()) {
869 debugCodeAssign("CallableStatement", TraceObject.CALLABLE_STATEMENT, id,
870 "prepareCall(" + quote(sql) + ", " + resultSetType + ", " + resultSetConcurrency + ")");
871 }
872 checkTypeConcurrency(resultSetType, resultSetConcurrency);
873 checkClosed();
874 sql = translateSQL(sql);
875 return new JdbcCallableStatement(this, sql, id, resultSetType, resultSetConcurrency);
876 } catch (Exception e) {
877 throw logAndConvert(e);
878 }
879 }
880
881 /**
882 * Creates a callable statement with the specified result set type,
883 * concurrency, and holdability.
884 *
885 * @param sql the SQL statement
886 * @param resultSetType the result set type (ResultSet.TYPE_*)
887 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
888 * @param resultSetHoldability the holdability (ResultSet.HOLD* / CLOSE*)
889 * @return the callable statement
890 * @throws SQLException
891 * if the connection is closed or the result set type,
892 * concurrency, or holdability are not supported
893 */
894 public CallableStatement prepareCall(String sql, int resultSetType,
895 int resultSetConcurrency, int resultSetHoldability) throws SQLException {
896 try {
897 int id = getNextId(TraceObject.CALLABLE_STATEMENT);
898 if (isDebugEnabled()) {
899 debugCodeAssign("CallableStatement", TraceObject.CALLABLE_STATEMENT, id,
900 "prepareCall(" + quote(sql) + ", " + resultSetType + ", " + resultSetConcurrency + ", "
901 + resultSetHoldability + ")");
902 }
903 checkTypeConcurrency(resultSetType, resultSetConcurrency);
904 checkHoldability(resultSetHoldability);
905 checkClosed();
906 sql = translateSQL(sql);
907 return new JdbcCallableStatement(this, sql, id, resultSetType, resultSetConcurrency);
908 } catch (Exception e) {
909 throw logAndConvert(e);
910 }
911 }
912
913 /**
914 * Creates a new unnamed savepoint.
915 *
916 * @return the new savepoint
917 */
918 public Savepoint setSavepoint() throws SQLException {
919 try {
920 int id = getNextId(TraceObject.SAVEPOINT);
921 if (isDebugEnabled()) {
922 debugCodeAssign("Savepoint", TraceObject.SAVEPOINT, id, "setSavepoint()");
923 }
924 checkClosed();
925 CommandInterface set = prepareCommand("SAVEPOINT " + JdbcSavepoint.getName(null, savepointId), Integer.MAX_VALUE);
926 set.executeUpdate();
927 JdbcSavepoint savepoint = new JdbcSavepoint(this, savepointId, null, trace, id);
928 savepointId++;
929 return savepoint;
930 } catch (Exception e) {
931 throw logAndConvert(e);
932 }
933 }
934
935 /**
936 * Creates a new named savepoint.
937 *
938 * @param name the savepoint name
939 * @return the new savepoint
940 */
941 public Savepoint setSavepoint(String name) throws SQLException {
942 try {
943 int id = getNextId(TraceObject.SAVEPOINT);
944 if (isDebugEnabled()) {
945 debugCodeAssign("Savepoint", TraceObject.SAVEPOINT, id, "setSavepoint(" + quote(name) + ")");
946 }
947 checkClosed();
948 CommandInterface set = prepareCommand("SAVEPOINT " + JdbcSavepoint.getName(name, 0), Integer.MAX_VALUE);
949 set.executeUpdate();
950 JdbcSavepoint savepoint = new JdbcSavepoint(this, 0, name, trace, id);
951 return savepoint;
952 } catch (Exception e) {
953 throw logAndConvert(e);
954 }
955 }
956
957 /**
958 * Rolls back to a savepoint.
959 *
960 * @param savepoint the savepoint
961 */
962 public void rollback(Savepoint savepoint) throws SQLException {
963 try {
964 JdbcSavepoint sp = convertSavepoint(savepoint);
965 debugCode("rollback(" + sp.getTraceObjectName() + ");");
966 checkClosedForWrite();
967 try {
968 sp.rollback();
969 } finally {
970 afterWriting();
971 }
972 } catch (Exception e) {
973 throw logAndConvert(e);
974 }
975 }
976
977 /**
978 * Releases a savepoint.
979 *
980 * @param savepoint the savepoint to release
981 */
982 public void releaseSavepoint(Savepoint savepoint) throws SQLException {
983 try {
984 debugCode("releaseSavepoint(savepoint);");
985 checkClosed();
986 convertSavepoint(savepoint).release();
987 } catch (Exception e) {
988 throw logAndConvert(e);
989 }
990 }
991
992 private static JdbcSavepoint convertSavepoint(Savepoint savepoint) {
993 if (!(savepoint instanceof JdbcSavepoint)) {
994 throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, "" + savepoint);
995 }
996 return (JdbcSavepoint) savepoint;
997 }
998
999 /**
1000 * Creates a prepared statement with the specified result set type,
1001 * concurrency, and holdability.
1002 *
1003 * @param sql the SQL statement
1004 * @param resultSetType the result set type (ResultSet.TYPE_*)
1005 * @param resultSetConcurrency the concurrency (ResultSet.CONCUR_*)
1006 * @param resultSetHoldability the holdability (ResultSet.HOLD* / CLOSE*)
1007 * @return the prepared statement
1008 * @throws SQLException if the connection is closed or the result set type,
1009 * concurrency, or holdability are not supported
1010 */
1011 public PreparedStatement prepareStatement(String sql, int resultSetType,
1012 int resultSetConcurrency, int resultSetHoldability) throws SQLException {
1013 try {
1014 int id = getNextId(TraceObject.PREPARED_STATEMENT);
1015 if (isDebugEnabled()) {
1016 debugCodeAssign("PreparedStatement", TraceObject.PREPARED_STATEMENT, id,
1017 "prepareStatement(" + quote(sql) + ", " + resultSetType + ", " + resultSetConcurrency + ", "
1018 + resultSetHoldability + ")");
1019 }
1020 checkTypeConcurrency(resultSetType, resultSetConcurrency);
1021 checkHoldability(resultSetHoldability);
1022 checkClosed();
1023 sql = translateSQL(sql);
1024 return new JdbcPreparedStatement(this, sql, id, resultSetType, resultSetConcurrency, false);
1025 } catch (Exception e) {
1026 throw logAndConvert(e);
1027 }
1028 }
1029
1030 /**
1031 * Creates a new prepared statement.
1032 * This method just calls prepareStatement(String sql) internally.
1033 * The method getGeneratedKeys only supports one column.
1034 *
1035 * @param sql the SQL statement
1036 * @param autoGeneratedKeys ignored
1037 * @return the prepared statement
1038 * @throws SQLException
1039 * if the connection is closed
1040 */
1041 public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
1042 try {
1043 if (isDebugEnabled()) {
1044 debugCode("prepareStatement(" + quote(sql) + ", " + autoGeneratedKeys + ");");
1045 }
1046 return prepareStatement(sql);
1047 } catch (Exception e) {
1048 throw logAndConvert(e);
1049 }
1050 }
1051
1052 /**
1053 * Creates a new prepared statement.
1054 * This method just calls prepareStatement(String sql) internally.
1055 * The method getGeneratedKeys only supports one column.
1056 *
1057 * @param sql the SQL statement
1058 * @param columnIndexes ignored
1059 * @return the prepared statement
1060 * @throws SQLException
1061 * if the connection is closed
1062 */
1063 public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
1064 try {
1065 if (isDebugEnabled()) {
1066 debugCode("prepareStatement(" + quote(sql) + ", " + quoteIntArray(columnIndexes) + ");");
1067 }
1068 return prepareStatement(sql);
1069 } catch (Exception e) {
1070 throw logAndConvert(e);
1071 }
1072 }
1073
1074 /**
1075 * Creates a new prepared statement.
1076 * This method just calls prepareStatement(String sql) internally.
1077 * The method getGeneratedKeys only supports one column.
1078 *
1079 * @param sql the SQL statement
1080 * @param columnNames ignored
1081 * @return the prepared statement
1082 * @throws SQLException
1083 * if the connection is closed
1084 */
1085 public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
1086 try {
1087 if (isDebugEnabled()) {
1088 debugCode("prepareStatement(" + quote(sql) + ", " + quoteArray(columnNames) + ");");
1089 }
1090 return prepareStatement(sql);
1091 } catch (Exception e) {
1092 throw logAndConvert(e);
1093 }
1094 }
1095
1096 // =============================================================
1097
1098 private static void checkJavaVersion() {
1099 try {
1100 // check for existence of this class (avoiding Class . forName)
1101 Class<?> clazz = java.sql.Savepoint.class;
1102 clazz.getClass();
1103 } catch (NoClassDefFoundError e) {
1104 throw DbException.get(ErrorCode.UNSUPPORTED_JAVA_VERSION);
1105 }
1106 }
1107
1108 /**
1109 * Prepare an command. This will parse the SQL statement.
1110 *
1111 * @param sql the SQL statement
1112 * @param fetchSize the fetch size (used in remote connections)
1113 * @return the command
1114 */
1115 CommandInterface prepareCommand(String sql, int fetchSize) {
1116 return session.prepareCommand(sql, fetchSize);
1117 }
1118
1119 private CommandInterface prepareCommand(String sql, CommandInterface old) {
1120 return old == null ? session.prepareCommand(sql, Integer.MAX_VALUE) : old;
1121 }
1122
1123 private static int translateGetEnd(String sql, int i, char c) {
1124 int len = sql.length();
1125 switch(c) {
1126 case '$': {
1127 if (i < len - 1 && sql.charAt(i + 1) == '$' && (i == 0 || sql.charAt(i - 1) <= ' ')) {
1128 int j = sql.indexOf("$$", i + 2);
1129 if (j < 0) {
1130 throw DbException.getSyntaxError(sql, i);
1131 }
1132 return j + 1;
1133 }
1134 return i;
1135 }
1136 case '\'': {
1137 int j = sql.indexOf('\'', i + 1);
1138 if (j < 0) {
1139 throw DbException.getSyntaxError(sql, i);
1140 }
1141 return j;
1142 }
1143 case '"': {
1144 int j = sql.indexOf('"', i + 1);
1145 if (j < 0) {
1146 throw DbException.getSyntaxError(sql, i);
1147 }
1148 return j;
1149 }
1150 case '/': {
1151 checkRunOver(i+1, len, sql);
1152 if (sql.charAt(i + 1) == '*') {
1153 // block comment
1154 int j = sql.indexOf("*/", i + 2);
1155 if (j < 0) {
1156 throw DbException.getSyntaxError(sql, i);
1157 }
1158 i = j + 1;
1159 } else if (sql.charAt(i + 1) == '/') {
1160 // single line comment
1161 i += 2;
1162 while (i < len && (c = sql.charAt(i)) != '\r' && c != '\n') {
1163 i++;
1164 }
1165 }
1166 return i;
1167 }
1168 case '-': {
1169 checkRunOver(i+1, len, sql);
1170 if (sql.charAt(i + 1) == '-') {
1171 // single line comment
1172 i += 2;
1173 while (i < len && (c = sql.charAt(i)) != '\r' && c != '\n') {
1174 i++;
1175 }
1176 }
1177 return i;
1178 }
1179 default:
1180 throw DbException.throwInternalError("c=" + c);
1181 }
1182 }
1183
1184 /**
1185 * Convert JDBC escape sequences in the SQL statement. This
1186 * method throws an exception if the SQL statement is null.
1187 *
1188 * @param sql the SQL statement with or without JDBC escape sequences
1189 * @return the SQL statement without JDBC escape sequences
1190 */
1191 private static String translateSQL(String sql) {
1192 return translateSQL(sql, true);
1193 }
1194
1195 /**
1196 * Convert JDBC escape sequences in the SQL statement if required. This
1197 * method throws an exception if the SQL statement is null.
1198 *
1199 * @param sql the SQL statement with or without JDBC escape sequences
1200 * @param escapeProcessing whether escape sequences should be replaced
1201 * @return the SQL statement without JDBC escape sequences
1202 */
1203 static String translateSQL(String sql, boolean escapeProcessing) {
1204 if (sql == null) {
1205 throw DbException.getInvalidValueException("SQL", null);
1206 }
1207 if (!escapeProcessing) {
1208 return sql;
1209 }
1210 if (sql.indexOf('{') < 0) {
1211 return sql;
1212 }
1213 int len = sql.length();
1214 char[] chars = null;
1215 int level = 0;
1216 for (int i = 0; i < len; i++) {
1217 char c = sql.charAt(i);
1218 switch (c) {
1219 case '\'':
1220 case '"':
1221 case '/':
1222 case '-':
1223 i = translateGetEnd(sql, i, c);
1224 break;
1225 case '{':
1226 level++;
1227 if (chars == null) {
1228 chars = sql.toCharArray();
1229 }
1230 chars[i] = ' ';
1231 while (Character.isSpaceChar(chars[i])) {
1232 i++;
1233 checkRunOver(i, len, sql);
1234 }
1235 int start = i;
1236 if (chars[i] >= '0' && chars[i] <= '9') {
1237 chars[i - 1] = '{';
1238 while (true) {
1239 checkRunOver(i, len, sql);
1240 c = chars[i];
1241 if (c == '}') {
1242 break;
1243 }
1244 switch (c) {
1245 case '\'':
1246 case '"':
1247 case '/':
1248 case '-':
1249 i = translateGetEnd(sql, i, c);
1250 break;
1251 default:
1252 }
1253 i++;
1254 }
1255 level--;
1256 break;
1257 } else if (chars[i] == '?') {
1258 i++;
1259 checkRunOver(i, len, sql);
1260 while (Character.isSpaceChar(chars[i])) {
1261 i++;
1262 checkRunOver(i, len, sql);
1263 }
1264 if (sql.charAt(i) != '=') {
1265 throw DbException.getSyntaxError(sql, i, "=");
1266 }
1267 i++;
1268 checkRunOver(i, len, sql);
1269 while (Character.isSpaceChar(chars[i])) {
1270 i++;
1271 checkRunOver(i, len, sql);
1272 }
1273 }
1274 while (!Character.isSpaceChar(chars[i])) {
1275 i++;
1276 checkRunOver(i, len, sql);
1277 }
1278 int remove = 0;
1279 if (found(sql, start, "fn")) {
1280 remove = 2;
1281 } else if (found(sql, start, "escape")) {
1282 break;
1283 } else if (found(sql, start, "call")) {
1284 break;
1285 } else if (found(sql, start, "oj")) {
1286 remove = 2;
1287 } else if (found(sql, start, "ts")) {
1288 remove = 2;
1289 } else if (found(sql, start, "t")) {
1290 remove = 1;
1291 } else if (found(sql, start, "d")) {
1292 remove = 1;
1293 } else if (found(sql, start, "params")) {
1294 remove = "params".length();
1295 }
1296 for (i = start; remove > 0; i++, remove--) {
1297 chars[i] = ' ';
1298 }
1299 break;
1300 case '}':
1301 if (--level < 0) {
1302 throw DbException.getSyntaxError(sql, i);
1303 }
1304 chars[i] = ' ';
1305 break;
1306 case '$':
1307 i = translateGetEnd(sql, i, c);
1308 break;
1309 default:
1310 }
1311 }
1312 if (level != 0) {
1313 throw DbException.getSyntaxError(sql, sql.length() - 1);
1314 }
1315 if (chars != null) {
1316 sql = new String(chars);
1317 }
1318 return sql;
1319 }
1320
1321 private static void checkRunOver(int i, int len, String sql) {
1322 if (i >= len) {
1323 throw DbException.getSyntaxError(sql, i);
1324 }
1325 }
1326
1327 private static boolean found(String sql, int start, String other) {
1328 return sql.regionMatches(true, start, other, 0, other.length());
1329 }
1330
1331 private static void checkTypeConcurrency(int resultSetType, int resultSetConcurrency) {
1332 switch (resultSetType) {
1333 case ResultSet.TYPE_FORWARD_ONLY:
1334 case ResultSet.TYPE_SCROLL_INSENSITIVE:
1335 case ResultSet.TYPE_SCROLL_SENSITIVE:
1336 break;
1337 default:
1338 throw DbException.getInvalidValueException("resultSetType", resultSetType);
1339 }
1340 switch (resultSetConcurrency) {
1341 case ResultSet.CONCUR_READ_ONLY:
1342 case ResultSet.CONCUR_UPDATABLE:
1343 break;
1344 default:
1345 throw DbException.getInvalidValueException("resultSetConcurrency", resultSetConcurrency);
1346 }
1347 }
1348
1349 private static void checkHoldability(int resultSetHoldability) {
1350 // TODO compatibility / correctness: DBPool uses
1351 // ResultSet.HOLD_CURSORS_OVER_COMMIT
1352 if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT
1353 && resultSetHoldability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
1354 throw DbException.getInvalidValueException("resultSetHoldability", resultSetHoldability);
1355 }
1356 }
1357
1358 /**
1359 * INTERNAL.
1360 * Check if this connection is closed.
1361 * The next operation is a read request.
1362 *
1363 * @throws DbException if the connection or session is closed
1364 */
1365 protected void checkClosed() {
1366 checkClosed(false);
1367 }
1368
1369 /**
1370 * Check if this connection is closed.
1371 * The next operation may be a write request.
1372 *
1373 * @throws DbException if the connection or session is closed
1374 */
1375 private void checkClosedForWrite() {
1376 checkClosed(true);
1377 }
1378
1379 /**
1380 * INTERNAL.
1381 * Check if this connection is closed.
1382 *
1383 * @param write if the next operation is possibly writing
1384 * @throws DbException if the connection or session is closed
1385 */
1386 protected void checkClosed(boolean write) {
1387 if (session == null) {
1388 throw DbException.get(ErrorCode.OBJECT_CLOSED);
1389 }
1390 if (session.isClosed()) {
1391 throw DbException.get(ErrorCode.DATABASE_CALLED_AT_SHUTDOWN);
1392 }
1393 if (session.isReconnectNeeded(write)) {
1394 trace.debug("reconnect");
1395 closePreparedCommands();
1396 session = session.reconnect(write);
1397 trace = session.getTrace();
1398 }
1399 }
1400
1401 /**
1402 * INTERNAL.
1403 * Called after executing a command that could have written something.
1404 */
1405 protected void afterWriting() {
1406 if (session != null) {
1407 session.afterWriting();
1408 }
1409 }
1410
1411 String getURL() {
1412 checkClosed();
1413 return url;
1414 }
1415
1416 String getUser() {
1417 checkClosed();
1418 return user;
1419 }
1420
1421 private void rollbackInternal() {
1422 rollback = prepareCommand("ROLLBACK", rollback);
1423 rollback.executeUpdate();
1424 }
1425
1426 /**
1427 * INTERNAL
1428 */
1429 public int getPowerOffCount() {
1430 return (session == null || session.isClosed()) ? 0 : session.getPowerOffCount();
1431 }
1432
1433 /**
1434 * INTERNAL
1435 */
1436 public void setPowerOffCount(int count) {
1437 if (session != null) {
1438 session.setPowerOffCount(count);
1439 }
1440 }
1441
1442 /**
1443 * INTERNAL
1444 */
1445 public void setExecutingStatement(Statement stat) {
1446 executingStatement = stat;
1447 }
1448
1449 /**
1450 * INTERNAL
1451 */
1452 ResultSet getGeneratedKeys(JdbcStatement stat, int id) {
1453 getGeneratedKeys = prepareCommand("SELECT SCOPE_IDENTITY() WHERE SCOPE_IDENTITY() IS NOT NULL", getGeneratedKeys);
1454 ResultInterface result = getGeneratedKeys.executeQuery(0, false);
1455 ResultSet rs = new JdbcResultSet(this, stat, result, id, false, true, false);
1456 return rs;
1457 }
1458
1459 /**
1460 * Create a new empty Clob object.
1461 *
1462 * @return the object
1463 */
1464 public Clob createClob() throws SQLException {
1465 try {
1466 int id = getNextId(TraceObject.CLOB);
1467 debugCodeAssign("Clob", TraceObject.CLOB, id, "createClob()");
1468 checkClosedForWrite();
1469 try {
1470 Value v = session.getDataHandler().getLobStorage().createClob(
1471 new InputStreamReader(
1472 new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0);
1473 return new JdbcClob(this, v, id);
1474 } finally {
1475 afterWriting();
1476 }
1477 } catch (Exception e) {
1478 throw logAndConvert(e);
1479 }
1480 }
1481
1482 /**
1483 * Create a new empty Blob object.
1484 *
1485 * @return the object
1486 */
1487 public Blob createBlob() throws SQLException {
1488 try {
1489 int id = getNextId(TraceObject.BLOB);
1490 debugCodeAssign("Blob", TraceObject.BLOB, id, "createClob()");
1491 checkClosedForWrite();
1492 try {
1493 Value v = session.getDataHandler().getLobStorage().createBlob(
1494 new ByteArrayInputStream(Utils.EMPTY_BYTES), 0);
1495 return new JdbcBlob(this, v, id);
1496 } finally {
1497 afterWriting();
1498 }
1499 } catch (Exception e) {
1500 throw logAndConvert(e);
1501 }
1502 }
1503
1504 /**
1505 * Create a new empty NClob object.
1506 *
1507 * @return the object
1508 */
1509 //## Java 1.6 ##
1510 public NClob createNClob() throws SQLException {
1511 try {
1512 int id = getNextId(TraceObject.CLOB);
1513 debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()");
1514 checkClosedForWrite();
1515 try {
1516 Value v = session.getDataHandler().getLobStorage().createClob(
1517 new InputStreamReader(
1518 new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0);
1519 return new JdbcClob(this, v, id);
1520 } finally {
1521 afterWriting();
1522 }
1523 } catch (Exception e) {
1524 throw logAndConvert(e);
1525 }
1526 }
1527 //*/
1528
1529 /**
1530 * [Not supported] Create a new empty SQLXML object.
1531 */
1532 //## Java 1.6 ##
1533 public SQLXML createSQLXML() throws SQLException {
1534 throw unsupported("SQLXML");
1535 }
1536 //*/
1537
1538 /**
1539 * [Not supported] Create a new empty Array object.
1540 */
1541 //## Java 1.6 ##
1542 public Array createArrayOf(String typeName, Object[] elements)
1543 throws SQLException {
1544 throw unsupported("createArray");
1545 }
1546 //*/
1547
1548 /**
1549 * [Not supported] Create a new empty Struct object.
1550 */
1551 //## Java 1.6 ##
1552 public Struct createStruct(String typeName, Object[] attributes)
1553 throws SQLException {
1554 throw unsupported("Struct");
1555 }
1556 //*/
1557
1558 /**
1559 * Returns true if this connection is still valid.
1560 *
1561 * @param timeout the number of seconds to wait for the database to respond
1562 * (ignored)
1563 * @return true if the connection is valid.
1564 */
1565 public synchronized boolean isValid(int timeout) {
1566 try {
1567 debugCodeCall("isValid", timeout);
1568 if (session == null || session.isClosed()) {
1569 return false;
1570 }
1571 // force a network round trip (if networked)
1572 getTransactionIsolation();
1573 return true;
1574 } catch (Exception e) {
1575 // this method doesn't throw an exception, but it logs it
1576 logAndConvert(e);
1577 return false;
1578 }
1579 }
1580
1581 /**
1582 * [Not supported] Set a client property.
1583 */
1584 //## Java 1.6 ##
1585 public void setClientInfo(String name, String value)
1586 throws SQLClientInfoException {
1587 throw new SQLClientInfoException();
1588 }
1589 //*/
1590
1591 /**
1592 * [Not supported] Set the client properties.
1593 */
1594 //## Java 1.6 ##
1595 public void setClientInfo(Properties properties) throws SQLClientInfoException {
1596 throw new SQLClientInfoException();
1597 }
1598 //*/
1599
1600 /**
1601 * [Not supported] Get the client properties.
1602 */
1603 //## Java 1.6 ##
1604 public Properties getClientInfo() throws SQLClientInfoException {
1605 throw new SQLClientInfoException();
1606 }
1607 //*/
1608
1609 /**
1610 * [Not supported] Set a client property.
1611 */
1612 //## Java 1.6 ##
1613 public String getClientInfo(String name) throws SQLException {
1614 throw unsupported("clientInfo");
1615 }
1616 //*/
1617
1618 /**
1619 * [Not supported] Return an object of this class if possible.
1620 *
1621 * @param iface the class
1622 */
1623 //## Java 1.6 ##
1624 public <T> T unwrap(Class<T> iface) throws SQLException {
1625 throw unsupported("unwrap");
1626 }
1627 //*/
1628
1629 /**
1630 * [Not supported] Checks if unwrap can return an object of this class.
1631 *
1632 * @param iface the class
1633 */
1634 //## Java 1.6 ##
1635 public boolean isWrapperFor(Class<?> iface) throws SQLException {
1636 throw unsupported("isWrapperFor");
1637 }
1638 //*/
1639
1640 /**
1641 * Create a Clob value from this reader.
1642 *
1643 * @param x the reader
1644 * @param length the length (if smaller or equal than 0, all data until the
1645 * end of file is read)
1646 * @return the value
1647 */
1648 public Value createClob(Reader x, long length) {
1649 if (x == null) {
1650 return ValueNull.INSTANCE;
1651 }
1652 if (length <= 0) {
1653 length = -1;
1654 }
1655 Value v = session.getDataHandler().getLobStorage().createClob(x, length);
1656 return v;
1657 }
1658
1659 /**
1660 * Create a Blob value from this input stream.
1661 *
1662 * @param x the input stream
1663 * @param length the length (if smaller or equal than 0, all data until the
1664 * end of file is read)
1665 * @return the value
1666 */
1667 public Value createBlob(InputStream x, long length) {
1668 if (x == null) {
1669 return ValueNull.INSTANCE;
1670 }
1671 if (length <= 0) {
1672 length = -1;
1673 }
1674 Value v = session.getDataHandler().getLobStorage().createBlob(x, length);
1675 return v;
1676 }
1677
1678 /**
1679 * [Not supported]
1680 *
1681 * @param schema the schema
1682 */
1683 /*## Java 1.7 ##
1684 public void setSchema(String schema) {
1685 // not supported
1686 }
1687 //*/
1688
1689 /**
1690 * [Not supported]
1691 */
1692 /*## Java 1.7 ##
1693 public String getSchema() {
1694 return null;
1695 }
1696 //*/
1697
1698 /**
1699 * [Not supported]
1700 *
1701 * @param executor the executor used by this method
1702 */
1703 /*## Java 1.7 ##
1704 public void abort(Executor executor) {
1705 // not supported
1706 }
1707 //*/
1708
1709 /**
1710 * [Not supported]
1711 *
1712 * @param executor the executor used by this method
1713 * @param milliseconds the TCP connection timeout
1714 */
1715 /*## Java 1.7 ##
1716 public void setNetworkTimeout(Executor executor, int milliseconds) {
1717 // not supported
1718 }
1719 //*/
1720
1721 /**
1722 * [Not supported]
1723 */
1724 /*## Java 1.7 ##
1725 public int getNetworkTimeout() {
1726 return 0;
1727 }
1728 //*/
1729
1730 private static void checkMap(Map<String, Class<?>> map) {
1731 if (map != null && map.size() > 0) {
1732 throw DbException.getUnsupportedException("map.size > 0");
1733 }
1734 }
1735
1736 /**
1737 * INTERNAL
1738 */
1739 public String toString() {
1740 return getTraceObjectName() + ": url=" + url + " user=" + user;
1741 }
1742
1743 /**
1744 * Convert an object to the default Java object for the given SQL type. For
1745 * example, LOB objects are converted to java.sql.Clob / java.sql.Blob.
1746 *
1747 * @param v the value
1748 * @return the object
1749 */
1750 Object convertToDefaultObject(Value v) {
1751 Object o;
1752 switch (v.getType()) {
1753 case Value.CLOB: {
1754 int id = getNextId(TraceObject.CLOB);
1755 o = new JdbcClob(this, v, id);
1756 break;
1757 }
1758 case Value.BLOB: {
1759 int id = getNextId(TraceObject.BLOB);
1760 o = new JdbcBlob(this, v, id);
1761 break;
1762 }
1763 case Value.JAVA_OBJECT:
1764 if (SysProperties.serializeJavaObject) {
1765 o = Utils.deserialize(v.getBytesNoCopy());
1766 break;
1767 }
1768 default:
1769 o = v.getObject();
1770 }
1771 return o;
1772 }
1773
1774 CompareMode getCompareMode() {
1775 return compareMode;
1776 }
1777
1778 /**
1779 * INTERNAL
1780 */
1781 public void setTraceLevel(int level) {
1782 trace.setLevel(level);
1783 }
1784
1785 }
1786