📄 embedconnection.java
字号:
/* Derby - Class org.apache.derby.impl.jdbc.EmbedConnection Copyright 1997, 2005 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.jdbc;import org.apache.derby.jdbc.InternalDriver;import org.apache.derby.iapi.reference.Attribute;import org.apache.derby.iapi.reference.JDBC20Translation;import org.apache.derby.iapi.reference.JDBC30Translation;import org.apache.derby.iapi.reference.MessageId;import org.apache.derby.iapi.reference.Property;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.services.context.ContextManager;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.jdbc.AuthenticationService;import org.apache.derby.iapi.jdbc.EngineConnection;import org.apache.derby.iapi.db.Database;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.services.i18n.MessageService;import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;import org.apache.derby.iapi.sql.execute.ExecutionContext;import org.apache.derby.iapi.sql.dictionary.DataDictionary;import org.apache.derby.iapi.store.access.XATransactionController;/* can't import due to name overlap:import java.sql.Connection;import java.sql.ResultSet;*/import java.sql.PreparedStatement;import java.sql.CallableStatement;import java.sql.DatabaseMetaData;import java.sql.SQLException;import java.sql.SQLWarning;import java.sql.Statement;import java.util.Properties;/** * Local implementation of Connection for a JDBC driver in * the same process as the database. * <p> * There is always a single root (parent) connection. The * initial JDBC connection is the root connection. A * call to <I>getCurrentConnection()</I> or with the URL * <I>jdbc:default:connection</I> yields a nested connection that shares * the same root connection as the parent. A nested connection * is implemented using this class. The nested connection copies the * state of the parent connection and shares some of the same * objects (e.g. ContextManager) that are shared across all * nesting levels. The proxy also maintains its own * state that is distinct from its parent connection (e.g. * autocommit or warnings). * <p> * <B>SYNCHRONIZATION</B>: Just about all JDBC actions are * synchronized across all connections stemming from the * same root connection. The synchronization is upon * the a synchronized object return by the rootConnection. <P><B>Supports</B> <UL> <LI> JDBC 2.0 </UL> * * @author djd * * @see TransactionResourceImpl * */public class EmbedConnection implements EngineConnection{ private static final StandardException exceptionClose = StandardException.closeException(); ////////////////////////////////////////////////////////// // OBJECTS SHARED ACROSS CONNECTION NESTING ////////////////////////////////////////////////////////// protected DatabaseMetaData dbMetadata; protected final TransactionResourceImpl tr; // always access tr thru getTR() ////////////////////////////////////////////////////////// // STATE (copied to new nested connections, but nesting // specific) ////////////////////////////////////////////////////////// private boolean active; protected boolean autoCommit = true; boolean needCommit; /* following is a new feature in JDBC3.0 where you can specify the holdability of a resultset at the end of the transaction. This gets set by the new method setHoldability(int) in JDBC3.0 * */ private int connectionHoldAbility = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT; ////////////////////////////////////////////////////////// // NESTING SPECIFIC OBJECTS ////////////////////////////////////////////////////////// /* ** The root connection is the base connection upon ** which all actions are synchronized. By default, ** we are the root connection unless we are created ** by copying the state from another connection. */ protected final EmbedConnection rootConnection; private SQLWarning topWarning; /** Factory for JDBC objects to be created. */ public InternalDriver factory; /** The Connection object the application is using when accessing the database through this connection. In most cases this will be equal to this. When Connection pooling is being used, then it will be set to the Connection object handed to the application. It is used for the getConnection() methods of various JDBC objects. */ private java.sql.Connection applicationConnection; /** An increasing counter to assign to a ResultSet on its creation. Used for ordering ResultSets returned from a procedure, always returned in order of their creation. Is maintained at the root connection. */ private int resultSetId; /** Cached string representation of the connection id */ private String idString; ////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////// // create a new Local Connection, using a new context manager // public EmbedConnection(InternalDriver driver, String url, Properties info) throws SQLException { // Create a root connection. applicationConnection = rootConnection = this; factory = driver; tr = new TransactionResourceImpl(driver, url, info); active = true; // register this thread and its context manager with // the global context service setupContextStack(); try { // stick my context into the context manager EmbedConnectionContext context = pushConnectionContext(tr.getContextManager()); // if we are shutting down don't attempt to boot or create the database boolean shutdown = Boolean.valueOf(info.getProperty(Attribute.SHUTDOWN_ATTR)).booleanValue(); // see if database is already booted Database database = (Database) Monitor.findService(Property.DATABASE_MODULE, tr.getDBName()); // See if user wants to create a new database. boolean createBoot = createBoot(info); if (database != null) { // database already booted by someone else tr.setDatabase(database); } else if (!shutdown) { // Return false iff the monitor cannot handle a service of the type // indicated by the proptocol within the name. If that's the case // then we are the wrong driver. if (!bootDatabase(info)) { tr.clearContextInError(); setInactive(); return; } } if (createBoot && !shutdown) { // if we are shutting down don't attempt to boot or create the database if (tr.getDatabase() != null) { addWarning(EmbedSQLWarning.newEmbedSQLWarning(SQLState.DATABASE_EXISTS, getDBName())); } else { // check for user's credential and authenticate the user // with system level authentication service. // FIXME: We should also check for CREATE DATABASE operation // authorization for the user if authorization was // set at the system level. // Right now, the authorization service does not // restrict/account for Create database op. checkUserCredentials(null, info); // Process with database creation database = createDatabase(tr.getDBName(), info); tr.setDatabase(database); } } if (tr.getDatabase() == null) { String dbname = tr.getDBName(); // do not clear the TransactionResource context. It will be restored // as part of the finally clause below. this.setInactive(); throw newSQLException(SQLState.DATABASE_NOT_FOUND, dbname); } // Check User's credentials and if it is a valid user of // the database // checkUserCredentials(tr.getDBName(), info); // Make a real connection into the database, setup lcc, tc and all // the rest. tr.startTransaction(); // now we have the database connection, we can shut down if (shutdown) { throw tr.shutdownDatabaseException(); } } catch (Throwable t) { throw handleException(t); } finally { restoreContextStack(); info = null; } } /** Examine the attributes set provided and determine if this is a create boot. A boot is a create boot iff. <OL> <LI>create=true - This means create a standard database. <LI> createFrom = Path - creates database from backup if it does not exist. <LI> restoreFrom = Path - database is restored completley from backup. if a database exists in the same place it is replaced by the version in the backup otherwise a new one is created using the backup copy. <LI> rollForwardRecoveryFrom = Path - rollforward is performed using the version backup and any active and archived log files. </OL> @param a the attribute set. @exception SQLException Ooops. */ private boolean createBoot(Properties p) throws SQLException { int createCount = 0; if (Boolean.valueOf(p.getProperty(Attribute.CREATE_ATTR)).booleanValue()) createCount++; int restoreCount=0; //check if the user has specified any /create/restore/recover from backup attributes. if (p.getProperty(Attribute.CREATE_FROM) != null) restoreCount++; if (p.getProperty(Attribute.RESTORE_FROM) != null) restoreCount++; if (p.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM)!=null) restoreCount++; if(restoreCount > 1) throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES); //add the restore count to create count to make sure //user has not specified and restore together by mistake. createCount = createCount + restoreCount ; // if (createCount > 1) throw newSQLException(SQLState.CONFLICTING_CREATE_ATTRIBUTES); //retuns true only for the create flag not for restore flags return (createCount - restoreCount) == 1; } /** * Create a new connection based off of the * connection passed in. Initializes state * based on input connection, and copies * appropriate object pointers. This is only used for nested connections. * * @param inputConnection the input connection */ public EmbedConnection(EmbedConnection inputConnection) { if (SanityManager.DEBUG) { SanityManager.ASSERT(inputConnection.active, "trying to create a proxy for an inactive conneciton"); } // Proxy connections are always autocommit false // thus needCommit is irrelavent. autoCommit = false; /* ** Nesting specific state we are copying from ** the inputConnection */ /* ** Objects we are sharing across nestings */ // set it to null to allow it to be final. tr = null; // a proxy connection has no direct // pointer to the tr. Every call has to go // thru the rootConnection's tr. active = true; this.rootConnection = inputConnection.rootConnection; this.applicationConnection = this; this.factory = inputConnection.factory; //if no holdability specified for the resultset, use the holability //defined for the connection this.connectionHoldAbility = inputConnection.connectionHoldAbility; //RESOLVE: although it looks like the right // thing to share the metadata object, if // we do we'll get the wrong behavior on // getCurrentConnection().getMetaData().isReadOnly() // so don't try to be smart and uncomment the // following. Ultimately, the metadata should // be shared by all connections anyway. //dbMetadata = inputConnection.dbMetadata; } // // Check passed-in user's credentials. // private void checkUserCredentials(String dbname, Properties userInfo) throws SQLException { if (SanityManager.DEBUG) SanityManager.ASSERT(!isClosed(), "connection is closed"); // If a database name was passed-in then check user's credential // in that database using the database's authentication service, // otherwise check if it is a valid user in the JBMS system. // // NOTE: We always expect an authentication service per database // and one at the system level. // AuthenticationService authenticationService = null; // Retrieve appropriate authentication service handle if (dbname == null) authenticationService = getLocalDriver().getAuthenticationService(); else authenticationService = getTR().getDatabase().getAuthenticationService(); // check that we do have a authentication service // it is _always_ expected. if (authenticationService == null) { String failedString = MessageService.getTextMessage( (dbname == null) ? MessageId.AUTH_NO_SERVICE_FOR_SYSTEM : MessageId.AUTH_NO_SERVICE_FOR_DB); throw newSQLException(SQLState.LOGIN_FAILED, failedString); } // Let's authenticate now if (!authenticationService.authenticate( dbname, userInfo )) { throw newSQLException(SQLState.LOGIN_FAILED, MessageService.getTextMessage(MessageId.AUTH_INVALID)); } } /** * Gets the EngineType of the connected database. * * @return 0 if there is no database, the engine type otherwise. @see org.apache.derby.iapi.reference.EngineType */ public int getEngineType() { Database db = getDatabase(); if( null == db) return 0; return db.getEngineType(); } /* ** Methods from java.sql.Connection */ /** * SQL statements without parameters are normally * executed using Statement objects. If the same SQL statement * is executed many times, it is more efficient to use a * PreparedStatement * * JDBC 2.0 * * Result sets created using the returned Statement will have * forward-only type, and read-only concurrency, by default. * * @return a new Statement object * @exception SQLException if a database-access error occurs. */ public final Statement createStatement() throws SQLException { return createStatement(JDBC20Translation.TYPE_FORWARD_ONLY, JDBC20Translation.CONCUR_READ_ONLY, connectionHoldAbility); } /** * JDBC 2.0 * * Same as createStatement() above, but allows the default result set * type and result set concurrency type to be overridden. * * @param resultSetType a result set type, see ResultSet.TYPE_XXX * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX * @return a new Statement object * @exception SQLException if a database-access error occurs. */ public final Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { return createStatement(resultSetType, resultSetConcurrency, connectionHoldAbility); } /** * JDBC 3.0 * * Same as createStatement() above, but allows the default result set * type, result set concurrency type and result set holdability type to * be overridden. * * @param resultSetType a result set type, see ResultSet.TYPE_XXX * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX * @param resultSetHoldability a holdability type, * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT * @return a new Statement object * @exception SQLException if a database-access error occurs. */ public final Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -