--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.jdbc.BrokeredConnection\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.jdbc;\r
+\r
+import java.sql.Connection;\r
+import java.sql.Statement;\r
+import java.sql.PreparedStatement;\r
+import java.sql.CallableStatement;\r
+import java.sql.DatabaseMetaData;\r
+import java.sql.SQLException;\r
+import java.sql.SQLWarning;\r
+\r
+import org.apache.derby.impl.jdbc.EmbedSQLWarning;\r
+import org.apache.derby.impl.jdbc.Util;\r
+\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+\r
+import java.lang.reflect.*;\r
+\r
+import org.apache.derby.iapi.reference.JDBC30Translation;\r
+import org.apache.derby.iapi.error.PublicAPI;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.shared.common.reference.SQLState;\r
+\r
+/**\r
+ * This is a rudimentary connection that delegates\r
+ * EVERYTHING to Connection.\r
+ */\r
+public abstract class BrokeredConnection implements EngineConnection\r
+{\r
+ \r
+ // default for Derby\r
+ int stateHoldability = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;\r
+\r
+ final BrokeredConnectionControl control;\r
+ private boolean isClosed;\r
+ private String connString;\r
+\r
+ /**\r
+ Maintain state as seen by this Connection handle, not the state\r
+ of the underlying Connection it is attached to.\r
+ */\r
+ private int stateIsolationLevel;\r
+ private boolean stateReadOnly;\r
+ private boolean stateAutoCommit;\r
+\r
+ /////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CONSTRUCTORS\r
+ //\r
+ /////////////////////////////////////////////////////////////////////////\r
+\r
+ public BrokeredConnection(BrokeredConnectionControl control)\r
+ {\r
+ this.control = control;\r
+ }\r
+\r
+ public final void setAutoCommit(boolean autoCommit) throws SQLException \r
+ {\r
+ try {\r
+ control.checkAutoCommit(autoCommit);\r
+\r
+ getRealConnection().setAutoCommit(autoCommit);\r
+\r
+ stateAutoCommit = autoCommit;\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+ public final boolean getAutoCommit() throws SQLException \r
+ {\r
+ try {\r
+ return getRealConnection().getAutoCommit();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+ public final Statement createStatement() throws SQLException \r
+ {\r
+ try {\r
+ return control.wrapStatement(getRealConnection().createStatement());\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final PreparedStatement prepareStatement(String sql)\r
+ throws SQLException \r
+ {\r
+ try {\r
+ return control.wrapStatement(getRealConnection().prepareStatement(sql), sql, null);\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final CallableStatement prepareCall(String sql) throws SQLException \r
+ {\r
+ try {\r
+ return control.wrapStatement(getRealConnection().prepareCall(sql), sql);\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final String nativeSQL(String sql) throws SQLException\r
+ {\r
+ try {\r
+ return getRealConnection().nativeSQL(sql);\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void commit() throws SQLException \r
+ {\r
+ try {\r
+ control.checkCommit();\r
+ getRealConnection().commit();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void rollback() throws SQLException \r
+ {\r
+ try {\r
+ control.checkRollback();\r
+ getRealConnection().rollback();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void close() throws SQLException \r
+ { \r
+ if (isClosed)\r
+ return;\r
+\r
+ try {\r
+ if (!control.closingConnection()) {\r
+ isClosed = true;\r
+ return;\r
+ }\r
+\r
+ isClosed = true;\r
+\r
+\r
+ getRealConnection().close();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final boolean isClosed() throws SQLException \r
+ {\r
+ if (isClosed)\r
+ return true;\r
+ try {\r
+ boolean realIsClosed = getRealConnection().isClosed();\r
+ if (realIsClosed) {\r
+ control.closingConnection();\r
+ isClosed = true;\r
+ }\r
+ return realIsClosed;\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final SQLWarning getWarnings() throws SQLException \r
+ {\r
+ try {\r
+ return getRealConnection().getWarnings();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void clearWarnings() throws SQLException \r
+ {\r
+ try {\r
+ getRealConnection().clearWarnings();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final DatabaseMetaData getMetaData() throws SQLException \r
+ {\r
+ try {\r
+ return getRealConnection().getMetaData();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void setReadOnly(boolean readOnly) throws SQLException \r
+ {\r
+ try {\r
+ getRealConnection().setReadOnly(readOnly);\r
+ stateReadOnly = readOnly;\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final boolean isReadOnly() throws SQLException \r
+ {\r
+ try {\r
+ return getRealConnection().isReadOnly();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void setCatalog(String catalog) throws SQLException \r
+ {\r
+ try {\r
+ getRealConnection().setCatalog(catalog);\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final String getCatalog() throws SQLException \r
+ {\r
+ try {\r
+ return getRealConnection().getCatalog();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final void setTransactionIsolation(int level) throws SQLException \r
+ {\r
+ try {\r
+ getRealConnection().setTransactionIsolation(level);\r
+ stateIsolationLevel = level;\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final int getTransactionIsolation() throws SQLException\r
+ {\r
+ try {\r
+ return getRealConnection().getTransactionIsolation();\r
+ } catch (SQLException sqle) {\r
+ notifyException(sqle);\r
+ throw sqle;\r
+ }\r
+ }\r
+\r
+ public final Statement createStatement(int resultSetType, int resultSetConcurrency) \r
+ throws SQLException\r
+ {\r
+ try\r
+ {\r
+ return control.wrapStatement(getRealConnection().\r
+ createStatement(resultSetType, resultSetConcurrency));\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+\r
+ public final PreparedStatement prepareStatement(String sql, int resultSetType, \r
+ int resultSetConcurrency)\r
+ throws SQLException\r
+ {\r
+ try\r
+ {\r
+ return control.wrapStatement(getRealConnection().\r
+ prepareStatement(sql, resultSetType, resultSetConcurrency), sql, null);\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ public final CallableStatement prepareCall(String sql, int resultSetType, \r
+ int resultSetConcurrency) throws SQLException\r
+ {\r
+ try\r
+ {\r
+ return control.wrapStatement(getRealConnection().\r
+ prepareCall(sql, resultSetType, resultSetConcurrency), sql);\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ public java.util.Map getTypeMap() throws SQLException\r
+ {\r
+ try\r
+ {\r
+ return getRealConnection().getTypeMap();\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ public final void setTypeMap(java.util.Map map) throws SQLException\r
+ {\r
+ try\r
+ {\r
+ getRealConnection().setTypeMap(map);\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ /////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // MINIONS\r
+ //\r
+ /////////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * A little indirection for getting the real connection. \r
+ *\r
+ * @return the current connection\r
+ */\r
+ final EngineConnection getRealConnection() throws SQLException {\r
+ if (isClosed)\r
+ throw Util.noCurrentConnection();\r
+\r
+ return control.getRealConnection();\r
+ }\r
+\r
+ final void notifyException(SQLException sqle) {\r
+ if (!isClosed)\r
+ control.notifyException(sqle);\r
+ }\r
+\r
+ /**\r
+ Sync up the state of the underlying connection\r
+ with the state of this new handle.\r
+ */\r
+ public void syncState() throws SQLException {\r
+ EngineConnection conn = getRealConnection();\r
+\r
+ stateIsolationLevel = conn.getTransactionIsolation();\r
+ stateReadOnly = conn.isReadOnly();\r
+ stateAutoCommit = conn.getAutoCommit();\r
+ stateHoldability = conn.getHoldability(); \r
+ }\r
+\r
+ /**\r
+ Isolation level state in BrokeredConnection can get out of sync\r
+ if the isolation is set using SQL rather than JDBC. In order to\r
+ ensure correct state level information, this method is called\r
+ at the start and end of a global transaction.\r
+ */\r
+ public void getIsolationUptoDate() throws SQLException {\r
+ if (control.isIsolationLevelSetUsingSQLorJDBC()) {\r
+ stateIsolationLevel = getRealConnection().getTransactionIsolation();\r
+ control.resetIsolationLevelFlag();\r
+ }\r
+ }\r
+ /**\r
+ Set the state of the underlying connection according to the\r
+ state of this connection's view of state.\r
+\r
+ @param complete If true set the complete state of the underlying\r
+ Connection, otherwise set only the Connection related state (ie.\r
+ the non-transaction specific state).\r
+\r
+\r
+ */\r
+ public void setState(boolean complete) throws SQLException {\r
+ Class[] CONN_PARAM = { Integer.TYPE };\r
+ Object[] CONN_ARG = { new Integer(stateHoldability)};\r
+\r
+ Connection conn = getRealConnection();\r
+\r
+ if (complete) {\r
+ conn.setTransactionIsolation(stateIsolationLevel);\r
+ conn.setReadOnly(stateReadOnly);\r
+ conn.setAutoCommit(stateAutoCommit);\r
+ // make the underlying connection pick my holdability state\r
+ // since holdability is a state of the connection handle\r
+ // not the underlying transaction.\r
+ // jdk13 does not have Connection.setHoldability method and hence using\r
+ // reflection to cover both jdk13 and higher jdks\r
+ try {\r
+ Method sh = conn.getClass().getMethod("setHoldability", CONN_PARAM);\r
+ sh.invoke(conn, CONN_ARG);\r
+ } catch( Exception e)\r
+ {\r
+ throw PublicAPI.wrapStandardException( StandardException.plainWrapException( e));\r
+ }\r
+ }\r
+ }\r
+\r
+ public BrokeredStatement newBrokeredStatement(BrokeredStatementControl statementControl) throws SQLException {\r
+ return new BrokeredStatement(statementControl);\r
+ }\r
+ public abstract BrokeredPreparedStatement\r
+ newBrokeredStatement(BrokeredStatementControl statementControl,\r
+ String sql, Object generatedKeys) throws SQLException;\r
+ public abstract BrokeredCallableStatement\r
+ newBrokeredStatement(BrokeredStatementControl statementControl,\r
+ String sql) throws SQLException;\r
+\r
+ /**\r
+ * set the DrdaId for this connection. The drdaID prints with the \r
+ * statement text to the errror log\r
+ * @param drdaID drdaID to be used for this connection\r
+ *\r
+ */\r
+ public final void setDrdaID(String drdaID)\r
+ {\r
+ try {\r
+ getRealConnection().setDrdaID(drdaID);\r
+ } catch (SQLException sqle)\r
+ {\r
+ // connection is closed, just ignore drdaId\r
+ // since connection cannot be used.\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the internal isolation level to use for preparing statements.\r
+ * Subsequent prepares will use this isoalation level\r
+ * @param level - internal isolation level \r
+ * @throws SQLException\r
+ * See EmbedConnection#setPrepareIsolation\r
+ * \r
+ */\r
+ public final void setPrepareIsolation(int level) throws SQLException\r
+ {\r
+ getRealConnection().setPrepareIsolation(level);\r
+ }\r
+\r
+ /**\r
+ * get the isolation level that is currently being used to prepare \r
+ * statements (used for network server)\r
+ * \r
+ * @throws SQLException\r
+ * @return current prepare isolation level \r
+ * See EmbedConnection#getPrepareIsolation\r
+ */\r
+ public final int getPrepareIsolation() throws SQLException\r
+ {\r
+ return getRealConnection().getPrepareIsolation();\r
+ }\r
+ \r
+ /**\r
+ * Add a SQLWarning to this Connection object.\r
+ * @throws SQLException \r
+ */\r
+ public final void addWarning(SQLWarning w) throws SQLException\r
+ {\r
+ getRealConnection().addWarning(w);\r
+ }\r
+ \r
+ /**\r
+ * Checks if the connection is closed and throws an exception if\r
+ * it is.\r
+ *\r
+ * @exception SQLException if the connection is closed\r
+ */\r
+ protected final void checkIfClosed() throws SQLException {\r
+ if (isClosed()) {\r
+ throw Util.noCurrentConnection();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the string representation for this connection. Return\r
+ * the class name/hash code and various debug information.\r
+ * \r
+ * @return unique string representation for this connection\r
+ */\r
+ public String toString() \r
+ {\r
+ if ( connString == null )\r
+ {\r
+ String wrappedString;\r
+ try\r
+ {\r
+ wrappedString = getRealConnection().toString();\r
+ }\r
+ catch ( SQLException e )\r
+ {\r
+ wrappedString = "<none>";\r
+ }\r
+ \r
+ connString = this.getClass().getName() + "@" + this.hashCode() +\r
+ ", Wrapped Connection = " + wrappedString;\r
+ }\r
+ \r
+ return connString;\r
+ }\r
+\r
+ /*\r
+ * JDBC 3.0 methods that are exposed through EngineConnection.\r
+ */\r
+ \r
+ /**\r
+ * Prepare statement with explicit holdability.\r
+ */\r
+ public final PreparedStatement prepareStatement(String sql,\r
+ int resultSetType, int resultSetConcurrency,\r
+ int resultSetHoldability) throws SQLException {\r
+ try {\r
+ resultSetHoldability = statementHoldabilityCheck(resultSetHoldability);\r
+ \r
+ return control.wrapStatement(\r
+ getRealConnection().prepareStatement(sql, resultSetType,\r
+ resultSetConcurrency, resultSetHoldability), sql, null);\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the holdability for statements created by this connection\r
+ * when holdability is not passed in.\r
+ */\r
+ public final int getHoldability() throws SQLException {\r
+ try {\r
+ return getRealConnection().getHoldability();\r
+ }\r
+ catch (SQLException se)\r
+ {\r
+ notifyException(se);\r
+ throw se;\r
+ }\r
+ }\r
+ \r
+ /*\r
+ ** Methods private to the class.\r
+ */\r
+ \r
+ /**\r
+ * Check the result set holdability when creating a statement\r
+ * object. Section 16.1.3.1 of JDBC 4.0 (proposed final draft)\r
+ * says the driver may change the holdabilty and add a SQLWarning\r
+ * to the Connection object.\r
+ * \r
+ * This work-in-progress implementation throws an exception\r
+ * to match the old behaviour just as part of incremental development.\r
+ */\r
+ final int statementHoldabilityCheck(int resultSetHoldability)\r
+ throws SQLException\r
+ {\r
+ int holdability = control.checkHoldCursors(resultSetHoldability, true);\r
+ if (holdability != resultSetHoldability) {\r
+ SQLWarning w =\r
+ EmbedSQLWarning.newEmbedSQLWarning(SQLState.HOLDABLE_RESULT_SET_NOT_AVAILABLE);\r
+ \r
+ addWarning(w);\r
+ }\r
+ \r
+ return holdability;\r
+ \r
+ }\r
+ \r
+ /**\r
+ * Clear the HashMap of all entries.\r
+ * Called when a commit or rollback of the transaction\r
+ * happens.\r
+ */\r
+ public void clearLOBMapping() throws SQLException {\r
+ //Forward the methods implementation to the implementation in the\r
+ //underlying EmbedConnection object. \r
+ getRealConnection().clearLOBMapping();\r
+ }\r
+\r
+ /**\r
+ * Get the LOB reference corresponding to the locator.\r
+ * @param key the integer that represents the LOB locator value.\r
+ * @return the LOB Object corresponding to this locator.\r
+ */\r
+ public Object getLOBMapping(int key) throws SQLException {\r
+ //Forward the methods implementation to the implementation in the\r
+ //underlying EmbedConnection object. \r
+ return getRealConnection().getLOBMapping(key);\r
+ }\r
+}\r