0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.jdbc.EmbedConnection
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.jdbc;
0023:
0024: import org.apache.derby.jdbc.InternalDriver;
0025:
0026: import org.apache.derby.iapi.reference.Attribute;
0027: import org.apache.derby.iapi.reference.JDBC20Translation;
0028: import org.apache.derby.iapi.reference.JDBC30Translation;
0029: import org.apache.derby.iapi.reference.MessageId;
0030: import org.apache.derby.iapi.reference.Property;
0031: import org.apache.derby.iapi.reference.SQLState;
0032:
0033: import org.apache.derby.iapi.services.context.ContextManager;
0034: import org.apache.derby.iapi.services.memory.LowMemory;
0035: import org.apache.derby.iapi.services.monitor.Monitor;
0036: import org.apache.derby.iapi.services.sanity.SanityManager;
0037:
0038: import org.apache.derby.iapi.jdbc.AuthenticationService;
0039: import org.apache.derby.iapi.jdbc.EngineConnection;
0040:
0041: import org.apache.derby.iapi.db.Database;
0042: import org.apache.derby.iapi.error.StandardException;
0043: import org.apache.derby.iapi.services.i18n.MessageService;
0044: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0045: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0046: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0047: import org.apache.derby.iapi.store.access.XATransactionController;
0048:
0049: /* can't import due to name overlap:
0050: import java.sql.Connection;
0051: import java.sql.ResultSet;
0052: */
0053: import java.sql.PreparedStatement;
0054: import java.sql.CallableStatement;
0055: import java.sql.DatabaseMetaData;
0056: import java.sql.SQLException;
0057: import java.sql.SQLWarning;
0058: import java.sql.Statement;
0059:
0060: import java.util.Properties;
0061:
0062: import org.apache.derby.impl.jdbc.authentication.NoneAuthenticationServiceImpl;
0063:
0064: /**
0065: * Local implementation of Connection for a JDBC driver in
0066: * the same process as the database.
0067: * <p>
0068: * There is always a single root (parent) connection. The
0069: * initial JDBC connection is the root connection. A
0070: * call to <I>getCurrentConnection()</I> or with the URL
0071: * <I>jdbc:default:connection</I> yields a nested connection that shares
0072: * the same root connection as the parent. A nested connection
0073: * is implemented using this class. The nested connection copies the
0074: * state of the parent connection and shares some of the same
0075: * objects (e.g. ContextManager) that are shared across all
0076: * nesting levels. The proxy also maintains its own
0077: * state that is distinct from its parent connection (e.g.
0078: * autocommit or warnings).
0079: * <p>
0080: * <B>SYNCHRONIZATION</B>: Just about all JDBC actions are
0081: * synchronized across all connections stemming from the
0082: * same root connection. The synchronization is upon
0083: * the a synchronized object return by the rootConnection.
0084: <P><B>Supports</B>
0085: <UL>
0086: <LI> JDBC 2.0
0087: </UL>
0088: *
0089: * @author djd
0090: *
0091: * @see TransactionResourceImpl
0092: *
0093: */
0094: public class EmbedConnection implements EngineConnection {
0095:
0096: private static final StandardException exceptionClose = StandardException
0097: .closeException();
0098:
0099: /**
0100: * Static exception to be thrown when a Connection request can not
0101: * be fulfilled due to lack of memory. A static exception as the lack
0102: * of memory would most likely cause another OutOfMemoryException and
0103: * if there is not enough memory to create the OOME exception then something
0104: * like the VM dying could occur. Simpler just to throw a static.
0105: */
0106: public static final SQLException NO_MEM = Util
0107: .generateCsSQLException(SQLState.LOGIN_FAILED,
0108: "java.lang.OutOfMemoryError");
0109:
0110: /**
0111: * Low memory state object for connection requests.
0112: */
0113: public static final LowMemory memoryState = new LowMemory();
0114:
0115: //////////////////////////////////////////////////////////
0116: // OBJECTS SHARED ACROSS CONNECTION NESTING
0117: //////////////////////////////////////////////////////////
0118: DatabaseMetaData dbMetadata;
0119:
0120: final TransactionResourceImpl tr; // always access tr thru getTR()
0121:
0122: //////////////////////////////////////////////////////////
0123: // STATE (copied to new nested connections, but nesting
0124: // specific)
0125: //////////////////////////////////////////////////////////
0126: private boolean active;
0127: boolean autoCommit = true;
0128: boolean needCommit;
0129:
0130: // Set to true if NONE authentication is being used
0131: private boolean usingNoneAuth;
0132:
0133: /*
0134: following is a new feature in JDBC3.0 where you can specify the holdability
0135: of a resultset at the end of the transaction. This gets set by the
0136: new method setHoldability(int) in JDBC3.0
0137: *
0138: */
0139: private int connectionHoldAbility = JDBC30Translation.HOLD_CURSORS_OVER_COMMIT;
0140:
0141: //////////////////////////////////////////////////////////
0142: // NESTING SPECIFIC OBJECTS
0143: //////////////////////////////////////////////////////////
0144: /*
0145: ** The root connection is the base connection upon
0146: ** which all actions are synchronized. By default,
0147: ** we are the root connection unless we are created
0148: ** by copying the state from another connection.
0149: */
0150: final EmbedConnection rootConnection;
0151: private SQLWarning topWarning;
0152: /**
0153: Factory for JDBC objects to be created.
0154: */
0155: private InternalDriver factory;
0156:
0157: /**
0158: The Connection object the application is using when accessing the
0159: database through this connection. In most cases this will be equal
0160: to this. When Connection pooling is being used, then it will
0161: be set to the Connection object handed to the application.
0162: It is used for the getConnection() methods of various JDBC objects.
0163: */
0164: private java.sql.Connection applicationConnection;
0165:
0166: /**
0167: An increasing counter to assign to a ResultSet on its creation.
0168: Used for ordering ResultSets returned from a procedure, always
0169: returned in order of their creation. Is maintained at the root connection.
0170: */
0171: private int resultSetId;
0172:
0173: /** Cached string representation of the connection id */
0174: private String connString;
0175:
0176: //////////////////////////////////////////////////////////
0177: // CONSTRUCTORS
0178: //////////////////////////////////////////////////////////
0179:
0180: // create a new Local Connection, using a new context manager
0181: //
0182: public EmbedConnection(InternalDriver driver, String url,
0183: Properties info) throws SQLException {
0184: // Create a root connection.
0185: applicationConnection = rootConnection = this ;
0186: factory = driver;
0187:
0188: tr = new TransactionResourceImpl(driver, url, info);
0189:
0190: active = true;
0191:
0192: // register this thread and its context manager with
0193: // the global context service
0194: setupContextStack();
0195:
0196: try {
0197:
0198: // stick my context into the context manager
0199: EmbedConnectionContext context = pushConnectionContext(tr
0200: .getContextManager());
0201:
0202: // if we are shutting down don't attempt to boot or create the database
0203: boolean shutdown = Boolean.valueOf(
0204: info.getProperty(Attribute.SHUTDOWN_ATTR))
0205: .booleanValue();
0206:
0207: // see if database is already booted
0208: Database database = (Database) Monitor.findService(
0209: Property.DATABASE_MODULE, tr.getDBName());
0210:
0211: // See if user wants to create a new database.
0212: boolean createBoot = createBoot(info);
0213: if (database != null) {
0214: // database already booted by someone else
0215: tr.setDatabase(database);
0216: } else if (!shutdown) {
0217: // Return false iff the monitor cannot handle a service of the type
0218: // indicated by the proptocol within the name. If that's the case
0219: // then we are the wrong driver.
0220: if (!bootDatabase(info)) {
0221: tr.clearContextInError();
0222: setInactive();
0223: return;
0224: }
0225: }
0226:
0227: if (createBoot && !shutdown) {
0228: // if we are shutting down don't attempt to boot or create the database
0229:
0230: if (tr.getDatabase() != null) {
0231: addWarning(EmbedSQLWarning.newEmbedSQLWarning(
0232: SQLState.DATABASE_EXISTS, getDBName()));
0233: } else {
0234:
0235: // check for user's credential and authenticate the user
0236: // with system level authentication service.
0237: // FIXME: We should also check for CREATE DATABASE operation
0238: // authorization for the user if authorization was
0239: // set at the system level.
0240: // Right now, the authorization service does not
0241: // restrict/account for Create database op.
0242: checkUserCredentials(null, info);
0243:
0244: // Process with database creation
0245: database = createDatabase(tr.getDBName(), info);
0246: tr.setDatabase(database);
0247: }
0248: }
0249:
0250: if (tr.getDatabase() == null) {
0251: String dbname = tr.getDBName();
0252: // do not clear the TransactionResource context. It will be restored
0253: // as part of the finally clause below.
0254: this .setInactive();
0255: throw newSQLException(SQLState.DATABASE_NOT_FOUND,
0256: dbname);
0257: }
0258:
0259: // Check User's credentials and if it is a valid user of
0260: // the database
0261: //
0262: checkUserCredentials(tr.getDBName(), info);
0263:
0264: // Make a real connection into the database, setup lcc, tc and all
0265: // the rest.
0266: tr.startTransaction();
0267:
0268: // now we have the database connection, we can shut down
0269: if (shutdown) {
0270: throw tr.shutdownDatabaseException();
0271: }
0272:
0273: // Raise a warning in sqlAuthorization mode if authentication is not ON
0274: if (usingNoneAuth
0275: && getLanguageConnection().usesSqlAuthorization())
0276: addWarning(EmbedSQLWarning
0277: .newEmbedSQLWarning(SQLState.SQL_AUTHORIZATION_WITH_NO_AUTHENTICATION));
0278: } catch (OutOfMemoryError noMemory) {
0279: //System.out.println("freeA");
0280: restoreContextStack();
0281: tr.lcc = null;
0282: tr.cm = null;
0283:
0284: //System.out.println("free");
0285: //System.out.println(Runtime.getRuntime().freeMemory());
0286: memoryState.setLowMemory();
0287:
0288: //noMemory.printStackTrace();
0289: // throw Util.generateCsSQLException(SQLState.LOGIN_FAILED, noMemory.getMessage(), noMemory);
0290: throw NO_MEM;
0291: } catch (Throwable t) {
0292: throw handleException(t);
0293: } finally {
0294: restoreContextStack();
0295: }
0296: }
0297:
0298: /**
0299: Examine the attributes set provided and determine if this is a create
0300: boot. A boot is a create boot iff.
0301:
0302: <OL>
0303: <LI>create=true - This means create a standard database.
0304: <LI> createFrom = Path - creates database from backup if it does not exist.
0305: <LI> restoreFrom = Path - database is restored completley from backup.
0306: if a database exists in the same place it is replaced by the version
0307: in the backup otherwise a new one is created using the backup copy.
0308: <LI> rollForwardRecoveryFrom = Path - rollforward is performed
0309: using the version backup and any active and archived log files.
0310: </OL>
0311:
0312: @param p the attribute set.
0313:
0314: @exception SQLException Ooops.
0315: */
0316: private boolean createBoot(Properties p) throws SQLException {
0317: int createCount = 0;
0318:
0319: if (Boolean.valueOf(p.getProperty(Attribute.CREATE_ATTR))
0320: .booleanValue())
0321: createCount++;
0322:
0323: int restoreCount = 0;
0324: //check if the user has specified any /create/restore/recover from backup attributes.
0325: if (p.getProperty(Attribute.CREATE_FROM) != null)
0326: restoreCount++;
0327: if (p.getProperty(Attribute.RESTORE_FROM) != null)
0328: restoreCount++;
0329: if (p.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM) != null)
0330: restoreCount++;
0331: if (restoreCount > 1)
0332: throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);
0333:
0334: // check if user has specified re-encryption attributes
0335: // in combination with create/restore/recover attributes.
0336: // re-encryption is not allowed when restoring from backup.
0337: if (restoreCount != 0
0338: && (Boolean.valueOf(
0339: p.getProperty(Attribute.DATA_ENCRYPTION))
0340: .booleanValue()
0341: || p.getProperty(Attribute.NEW_BOOT_PASSWORD) != null || p
0342: .getProperty(Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null)) {
0343: throw newSQLException(SQLState.CONFLICTING_RESTORE_ATTRIBUTES);
0344: }
0345:
0346: //add the restore count to create count to make sure
0347: //user has not specified and restore together by mistake.
0348: createCount = createCount + restoreCount;
0349:
0350: //
0351: if (createCount > 1)
0352: throw newSQLException(SQLState.CONFLICTING_CREATE_ATTRIBUTES);
0353:
0354: //retuns true only for the create flag not for restore flags
0355: return (createCount - restoreCount) == 1;
0356: }
0357:
0358: /**
0359: * Create a new connection based off of the
0360: * connection passed in. Initializes state
0361: * based on input connection, and copies
0362: * appropriate object pointers. This is only used
0363: for nested connections.
0364: *
0365: * @param inputConnection the input connection
0366: */
0367: public EmbedConnection(EmbedConnection inputConnection) {
0368: if (SanityManager.DEBUG) {
0369: SanityManager
0370: .ASSERT(inputConnection.active,
0371: "trying to create a proxy for an inactive conneciton");
0372: }
0373:
0374: // Proxy connections are always autocommit false
0375: // thus needCommit is irrelavent.
0376: autoCommit = false;
0377:
0378: /*
0379: ** Nesting specific state we are copying from
0380: ** the inputConnection
0381: */
0382:
0383: /*
0384: ** Objects we are sharing across nestings
0385: */
0386: // set it to null to allow it to be final.
0387: tr = null; // a proxy connection has no direct
0388: // pointer to the tr. Every call has to go
0389: // thru the rootConnection's tr.
0390: active = true;
0391: this .rootConnection = inputConnection.rootConnection;
0392: this .applicationConnection = this ;
0393: this .factory = inputConnection.factory;
0394:
0395: //if no holdability specified for the resultset, use the holability
0396: //defined for the connection
0397: this .connectionHoldAbility = inputConnection.connectionHoldAbility;
0398:
0399: //RESOLVE: although it looks like the right
0400: // thing to share the metadata object, if
0401: // we do we'll get the wrong behavior on
0402: // getCurrentConnection().getMetaData().isReadOnly()
0403: // so don't try to be smart and uncomment the
0404: // following. Ultimately, the metadata should
0405: // be shared by all connections anyway.
0406: //dbMetadata = inputConnection.dbMetadata;
0407: }
0408:
0409: //
0410: // Check passed-in user's credentials.
0411: //
0412: private void checkUserCredentials(String dbname, Properties userInfo)
0413: throws SQLException {
0414: if (SanityManager.DEBUG)
0415: SanityManager.ASSERT(!isClosed(), "connection is closed");
0416:
0417: // If a database name was passed-in then check user's credential
0418: // in that database using the database's authentication service,
0419: // otherwise check if it is a valid user in the JBMS system.
0420: //
0421: // NOTE: We always expect an authentication service per database
0422: // and one at the system level.
0423: //
0424: AuthenticationService authenticationService = null;
0425:
0426: // Retrieve appropriate authentication service handle
0427: if (dbname == null)
0428: authenticationService = getLocalDriver()
0429: .getAuthenticationService();
0430: else
0431: authenticationService = getTR().getDatabase()
0432: .getAuthenticationService();
0433:
0434: // check that we do have a authentication service
0435: // it is _always_ expected.
0436: if (authenticationService == null) {
0437: String failedString = MessageService
0438: .getTextMessage((dbname == null) ? MessageId.AUTH_NO_SERVICE_FOR_SYSTEM
0439: : MessageId.AUTH_NO_SERVICE_FOR_DB);
0440:
0441: throw newSQLException(SQLState.LOGIN_FAILED, failedString);
0442: }
0443:
0444: // Let's authenticate now
0445:
0446: if (!authenticationService.authenticate(dbname, userInfo)) {
0447:
0448: throw newSQLException(SQLState.LOGIN_FAILED, MessageService
0449: .getTextMessage(MessageId.AUTH_INVALID));
0450:
0451: }
0452:
0453: // If authentication is not on, we have to raise a warning if sqlAuthorization is ON
0454: // Since NoneAuthenticationService is the default for Derby, it should be ok to refer
0455: // to its implementation here, since it will always be present.
0456: if (authenticationService instanceof NoneAuthenticationServiceImpl)
0457: usingNoneAuth = true;
0458: }
0459:
0460: /**
0461: * Gets the EngineType of the connected database.
0462: *
0463: * @return 0 if there is no database, the engine type otherwise. @see org.apache.derby.iapi.reference.EngineType
0464: */
0465: public int getEngineType() {
0466: Database db = getDatabase();
0467:
0468: if (null == db)
0469: return 0;
0470: return db.getEngineType();
0471: }
0472:
0473: /*
0474: ** Methods from java.sql.Connection
0475: */
0476:
0477: /**
0478: * SQL statements without parameters are normally
0479: * executed using Statement objects. If the same SQL statement
0480: * is executed many times, it is more efficient to use a
0481: * PreparedStatement
0482: *
0483: * JDBC 2.0
0484: *
0485: * Result sets created using the returned Statement will have
0486: * forward-only type, and read-only concurrency, by default.
0487: *
0488: * @return a new Statement object
0489: * @exception SQLException if a database-access error occurs.
0490: */
0491: public final Statement createStatement() throws SQLException {
0492: return createStatement(JDBC20Translation.TYPE_FORWARD_ONLY,
0493: JDBC20Translation.CONCUR_READ_ONLY,
0494: connectionHoldAbility);
0495: }
0496:
0497: /**
0498: * JDBC 2.0
0499: *
0500: * Same as createStatement() above, but allows the default result set
0501: * type and result set concurrency type to be overridden.
0502: *
0503: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0504: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0505: * @return a new Statement object
0506: * @exception SQLException if a database-access error occurs.
0507: */
0508: public final Statement createStatement(int resultSetType,
0509: int resultSetConcurrency) throws SQLException {
0510: return createStatement(resultSetType, resultSetConcurrency,
0511: connectionHoldAbility);
0512: }
0513:
0514: /**
0515: * JDBC 3.0
0516: *
0517: * Same as createStatement() above, but allows the default result set
0518: * type, result set concurrency type and result set holdability type to
0519: * be overridden.
0520: *
0521: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0522: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0523: * @param resultSetHoldability a holdability type,
0524: * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
0525: * @return a new Statement object
0526: * @exception SQLException if a database-access error occurs.
0527: */
0528: public final Statement createStatement(int resultSetType,
0529: int resultSetConcurrency, int resultSetHoldability)
0530: throws SQLException {
0531: checkIfClosed();
0532:
0533: return factory.newEmbedStatement(this , false,
0534: setResultSetType(resultSetType), resultSetConcurrency,
0535: resultSetHoldability);
0536: }
0537:
0538: /**
0539: * A SQL statement with or without IN parameters can be
0540: * pre-compiled and stored in a PreparedStatement object. This
0541: * object can then be used to efficiently execute this statement
0542: * multiple times.
0543: *
0544: * <P><B>Note:</B> This method is optimized for handling
0545: * parametric SQL statements that benefit from precompilation. If
0546: * the driver supports precompilation, prepareStatement will send
0547: * the statement to the database for precompilation. Some drivers
0548: * may not support precompilation. In this case, the statement may
0549: * not be sent to the database until the PreparedStatement is
0550: * executed. This has no direct affect on users; however, it does
0551: * affect which method throws certain SQLExceptions.
0552: *
0553: * JDBC 2.0
0554: *
0555: * Result sets created using the returned PreparedStatement will have
0556: * forward-only type, and read-only concurrency, by default.
0557: *
0558: * @param sql a SQL statement that may contain one or more '?' IN
0559: * parameter placeholders
0560: * @return a new PreparedStatement object containing the
0561: * pre-compiled statement
0562: * @exception SQLException if a database-access error occurs.
0563: */
0564: public final PreparedStatement prepareStatement(String sql)
0565: throws SQLException {
0566: return prepareStatement(sql,
0567: JDBC20Translation.TYPE_FORWARD_ONLY,
0568: JDBC20Translation.CONCUR_READ_ONLY,
0569: connectionHoldAbility,
0570: JDBC30Translation.NO_GENERATED_KEYS, null, null);
0571: }
0572:
0573: /**
0574: * JDBC 2.0
0575: *
0576: * Same as prepareStatement() above, but allows the default result set
0577: * type and result set concurrency type to be overridden.
0578: *
0579: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0580: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0581: * @return a new PreparedStatement object containing the
0582: * pre-compiled SQL statement
0583: * @exception SQLException if a database-access error occurs.
0584: */
0585: public final PreparedStatement prepareStatement(String sql,
0586: int resultSetType, int resultSetConcurrency)
0587: throws SQLException {
0588: return prepareStatement(sql, resultSetType,
0589: resultSetConcurrency, connectionHoldAbility,
0590: JDBC30Translation.NO_GENERATED_KEYS, null, null);
0591: }
0592:
0593: /**
0594: * JDBC 3.0
0595: *
0596: * Same as prepareStatement() above, but allows the default result set
0597: * type, result set concurrency type and result set holdability
0598: * to be overridden.
0599: *
0600: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0601: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0602: * @param resultSetHoldability - one of the following ResultSet constants:
0603: * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
0604: * @return a new PreparedStatement object containing the
0605: * pre-compiled SQL statement
0606: * @exception SQLException if a database-access error occurs.
0607: */
0608: public final PreparedStatement prepareStatement(String sql,
0609: int resultSetType, int resultSetConcurrency,
0610: int resultSetHoldability) throws SQLException {
0611: return prepareStatement(sql, resultSetType,
0612: resultSetConcurrency, resultSetHoldability,
0613: JDBC30Translation.NO_GENERATED_KEYS, null, null);
0614: }
0615:
0616: /**
0617: * Creates a default PreparedStatement object capable of returning
0618: * the auto-generated keys designated by the given array. This array contains
0619: * the indexes of the columns in the target table that contain the auto-generated
0620: * keys that should be made available. This array is ignored if the SQL statement
0621: * is not an INSERT statement
0622:
0623: JDBC 3.0
0624: *
0625: *
0626: * @param sql An SQL statement that may contain one or more ? IN parameter placeholders
0627: * @param columnIndexes An array of column indexes indicating the columns
0628: * that should be returned from the inserted row or rows
0629: *
0630: * @return A new PreparedStatement object, containing the pre-compiled
0631: * SQL statement, that will have the capability of returning auto-generated keys
0632: * designated by the given array of column indexes
0633: *
0634: * @exception SQLException Feature not implemented for now.
0635: */
0636: public final PreparedStatement prepareStatement(String sql,
0637: int[] columnIndexes) throws SQLException {
0638: throw Util.notImplemented("prepareStatement(String, int[])");
0639: }
0640:
0641: /**
0642: * Creates a default PreparedStatement object capable of returning
0643: * the auto-generated keys designated by the given array. This array contains
0644: * the names of the columns in the target table that contain the auto-generated
0645: * keys that should be returned. This array is ignored if the SQL statement
0646: * is not an INSERT statement
0647: *
0648: JDBC 3.0
0649: *
0650: * @param sql An SQL statement that may contain one or more ? IN parameter placeholders
0651: * @param columnNames An array of column names indicating the columns
0652: * that should be returned from the inserted row or rows
0653: *
0654: * @return A new PreparedStatement object, containing the pre-compiled
0655: * SQL statement, that will have the capability of returning auto-generated keys
0656: * designated by the given array of column names
0657: *
0658: * @exception SQLException Feature not implemented for now.
0659: */
0660: public final PreparedStatement prepareStatement(String sql,
0661: String[] columnNames) throws SQLException {
0662: throw Util.notImplemented("prepareStatement(String, String[])");
0663: }
0664:
0665: /**
0666: * Creates a default PreparedStatement object that has the capability to
0667: * retieve auto-generated keys. The given constant tells the driver
0668: * whether it should make auto-generated keys available for retrieval.
0669: * This parameter is ignored if the SQL statement is not an INSERT statement.
0670: * JDBC 3.0
0671: *
0672: * @param sql A SQL statement that may contain one or more ? IN parameter placeholders
0673: * @param autoGeneratedKeys A flag indicating whether auto-generated keys
0674: * should be returned
0675: *
0676: * @return A new PreparedStatement object, containing the pre-compiled
0677: * SQL statement, that will have the capability of returning auto-generated keys
0678: *
0679: * @exception SQLException Feature not implemented for now.
0680: */
0681: public final PreparedStatement prepareStatement(String sql,
0682: int autoGeneratedKeys) throws SQLException {
0683: return prepareStatement(sql,
0684: JDBC20Translation.TYPE_FORWARD_ONLY,
0685: JDBC20Translation.CONCUR_READ_ONLY,
0686: connectionHoldAbility, autoGeneratedKeys, null, null);
0687: }
0688:
0689: private PreparedStatement prepareStatement(String sql,
0690: int resultSetType, int resultSetConcurrency,
0691: int resultSetHoldability, int autoGeneratedKeys,
0692: int[] columnIndexes, String[] columnNames)
0693: throws SQLException {
0694: synchronized (getConnectionSynchronization()) {
0695: setupContextStack();
0696: try {
0697: return factory.newEmbedPreparedStatement(this , sql,
0698: false, setResultSetType(resultSetType),
0699: resultSetConcurrency, resultSetHoldability,
0700: autoGeneratedKeys, columnIndexes, columnNames);
0701: } finally {
0702: restoreContextStack();
0703: }
0704: }
0705: }
0706:
0707: /**
0708: * A SQL stored procedure call statement is handled by creating a
0709: * CallableStatement for it. The CallableStatement provides
0710: * methods for setting up its IN and OUT parameters, and
0711: * methods for executing it.
0712: *
0713: * <P><B>Note:</B> This method is optimized for handling stored
0714: * procedure call statements. Some drivers may send the call
0715: * statement to the database when the prepareCall is done; others
0716: * may wait until the CallableStatement is executed. This has no
0717: * direct affect on users; however, it does affect which method
0718: * throws certain SQLExceptions.
0719: *
0720: * JDBC 2.0
0721: *
0722: * Result sets created using the returned CallableStatement will have
0723: * forward-only type, and read-only concurrency, by default.
0724: *
0725: * @param sql a SQL statement that may contain one or more '?'
0726: * parameter placeholders. Typically this statement is a JDBC
0727: * function call escape string.
0728: * @return a new CallableStatement object containing the
0729: * pre-compiled SQL statement
0730: * @exception SQLException if a database-access error occurs.
0731: */
0732: public final CallableStatement prepareCall(String sql)
0733: throws SQLException {
0734: return prepareCall(sql, JDBC20Translation.TYPE_FORWARD_ONLY,
0735: JDBC20Translation.CONCUR_READ_ONLY,
0736: connectionHoldAbility);
0737: }
0738:
0739: /**
0740: * JDBC 2.0
0741: *
0742: * Same as prepareCall() above, but allows the default result set
0743: * type and result set concurrency type to be overridden.
0744: *
0745: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0746: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0747: * @return a new CallableStatement object containing the
0748: * pre-compiled SQL statement
0749: * @exception SQLException if a database-access error occurs.
0750: */
0751: public final CallableStatement prepareCall(String sql,
0752: int resultSetType, int resultSetConcurrency)
0753: throws SQLException {
0754: return prepareCall(sql, resultSetType, resultSetConcurrency,
0755: connectionHoldAbility);
0756: }
0757:
0758: /**
0759: * JDBC 3.0
0760: *
0761: * Same as prepareCall() above, but allows the default result set
0762: * type, result set concurrency type and result set holdability
0763: * to be overridden.
0764: *
0765: * @param resultSetType a result set type, see ResultSet.TYPE_XXX
0766: * @param resultSetConcurrency a concurrency type, see ResultSet.CONCUR_XXX
0767: * @param resultSetHoldability - one of the following ResultSet constants:
0768: * ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT
0769: * @return a new CallableStatement object containing the
0770: * pre-compiled SQL statement
0771: * @exception SQLException if a database-access error occurs.
0772: */
0773: public final CallableStatement prepareCall(String sql,
0774: int resultSetType, int resultSetConcurrency,
0775: int resultSetHoldability) throws SQLException {
0776: checkIfClosed();
0777:
0778: synchronized (getConnectionSynchronization()) {
0779: setupContextStack();
0780: try {
0781: return factory.newEmbedCallableStatement(this , sql,
0782: setResultSetType(resultSetType),
0783: resultSetConcurrency, resultSetHoldability);
0784: } finally {
0785: restoreContextStack();
0786: }
0787: }
0788: }
0789:
0790: /**
0791: * A driver may convert the JDBC sql grammar into its system's
0792: * native SQL grammar prior to sending it; nativeSQL returns the
0793: * native form of the statement that the driver would have sent.
0794: *
0795: * @param sql a SQL statement that may contain one or more '?'
0796: * parameter placeholders
0797: * @return the native form of this statement
0798: */
0799: public String nativeSQL(String sql) throws SQLException {
0800: checkIfClosed();
0801: // we don't massage the strings at all, so this is easy:
0802: return sql;
0803: }
0804:
0805: /**
0806: * If a connection is in auto-commit mode, then all its SQL
0807: * statements will be executed and committed as individual
0808: * transactions. Otherwise, its SQL statements are grouped into
0809: * transactions that are terminated by either commit() or
0810: * rollback(). By default, new connections are in auto-commit
0811: * mode.
0812: *
0813: * The commit occurs when the statement completes or the next
0814: * execute occurs, whichever comes first. In the case of
0815: * statements returning a ResultSet, the statement completes when
0816: * the last row of the ResultSet has been retrieved or the
0817: * ResultSet has been closed. In advanced cases, a single
0818: * statement may return multiple results as well as output
0819: * parameter values. Here the commit occurs when all results and
0820: * output param values have been retrieved.
0821: *
0822: * @param autoCommit true enables auto-commit; false disables
0823: * auto-commit.
0824: * @exception SQLException if a database-access error occurs.
0825: */
0826: public void setAutoCommit(boolean autoCommit) throws SQLException {
0827: checkIfClosed();
0828:
0829: // Is this a nested connection
0830: if (rootConnection != this ) {
0831: if (autoCommit)
0832: throw newSQLException(SQLState.NO_AUTO_COMMIT_ON);
0833: }
0834:
0835: if (this .autoCommit != autoCommit)
0836: commit();
0837:
0838: this .autoCommit = autoCommit;
0839: }
0840:
0841: /**
0842: * Get the current auto-commit state.
0843: *
0844: * @return Current state of auto-commit mode.
0845: * @see #setAutoCommit
0846: */
0847: public boolean getAutoCommit() throws SQLException {
0848: checkIfClosed();
0849: return autoCommit;
0850: }
0851:
0852: /**
0853: * Commit makes all changes made since the previous
0854: * commit/rollback permanent and releases any database locks
0855: * currently held by the Connection. This method should only be
0856: * used when auto commit has been disabled.
0857: *
0858: * @exception SQLException if a database-access error occurs.
0859: * @see #setAutoCommit
0860: */
0861: public void commit() throws SQLException {
0862: synchronized (getConnectionSynchronization()) {
0863: /*
0864: ** Note that the context stack is
0865: ** needed even for rollback & commit
0866: */
0867: setupContextStack();
0868:
0869: try {
0870: getTR().commit();
0871: } catch (Throwable t) {
0872: throw handleException(t);
0873: } finally {
0874: restoreContextStack();
0875: }
0876:
0877: needCommit = false;
0878: }
0879: }
0880:
0881: /**
0882: * Rollback drops all changes made since the previous
0883: * commit/rollback and releases any database locks currently held
0884: * by the Connection. This method should only be used when auto
0885: * commit has been disabled.
0886: *
0887: * @exception SQLException if a database-access error occurs.
0888: * @see #setAutoCommit
0889: */
0890: public void rollback() throws SQLException {
0891:
0892: synchronized (getConnectionSynchronization()) {
0893: /*
0894: ** Note that the context stack is
0895: ** needed even for rollback & commit
0896: */
0897: setupContextStack();
0898: try {
0899: getTR().rollback();
0900: } catch (Throwable t) {
0901: throw handleException(t);
0902: } finally {
0903: restoreContextStack();
0904: }
0905: needCommit = false;
0906: }
0907: }
0908:
0909: /**
0910: * In some cases, it is desirable to immediately release a
0911: * Connection's database and JDBC resources instead of waiting for
0912: * them to be automatically released; the close method provides this
0913: * immediate release.
0914: *
0915: * <P><B>Note:</B> A Connection is automatically closed when it is
0916: * garbage collected. Certain fatal errors also result in a closed
0917: * Connection.
0918: *
0919: * @exception SQLException if a database-access error occurs.
0920: */
0921: public void close() throws SQLException {
0922: // JDK 1.4 javadoc indicates close on a closed connection is a no-op
0923: if (isClosed())
0924: return;
0925:
0926: if (rootConnection == this ) {
0927: /* Throw error to match DB2/JDBC if a tran is pending in non-autocommit mode */
0928: if (!autoCommit && !transactionIsIdle()) {
0929: throw newSQLException(SQLState.LANG_INVALID_TRANSACTION_STATE);
0930: }
0931:
0932: close(exceptionClose);
0933: } else
0934: setInactive(); // nested connection
0935: }
0936:
0937: // This inner close takes the exception and calls
0938: // the context manager to make the connection close.
0939: // The exception must be a session severity exception.
0940: //
0941: // NOTE: This method is not part of JDBC specs.
0942: //
0943: private void close(StandardException e) throws SQLException {
0944:
0945: synchronized (getConnectionSynchronization()) {
0946: if (rootConnection == this ) {
0947: /*
0948: * If it isn't active, it's already been closed.
0949: */
0950: if (active) {
0951: setupContextStack();
0952: try {
0953: tr.rollback();
0954:
0955: // Let go of lcc reference so it can be GC'ed after
0956: // cleanupOnError, the tr will stay around until the
0957: // rootConnection itself is GC'ed, which is dependent
0958: // on how long the client program wants to hold on to
0959: // the Connection object.
0960: tr.clearLcc();
0961: tr.cleanupOnError(e);
0962:
0963: } catch (Throwable t) {
0964: throw handleException(t);
0965: } finally {
0966: restoreContextStack();
0967: }
0968: }
0969: }
0970:
0971: if (!isClosed())
0972: setInactive();
0973: }
0974: }
0975:
0976: /**
0977: * Tests to see if a Connection is closed.
0978: *
0979: * @return true if the connection is closed; false if it's still open
0980: */
0981: public final boolean isClosed() {
0982: if (active) {
0983:
0984: // I am attached, check the database state
0985: if (getTR().isActive()) {
0986: return false;
0987: }
0988:
0989: setInactive();
0990:
0991: }
0992: return true;
0993: }
0994:
0995: /**
0996: * A Connection's database is able to provide information
0997: * describing its tables, its supported SQL grammar, its stored
0998: * procedures, the capabilities of this connection, etc. This
0999: * information is made available through a DatabaseMetaData
1000: * object.
1001: *
1002: * @return a DatabaseMetaData object for this Connection
1003: * @exception SQLException if a database-access error occurs.
1004: */
1005: public DatabaseMetaData getMetaData() throws SQLException {
1006: checkIfClosed();
1007:
1008: if (dbMetadata == null) {
1009:
1010: // There is a case where dbname can be null.
1011: // Replication client of this method does not have a
1012: // JDBC connection; therefore dbname is null and this
1013: // is expected.
1014: //
1015: dbMetadata = factory.newEmbedDatabaseMetaData(this , getTR()
1016: .getUrl());
1017: }
1018: return dbMetadata;
1019: }
1020:
1021: /**
1022: JDBC 3.0
1023: * Retrieves the current holdability of ResultSet objects created using this
1024: * Connection object.
1025: *
1026: *
1027: * @return The holdability, one of ResultSet.HOLD_CURSORS_OVER_COMMIT
1028: * or ResultSet.CLOSE_CURSORS_AT_COMMIT
1029: *
1030: */
1031: public final int getHoldability() throws SQLException {
1032: checkIfClosed();
1033: return connectionHoldAbility;
1034: }
1035:
1036: /**
1037: JDBC 3.0
1038: * Changes the holdability of ResultSet objects created using this
1039: * Connection object to the given holdability.
1040: *
1041: *
1042: * @param holdability A ResultSet holdability constant, one of ResultSet.HOLD_CURSORS_OVER_COMMIT
1043: * or ResultSet.CLOSE_CURSORS_AT_COMMIT
1044: *
1045: */
1046: public final void setHoldability(int holdability)
1047: throws SQLException {
1048: checkIfClosed();
1049: connectionHoldAbility = holdability;
1050: }
1051:
1052: /**
1053: * You can put a connection in read-only mode as a hint to enable
1054: * database optimizations.
1055: *
1056: * <P><B>Note:</B> setReadOnly cannot be called while in the
1057: * middle of a transaction.
1058: *
1059: * @param readOnly true enables read-only mode; false disables
1060: * read-only mode.
1061: * @exception SQLException if a database-access error occurs.
1062: */
1063: public final void setReadOnly(boolean readOnly) throws SQLException {
1064: synchronized (getConnectionSynchronization()) {
1065: setupContextStack();
1066: try {
1067: getLanguageConnection().setReadOnly(readOnly);
1068: } catch (StandardException e) {
1069: throw handleException(e);
1070: } finally {
1071: restoreContextStack();
1072: }
1073: }
1074: }
1075:
1076: /**
1077: * Tests to see if the connection is in read-only mode.
1078: *
1079: * @return true if connection is read-only
1080: * @exception SQLException if a database-access error occurs.
1081: */
1082: public final boolean isReadOnly() throws SQLException {
1083: checkIfClosed();
1084: return getLanguageConnection().isReadOnly();
1085: }
1086:
1087: /**
1088: * A sub-space of this Connection's database may be selected by setting a
1089: * catalog name. If the driver does not support catalogs it will
1090: * silently ignore this request.
1091: *
1092: * @exception SQLException if a database-access error occurs.
1093: */
1094: public void setCatalog(String catalog) throws SQLException {
1095: checkIfClosed();
1096: // silently ignoring this request like the javadoc said.
1097: return;
1098: }
1099:
1100: /**
1101: * Return the Connection's current catalog name.
1102: *
1103: * @return the current catalog name or null
1104: * @exception SQLException if a database-access error occurs.
1105: */
1106: public String getCatalog() throws SQLException {
1107: checkIfClosed();
1108: // we do not have support for Catalog, just return null as
1109: // the JDBC specs mentions then.
1110: return null;
1111: }
1112:
1113: /**
1114: * You can call this method to try to change the transaction
1115: * isolation level using one of the TRANSACTION_* values.
1116: *
1117: * <P><B>Note:</B> setTransactionIsolation causes the current
1118: * transaction to commit
1119: *
1120: * @param level one of the TRANSACTION_* isolation values with the
1121: * exception of TRANSACTION_NONE; some databases may not support
1122: * other values
1123: * @exception SQLException if a database-access error occurs.
1124: * @see DatabaseMetaData#supportsTransactionIsolationLevel
1125: */
1126: public void setTransactionIsolation(int level) throws SQLException {
1127:
1128: if (level == getTransactionIsolation())
1129: return;
1130:
1131: // Convert the isolation level to the internal one
1132: int iLevel;
1133: switch (level) {
1134: case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
1135: iLevel = ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL;
1136: break;
1137:
1138: case java.sql.Connection.TRANSACTION_READ_COMMITTED:
1139: iLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;
1140: break;
1141:
1142: case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
1143: iLevel = ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL;
1144: break;
1145:
1146: case java.sql.Connection.TRANSACTION_SERIALIZABLE:
1147: iLevel = ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL;
1148: break;
1149: default:
1150: throw newSQLException(
1151: SQLState.UNIMPLEMENTED_ISOLATION_LEVEL,
1152: new Integer(level));
1153: }
1154:
1155: synchronized (getConnectionSynchronization()) {
1156: setupContextStack();
1157: try {
1158: getLanguageConnection().setIsolationLevel(iLevel);
1159: } catch (StandardException e) {
1160: throw handleException(e);
1161: } finally {
1162: restoreContextStack();
1163: }
1164: }
1165: }
1166:
1167: /**
1168: * Get this Connection's current transaction isolation mode.
1169: *
1170: * @return the current TRANSACTION_* mode value
1171: * @exception SQLException if a database-access error occurs.
1172: */
1173: public final int getTransactionIsolation() throws SQLException {
1174: checkIfClosed();
1175: return ExecutionContext.CS_TO_JDBC_ISOLATION_LEVEL_MAP[getLanguageConnection()
1176: .getCurrentIsolationLevel()];
1177: }
1178:
1179: /**
1180: * The first warning reported by calls on this Connection is
1181: * returned.
1182: *
1183: * <P><B>Note:</B> Subsequent warnings will be chained to this
1184: * SQLWarning.
1185: *
1186: * @return the first SQLWarning or null
1187: *
1188: * Synchronization note: Warnings are synchronized
1189: * on nesting level
1190: */
1191: public final synchronized SQLWarning getWarnings()
1192: throws SQLException {
1193: checkIfClosed();
1194: return topWarning;
1195: }
1196:
1197: /**
1198: * After this call, getWarnings returns null until a new warning is
1199: * reported for this Connection.
1200: *
1201: * Synchronization node: Warnings are synchonized
1202: * on nesting level
1203: */
1204: public final synchronized void clearWarnings() throws SQLException {
1205: checkIfClosed();
1206: topWarning = null;
1207: }
1208:
1209: /////////////////////////////////////////////////////////////////////////
1210: //
1211: // JDBC 2.0 - New public methods
1212: //
1213: /////////////////////////////////////////////////////////////////////////
1214:
1215: /**
1216: *
1217: * Get the type-map object associated with this connection.
1218: * By default, the map returned is empty.
1219: * JDBC 2.0 - java.util.Map requires JDK 1
1220: *
1221: */
1222: public java.util.Map getTypeMap() throws SQLException {
1223: checkIfClosed();
1224: // just return an immuntable empty map
1225: return java.util.Collections.EMPTY_MAP;
1226: }
1227:
1228: /**
1229: * Install a type-map object as the default type-map for
1230: * this connection.
1231: * JDBC 2.0 - java.util.Map requires JDK 1
1232: *
1233: * @exception SQLException Feature not implemented for now.
1234: */
1235: public final void setTypeMap(java.util.Map map) throws SQLException {
1236: checkIfClosed();
1237: if (map == null)
1238: throw Util.generateCsSQLException(
1239: SQLState.INVALID_API_PARAMETER, map, "map",
1240: "java.sql.Connection.setTypeMap");
1241: if (!(map.isEmpty()))
1242: throw Util.notImplemented();
1243: }
1244:
1245: /////////////////////////////////////////////////////////////////////////
1246: //
1247: // Implementation specific methods
1248: //
1249: /////////////////////////////////////////////////////////////////////////
1250:
1251: /**
1252: Add a warning to the current list of warnings, to follow
1253: this note from Connection.getWarnings.
1254: Note: Subsequent warnings will be chained to this SQLWarning.
1255:
1256: @see java.sql.Connection#getWarnings
1257: */
1258: public final synchronized void addWarning(SQLWarning newWarning) {
1259: if (topWarning == null) {
1260: topWarning = newWarning;
1261: return;
1262: }
1263:
1264: topWarning.setNextWarning(newWarning);
1265: }
1266:
1267: /**
1268: * Return the dbname for this connection.
1269: *
1270: * @return String The dbname for this connection.
1271: */
1272: public String getDBName() {
1273: if (SanityManager.DEBUG)
1274: SanityManager.ASSERT(!isClosed(), "connection is closed");
1275:
1276: return getTR().getDBName();
1277: }
1278:
1279: public final LanguageConnectionContext getLanguageConnection() {
1280:
1281: if (SanityManager.DEBUG)
1282: SanityManager.ASSERT(!isClosed(), "connection is closed");
1283:
1284: return getTR().getLcc();
1285: }
1286:
1287: /**
1288: * Raises an exception if the connection is closed.
1289: *
1290: * @exception SQLException if the connection is closed
1291: */
1292: protected final void checkIfClosed() throws SQLException {
1293: if (isClosed()) {
1294: throw Util.noCurrentConnection();
1295: }
1296: }
1297:
1298: //EmbedConnection30 overrides this method so it can release the savepoints array if
1299: //the exception severity is transaction level
1300: SQLException handleException(Throwable thrownException)
1301: throws SQLException {
1302: /*
1303: ** By default, rollback the connection on if autocommit
1304: ** is on.
1305: */
1306: return getTR().handleException(thrownException, autoCommit,
1307: true // Rollback xact on auto commit
1308: );
1309: }
1310:
1311: /**
1312: Handle any type of Exception.
1313: <UL>
1314: <LI> Inform the contexts of the error
1315: <LI> Throw an Util based upon the thrown exception.
1316: </UL>
1317:
1318: REMIND: now that we know all the exceptions from our driver
1319: are Utils, would it make sense to shut down the system
1320: for unknown SQLExceptions? At present, we do not.
1321:
1322: Because this is the last stop for exceptions,
1323: it will catch anything that occurs in it and try
1324: to cleanup before re-throwing them.
1325:
1326: @param thrownException the exception
1327: @param rollbackOnAutoCommit rollback the xact on if autocommit is
1328: on, otherwise rollback stmt but leave xact open (and
1329: continue to hold on to locks). Most of the time, this
1330: will be true, excepting operations on result sets, like
1331: getInt().
1332: */
1333: final SQLException handleException(Throwable thrownException,
1334: boolean rollbackOnAutoCommit) throws SQLException {
1335: return getTR().handleException(thrownException, autoCommit,
1336: rollbackOnAutoCommit);
1337:
1338: }
1339:
1340: /*
1341: This is called from the EmbedConnectionContext to
1342: close on errors. We assume all handling of the connectin
1343: is dealt with via the context stack, and our only role
1344: is to mark ourself as closed.
1345: */
1346:
1347: /**
1348: Close the connection when processing errors, or when
1349: closing a nested connection.
1350: <p>
1351: This only marks it as closed and frees up its resources;
1352: any closing of the underlying connection or commit work
1353: is assumed to be done elsewhere.
1354:
1355: Called from EmbedConnectionContext's cleanup routine,
1356: and by proxy.close().
1357: */
1358:
1359: public final void setInactive() {
1360:
1361: if (active == false)
1362: return;
1363: // active = false
1364: // tr = null !-> active = false
1365:
1366: synchronized (getConnectionSynchronization()) {
1367: active = false;
1368: // tr = null; cleanupOnerror sets inactive but still needs tr to
1369: // restore context later
1370: dbMetadata = null;
1371: }
1372: }
1373:
1374: /**
1375: @exception Throwable standard error policy
1376: */
1377: protected void finalize() throws Throwable {
1378: if (rootConnection == this ) {
1379: super .finalize();
1380: if (!isClosed())
1381: close(exceptionClose);
1382: }
1383: }
1384:
1385: /**
1386: * if auto commit is on, remember that we need to commit
1387: * the current statement.
1388: */
1389: protected void needCommit() {
1390: if (!needCommit)
1391: needCommit = true;
1392: }
1393:
1394: /**
1395: * if a commit is needed, perform it.
1396: *
1397: * Must have connection synchonization and context set up already.
1398: *
1399: * @exception SQLException if commit returns error
1400: */
1401: protected void commitIfNeeded() throws SQLException {
1402: if (autoCommit && needCommit) {
1403: try {
1404: getTR().commit();
1405: } catch (Throwable t) {
1406: throw handleException(t);
1407: }
1408: needCommit = false;
1409: }
1410: }
1411:
1412: /**
1413: * If in autocommit, then commit.
1414: *
1415: * Used to force a commit after a result set closes in autocommit mode.
1416: * The needCommit mechanism does not work correctly as there are times
1417: * with cursors (like a commit, followed by a next, followed by a close)
1418: * where the system does not think it needs a commit but we need to
1419: * force the commit on close. It seemed safer to just force a commit
1420: * on close rather than count on keeping the needCommit flag correct for
1421: * all cursor cases.
1422: *
1423: * Must have connection synchonization and context set up already.
1424: *
1425: * @exception SQLException if commit returns error
1426: */
1427: protected void commitIfAutoCommit() throws SQLException {
1428: if (autoCommit) {
1429: try {
1430: getTR().commit();
1431: } catch (Throwable t) {
1432: throw handleException(t);
1433: }
1434: needCommit = false;
1435: }
1436: }
1437:
1438: final protected Object getConnectionSynchronization() {
1439: return rootConnection;
1440: }
1441:
1442: /**
1443: Install the context manager for this thread. Check connection status here.
1444: @exception SQLException if fails
1445: */
1446: protected final void setupContextStack() throws SQLException {
1447:
1448: /*
1449: Track this entry, then throw an exception
1450: rather than doing the quiet return. Need the
1451: track before the throw because the backtrack
1452: is in a finally block.
1453: */
1454:
1455: checkIfClosed();
1456:
1457: getTR().setupContextStack();
1458:
1459: }
1460:
1461: protected final void restoreContextStack() throws SQLException {
1462:
1463: if (SanityManager.DEBUG)
1464: Util.ASSERT(this , (active) || getTR().getCsf() != null,
1465: "No context service to do restore");
1466:
1467: TransactionResourceImpl tr = getTR();
1468:
1469: //REMIND: someone is leaving an incorrect manager on when they
1470: // are exiting the system in the nested case.
1471: if (SanityManager.DEBUG) {
1472: if ((tr.getCsf() != null)
1473: && (tr.getCsf().getCurrentContextManager() != tr
1474: .getContextManager())) {
1475: Util.THROWASSERT(this ,
1476: "Current Context Manager not the one was expected: "
1477: + tr.getCsf()
1478: .getCurrentContextManager()
1479: + " " + tr.getContextManager());
1480: }
1481: }
1482:
1483: tr.restoreContextStack();
1484: }
1485:
1486: /*
1487: ** Create database methods.
1488: */
1489:
1490: /**
1491: Create a new database.
1492: @param dbname the database name
1493: @param info the properties
1494:
1495: @return Database The newly created database or null.
1496:
1497: @exception SQLException if fails to create database
1498: */
1499:
1500: private Database createDatabase(String dbname, Properties info)
1501: throws SQLException {
1502:
1503: info = filterProperties(info);
1504:
1505: try {
1506: if (Monitor.createPersistentService(
1507: Property.DATABASE_MODULE, dbname, info) == null) {
1508: // service already exists, create a warning
1509: addWarning(EmbedSQLWarning.newEmbedSQLWarning(
1510: SQLState.DATABASE_EXISTS, dbname));
1511: }
1512: } catch (StandardException mse) {
1513:
1514: SQLException se = newSQLException(
1515: SQLState.CREATE_DATABASE_FAILED, dbname);
1516: se.setNextException(handleException(mse));
1517: throw se;
1518: }
1519:
1520: // clear these values as some modules hang onto
1521: // the properties set corresponding to service.properties
1522: // and they shouldn't be interested in these JDBC attributes.
1523: info.clear();
1524:
1525: return (Database) Monitor.findService(Property.DATABASE_MODULE,
1526: dbname);
1527: }
1528:
1529: /**
1530: Return false iff the monitor cannot handle a service
1531: of the type indicated by the protocol within the name.
1532: If that's the case then we are the wrong driver.
1533:
1534: Throw exception if anything else is wrong.
1535: */
1536:
1537: private boolean bootDatabase(Properties info) throws Throwable {
1538: String dbname = tr.getDBName();
1539:
1540: // boot database now
1541: try {
1542:
1543: info = filterProperties(info);
1544:
1545: // try to start the service if it doesn't already exist
1546: if (!Monitor.startPersistentService(dbname, info)) {
1547: // a false indicates the monitor cannot handle a service
1548: // of the type indicated by the protocol within the name.
1549: // If that's the case then we are the wrong driver
1550: // so just return null.
1551: return false;
1552: }
1553:
1554: // clear these values as some modules hang onto
1555: // the properties set corresponding to service.properties
1556: // and they shouldn't be interested in these JDBC attributes.
1557: info.clear();
1558:
1559: Database database = (Database) Monitor.findService(
1560: Property.DATABASE_MODULE, dbname);
1561: tr.setDatabase(database);
1562:
1563: } catch (StandardException mse) {
1564: SQLException se = newSQLException(
1565: SQLState.BOOT_DATABASE_FAILED, dbname);
1566:
1567: Throwable ne = mse.getNestedException();
1568: SQLException nse;
1569:
1570: /*
1571: If there is a next exception, assume
1572: that the first one is just a redundant "see the
1573: next exception" message.
1574: if it is a BEI, treat it as a database exception.
1575: If there isn't a BEI, treat it as a java exception.
1576:
1577: In general we probably want to walk the chain
1578: and return all of them, but empirically, this
1579: is all we need to do for now.
1580: */
1581: if (ne instanceof StandardException)
1582: nse = Util
1583: .generateCsSQLException((StandardException) ne);
1584: else if (ne != null)
1585: nse = Util.javaException(ne);
1586: else
1587: nse = Util.generateCsSQLException(mse);
1588:
1589: se.setNextException(nse);
1590: throw se;
1591: }
1592:
1593: // If database exists, getDatabase() will return the database object.
1594: // If any error occured while booting an existing database, an
1595: // exception would have been thrown already.
1596: return true;
1597:
1598: }
1599:
1600: /*
1601: * Class interface methods used by database metadata to ensure
1602: * good relations with autocommit.
1603: */
1604:
1605: PreparedStatement prepareMetaDataStatement(String sql)
1606: throws SQLException {
1607: synchronized (getConnectionSynchronization()) {
1608: setupContextStack();
1609: PreparedStatement s = null;
1610: try {
1611: s = factory
1612: .newEmbedPreparedStatement(this , sql, true,
1613: JDBC20Translation.TYPE_FORWARD_ONLY,
1614: JDBC20Translation.CONCUR_READ_ONLY,
1615: connectionHoldAbility,
1616: JDBC30Translation.NO_GENERATED_KEYS,
1617: null, null);
1618: } finally {
1619: restoreContextStack();
1620: }
1621: return s;
1622: }
1623: }
1624:
1625: public final InternalDriver getLocalDriver() {
1626: if (SanityManager.DEBUG)
1627: SanityManager.ASSERT(!isClosed(), "connection is closed");
1628:
1629: return getTR().getDriver();
1630: }
1631:
1632: /**
1633: Return the context manager for this connection.
1634: */
1635: public final ContextManager getContextManager() {
1636:
1637: if (SanityManager.DEBUG)
1638: SanityManager.ASSERT(!isClosed(), "connection is closed");
1639:
1640: return getTR().getContextManager();
1641: }
1642:
1643: /**
1644: * Filter out properties from the passed in set of JDBC attributes
1645: * to remove any derby.* properties. This is to ensure that setting
1646: * derby.* properties does not work this way, it's not a defined way
1647: * to set such properties and could be a secuirty hole in allowing
1648: * remote connections to override system, application or database settings.
1649: *
1650: * @return a new Properties set copied from the parameter but with no
1651: * derby.* properties.
1652: */
1653: private Properties filterProperties(Properties inputSet) {
1654: Properties limited = new Properties();
1655:
1656: // filter out any derby.* properties, only
1657: // JDBC attributes can be set this way
1658: for (java.util.Enumeration e = inputSet.propertyNames(); e
1659: .hasMoreElements();) {
1660:
1661: String key = (String) e.nextElement();
1662:
1663: // we don't allow properties to be set this way
1664: if (key.startsWith("derby."))
1665: continue;
1666: limited.put(key, inputSet.getProperty(key));
1667: }
1668: return limited;
1669: }
1670:
1671: /*
1672: ** methods to be overridden by subimplementations wishing to insert
1673: ** their classes into the mix.
1674: */
1675:
1676: protected Database getDatabase() {
1677: if (SanityManager.DEBUG)
1678: SanityManager.ASSERT(!isClosed(), "connection is closed");
1679:
1680: return getTR().getDatabase();
1681: }
1682:
1683: final protected TransactionResourceImpl getTR() {
1684: return rootConnection.tr;
1685: }
1686:
1687: private EmbedConnectionContext pushConnectionContext(
1688: ContextManager cm) {
1689: return new EmbedConnectionContext(cm, this );
1690: }
1691:
1692: public final void setApplicationConnection(
1693: java.sql.Connection applicationConnection) {
1694: this .applicationConnection = applicationConnection;
1695: }
1696:
1697: public final java.sql.Connection getApplicationConnection() {
1698: return applicationConnection;
1699: }
1700:
1701: public void setDrdaID(String drdaID) {
1702: getLanguageConnection().setDrdaID(drdaID);
1703: }
1704:
1705: /**
1706: Reset the connection before it is returned from a PooledConnection
1707: to a new application request (wrapped by a BrokeredConnection).
1708: Examples of reset covered here is dropping session temporary tables
1709: and reseting IDENTITY_VAL_LOCAL.
1710: Most JDBC level reset is handled by calling standard java.sql.Connection
1711: methods from EmbedPooledConnection.
1712: */
1713: public void resetFromPool() throws SQLException {
1714: synchronized (getConnectionSynchronization()) {
1715: setupContextStack();
1716: try {
1717: getLanguageConnection().resetFromPool();
1718: } catch (StandardException t) {
1719: throw handleException(t);
1720: } finally {
1721: restoreContextStack();
1722: }
1723: }
1724: }
1725:
1726: /*
1727: ** methods to be overridden by subimplementations wishing to insert
1728: ** their classes into the mix.
1729: ** The reason we need to override them is because we want to create a
1730: ** Local20/LocalStatment object (etc) rather than a Local/LocalStatment
1731: ** object (etc).
1732: */
1733:
1734: /*
1735: ** XA support
1736: */
1737:
1738: public final int xa_prepare() throws SQLException {
1739:
1740: synchronized (getConnectionSynchronization()) {
1741: setupContextStack();
1742: try {
1743: XATransactionController tc = (XATransactionController) getLanguageConnection()
1744: .getTransactionExecute();
1745:
1746: int ret = tc.xa_prepare();
1747:
1748: if (ret == XATransactionController.XA_RDONLY) {
1749: // On a prepare call, xa allows an optimization that if the
1750: // transaction is read only, the RM can just go ahead and
1751: // commit it. So if store returns this read only status -
1752: // meaning store has taken the liberty to commit already - we
1753: // needs to turn around and call internalCommit (without
1754: // committing the store again) to make sure the state is
1755: // consistent. Since the transaction is read only, there is
1756: // probably not much that needs to be done.
1757:
1758: getLanguageConnection()
1759: .internalCommit(false /* don't commitStore again */);
1760: }
1761: return ret;
1762: } catch (StandardException t) {
1763: throw handleException(t);
1764: } finally {
1765: restoreContextStack();
1766: }
1767: }
1768: }
1769:
1770: public final void xa_commit(boolean onePhase) throws SQLException {
1771:
1772: synchronized (getConnectionSynchronization()) {
1773: setupContextStack();
1774: try {
1775: getLanguageConnection().xaCommit(onePhase);
1776: } catch (StandardException t) {
1777: throw handleException(t);
1778: } finally {
1779: restoreContextStack();
1780: }
1781: }
1782: }
1783:
1784: public final void xa_rollback() throws SQLException {
1785:
1786: synchronized (getConnectionSynchronization()) {
1787: setupContextStack();
1788: try {
1789: getLanguageConnection().xaRollback();
1790: } catch (StandardException t) {
1791: throw handleException(t);
1792: } finally {
1793: restoreContextStack();
1794: }
1795: }
1796: }
1797:
1798: /**
1799: * returns false if there is an underlying transaction and that transaction
1800: * has done work. True if there is no underlying transaction or that
1801: * underlying transaction is idle
1802: */
1803: public final boolean transactionIsIdle() {
1804: return getTR().isIdle();
1805: }
1806:
1807: private int setResultSetType(int resultSetType) {
1808:
1809: /* Add warning if scroll sensitive cursor
1810: * and downgrade to scroll insensitive cursor.
1811: */
1812: if (resultSetType == JDBC20Translation.TYPE_SCROLL_SENSITIVE) {
1813: addWarning(EmbedSQLWarning
1814: .newEmbedSQLWarning(SQLState.NO_SCROLL_SENSITIVE_CURSORS));
1815: resultSetType = JDBC20Translation.TYPE_SCROLL_INSENSITIVE;
1816: }
1817: return resultSetType;
1818: }
1819:
1820: /**
1821: * Set the transaction isolation level that will be used for the
1822: * next prepare. Used by network server to implement DB2 style
1823: * isolation levels.
1824: * @param level Isolation level to change to. level is the DB2 level
1825: * specified in the package names which happen to correspond
1826: * to our internal levels. If
1827: * level == ExecutionContext.UNSPECIFIED_ISOLATION,
1828: * the statement won't be prepared with an isolation level.
1829: *
1830: *
1831: */
1832: public void setPrepareIsolation(int level) throws SQLException {
1833: if (level == getPrepareIsolation())
1834: return;
1835:
1836: switch (level) {
1837: case ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL:
1838: case ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL:
1839: case ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL:
1840: case ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL:
1841: case ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL:
1842: break;
1843: default:
1844: throw Util.generateCsSQLException(
1845: SQLState.UNIMPLEMENTED_ISOLATION_LEVEL,
1846: new Integer(level));
1847: }
1848:
1849: synchronized (getConnectionSynchronization()) {
1850: getLanguageConnection().setPrepareIsolationLevel(level);
1851: }
1852: }
1853:
1854: /**
1855: * Return prepare isolation
1856: */
1857: public int getPrepareIsolation() {
1858: return getLanguageConnection().getPrepareIsolationLevel();
1859: }
1860:
1861: /**
1862: Return a unique order number for a result set.
1863: A unique value is only needed if the result set is
1864: being created within procedure and thus must be using
1865: a nested connection.
1866: */
1867: final int getResultSetOrderId() {
1868:
1869: if (this == rootConnection) {
1870: return 0;
1871: } else {
1872: return rootConnection.resultSetId++;
1873: }
1874: }
1875:
1876: protected SQLException newSQLException(String messageId) {
1877: return Util.generateCsSQLException(messageId);
1878: }
1879:
1880: protected SQLException newSQLException(String messageId, Object arg1) {
1881: return Util.generateCsSQLException(messageId, arg1);
1882: }
1883:
1884: protected SQLException newSQLException(String messageId,
1885: Object arg1, Object arg2) {
1886: return Util.generateCsSQLException(messageId, arg1, arg2);
1887: }
1888:
1889: /////////////////////////////////////////////////////////////////////////
1890: //
1891: // OBJECT OVERLOADS
1892: //
1893: /////////////////////////////////////////////////////////////////////////
1894:
1895: /**
1896: * Get a String representation that uniquely identifies
1897: * this connection. Include the same information that is
1898: * printed in the log for various trace and error messages.
1899: *
1900: * In Derby the "physical" connection is a LanguageConnectionContext,
1901: * or LCC.
1902: * The JDBC Connection is an JDBC-specific layer on top of this. Rather
1903: * than create a new id here, we simply use the id of the underlying LCC.
1904: * Note that this is a big aid in debugging, because much of the
1905: * engine trace and log code prints the LCC id.
1906: *
1907: * @return a string representation for this connection
1908: */
1909: public String toString() {
1910: if (connString == null) {
1911:
1912: LanguageConnectionContext lcc = getLanguageConnection();
1913:
1914: connString = this .getClass().getName()
1915: + "@"
1916: + this .hashCode()
1917: + " "
1918: + lcc.xidStr
1919: + lcc.getTransactionExecute()
1920: .getTransactionIdString() + "), "
1921: + lcc.lccStr
1922: + Integer.toString(lcc.getInstanceNumber()) + "), "
1923: + lcc.dbnameStr + lcc.getDbname() + "), "
1924: + lcc.drdaStr + lcc.getDrdaID() + ") ";
1925: }
1926:
1927: return connString;
1928: }
1929:
1930: }
|