--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.jdbc.EmbedConnection\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.impl.jdbc;\r
+\r
+import org.apache.derby.iapi.error.ExceptionSeverity;\r
+import org.apache.derby.jdbc.InternalDriver;\r
+\r
+import org.apache.derby.iapi.reference.Attribute;\r
+import org.apache.derby.iapi.reference.JDBC20Translation;\r
+import org.apache.derby.iapi.reference.JDBC30Translation;\r
+import org.apache.derby.iapi.reference.MessageId;\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+import org.apache.derby.iapi.services.memory.LowMemory;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.jdbc.AuthenticationService;\r
+import org.apache.derby.iapi.jdbc.EngineConnection;\r
+\r
+import org.apache.derby.iapi.db.Database;\r
+import org.apache.derby.iapi.error.ExceptionSeverity;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.execute.ExecutionContext;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.store.access.XATransactionController;\r
+\r
+/* can't import due to name overlap:\r
+import java.sql.Connection;\r
+import java.sql.ResultSet;\r
+*/\r
+import java.sql.PreparedStatement;\r
+import java.sql.CallableStatement;\r
+import java.sql.Blob;\r
+import java.sql.Clob;\r
+import java.sql.DatabaseMetaData;\r
+import java.sql.SQLException;\r
+import java.sql.SQLWarning;\r
+import java.sql.Statement;\r
+\r
+import java.util.Map;\r
+import java.util.WeakHashMap;\r
+import java.util.HashMap;\r
+import java.util.Properties;\r
+import java.util.Iterator;\r
+\r
+import org.apache.derby.iapi.jdbc.EngineLOB;\r
+import org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl;\r
+\r
+/**\r
+ * Local implementation of Connection for a JDBC driver in \r
+ * the same process as the database.\r
+ * <p> \r
+ * There is always a single root (parent) connection. The\r
+ * initial JDBC connection is the root connection. A\r
+ * call to <I>getCurrentConnection()</I> or with the URL \r
+ * <I>jdbc:default:connection</I> yields a nested connection that shares\r
+ * the same root connection as the parent. A nested connection\r
+ * is implemented using this class. The nested connection copies the \r
+ * state of the parent connection and shares some of the same \r
+ * objects (e.g. ContextManager) that are shared across all\r
+ * nesting levels. The proxy also maintains its own\r
+ * state that is distinct from its parent connection (e.g.\r
+ * autocommit or warnings).\r
+ * <p>\r
+ * <B>SYNCHRONIZATION</B>: Just about all JDBC actions are\r
+ * synchronized across all connections stemming from the\r
+ * same root connection. The synchronization is upon\r
+ * the a synchronized object return by the rootConnection.\r
+ <P><B>Supports</B>\r
+ <UL>\r
+ <LI> JDBC 2.0\r
+ </UL>\r
+ * \r
+ *\r
+ * @see TransactionResourceImpl\r
+ *\r
+ */\r
+public abstract class EmbedConnection implements EngineConnection\r
+{\r
+\r
+ private static final StandardException exceptionClose = StandardException.closeException();\r
+ \r
+ /**\r
+ * Static exception to be thrown when a Connection request can not\r
+ * be fulfilled due to lack of memory. A static exception as the lack\r
+ * of memory would most likely cause another OutOfMemoryException and\r
+ * if there is not enough memory to create the OOME exception then something\r
+ * like the VM dying could occur. Simpler just to throw a static.\r
+ */\r
+ public static final SQLException NO_MEM =\r
+ Util.generateCsSQLException(SQLState.LOGIN_FAILED, "java.lang.OutOfMemoryError");\r
+ \r
+ /**\r
+ * Low memory state object for connection requests.\r
+ */\r
+ public static final LowMemory memoryState = new LowMemory();\r
+\r
+ //////////////////////////////////////////////////////////\r
+ // OBJECTS SHARED ACROSS CONNECTION NESTING\r
+ //////////////////////////////////////////////////////////\r
+ DatabaseMetaData dbMetadata;\r
+\r
+ TransactionResourceImpl tr; // always access tr thru getTR()\r
+\r
+ private HashMap lobHashMap = null;\r
+ private int lobHMKey = 0;\r
+\r
+ /**\r
+ * Map to keep track of all the lobs associated with this\r
+ * connection. These lobs will be cleared after the transaction\r
+ * is no longer valid or when connection is closed\r
+ */\r
+ private WeakHashMap lobReferences = null;\r
+\r
+ //////////////////////////////////////////////////////////\r
+ // STATE (copied to new nested connections, but nesting\r
+ // specific)\r
+ //////////////////////////////////////////////////////////\r
+ private boolean active;\r
+ boolean autoCommit = true;\r
+ boolean needCommit;\r
+\r
+ // Set to true if NONE authentication is being used\r
+ private boolean usingNoneAuth;\r
+\r
+ /*\r
+ following is a new feature in JDBC3.0 where you can specify the holdability\r
+ of a resultset at the end of the transaction. This gets set by the\r
+ new method setHoldability(int) in JDBC3.0\r
+ * \r
+ */\r
+ private int connectionHoldAbility = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;\r
+\r
+\r
+ //////////////////////////////////////////////////////////\r
+ // NESTING SPECIFIC OBJECTS\r
+ //////////////////////////////////////////////////////////\r
+ /*\r
+ ** The root connection is the base connection upon\r
+ ** which all actions are synchronized. By default,\r
+ ** we are the root connection unless we are created\r
+ ** by copying the state from another connection.\r
+ */\r
+ final EmbedConnection rootConnection;\r
+ private SQLWarning topWarning;\r
+ /** \r
+ Factory for JDBC objects to be created.\r
+ */\r
+ private InternalDriver factory;\r
+\r
+ /**\r
+ The Connection object the application is using when accessing the\r
+ database through this connection. In most cases this will be equal\r
+ to this. When Connection pooling is being used, then it will\r
+ be set to the Connection object handed to the application.\r
+ It is used for the getConnection() methods of various JDBC objects.\r
+ */\r
+ private java.sql.Connection applicationConnection;\r
+\r
+ /**\r
+ An increasing counter to assign to a ResultSet on its creation.\r
+ Used for ordering ResultSets returned from a procedure, always\r
+ returned in order of their creation. Is maintained at the root connection.\r
+ */\r
+ private int resultSetId;\r
+ \r
+ /** Cached string representation of the connection id */\r
+ private String connString;\r
+\r
+\r
+ //////////////////////////////////////////////////////////\r
+ // CONSTRUCTORS\r
+ //////////////////////////////////////////////////////////\r
+\r
+ // create a new Local Connection, using a new context manager\r
+ //\r
+ public EmbedConnection(InternalDriver driver, String url, Properties info)\r
+ throws SQLException\r
+ {\r
+ // Create a root connection.\r
+ applicationConnection = rootConnection = this;\r
+ factory = driver;\r
+\r
+\r
+ tr = new TransactionResourceImpl(driver, url, info);\r
+\r
+ active = true;\r
+\r
+ // register this thread and its context manager with\r
+ // the global context service\r
+ setupContextStack();\r
+\r
+ try {\r
+\r
+ // stick my context into the context manager\r
+ EmbedConnectionContext context = pushConnectionContext(tr.getContextManager());\r
+\r
+ // if we are shutting down don't attempt to boot or create the database\r
+ boolean shutdown = Boolean.valueOf(info.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue();\r
+\r
+ // see if database is already booted\r
+ Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, tr.getDBName());\r
+\r
+ // See if user wants to create a new database.\r
+ boolean createBoot = createBoot(info); \r
+\r
+ // DERBY-2264: keeps track of whether we do a plain boot before an\r
+ // (re)encryption or hard upgrade boot to (possibly) authenticate\r
+ // first. We can not authenticate before we have booted, so in\r
+ // order to enforce data base owner powers over encryption or\r
+ // upgrade, we need a plain boot, then authenticate, then, if all\r
+ // is well, boot with (re)encryption or upgrade. Encryption at\r
+ // create time is not checked.\r
+ boolean isTwoPhaseEncryptionBoot = (!createBoot &&\r
+ isEncryptionBoot(info));\r
+ boolean isTwoPhaseUpgradeBoot = (!createBoot &&\r
+ isHardUpgradeBoot(info));\r
+\r
+ // Save original properties if we modified them for\r
+ // two phase encryption or upgrade boot.\r
+ Properties savedInfo = null;\r
+\r
+ if (database != null)\r
+ {\r
+ // database already booted by someone else\r
+ tr.setDatabase(database);\r
+ isTwoPhaseEncryptionBoot = false;\r
+ isTwoPhaseUpgradeBoot = false;\r
+ }\r
+ else if (!shutdown)\r
+ {\r
+ if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {\r
+ savedInfo = info;\r
+ info = removePhaseTwoProps((Properties)info.clone());\r
+ }\r
+\r
+ // Return false iff the monitor cannot handle a service of the\r
+ // type indicated by the proptocol within the name. If that's\r
+ // the case then we are the wrong driver.\r
+\r
+ if (!bootDatabase(info, isTwoPhaseUpgradeBoot))\r
+ {\r
+ tr.clearContextInError();\r
+ setInactive();\r
+ return;\r
+ }\r
+ }\r
+\r
+\r
+ if (createBoot && !shutdown)\r
+ {\r
+ // if we are shutting down don't attempt to boot or create the\r
+ // database\r
+\r
+ if (tr.getDatabase() != null) {\r
+ addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, getDBName()));\r
+ } else {\r
+\r
+ // check for user's credential and authenticate the user\r
+ // with system level authentication service.\r
+ // FIXME: We should also check for CREATE DATABASE operation\r
+ // authorization for the user if authorization was\r
+ // set at the system level.\r
+ // Right now, the authorization service does not\r
+ // restrict/account for Create database op.\r
+ checkUserCredentials(null, info);\r
+ \r
+ // Process with database creation\r
+ database = createDatabase(tr.getDBName(), info);\r
+ tr.setDatabase(database);\r
+ }\r
+ }\r
+\r
+\r
+ if (tr.getDatabase() == null) {\r
+ String dbname = tr.getDBName();\r
+ // do not clear the TransactionResource context. It will be restored\r
+ // as part of the finally clause below.\r
+ this.setInactive();\r
+ throw newSQLException(SQLState.DATABASE_NOT_FOUND, dbname);\r
+ }\r
+\r
+\r
+ // Check User's credentials and if it is a valid user of\r
+ // the database\r
+ //\r
+ checkUserCredentials(tr.getDBName(), info);\r
+\r
+ // Make a real connection into the database, setup lcc, tc and all\r
+ // the rest.\r
+ tr.startTransaction();\r
+\r
+ if (isTwoPhaseEncryptionBoot || isTwoPhaseUpgradeBoot) {\r
+\r
+ // DERBY-2264: shutdown and boot again with encryption or\r
+ // upgrade attributes active. This is restricted to the\r
+ // database owner if authentication and sqlAuthorization is on.\r
+ if (!usingNoneAuth &&\r
+ getLanguageConnection().usesSqlAuthorization()) {\r
+ // a failure here leaves database booted, but no\r
+ // (re)encryption has taken place and the connection is\r
+ // rejected.\r
+ checkIsDBOwner(isTwoPhaseEncryptionBoot? OP_ENCRYPT :\r
+ OP_HARD_UPGRADE);\r
+ }\r
+\r
+ // shutdown and reboot using saved properties which\r
+ // include the (re)encyption or upgrade attribute(s)\r
+ info = savedInfo;\r
+ handleException(tr.shutdownDatabaseException());\r
+ restoreContextStack();\r
+ tr = new TransactionResourceImpl(driver, url, info);\r
+ active = true;\r
+ setupContextStack();\r
+ context = pushConnectionContext(tr.getContextManager());\r
+\r
+ if (!bootDatabase(info, false))\r
+ {\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.THROWASSERT(\r
+ "bootDatabase failed after initial plain boot " +\r
+ "for (re)encryption or upgrade");\r
+ }\r
+ tr.clearContextInError();\r
+ setInactive();\r
+ return;\r
+ }\r
+ // don't need to check user credentials again, did\r
+ // that on first plain boot, so just start\r
+ tr.startTransaction();\r
+ }\r
+\r
+ // now we have the database connection, we can shut down\r
+ if (shutdown) {\r
+ if (!usingNoneAuth &&\r
+ getLanguageConnection().usesSqlAuthorization()) {\r
+ // DERBY-2264: Only allow database owner to shut down if\r
+ // authentication and sqlAuthorization is on.\r
+ checkIsDBOwner(OP_SHUTDOWN);\r
+ }\r
+ throw tr.shutdownDatabaseException();\r
+ }\r
+\r
+ // Raise a warning in sqlAuthorization mode if authentication is not ON\r
+ if (usingNoneAuth && getLanguageConnection().usesSqlAuthorization())\r
+ addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.SQL_AUTHORIZATION_WITH_NO_AUTHENTICATION));\r
+ }\r
+ catch (OutOfMemoryError noMemory)\r
+ {\r
+ //System.out.println("freeA");\r
+ restoreContextStack();\r
+ tr.lcc = null;\r
+ tr.cm = null;\r
+ \r
+ //System.out.println("free");\r
+ //System.out.println(Runtime.getRuntime().freeMemory());\r
+ memoryState.setLowMemory();\r
+ \r
+ //noMemory.printStackTrace();\r
+ // throw Util.generateCsSQLException(SQLState.LOGIN_FAILED, noMemory.getMessage(), noMemory);\r
+ throw NO_MEM;\r
+ }\r
+ catch (Throwable t) {\r
+ if (t instanceof StandardException)\r
+ {\r
+ StandardException se = (StandardException) t;\r
+ if (se.getSeverity() < ExceptionSeverity.SESSION_SEVERITY)\r
+ se.setSeverity(ExceptionSeverity.SESSION_SEVERITY);\r
+ }\r
+ tr.cleanupOnError(t);\r
+ throw handleException(t);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ Examine the attributes set provided for illegal boot\r
+ combinations and determine if this is a create boot.\r
+\r
+ @return true iff the attribute <em>create=true</em> is provided. This\r
+ means create a standard database. In other cases, returns\r
+ false.\r
+\r
+ @param p the attribute set.\r
+\r
+ @exception SQLException Throw if more than one of\r
+ <em>create</em>, <em>createFrom</em>, <em>restoreFrom</em> and\r
+ <em>rollForwardRecoveryFrom</em> is used simultaneously. <br>\r
+\r
+ Also, throw if (re)encryption is attempted with one of\r
+ <em>createFrom</em>, <em>restoreFrom</em> and\r
+ <em>rollForwardRecoveryFrom</em>.\r
+\r
+ */\r
+ private boolean createBoot(Properties p) throws SQLException\r
+ {\r
+ int createCount = 0;\r
+\r
+ if (Boolean.valueOf(p.getProperty(Attribute.CREATE_ATTR)).booleanValue())\r
+ createCount++;\r
+\r
+ int restoreCount=0;\r
+ //check if the user has specified any /create/restore/recover from backup attributes.\r
+ if (p.getProperty(Attribute.CREATE_FROM) != null)\r
+ restoreCount++;\r
+ if (p.getProperty(Attribute.RESTORE_FROM) != null)\r
+ restoreCount++;\r
+ if (p.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM)!=null)\r
+ restoreCount++;\r
+ if(restoreCount > 1)\r
+ throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);\r
+ \r
+ // check if user has specified re-encryption attributes in\r
+ // combination with createFrom/restoreFrom/rollForwardRecoveryFrom\r
+ // attributes. Re-encryption is not\r
+ // allowed when restoring from backup.\r
+ if (restoreCount != 0 && isEncryptionBoot(p)) {\r
+ throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);\r
+ }\r
+\r
+\r
+ //add the restore count to create count to make sure \r
+ //user has not specified and restore together by mistake.\r
+ createCount = createCount + restoreCount ;\r
+\r
+ //\r
+ if (createCount > 1) throw newSQLException(SQLState.CONFLICTING_CREATE_ATTRIBUTES);\r
+ \r
+ //retuns true only for the create flag not for restore flags\r
+ return (createCount - restoreCount) == 1;\r
+ }\r
+\r
+ /**\r
+ * Examine boot properties and determine if a boot with the given\r
+ * attributes would entail an encryption operation.\r
+ *\r
+ * @param p the attribute set\r
+ * @return true if a boot will encrypt or re-encrypt the database\r
+ */\r
+ private boolean isEncryptionBoot(Properties p)\r
+ {\r
+ return ((Boolean.valueOf(\r
+ p.getProperty(Attribute.DATA_ENCRYPTION)).booleanValue()) ||\r
+ (p.getProperty(Attribute.NEW_BOOT_PASSWORD) != null) ||\r
+ (p.getProperty(Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null));\r
+ }\r
+\r
+ /**\r
+ * Examine boot properties and determine if a boot with the given\r
+ * attributes would entail a hard upgrade.\r
+ *\r
+ * @param p the attribute set\r
+ * @return true if a boot will hard upgrade the database\r
+ */\r
+ private boolean isHardUpgradeBoot(Properties p)\r
+ {\r
+ return Boolean.valueOf(\r
+ p.getProperty(Attribute.UPGRADE_ATTR)).booleanValue();\r
+ }\r
+\r
+ /**\r
+ * Remove any encryption or upgarde properties from the given properties\r
+ *\r
+ * @param p the attribute set\r
+ * @return clone sans encryption properties\r
+ */\r
+ private Properties removePhaseTwoProps(Properties p)\r
+ {\r
+ p.remove(Attribute.DATA_ENCRYPTION);\r
+ p.remove(Attribute.NEW_BOOT_PASSWORD);\r
+ p.remove(Attribute.NEW_CRYPTO_EXTERNAL_KEY);\r
+ p.remove(Attribute.UPGRADE_ATTR);\r
+ return p;\r
+ }\r
+\r
+\r
+ /**\r
+ * Create a new connection based off of the \r
+ * connection passed in. Initializes state\r
+ * based on input connection, and copies \r
+ * appropriate object pointers. This is only used\r
+ for nested connections.\r
+ *\r
+ * @param inputConnection the input connection\r
+ */\r
+ public EmbedConnection(EmbedConnection inputConnection) \r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(inputConnection.active, \r
+ "trying to create a proxy for an inactive conneciton");\r
+ }\r
+\r
+ // Proxy connections are always autocommit false\r
+ // thus needCommit is irrelavent.\r
+ autoCommit = false;\r
+\r
+\r
+ /*\r
+ ** Nesting specific state we are copying from \r
+ ** the inputConnection\r
+ */\r
+\r
+ /*\r
+ ** Objects we are sharing across nestings\r
+ */\r
+ // set it to null to allow it to be final.\r
+ tr = null; // a proxy connection has no direct\r
+ // pointer to the tr. Every call has to go\r
+ // thru the rootConnection's tr.\r
+ active = true;\r
+ this.rootConnection = inputConnection.rootConnection;\r
+ this.applicationConnection = this;\r
+ this.factory = inputConnection.factory;\r
+\r
+ //if no holdability specified for the resultset, use the holability\r
+ //defined for the connection\r
+ this.connectionHoldAbility = inputConnection.connectionHoldAbility;\r
+\r
+ //RESOLVE: although it looks like the right\r
+ // thing to share the metadata object, if\r
+ // we do we'll get the wrong behavior on\r
+ // getCurrentConnection().getMetaData().isReadOnly()\r
+ // so don't try to be smart and uncomment the\r
+ // following. Ultimately, the metadata should\r
+ // be shared by all connections anyway.\r
+ //dbMetadata = inputConnection.dbMetadata;\r
+ }\r
+\r
+ //\r
+ // Check passed-in user's credentials.\r
+ //\r
+ private void checkUserCredentials(String dbname,\r
+ Properties userInfo)\r
+ throws SQLException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ // If a database name was passed-in then check user's credential\r
+ // in that database using the database's authentication service,\r
+ // otherwise check if it is a valid user in the JBMS system.\r
+ //\r
+ // NOTE: We always expect an authentication service per database\r
+ // and one at the system level.\r
+ //\r
+ AuthenticationService authenticationService = null;\r
+\r
+ // Retrieve appropriate authentication service handle\r
+ if (dbname == null)\r
+ authenticationService = getLocalDriver().getAuthenticationService();\r
+ else\r
+ authenticationService = getTR().getDatabase().getAuthenticationService();\r
+\r
+ // check that we do have a authentication service\r
+ // it is _always_ expected.\r
+ if (authenticationService == null)\r
+ {\r
+ String failedString = MessageService.getTextMessage(\r
+ (dbname == null) ? MessageId.AUTH_NO_SERVICE_FOR_SYSTEM : MessageId.AUTH_NO_SERVICE_FOR_DB);\r
+\r
+ throw newSQLException(SQLState.LOGIN_FAILED, failedString);\r
+ }\r
+ \r
+ // Let's authenticate now\r
+ \r
+ if (!authenticationService.authenticate(\r
+ dbname,\r
+ userInfo\r
+ )) {\r
+\r
+ throw newSQLException(SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID));\r
+\r
+ }\r
+\r
+ // If authentication is not on, we have to raise a warning if sqlAuthorization is ON\r
+ // Since NoneAuthenticationService is the default for Derby, it should be ok to refer\r
+ // to its implementation here, since it will always be present.\r
+ if (authenticationService instanceof NoneAuthenticationServiceImpl)\r
+ usingNoneAuth = true;\r
+ }\r
+\r
+ /* Enumerate operations controlled by database owner powers */\r
+ private static final int OP_ENCRYPT = 0;\r
+ private static final int OP_SHUTDOWN = 1;\r
+ private static final int OP_HARD_UPGRADE = 2;\r
+ /**\r
+ * Check if actual authenticationId is equal to the database owner's.\r
+ *\r
+ * @param operation attempted operation which needs database owner powers\r
+ * @throws SQLException if actual authenticationId is different\r
+ * from authenticationId of database owner.\r
+ */\r
+ private void checkIsDBOwner(int operation) throws SQLException\r
+ {\r
+ final LanguageConnectionContext lcc = getLanguageConnection();\r
+ final String actualId = lcc.getAuthorizationId();\r
+ final String dbOwnerId = lcc.getDataDictionary().\r
+ getAuthorizationDatabaseOwner();\r
+ if (!actualId.equals(dbOwnerId)) {\r
+ switch (operation) {\r
+ case OP_ENCRYPT:\r
+ throw newSQLException(SQLState.AUTH_ENCRYPT_NOT_DB_OWNER,\r
+ actualId, tr.getDBName());\r
+ case OP_SHUTDOWN:\r
+ throw newSQLException(SQLState.AUTH_SHUTDOWN_NOT_DB_OWNER,\r
+ actualId, tr.getDBName());\r
+ case OP_HARD_UPGRADE:\r
+ throw newSQLException(SQLState.AUTH_HARD_UPGRADE_NOT_DB_OWNER,\r
+ actualId, tr.getDBName());\r
+ default:\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.THROWASSERT(\r
+ "illegal checkIsDBOwner operation");\r
+ }\r
+ throw newSQLException(\r
+ SQLState.AUTH_DATABASE_CONNECTION_REFUSED);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Gets the EngineType of the connected database.\r
+ *\r
+ * @return 0 if there is no database, the engine type otherwise. @see org.apache.derby.iapi.reference.EngineType\r
+ */\r
+ public int getEngineType()\r
+ {\r
+ Database db = getDatabase();\r
+\r
+ if( null == db)\r
+ return 0;\r
+ return db.getEngineType();\r
+ }\r
+ \r
+ /*\r
+ ** Methods from java.sql.Connection\r
+ */\r
+\r
+ /**\r
+ * SQL statements without parameters are normally\r
+ * executed using Statement objects. If the same SQL statement \r
+ * is executed many times, it is more efficient to use a \r
+ * PreparedStatement\r
+ *\r
+ * JDBC 2.0\r
+ *\r
+ * Result sets created using the returned Statement will have\r
+ * forward-only type, and read-only concurrency, by default.\r
+ *\r
+ * @return a new Statement object \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final Statement createStatement() throws SQLException \r
+ {\r
+ return createStatement(JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility);\r
+ }\r
+\r
+ /**\r
+ * JDBC 2.0\r
+ *\r
+ * Same as createStatement() above, but allows the default result set\r
+ * type and result set concurrency type to be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @return a new Statement object \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final Statement createStatement(int resultSetType,\r
+ int resultSetConcurrency) \r
+ throws SQLException\r
+ {\r
+ return createStatement(resultSetType, resultSetConcurrency,\r
+ connectionHoldAbility);\r
+ }\r
+\r
+ /**\r
+ * JDBC 3.0\r
+ *\r
+ * Same as createStatement() above, but allows the default result set\r
+ * type, result set concurrency type and result set holdability type to\r
+ * be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @param resultSetHoldability a holdability type,\r
+ * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ * @return a new Statement object\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final Statement createStatement(int resultSetType,\r
+ int resultSetConcurrency,\r
+ int resultSetHoldability)\r
+ throws SQLException\r
+ {\r
+ checkIfClosed();\r
+\r
+ return factory.newEmbedStatement(this, false,\r
+ setResultSetType(resultSetType), resultSetConcurrency,\r
+ resultSetHoldability);\r
+ }\r
+\r
+ /**\r
+ * A SQL statement with or without IN parameters can be\r
+ * pre-compiled and stored in a PreparedStatement object. This\r
+ * object can then be used to efficiently execute this statement\r
+ * multiple times.\r
+ *\r
+ * <P><B>Note:</B> This method is optimized for handling\r
+ * parametric SQL statements that benefit from precompilation. If\r
+ * the driver supports precompilation, prepareStatement will send\r
+ * the statement to the database for precompilation. Some drivers\r
+ * may not support precompilation. In this case, the statement may\r
+ * not be sent to the database until the PreparedStatement is\r
+ * executed. This has no direct affect on users; however, it does\r
+ * affect which method throws certain SQLExceptions.\r
+ *\r
+ * JDBC 2.0\r
+ *\r
+ * Result sets created using the returned PreparedStatement will have\r
+ * forward-only type, and read-only concurrency, by default.\r
+ *\r
+ * @param sql a SQL statement that may contain one or more '?' IN\r
+ * parameter placeholders\r
+ * @return a new PreparedStatement object containing the\r
+ * pre-compiled statement \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final PreparedStatement prepareStatement(String sql)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility,\r
+ JDBC30Translation.NO_GENERATED_KEYS,\r
+ null,\r
+ null);\r
+ }\r
+\r
+\r
+ /**\r
+ * JDBC 2.0\r
+ *\r
+ * Same as prepareStatement() above, but allows the default result set\r
+ * type and result set concurrency type to be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @return a new PreparedStatement object containing the\r
+ * pre-compiled SQL statement\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final PreparedStatement prepareStatement(String sql, int resultSetType,\r
+ int resultSetConcurrency)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,\r
+ resultSetType,\r
+ resultSetConcurrency,\r
+ connectionHoldAbility,\r
+ JDBC30Translation.NO_GENERATED_KEYS,\r
+ null,\r
+ null);\r
+ }\r
+\r
+ /**\r
+ * JDBC 3.0\r
+ *\r
+ * Same as prepareStatement() above, but allows the default result set\r
+ * type, result set concurrency type and result set holdability\r
+ * to be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @param resultSetHoldability - one of the following ResultSet constants:\r
+ * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ * @return a new PreparedStatement object containing the\r
+ * pre-compiled SQL statement\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final PreparedStatement prepareStatement(String sql, int resultSetType,\r
+ int resultSetConcurrency, int resultSetHoldability)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,\r
+ resultSetType,\r
+ resultSetConcurrency,\r
+ resultSetHoldability,\r
+ JDBC30Translation.NO_GENERATED_KEYS,\r
+ null,\r
+ null);\r
+ }\r
+\r
+\r
+ /**\r
+ * Creates a default PreparedStatement object capable of returning\r
+ * the auto-generated keys designated by the given array. This array contains\r
+ * the indexes of the columns in the target table that contain the auto-generated\r
+ * keys that should be made available. This array is ignored if the SQL statement\r
+ * is not an INSERT statement\r
+\r
+ JDBC 3.0\r
+ *\r
+ *\r
+ * @param sql An SQL statement that may contain one or more ? IN parameter placeholders\r
+ * @param columnIndexes An array of column indexes indicating the columns\r
+ * that should be returned from the inserted row or rows\r
+ *\r
+ * @return A new PreparedStatement object, containing the pre-compiled\r
+ * SQL statement, that will have the capability of returning auto-generated keys\r
+ * designated by the given array of column indexes\r
+ *\r
+ * @exception SQLException Thrown on error.\r
+ */\r
+ public final PreparedStatement prepareStatement(\r
+ String sql,\r
+ int[] columnIndexes)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,\r
+ JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility,\r
+ columnIndexes == null\r
+ ? JDBC30Translation.NO_GENERATED_KEYS\r
+ : JDBC30Translation.RETURN_GENERATED_KEYS,\r
+ columnIndexes,\r
+ null);\r
+ }\r
+\r
+ /**\r
+ * Creates a default PreparedStatement object capable of returning\r
+ * the auto-generated keys designated by the given array. This array contains\r
+ * the names of the columns in the target table that contain the auto-generated\r
+ * keys that should be returned. This array is ignored if the SQL statement\r
+ * is not an INSERT statement\r
+ *\r
+ JDBC 3.0\r
+ *\r
+ * @param sql An SQL statement that may contain one or more ? IN parameter placeholders\r
+ * @param columnNames An array of column names indicating the columns\r
+ * that should be returned from the inserted row or rows\r
+ *\r
+ * @return A new PreparedStatement object, containing the pre-compiled\r
+ * SQL statement, that will have the capability of returning auto-generated keys\r
+ * designated by the given array of column names\r
+ *\r
+ * @exception SQLException Thrown on error.\r
+ */\r
+ public final PreparedStatement prepareStatement(\r
+ String sql,\r
+ String[] columnNames)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,\r
+ JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility,\r
+ columnNames == null\r
+ ? JDBC30Translation.NO_GENERATED_KEYS\r
+ : JDBC30Translation.RETURN_GENERATED_KEYS,\r
+ null,\r
+ columnNames);\r
+ }\r
+\r
+ /**\r
+ * Creates a default PreparedStatement object that has the capability to\r
+ * retieve auto-generated keys. The given constant tells the driver\r
+ * whether it should make auto-generated keys available for retrieval.\r
+ * This parameter is ignored if the SQL statement is not an INSERT statement.\r
+ * JDBC 3.0\r
+ *\r
+ * @param sql A SQL statement that may contain one or more ? IN parameter placeholders\r
+ * @param autoGeneratedKeys A flag indicating whether auto-generated keys\r
+ * should be returned\r
+ *\r
+ * @return A new PreparedStatement object, containing the pre-compiled\r
+ * SQL statement, that will have the capability of returning auto-generated keys\r
+ *\r
+ * @exception SQLException Feature not implemented for now.\r
+ */\r
+ public final PreparedStatement prepareStatement(\r
+ String sql,\r
+ int autoGeneratedKeys)\r
+ throws SQLException\r
+ {\r
+ return prepareStatement(sql,\r
+ JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility,\r
+ autoGeneratedKeys,\r
+ null,\r
+ null);\r
+ }\r
+ \r
+ private PreparedStatement prepareStatement(String sql, int resultSetType,\r
+ int resultSetConcurrency, int resultSetHoldability,\r
+ int autoGeneratedKeys, int[] columnIndexes, String[] columnNames)\r
+ throws SQLException\r
+ {\r
+ synchronized (getConnectionSynchronization()) {\r
+ setupContextStack();\r
+ try {\r
+ return factory.newEmbedPreparedStatement(this, sql, false,\r
+ setResultSetType(resultSetType),\r
+ resultSetConcurrency,\r
+ resultSetHoldability,\r
+ autoGeneratedKeys,\r
+ columnIndexes,\r
+ columnNames);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * A SQL stored procedure call statement is handled by creating a\r
+ * CallableStatement for it. The CallableStatement provides\r
+ * methods for setting up its IN and OUT parameters, and\r
+ * methods for executing it.\r
+ *\r
+ * <P><B>Note:</B> This method is optimized for handling stored\r
+ * procedure call statements. Some drivers may send the call\r
+ * statement to the database when the prepareCall is done; others\r
+ * may wait until the CallableStatement is executed. This has no\r
+ * direct affect on users; however, it does affect which method\r
+ * throws certain SQLExceptions.\r
+ *\r
+ * JDBC 2.0\r
+ *\r
+ * Result sets created using the returned CallableStatement will have\r
+ * forward-only type, and read-only concurrency, by default.\r
+ *\r
+ * @param sql a SQL statement that may contain one or more '?'\r
+ * parameter placeholders. Typically this statement is a JDBC\r
+ * function call escape string.\r
+ * @return a new CallableStatement object containing the\r
+ * pre-compiled SQL statement \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final CallableStatement prepareCall(String sql) \r
+ throws SQLException \r
+ {\r
+ return prepareCall(sql, JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility);\r
+ }\r
+\r
+ /**\r
+ * JDBC 2.0\r
+ *\r
+ * Same as prepareCall() above, but allows the default result set\r
+ * type and result set concurrency type to be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @return a new CallableStatement object containing the\r
+ * pre-compiled SQL statement \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final CallableStatement prepareCall(String sql, int resultSetType,\r
+ int resultSetConcurrency)\r
+ throws SQLException \r
+ {\r
+ return prepareCall(sql, resultSetType, resultSetConcurrency,\r
+ connectionHoldAbility);\r
+ }\r
+\r
+ /**\r
+ * JDBC 3.0\r
+ *\r
+ * Same as prepareCall() above, but allows the default result set\r
+ * type, result set concurrency type and result set holdability\r
+ * to be overridden.\r
+ *\r
+ * @param resultSetType a result set type, see ResultSet.TYPE_XXX\r
+ * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX\r
+ * @param resultSetHoldability - one of the following ResultSet constants:\r
+ * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ * @return a new CallableStatement object containing the\r
+ * pre-compiled SQL statement \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final CallableStatement prepareCall(String sql, int resultSetType, \r
+ int resultSetConcurrency, int resultSetHoldability)\r
+ throws SQLException \r
+ {\r
+ checkIfClosed();\r
+\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try \r
+ {\r
+ return factory.newEmbedCallableStatement(this, sql,\r
+ setResultSetType(resultSetType),\r
+ resultSetConcurrency,\r
+ resultSetHoldability);\r
+ } \r
+ finally \r
+ {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * A driver may convert the JDBC sql grammar into its system's\r
+ * native SQL grammar prior to sending it; nativeSQL returns the\r
+ * native form of the statement that the driver would have sent.\r
+ *\r
+ * @param sql a SQL statement that may contain one or more '?'\r
+ * parameter placeholders\r
+ * @return the native form of this statement\r
+ */\r
+ public String nativeSQL(String sql) throws SQLException {\r
+ checkIfClosed();\r
+ // we don't massage the strings at all, so this is easy:\r
+ return sql;\r
+ }\r
+\r
+ /**\r
+ * If a connection is in auto-commit mode, then all its SQL\r
+ * statements will be executed and committed as individual\r
+ * transactions. Otherwise, its SQL statements are grouped into\r
+ * transactions that are terminated by either commit() or\r
+ * rollback(). By default, new connections are in auto-commit\r
+ * mode.\r
+ *\r
+ * The commit occurs when the statement completes or the next\r
+ * execute occurs, whichever comes first. In the case of\r
+ * statements returning a ResultSet, the statement completes when\r
+ * the last row of the ResultSet has been retrieved or the\r
+ * ResultSet has been closed. In advanced cases, a single\r
+ * statement may return multiple results as well as output\r
+ * parameter values. Here the commit occurs when all results and\r
+ * output param values have been retrieved.\r
+ *\r
+ * @param autoCommit true enables auto-commit; false disables\r
+ * auto-commit. \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public void setAutoCommit(boolean autoCommit) throws SQLException {\r
+ checkIfClosed();\r
+\r
+ // Is this a nested connection\r
+ if (rootConnection != this) {\r
+ if (autoCommit)\r
+ throw newSQLException(SQLState.NO_AUTO_COMMIT_ON);\r
+ }\r
+\r
+ if (this.autoCommit != autoCommit)\r
+ commit();\r
+\r
+ this.autoCommit = autoCommit;\r
+ }\r
+\r
+ /**\r
+ * Get the current auto-commit state.\r
+ *\r
+ * @return Current state of auto-commit mode.\r
+ * @see #setAutoCommit \r
+ */\r
+ public boolean getAutoCommit() throws SQLException {\r
+ checkIfClosed();\r
+ return autoCommit;\r
+ }\r
+\r
+ /**\r
+ * Commit makes all changes made since the previous\r
+ * commit/rollback permanent and releases any database locks\r
+ * currently held by the Connection. This method should only be\r
+ * used when auto commit has been disabled.\r
+ *\r
+ * @exception SQLException if a database-access error occurs.\r
+ * @see #setAutoCommit \r
+ */\r
+ public void commit() throws SQLException {\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ /*\r
+ ** Note that the context stack is\r
+ ** needed even for rollback & commit\r
+ */\r
+ setupContextStack();\r
+\r
+ try\r
+ {\r
+ getTR().commit();\r
+ clearLOBMapping();\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ finally \r
+ {\r
+ restoreContextStack();\r
+ }\r
+\r
+ needCommit = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Rollback drops all changes made since the previous\r
+ * commit/rollback and releases any database locks currently held\r
+ * by the Connection. This method should only be used when auto\r
+ * commit has been disabled.\r
+ *\r
+ * @exception SQLException if a database-access error occurs.\r
+ * @see #setAutoCommit \r
+ */\r
+ public void rollback() throws SQLException {\r
+\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ /*\r
+ ** Note that the context stack is\r
+ ** needed even for rollback & commit\r
+ */\r
+ setupContextStack();\r
+ try\r
+ {\r
+ getTR().rollback();\r
+ clearLOBMapping();\r
+ } catch (Throwable t) {\r
+ throw handleException(t);\r
+ }\r
+ finally \r
+ {\r
+ restoreContextStack();\r
+ }\r
+ needCommit = false;\r
+ } \r
+ }\r
+\r
+ /**\r
+ * In some cases, it is desirable to immediately release a\r
+ * Connection's database and JDBC resources instead of waiting for\r
+ * them to be automatically released; the close method provides this\r
+ * immediate release. \r
+ *\r
+ * <P><B>Note:</B> A Connection is automatically closed when it is\r
+ * garbage collected. Certain fatal errors also result in a closed\r
+ * Connection.\r
+ *\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public void close() throws SQLException {\r
+ // JDK 1.4 javadoc indicates close on a closed connection is a no-op\r
+ if (!isClosed() &&\r
+ (rootConnection == this) && \r
+ (!autoCommit && !transactionIsIdle())) {\r
+ throw newSQLException(\r
+ SQLState.LANG_INVALID_TRANSACTION_STATE);\r
+ }\r
+ \r
+ close(exceptionClose);\r
+ }\r
+\r
+ // This inner close takes the exception and calls \r
+ // the context manager to make the connection close.\r
+ // The exception must be a session severity exception.\r
+ //\r
+ // NOTE: This method is not part of JDBC specs.\r
+ //\r
+ private void close(StandardException e) throws SQLException {\r
+ \r
+ synchronized(getConnectionSynchronization())\r
+ {\r
+ if (rootConnection == this)\r
+ {\r
+ /*\r
+ * If it isn't active, it's already been closed.\r
+ */\r
+ if (active) {\r
+ if (tr.isActive()) {\r
+ setupContextStack();\r
+ try {\r
+ tr.rollback();\r
+ \r
+ // Let go of lcc reference so it can be GC'ed after\r
+ // cleanupOnError, the tr will stay around until the\r
+ // rootConnection itself is GC'ed, which is dependent\r
+ // on how long the client program wants to hold on to\r
+ // the Connection object.\r
+ tr.clearLcc(); \r
+ tr.cleanupOnError(e);\r
+ \r
+ } catch (Throwable t) {\r
+ throw handleException(t);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ } else {\r
+ // DERBY-1947: If another connection has closed down\r
+ // the database, the transaction is not active, but\r
+ // the cleanup has not been done yet.\r
+ tr.clearLcc(); \r
+ tr.cleanupOnError(e);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!isClosed())\r
+ setInactive();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Tests to see if a Connection is closed.\r
+ *\r
+ * @return true if the connection is closed; false if it's still open\r
+ */\r
+ public final boolean isClosed() {\r
+ if (active) {\r
+\r
+ // I am attached, check the database state\r
+ if (getTR().isActive()) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * A Connection's database is able to provide information\r
+ * describing its tables, its supported SQL grammar, its stored\r
+ * procedures, the capabilities of this connection, etc. This\r
+ * information is made available through a DatabaseMetaData\r
+ * object.\r
+ *\r
+ * @return a DatabaseMetaData object for this Connection \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public DatabaseMetaData getMetaData() throws SQLException {\r
+ checkIfClosed();\r
+\r
+ if (dbMetadata == null) {\r
+\r
+ // There is a case where dbname can be null.\r
+ // Replication client of this method does not have a\r
+ // JDBC connection; therefore dbname is null and this\r
+ // is expected.\r
+ //\r
+ dbMetadata = factory.newEmbedDatabaseMetaData(this, getTR().getUrl());\r
+ }\r
+ return dbMetadata;\r
+ }\r
+\r
+ /**\r
+ JDBC 3.0\r
+ * Retrieves the current holdability of ResultSet objects created using this\r
+ * Connection object.\r
+ *\r
+ *\r
+ * @return The holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT\r
+ * or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ *\r
+ */\r
+ public final int getHoldability() throws SQLException {\r
+ checkIfClosed();\r
+ return connectionHoldAbility;\r
+ }\r
+\r
+ /**\r
+ JDBC 3.0\r
+ * Changes the holdability of ResultSet objects created using this\r
+ * Connection object to the given holdability.\r
+ *\r
+ *\r
+ * @param holdability A ResultSet holdability constant, one of ResultSet.HOLD_CURSORS_OVER_COMMIT\r
+ * or ResultSet.CLOSE_CURSORS_AT_COMMIT\r
+ *\r
+ */\r
+ public final void setHoldability(int holdability) throws SQLException {\r
+ checkIfClosed();\r
+ connectionHoldAbility = holdability;\r
+ }\r
+\r
+ /**\r
+ * You can put a connection in read-only mode as a hint to enable \r
+ * database optimizations.\r
+ *\r
+ * <P><B>Note:</B> setReadOnly cannot be called while in the\r
+ * middle of a transaction.\r
+ *\r
+ * @param readOnly true enables read-only mode; false disables\r
+ * read-only mode. \r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final void setReadOnly(boolean readOnly) throws SQLException\r
+ {\r
+ synchronized(getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try {\r
+ getLanguageConnection().setReadOnly(readOnly);\r
+ } catch (StandardException e) {\r
+ throw handleException(e);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Tests to see if the connection is in read-only mode.\r
+ *\r
+ * @return true if connection is read-only\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final boolean isReadOnly() throws SQLException\r
+ {\r
+ checkIfClosed();\r
+ return getLanguageConnection().isReadOnly();\r
+ }\r
+\r
+ /**\r
+ * A sub-space of this Connection's database may be selected by setting a\r
+ * catalog name. If the driver does not support catalogs it will\r
+ * silently ignore this request.\r
+ *\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public void setCatalog(String catalog) throws SQLException {\r
+ checkIfClosed();\r
+ // silently ignoring this request like the javadoc said.\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Return the Connection's current catalog name.\r
+ *\r
+ * @return the current catalog name or null\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public String getCatalog() throws SQLException {\r
+ checkIfClosed();\r
+ // we do not have support for Catalog, just return null as\r
+ // the JDBC specs mentions then.\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * You can call this method to try to change the transaction\r
+ * isolation level using one of the TRANSACTION_* values.\r
+ *\r
+ * <P><B>Note:</B> setTransactionIsolation causes the current\r
+ * transaction to commit if the isolation level is changed. Otherwise, if\r
+ * the requested isolation level is the same as the current isolation\r
+ * level, this method is a no-op.\r
+ *\r
+ * @param level one of the TRANSACTION_* isolation values with the\r
+ * exception of TRANSACTION_NONE; some databases may not support\r
+ * other values\r
+ * @exception SQLException if a database-access error occurs.\r
+ * @see DatabaseMetaData#supportsTransactionIsolationLevel \r
+ */\r
+ public void setTransactionIsolation(int level) throws SQLException {\r
+\r
+ if (level == getTransactionIsolation())\r
+ return;\r
+\r
+ // Convert the isolation level to the internal one\r
+ int iLevel;\r
+ switch (level)\r
+ {\r
+ case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:\r
+ iLevel = ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL;\r
+ break;\r
+\r
+ case java.sql.Connection.TRANSACTION_READ_COMMITTED:\r
+ iLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;\r
+ break;\r
+\r
+ case java.sql.Connection.TRANSACTION_REPEATABLE_READ:\r
+ iLevel = ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL;\r
+ break;\r
+\r
+ case java.sql.Connection.TRANSACTION_SERIALIZABLE:\r
+ iLevel = ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL;\r
+ break;\r
+ default:\r
+ throw newSQLException(SQLState.UNIMPLEMENTED_ISOLATION_LEVEL, new Integer(level));\r
+ }\r
+\r
+ synchronized(getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try {\r
+ getLanguageConnection().setIsolationLevel(iLevel);\r
+ } catch (StandardException e) {\r
+ throw handleException(e);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Get this Connection's current transaction isolation mode.\r
+ *\r
+ * @return the current TRANSACTION_* mode value\r
+ * @exception SQLException if a database-access error occurs.\r
+ */\r
+ public final int getTransactionIsolation() throws SQLException {\r
+ checkIfClosed();\r
+ return ExecutionContext.CS_TO_JDBC_ISOLATION_LEVEL_MAP[getLanguageConnection().getCurrentIsolationLevel()];\r
+ }\r
+\r
+ /**\r
+ * The first warning reported by calls on this Connection is\r
+ * returned. \r
+ *\r
+ * <P><B>Note:</B> Subsequent warnings will be chained to this\r
+ * SQLWarning.\r
+ *\r
+ * @return the first SQLWarning or null \r
+ *\r
+ * Synchronization note: Warnings are synchronized \r
+ * on nesting level\r
+ */\r
+ public final synchronized SQLWarning getWarnings() throws SQLException {\r
+ checkIfClosed();\r
+ return topWarning;\r
+ }\r
+\r
+ /**\r
+ * After this call, getWarnings returns null until a new warning is\r
+ * reported for this Connection. \r
+ *\r
+ * Synchronization node: Warnings are synchonized \r
+ * on nesting level\r
+ */\r
+ public final synchronized void clearWarnings() throws SQLException {\r
+ checkIfClosed();\r
+ topWarning = null;\r
+ }\r
+\r
+ /////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // JDBC 2.0 - New public methods\r
+ //\r
+ /////////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ *\r
+ * Get the type-map object associated with this connection.\r
+ * By default, the map returned is empty.\r
+ * JDBC 2.0 - java.util.Map requires JDK 1\r
+ *\r
+ */\r
+ public java.util.Map getTypeMap() throws SQLException {\r
+ checkIfClosed();\r
+ // just return an immuntable empty map\r
+ return java.util.Collections.EMPTY_MAP;\r
+ }\r
+\r
+ /** \r
+ * Install a type-map object as the default type-map for\r
+ * this connection.\r
+ * JDBC 2.0 - java.util.Map requires JDK 1\r
+ *\r
+ * @exception SQLException Feature not implemented for now.\r
+ */\r
+ public final void setTypeMap(java.util.Map map) throws SQLException {\r
+ checkIfClosed();\r
+ if( map == null)\r
+ throw Util.generateCsSQLException(SQLState.INVALID_API_PARAMETER,map,"map",\r
+ "java.sql.Connection.setTypeMap");\r
+ if(!(map.isEmpty()))\r
+ throw Util.notImplemented();\r
+ }\r
+\r
+ /////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // Implementation specific methods \r
+ //\r
+ /////////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ Add a warning to the current list of warnings, to follow\r
+ this note from Connection.getWarnings.\r
+ Note: Subsequent warnings will be chained to this SQLWarning. \r
+\r
+ @see java.sql.Connection#getWarnings\r
+ */\r
+ public final synchronized void addWarning(SQLWarning newWarning) {\r
+ if (topWarning == null) {\r
+ topWarning = newWarning;\r
+ return;\r
+ }\r
+\r
+ topWarning.setNextWarning(newWarning);\r
+ }\r
+\r
+ /**\r
+ * Return the dbname for this connection.\r
+ *\r
+ * @return String The dbname for this connection.\r
+ */\r
+ public String getDBName()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ return getTR().getDBName();\r
+ }\r
+\r
+ public final LanguageConnectionContext getLanguageConnection() {\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ return getTR().getLcc();\r
+ }\r
+\r
+ /**\r
+ * Raises an exception if the connection is closed.\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
+ //EmbedConnection30 overrides this method so it can release the savepoints array if\r
+ //the exception severity is transaction level\r
+ SQLException handleException(Throwable thrownException)\r
+ throws SQLException\r
+ {\r
+ //assume in case of SQLException cleanup is \r
+ //done already. This assumption is inline with\r
+ //TR's assumption. In case no rollback was \r
+ //called lob objects will remain valid.\r
+ if (thrownException instanceof StandardException) {\r
+ if (((StandardException) thrownException)\r
+ .getSeverity() \r
+ >= ExceptionSeverity.TRANSACTION_SEVERITY) {\r
+ clearLOBMapping();\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** By default, rollback the connection on if autocommit\r
+ ** is on.\r
+ */\r
+ return getTR().handleException(thrownException, \r
+ autoCommit,\r
+ true // Rollback xact on auto commit\r
+ );\r
+ }\r
+\r
+ /**\r
+ Handle any type of Exception.\r
+ <UL>\r
+ <LI> Inform the contexts of the error\r
+ <LI> Throw an Util based upon the thrown exception.\r
+ </UL>\r
+\r
+ REMIND: now that we know all the exceptions from our driver\r
+ are Utils, would it make sense to shut down the system\r
+ for unknown SQLExceptions? At present, we do not.\r
+\r
+ Because this is the last stop for exceptions,\r
+ it will catch anything that occurs in it and try\r
+ to cleanup before re-throwing them.\r
+ \r
+ @param thrownException the exception\r
+ @param rollbackOnAutoCommit rollback the xact on if autocommit is\r
+ on, otherwise rollback stmt but leave xact open (and\r
+ continue to hold on to locks). Most of the time, this\r
+ will be true, excepting operations on result sets, like\r
+ getInt().\r
+ */\r
+ final SQLException handleException(Throwable thrownException, \r
+ boolean rollbackOnAutoCommit) \r
+ throws SQLException \r
+ {\r
+ //assume in case of SQLException cleanup is \r
+ //done already. This assumption is inline with\r
+ //TR's assumption. In case no rollback was \r
+ //called lob objects will remain valid.\r
+ if (thrownException instanceof StandardException) {\r
+ if (((StandardException) thrownException)\r
+ .getSeverity() \r
+ >= ExceptionSeverity.TRANSACTION_SEVERITY) {\r
+ clearLOBMapping();\r
+ }\r
+ }\r
+ return getTR().handleException(thrownException, autoCommit,\r
+ rollbackOnAutoCommit); \r
+\r
+ }\r
+\r
+ /*\r
+ This is called from the EmbedConnectionContext to\r
+ close on errors. We assume all handling of the connectin\r
+ is dealt with via the context stack, and our only role\r
+ is to mark ourself as closed.\r
+ */\r
+\r
+ /**\r
+ Close the connection when processing errors, or when\r
+ closing a nested connection.\r
+ <p>\r
+ This only marks it as closed and frees up its resources;\r
+ any closing of the underlying connection or commit work\r
+ is assumed to be done elsewhere.\r
+\r
+ Called from EmbedConnectionContext's cleanup routine, \r
+ and by proxy.close().\r
+ */\r
+\r
+ public final void setInactive() {\r
+\r
+ if (active == false)\r
+ return;\r
+ // active = false\r
+ // tr = null !-> active = false\r
+\r
+ synchronized (getConnectionSynchronization()) {\r
+ active = false;\r
+ // tr = null; cleanupOnerror sets inactive but still needs tr to\r
+ // restore context later\r
+ dbMetadata = null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ @exception Throwable standard error policy\r
+ */\r
+ protected void finalize() throws Throwable \r
+ {\r
+ try {\r
+ // Only close root connections, since for nested\r
+ // connections, it is not strictly necessary and close()\r
+ // synchronizes on the root connection which can cause\r
+ // deadlock with the call to runFinalization from\r
+ // GenericPreparedStatement#prepareToInvalidate (see\r
+ // DERBY-1947) on SUN VMs.\r
+ if (rootConnection == this) {\r
+ close(exceptionClose);\r
+ }\r
+ }\r
+ finally {\r
+ super.finalize();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * if auto commit is on, remember that we need to commit\r
+ * the current statement.\r
+ */\r
+ protected void needCommit() {\r
+ if (!needCommit) needCommit = true;\r
+ }\r
+\r
+ /**\r
+ * if a commit is needed, perform it.\r
+ *\r
+ * Must have connection synchonization and context set up already.\r
+ *\r
+ * @exception SQLException if commit returns error\r
+ */\r
+ protected void commitIfNeeded() throws SQLException \r
+ {\r
+ if (autoCommit && needCommit) \r
+ {\r
+ try\r
+ {\r
+ getTR().commit();\r
+ clearLOBMapping();\r
+ } \r
+ catch (Throwable t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ needCommit = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * If in autocommit, then commit.\r
+ * \r
+ * Used to force a commit after a result set closes in autocommit mode.\r
+ * The needCommit mechanism does not work correctly as there are times\r
+ * with cursors (like a commit, followed by a next, followed by a close)\r
+ * where the system does not think it needs a commit but we need to \r
+ * force the commit on close. It seemed safer to just force a commit\r
+ * on close rather than count on keeping the needCommit flag correct for\r
+ * all cursor cases.\r
+ *\r
+ * Must have connection synchonization and context set up already.\r
+ *\r
+ * @exception SQLException if commit returns error\r
+ */\r
+ protected void commitIfAutoCommit() throws SQLException \r
+ {\r
+ if (autoCommit) \r
+ {\r
+ try\r
+ {\r
+ getTR().commit();\r
+ clearLOBMapping();\r
+ } \r
+ catch (Throwable t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ needCommit = false;\r
+ }\r
+ }\r
+\r
+\r
+ final protected Object getConnectionSynchronization()\r
+ {\r
+ return rootConnection;\r
+ }\r
+\r
+ /**\r
+ Install the context manager for this thread. Check connection status here.\r
+ @exception SQLException if fails\r
+ */\r
+ protected final void setupContextStack() throws SQLException {\r
+\r
+ /*\r
+ Track this entry, then throw an exception\r
+ rather than doing the quiet return. Need the\r
+ track before the throw because the backtrack\r
+ is in a finally block.\r
+ */\r
+\r
+ checkIfClosed();\r
+\r
+ getTR().setupContextStack();\r
+\r
+ }\r
+\r
+ protected final void restoreContextStack() throws SQLException {\r
+\r
+ if (SanityManager.DEBUG)\r
+ Util.ASSERT(this, (active) || getTR().getCsf() !=null, "No context service to do restore");\r
+\r
+ TransactionResourceImpl tr = getTR();\r
+\r
+ //REMIND: someone is leaving an incorrect manager on when they\r
+ // are exiting the system in the nested case.\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (tr.getCsf() != null) {\r
+ ContextManager cm1 = tr.getCsf().getCurrentContextManager();\r
+ ContextManager cm2 = tr.getContextManager();\r
+ // If the system has been shut down, cm1 can be null.\r
+ // Otherwise, cm1 and cm2 should be identical.\r
+ Util.ASSERT(this, (cm1 == cm2 || cm1 == null),\r
+ "Current Context Manager not the one was expected: " +\r
+ cm1 + " " + cm2);\r
+ }\r
+ }\r
+\r
+ tr.restoreContextStack();\r
+ }\r
+\r
+ /*\r
+ ** Create database methods.\r
+ */\r
+\r
+ /**\r
+ Create a new database.\r
+ @param dbname the database name\r
+ @param info the properties\r
+\r
+ @return Database The newly created database or null.\r
+\r
+ @exception SQLException if fails to create database\r
+ */\r
+\r
+ private Database createDatabase(String dbname, Properties info)\r
+ throws SQLException {\r
+\r
+ info = filterProperties(info);\r
+\r
+ try {\r
+ if (Monitor.createPersistentService(Property.DATABASE_MODULE, dbname, info) == null) \r
+ {\r
+ // service already exists, create a warning\r
+ addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, dbname));\r
+ }\r
+ } catch (StandardException mse) {\r
+ throw Util.seeNextException(SQLState.CREATE_DATABASE_FAILED,\r
+ new Object[] { dbname },\r
+ handleException(mse));\r
+ }\r
+\r
+ // clear these values as some modules hang onto\r
+ // the properties set corresponding to service.properties\r
+ // and they shouldn't be interested in these JDBC attributes.\r
+ info.clear();\r
+\r
+ return (Database) Monitor.findService(Property.DATABASE_MODULE, dbname);\r
+ }\r
+\r
+\r
+ /**\r
+ * Boot database.\r
+ *\r
+ * @param info boot properties\r
+ *\r
+ * @param softAuthenticationBoot If true, don't fail soft upgrade due\r
+ * to missing features (phase one of two phased hard upgrade boot).\r
+ *\r
+ * @return false iff the monitor cannot handle a service\r
+ * of the type indicated by the protocol within the name.\r
+ * If that's the case then we are the wrong driver.\r
+ *\r
+ * @throws Throwable if anything else is wrong.\r
+ */\r
+\r
+ private boolean bootDatabase(Properties info,\r
+ boolean softAuthenticationBoot\r
+ ) throws Throwable\r
+ {\r
+ String dbname = tr.getDBName();\r
+\r
+ // boot database now\r
+ try {\r
+\r
+ info = filterProperties(info);\r
+\r
+ if (softAuthenticationBoot) {\r
+ info.setProperty(Attribute.SOFT_UPGRADE_NO_FEATURE_CHECK,\r
+ "true");\r
+ } else {\r
+ info.remove(Attribute.SOFT_UPGRADE_NO_FEATURE_CHECK);\r
+ }\r
+ \r
+ // try to start the service if it doesn't already exist\r
+ if (!Monitor.startPersistentService(dbname, info)) {\r
+ // a false indicates the monitor cannot handle a service\r
+ // of the type indicated by the protocol within the name.\r
+ // If that's the case then we are the wrong driver\r
+ // so just return null.\r
+ return false;\r
+ }\r
+\r
+ // clear these values as some modules hang onto\r
+ // the properties set corresponding to service.properties\r
+ // and they shouldn't be interested in these JDBC attributes.\r
+ info.clear();\r
+\r
+ Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, dbname);\r
+ tr.setDatabase(database);\r
+\r
+ } catch (StandardException mse) {\r
+\r
+ Throwable ne = mse.getCause();\r
+ SQLException nse;\r
+\r
+ /*\r
+ If there is a next exception, assume\r
+ that the first one is just a redundant "see the\r
+ next exception" message.\r
+ if it is a BEI, treat it as a database exception.\r
+ If there isn't a BEI, treat it as a java exception.\r
+\r
+ In general we probably want to walk the chain\r
+ and return all of them, but empirically, this\r
+ is all we need to do for now.\r
+ */\r
+ if (ne instanceof StandardException)\r
+ nse = Util.generateCsSQLException((StandardException)ne);\r
+ else if (ne != null)\r
+ nse = Util.javaException(ne);\r
+ else\r
+ nse = Util.generateCsSQLException(mse);\r
+\r
+ throw Util.seeNextException(SQLState.BOOT_DATABASE_FAILED,\r
+ new Object[] { dbname }, nse);\r
+ }\r
+\r
+ // If database exists, getDatabase() will return the database object.\r
+ // If any error occured while booting an existing database, an\r
+ // exception would have been thrown already.\r
+ return true;\r
+\r
+ }\r
+\r
+ /*\r
+ * Class interface methods used by database metadata to ensure\r
+ * good relations with autocommit.\r
+ */\r
+\r
+ PreparedStatement prepareMetaDataStatement(String sql)\r
+ throws SQLException {\r
+ synchronized (getConnectionSynchronization()) {\r
+ setupContextStack();\r
+ PreparedStatement s = null;\r
+ try {\r
+ s = factory.newEmbedPreparedStatement(this, sql, true,\r
+ JDBC20Translation.TYPE_FORWARD_ONLY,\r
+ JDBC20Translation.CONCUR_READ_ONLY,\r
+ connectionHoldAbility,\r
+ JDBC30Translation.NO_GENERATED_KEYS,\r
+ null,\r
+ null);\r
+ } finally {\r
+ restoreContextStack();\r
+ }\r
+ return s;\r
+ }\r
+ }\r
+\r
+ public final InternalDriver getLocalDriver()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ return getTR().getDriver();\r
+ }\r
+\r
+ /**\r
+ Return the context manager for this connection.\r
+ */\r
+ public final ContextManager getContextManager() {\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ return getTR().getContextManager();\r
+ }\r
+\r
+ /**\r
+ * Filter out properties from the passed in set of JDBC attributes\r
+ * to remove any derby.* properties. This is to ensure that setting\r
+ * derby.* properties does not work this way, it's not a defined way\r
+ * to set such properties and could be a secuirty hole in allowing\r
+ * remote connections to override system, application or database settings.\r
+ * \r
+ * @return a new Properties set copied from the parameter but with no\r
+ * derby.* properties.\r
+ */\r
+ private Properties filterProperties(Properties inputSet) {\r
+ Properties limited = new Properties();\r
+\r
+ // filter out any derby.* properties, only\r
+ // JDBC attributes can be set this way\r
+ for (java.util.Enumeration e = inputSet.propertyNames(); e.hasMoreElements(); ) {\r
+\r
+ String key = (String) e.nextElement();\r
+\r
+ // we don't allow properties to be set this way\r
+ if (key.startsWith("derby."))\r
+ continue;\r
+ limited.put(key, inputSet.getProperty(key));\r
+ }\r
+ return limited;\r
+ }\r
+\r
+ /*\r
+ ** methods to be overridden by subimplementations wishing to insert\r
+ ** their classes into the mix.\r
+ */\r
+\r
+ protected Database getDatabase() \r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(!isClosed(), "connection is closed");\r
+\r
+ return getTR().getDatabase();\r
+ }\r
+\r
+ final protected TransactionResourceImpl getTR()\r
+ {\r
+ return rootConnection.tr;\r
+ }\r
+\r
+ private EmbedConnectionContext pushConnectionContext(ContextManager cm) {\r
+ return new EmbedConnectionContext(cm, this);\r
+ }\r
+\r
+ public final void setApplicationConnection(java.sql.Connection applicationConnection) {\r
+ this.applicationConnection = applicationConnection;\r
+ }\r
+\r
+ public final java.sql.Connection getApplicationConnection() {\r
+ return applicationConnection;\r
+ }\r
+\r
+ public void setDrdaID(String drdaID) {\r
+ getLanguageConnection().setDrdaID(drdaID);\r
+ }\r
+\r
+ /**\r
+ Reset the connection before it is returned from a PooledConnection\r
+ to a new application request (wrapped by a BrokeredConnection).\r
+ Examples of reset covered here is dropping session temporary tables\r
+ and reseting IDENTITY_VAL_LOCAL.\r
+ Most JDBC level reset is handled by calling standard java.sql.Connection\r
+ methods from EmbedPooledConnection.\r
+ */\r
+ public void resetFromPool() throws SQLException {\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try {\r
+ getLanguageConnection().resetFromPool();\r
+ } catch (StandardException t) {\r
+ throw handleException(t);\r
+ }\r
+ finally\r
+ {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** methods to be overridden by subimplementations wishing to insert\r
+ ** their classes into the mix.\r
+ ** The reason we need to override them is because we want to create a\r
+ ** Local20/LocalStatment object (etc) rather than a Local/LocalStatment\r
+ ** object (etc).\r
+ */\r
+\r
+\r
+ /*\r
+ ** XA support\r
+ */\r
+\r
+ /**\r
+ * Do not use this method directly use XATransactionState.xa_prepare\r
+ * instead because it also maintains/cancels the timout task which is\r
+ * scheduled to cancel/rollback the global transaction.\r
+ */\r
+ public final int xa_prepare() throws SQLException {\r
+\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try\r
+ {\r
+ XATransactionController tc = \r
+ (XATransactionController) getLanguageConnection().getTransactionExecute();\r
+\r
+ int ret = tc.xa_prepare();\r
+\r
+ if (ret == XATransactionController.XA_RDONLY)\r
+ {\r
+ // On a prepare call, xa allows an optimization that if the\r
+ // transaction is read only, the RM can just go ahead and\r
+ // commit it. So if store returns this read only status -\r
+ // meaning store has taken the liberty to commit already - we\r
+ // needs to turn around and call internalCommit (without\r
+ // committing the store again) to make sure the state is\r
+ // consistent. Since the transaction is read only, there is\r
+ // probably not much that needs to be done.\r
+\r
+ getLanguageConnection().internalCommit(false /* don't commitStore again */);\r
+ }\r
+ return ret;\r
+ } catch (StandardException t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ finally\r
+ {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Do not use this method directly use XATransactionState.xa_commit\r
+ * instead because it also maintains/cancels the timout task which is\r
+ * scheduled to cancel/rollback the global transaction.\r
+ */\r
+ public final void xa_commit(boolean onePhase) throws SQLException {\r
+\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try\r
+ {\r
+ getLanguageConnection().xaCommit(onePhase);\r
+ } catch (StandardException t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ finally \r
+ {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Do not use this method directly use XATransactionState.xa_rollback\r
+ * instead because it also maintains/cancels the timout task which is\r
+ * scheduled to cancel/rollback the global transaction.\r
+ */\r
+ public final void xa_rollback() throws SQLException {\r
+ synchronized (getConnectionSynchronization())\r
+ {\r
+ setupContextStack();\r
+ try\r
+ {\r
+ getLanguageConnection().xaRollback();\r
+ } catch (StandardException t)\r
+ {\r
+ throw handleException(t);\r
+ }\r
+ finally \r
+ {\r
+ restoreContextStack();\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * returns false if there is an underlying transaction and that transaction\r
+ * has done work. True if there is no underlying transaction or that\r
+ * underlying transaction is idle\r
+ */\r
+ public final boolean transactionIsIdle()\r
+ {\r
+ return getTR().isIdle();\r
+ }\r
+ private int setResultSetType(int resultSetType) {\r
+\r
+ /* Add warning if scroll sensitive cursor\r
+ * and downgrade to scroll insensitive cursor.\r
+ */\r
+ if (resultSetType == JDBC20Translation.TYPE_SCROLL_SENSITIVE)\r
+ {\r
+ addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.NO_SCROLL_SENSITIVE_CURSORS));\r
+ resultSetType = JDBC20Translation.TYPE_SCROLL_INSENSITIVE;\r
+ }\r
+ return resultSetType;\r
+ }\r
+ \r
+\r
+ /** \r
+ * Set the transaction isolation level that will be used for the \r
+ * next prepare. Used by network server to implement DB2 style \r
+ * isolation levels.\r
+ * @param level Isolation level to change to. level is the DB2 level\r
+ * specified in the package names which happen to correspond\r
+ * to our internal levels. If \r
+ * level == ExecutionContext.UNSPECIFIED_ISOLATION,\r
+ * the statement won't be prepared with an isolation level.\r
+ * \r
+ * \r
+ */\r
+ public void setPrepareIsolation(int level) throws SQLException\r
+ {\r
+ if (level == getPrepareIsolation())\r
+ return;\r
+\r
+ switch (level)\r
+ {\r
+ case ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL:\r
+ case ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL:\r
+ case ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL:\r
+ case ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL:\r
+ case ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL:\r
+ break;\r
+ default:\r
+ throw Util.generateCsSQLException(\r
+ SQLState.UNIMPLEMENTED_ISOLATION_LEVEL, new Integer(level));\r
+ }\r
+ \r
+ synchronized(getConnectionSynchronization())\r
+ {\r
+ getLanguageConnection().setPrepareIsolationLevel(level);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Return prepare isolation \r
+ */\r
+ public int getPrepareIsolation()\r
+ {\r
+ return getLanguageConnection().getPrepareIsolationLevel();\r
+ }\r
+\r
+ /**\r
+ Return a unique order number for a result set.\r
+ A unique value is only needed if the result set is\r
+ being created within procedure and thus must be using\r
+ a nested connection.\r
+ */\r
+ final int getResultSetOrderId() {\r
+\r
+ if (this == rootConnection) {\r
+ return 0;\r
+ } else {\r
+ return rootConnection.resultSetId++;\r
+ }\r
+ }\r
+\r
+ protected SQLException newSQLException(String messageId) {\r
+ return Util.generateCsSQLException(messageId);\r
+ }\r
+ protected SQLException newSQLException(String messageId, Object arg1) {\r
+ return Util.generateCsSQLException(messageId, arg1);\r
+ }\r
+ protected SQLException newSQLException(String messageId, Object arg1, Object arg2) {\r
+ return Util.generateCsSQLException(messageId, arg1, arg2);\r
+ }\r
+\r
+ /////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // OBJECT OVERLOADS\r
+ //\r
+ /////////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Get a String representation that uniquely identifies\r
+ * this connection. Include the same information that is\r
+ * printed in the log for various trace and error messages.\r
+ *\r
+ * In Derby the "physical" connection is a LanguageConnectionContext, \r
+ * or LCC.\r
+ * The JDBC Connection is an JDBC-specific layer on top of this. Rather\r
+ * than create a new id here, we simply use the id of the underlying LCC.\r
+ * Note that this is a big aid in debugging, because much of the\r
+ * engine trace and log code prints the LCC id. \r
+ *\r
+ * @return a string representation for this connection\r
+ */\r
+ public String toString()\r
+ {\r
+ if ( connString == null )\r
+ {\r
+ \r
+ LanguageConnectionContext lcc = getLanguageConnection();\r
+\r
+ connString = \r
+ this.getClass().getName() + "@" + this.hashCode() + " " +\r
+ lcc.xidStr + \r
+ lcc.getTransactionExecute().getTransactionIdString() + \r
+ "), " +\r
+ lcc.lccStr + \r
+ Integer.toString(lcc.getInstanceNumber()) + "), " +\r
+ lcc.dbnameStr + lcc.getDbname() + "), " +\r
+ lcc.drdaStr + lcc.getDrdaID() + ") ";\r
+ } \r
+ \r
+ return connString;\r
+ }\r
+\r
+\r
+ /**\r
+ *\r
+ * Constructs an object that implements the <code>Clob</code> interface. The object\r
+ * returned initially contains no data. The <code>setAsciiStream</code>,\r
+ * <code>setCharacterStream</code> and <code>setString</code> methods of\r
+ * the <code>Clob</code> interface may be used to add data to the <code>Clob</code>.\r
+ *\r
+ * @return An object that implements the <code>Clob</code> interface\r
+ * @throws SQLException if an object that implements the\r
+ * <code>Clob</code> interface can not be constructed, this method is\r
+ * called on a closed connection or a database access error occurs.\r
+ *\r
+ */\r
+ public Clob createClob() throws SQLException {\r
+ checkIfClosed();\r
+ return new EmbedClob(this);\r
+ }\r
+\r
+ /**\r
+ *\r
+ * Constructs an object that implements the <code>Blob</code> interface. The object\r
+ * returned initially contains no data. The <code>setBinaryStream</code> and\r
+ * <code>setBytes</code> methods of the <code>Blob</code> interface may be used to add data to\r
+ * the <code>Blob</code>.\r
+ *\r
+ * @return An object that implements the <code>Blob</code> interface\r
+ * @throws SQLException if an object that implements the\r
+ * <code>Blob</code> interface can not be constructed, this method is\r
+ * called on a closed connection or a database access error occurs.\r
+ *\r
+ */\r
+ public Blob createBlob() throws SQLException {\r
+ checkIfClosed();\r
+ return new EmbedBlob(new byte[0], this);\r
+ }\r
+\r
+ /**\r
+ * Add the locator and the corresponding LOB object into the\r
+ * HashMap\r
+ *\r
+ * @param LOBReference The object which contains the LOB object that\r
+ * that is added to the HashMap.\r
+ * @return an integer that represents the locator that has been\r
+ * allocated to this LOB.\r
+ */\r
+ public int addLOBMapping(Object LOBReference) {\r
+ int loc = getIncLOBKey();\r
+ getlobHMObj().put(new Integer(loc), LOBReference);\r
+ return loc;\r
+ }\r
+\r
+ /**\r
+ * Remove the key(LOCATOR) from the hash table.\r
+ * @param key an integer that represents the locator that needs to be\r
+ * removed from the table.\r
+ */\r
+ public void removeLOBMapping(int key) {\r
+ getlobHMObj().remove(new Integer(key));\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) {\r
+ return getlobHMObj().get(new Integer(key));\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
+\r
+ //free all the lob resources in the HashMap\r
+ //initialize the locator value to 0 and\r
+ //the hash table object to null.\r
+ Map map = rootConnection.lobReferences;\r
+ if (map != null) {\r
+ Iterator it = map.keySet ().iterator ();\r
+ while (it.hasNext()) {\r
+ ((EngineLOB)it.next()).free();\r
+ }\r
+ map.clear();\r
+ }\r
+ if (rootConnection.lobHashMap != null) {\r
+ rootConnection.lobHashMap.clear ();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Return the current locator value/\r
+ * 0x800x values are not valid values as they are used to indicate the BLOB \r
+ * is being sent by value, so we skip those values (DERBY-3243)\r
+ * \r
+ * @return an integer that represents the most recent locator value.\r
+ */\r
+ private int getIncLOBKey() {\r
+ int newKey = ++rootConnection.lobHMKey;\r
+ // Skip 0x8000, 0x8002, 0x8004, 0x8006, for DERBY-3243\r
+ // Earlier versions of the Derby Network Server (<10.3) didn't\r
+ // support locators and would send an extended length field\r
+ // with one of the above mentioned values instead of a\r
+ // locator, even when locators were requested. To enable the\r
+ // client driver to detect that locators aren't supported,\r
+ // we don't use any of them as locator values.\r
+ if (newKey == 0x8000 || newKey == 0x8002 || newKey == 0x8004 ||\r
+ newKey == 0x8006 || newKey == 0x8008)\r
+ newKey = ++rootConnection.lobHMKey;\r
+ // Also roll over when the high bit of four byte locator is set.\r
+ // This will prevent us from sending a negative locator to the\r
+ // client. Don't allow zero since it is not a valid locator for the \r
+ // client.\r
+ if (newKey == 0x80000000 || newKey == 0)\r
+ newKey = rootConnection.lobHMKey = 1;\r
+ return newKey;\r
+ }\r
+\r
+ /**\r
+ * Adds an entry of the lob in WeakHashMap. These entries are used\r
+ * for cleanup during commit/rollback or close.\r
+ * @param lobReference LOB Object\r
+ */\r
+ void addLOBReference (Object lobReference) {\r
+ if (rootConnection.lobReferences == null) {\r
+ rootConnection.lobReferences = new WeakHashMap ();\r
+ }\r
+ rootConnection.lobReferences.put (lobReference, null);\r
+ }\r
+\r
+ /**\r
+ * Return the Hash Map in the root connection\r
+ * @return the HashMap that contains the locator to LOB object mapping\r
+ */\r
+ public HashMap getlobHMObj() {\r
+ if (rootConnection.lobHashMap == null) {\r
+ rootConnection.lobHashMap = new HashMap();\r
+ }\r
+ return rootConnection.lobHashMap;\r
+ }\r
+\r
+ /** Cancels the current running statement. */\r
+ public void cancelRunningStatement() {\r
+ getLanguageConnection().getStatementContext().cancel();\r
+ }\r
+}\r