/** * INTERNAL: Get a timestamp value from a result set. Overrides the default behavior to * specifically return a timestamp. Added to overcome an issue with the oracle 9.0.1.4 JDBC * driver. */ public Object getObjectFromResultSet( ResultSet resultSet, int columnNumber, int type, AbstractSession session) throws java.sql.SQLException { // Bug#3381652 10G Drivers return sql.Date instead of timestamp on DATE field if ((type == Types.TIMESTAMP) || (type == Types.DATE)) { return resultSet.getTimestamp(columnNumber); } else if (type == OracleTypes.TIMESTAMPTZ) { TIMESTAMPTZ tsTZ = (TIMESTAMPTZ) resultSet.getObject(columnNumber); // Need to call timestampValue once here with the connection to avoid null point // exception later when timestampValue is called in converObject() if ((tsTZ != null) && (tsTZ.getLength() != 0)) { Connection connection = getConnection(session, resultSet.getStatement().getConnection()); // Bug#4364359 Add a wrapper to overcome TIMESTAMPTZ not serializable as of jdbc 9.2.0.5 // and 10.1.0.2. // It has been fixed in the next version for both streams return new TIMESTAMPTZWrapper(tsTZ, connection, isTimestampInGmt(connection)); } return null; } else if (type == OracleTypes.TIMESTAMPLTZ) { // TIMESTAMPLTZ needs to be converted to Timestamp here because it requires the connection. // However the java object is not know here. The solution is to store Timestamp and the // session timezone in a wrapper class, which will be used later in converObject(). TIMESTAMPLTZ tsLTZ = (TIMESTAMPLTZ) resultSet.getObject(columnNumber); if ((tsLTZ != null) && (tsLTZ.getLength() != 0)) { Timestamp ts = TIMESTAMPLTZ.toTimestamp( getConnection(session, resultSet.getStatement().getConnection()), tsLTZ.toBytes()); // Bug#4364359 Add a separate wrapper for TIMESTAMPLTZ. return new TIMESTAMPLTZWrapper( ts, ((OracleConnection) getConnection(session, resultSet.getStatement().getConnection())) .getSessionTimeZone()); } return null; } else if (type == OracleTypes.OPAQUE) { try { Object result = resultSet.getObject(columnNumber); if (!(result instanceof OPAQUE)) { // Report Queries can cause result to not be an instance of OPAQUE. return result; } return getXMLTypeFactory().getString((OPAQUE) result); } catch (SQLException ex) { throw DatabaseException.sqlException(ex, null, session, false); } } else { Object value = super.getObjectFromResultSet(resultSet, columnNumber, type, session); if (type == OracleTypes_NCLOB) { value = convertObject(value, ClassConstants.STRING); } return value; } }
/** * INTERNAL: Execute the query building the objects directly from the database result-set. * * @exception DatabaseException - an error has occurred on the database * @return object - the first object found or null if none. */ protected Object executeObjectLevelReadQueryFromResultSet() throws DatabaseException { UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl) getSession(); DatabaseAccessor accessor = (DatabaseAccessor) unitOfWork.getAccessor(); DatabasePlatform platform = accessor.getPlatform(); DatabaseCall call = (DatabaseCall) getCall().clone(); call.setQuery(this); call.translate(this.translationRow, null, unitOfWork); Statement statement = null; ResultSet resultSet = null; boolean exceptionOccured = false; try { accessor.incrementCallCount(unitOfWork); statement = call.prepareStatement(accessor, this.translationRow, unitOfWork); resultSet = accessor.executeSelect(call, statement, unitOfWork); ResultSetMetaData metaData = resultSet.getMetaData(); Vector results = new Vector(); ObjectBuilder builder = this.descriptor.getObjectBuilder(); while (resultSet.next()) { results.add( builder.buildWorkingCopyCloneFromResultSet( this, this.joinedAttributeManager, resultSet, unitOfWork, accessor, metaData, platform)); } return results; } catch (SQLException exception) { exceptionOccured = true; DatabaseException commException = accessor.processExceptionForCommError(session, exception, call); if (commException != null) throw commException; throw DatabaseException.sqlException(exception, call, accessor, unitOfWork, false); } finally { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { accessor.releaseStatement(statement, call.getSQLString(), call, unitOfWork); } } catch (SQLException exception) { if (!exceptionOccured) { // in the case of an external connection pool the connection may be null after the // statement release // if it is null we will be unable to check the connection for a comm error and // therefore must return as if it was not a comm error. DatabaseException commException = accessor.processExceptionForCommError(session, exception, call); if (commException != null) throw commException; throw DatabaseException.sqlException(exception, call, accessor, session, false); } } } }
/** INTERNAL: Build a ADT structure from the row data. */ public Struct buildStructureFromRow( AbstractRecord row, AbstractSession session, java.sql.Connection connection) throws DatabaseException { Struct structure; boolean reconnected = false; try { if (connection == null) { ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session); reconnected = true; connection = ((DatabaseAccessor) session.getAccessor()).getConnection(); } Object[] fields = new Object[getOrderedFields().size()]; for (int index = 0; index < getOrderedFields().size(); index++) { DatabaseField field = (DatabaseField) getOrderedFields().elementAt(index); fields[index] = row.get(field); } structure = session.getPlatform().createStruct(getStructureName(), fields, session, connection); } catch (java.sql.SQLException exception) { throw DatabaseException.sqlException(exception, session, false); } finally { if (reconnected) { ((DatabaseAccessor) session.getAccessor()).decrementCallCount(); } } return structure; }
/** * INTERNAL: Return the value of the field from the row or a value holder on the query to obtain * the object. Check for batch + aggregation reading. */ public Object valueFromRow( AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, AbstractSession executionSession) throws DatabaseException { Ref ref = (Ref) row.get(getField()); if (ref == null) { return null; } Struct struct; try { ((DatabaseAccessor) executionSession.getAccessor()).incrementCallCount(executionSession); java.sql.Connection connection = ((DatabaseAccessor) executionSession.getAccessor()).getConnection(); struct = (Struct) executionSession.getPlatform().getRefValue(ref, executionSession, connection); } catch (java.sql.SQLException exception) { throw DatabaseException.sqlException(exception, executionSession, false); } AbstractRecord targetRow = ((ObjectRelationalDataTypeDescriptor) getReferenceDescriptor()) .buildRowFromStructure(struct); ((DatabaseAccessor) executionSession.getAccessor()).decrementCallCount(); return getReferenceDescriptor().getObjectBuilder().buildObject(query, targetRow, joinManager); }
/** * INTERNAL: Build and return the appropriate field value for the specified set of nested rows. * The database better be expecting an ARRAY. It looks like we can ignore inheritance here.... */ public Object buildFieldValueFromNestedRows( Vector nestedRows, String structureName, AbstractSession session) throws DatabaseException { Object[] fields = new Object[nestedRows.size()]; java.sql.Connection connection = ((DatabaseAccessor) session.getAccessor()).getConnection(); boolean reconnected = false; try { if (connection == null) { ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session); reconnected = true; connection = ((DatabaseAccessor) session.getAccessor()).getConnection(); } int i = 0; for (Enumeration stream = nestedRows.elements(); stream.hasMoreElements(); ) { AbstractRecord nestedRow = (AbstractRecord) stream.nextElement(); fields[i++] = this.buildStructureFromRow(nestedRow, session, connection); } return session.getPlatform().createArray(structureName, fields, session, connection); } catch (java.sql.SQLException exception) { throw DatabaseException.sqlException(exception, session, false); } finally { if (reconnected) { ((DatabaseAccessor) session.getAccessor()).decrementCallCount(); } } }
/** * INTERNAL: Build the appropriate field value for the specified set of direct values. The * database better be expecting an ARRAY. */ public Object buildFieldValueFromDirectValues( Vector directValues, String elementDataTypeName, AbstractSession session) throws DatabaseException { Object[] fields = Helper.arrayFromVector(directValues); try { ((DatabaseAccessor) session.getAccessor()).incrementCallCount(session); java.sql.Connection connection = ((DatabaseAccessor) session.getAccessor()).getConnection(); return session.getPlatform().createArray(elementDataTypeName, fields, session, connection); } catch (java.sql.SQLException ex) { throw DatabaseException.sqlException(ex, session, false); } finally { ((DatabaseAccessor) session.getAccessor()).decrementCallCount(); } }
/** * INTERNAL: Build a row representation from the ADT structure field array. TopLink will then * build the object from the row. */ public AbstractRecord buildRowFromStructure(Struct structure) throws DatabaseException { Object[] attributes; try { attributes = structure.getAttributes(); } catch (java.sql.SQLException exception) { throw DatabaseException.sqlException(exception); } if (attributes != null) { for (int i = 0; i < attributes.length; i++) { if (attributes[i] instanceof Array) { attributes[i] = ObjectRelationalDataTypeDescriptor.buildArrayObjectFromArray(attributes[i]); } else if (attributes[i] instanceof Struct) { attributes[i] = ObjectRelationalDataTypeDescriptor.buildArrayObjectFromStruct(attributes[i]); } } } return buildNestedRowFromFieldValue(attributes); }
/** INTERNAL: Build array of objects for Struct data type. */ public static Object buildArrayObjectFromStruct(Object structure) throws DatabaseException { Object[] attributes = null; if (structure == null) { return structure; } try { attributes = ((Struct) structure).getAttributes(); } catch (java.sql.SQLException exception) { throw DatabaseException.sqlException(exception); } if (attributes == null) { return null; } else { for (int i = 0; i < attributes.length; i++) { if (attributes[i] instanceof Array) { attributes[i] = buildArrayObjectFromArray(attributes[i]); } if (attributes[i] instanceof Struct) { attributes[i] = buildArrayObjectFromStruct(attributes[i]); } } } return attributes; }
/** INTERNAL: Build array of objects for Array data type. */ public static Object buildArrayObjectFromArray(Object array) throws DatabaseException { Object[] objects = null; if (array == null) { return array; } try { objects = (Object[]) ((Array) array).getArray(); } catch (java.sql.SQLException ex) { throw DatabaseException.sqlException(ex); } if (objects == null) { return null; } else { for (int i = 0; i < objects.length; i++) { if (objects[i] instanceof Array) { objects[i] = buildArrayObjectFromArray(objects[i]); } if (objects[i] instanceof Struct) { objects[i] = buildArrayObjectFromStruct(objects[i]); } } } return objects; }
/** INTERNAL: Allow for conversion from the Oracle type to the Java type. */ public Object convertObject(Object sourceObject, Class javaClass) throws ConversionException, DatabaseException { if ((javaClass == null) || ((sourceObject != null) && (sourceObject.getClass() == javaClass))) { return sourceObject; } Object valueToConvert = sourceObject; // Used in Type Conversion Mapping on write if ((javaClass == TIMESTAMPTypes.TIMESTAMP_CLASS) || (javaClass == TIMESTAMPTypes.TIMESTAMPLTZ_CLASS)) { return sourceObject; } if (javaClass == TIMESTAMPTypes.TIMESTAMPTZ_CLASS) { if (sourceObject instanceof java.util.Date) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(((java.util.Date) sourceObject).getTime()); return cal; } else { return sourceObject; } } if (javaClass == XMLTYPE) { // Don't convert to XMLTypes. This will be done by the // XMLTypeBindCallCustomParameter to ensure the correct // Connection is used return sourceObject; } // Added to overcome an issue with the oracle 9.0.1.1.0 JDBC driver. if (sourceObject instanceof TIMESTAMP) { try { valueToConvert = ((TIMESTAMP) sourceObject).timestampValue(); } catch (SQLException exception) { throw DatabaseException.sqlException(exception); } } else if (sourceObject instanceof TIMESTAMPTZWrapper) { // Bug#4364359 Used when database type is TIMESTAMPTZ. Timestamp and session timezone are // wrapped // in TIMESTAMPTZWrapper. Separate Calendar from any other types. if (((javaClass == ClassConstants.CALENDAR) || (javaClass == ClassConstants.GREGORIAN_CALENDAR))) { try { return TIMESTAMPHelper.buildCalendar((TIMESTAMPTZWrapper) sourceObject); } catch (SQLException exception) { throw DatabaseException.sqlException(exception); } } else { // If not using native sql, Calendar will be converted to Timestamp just as // other date time types valueToConvert = ((TIMESTAMPTZWrapper) sourceObject).getTimestamp(); } } else if (sourceObject instanceof TIMESTAMPLTZWrapper) { // Bug#4364359 Used when database type is TIMESTAMPLTZ. Timestamp and session timezone id are // wrapped // in TIMESTAMPLTZWrapper. Separate Calendar from any other types. if (((javaClass == ClassConstants.CALENDAR) || (javaClass == ClassConstants.GREGORIAN_CALENDAR))) { try { return TIMESTAMPHelper.buildCalendar((TIMESTAMPLTZWrapper) sourceObject); } catch (SQLException exception) { throw DatabaseException.sqlException(exception); } } else { // If not using native sql, Calendar will be converted to Timestamp just as // other date time types valueToConvert = ((TIMESTAMPLTZWrapper) sourceObject).getTimestamp(); } } return super.convertObject(valueToConvert, javaClass); }
/** * INTERNAL: Applies customization to connection. Called only if connection is not already * customized (isActive()==false). The method may throw SQLException wrapped into * DatabaseException. isActive method called after this method should return true only in case the * connection was actually customized. */ public void customize() { // Lazily initialize proxy properties - customize method may be never called // in case of ClientSession using external connection pooling. if (proxyProperties == null) { buildProxyProperties(); } Connection connection = accessor.getConnection(); if (connection instanceof OracleConnection) { oracleConnection = (OracleConnection) connection; } else { connection = session.getServerPlatform().unwrapConnection(connection); if (connection instanceof OracleConnection) { oracleConnection = (OracleConnection) connection; } else { throw ValidationException.oracleJDBC10_1_0_2ProxyConnectorRequiresOracleConnection(); } } try { clearConnectionCache(); Object[] args = null; if (this.session.shouldLog(SessionLog.FINEST, SessionLog.CONNECTION)) { Properties logProperties = proxyProperties; if (proxyProperties.containsKey(OracleConnection.PROXY_USER_PASSWORD)) { logProperties = (Properties) proxyProperties.clone(); logProperties.setProperty(OracleConnection.PROXY_USER_PASSWORD, "******"); } args = new Object[] {oracleConnection, logProperties}; } if (oracleConnection.isProxySession()) { // Unexpectedly oracleConnection already has a proxy session - probably it was not closed // when connection was returned back to connection pool. // That may happen on jta transaction rollback (especially triggered outside of user's // thread - such as timeout) // when beforeCompletion is never issued // and application server neither closes proxySession nor allows access to connection in // afterCompletion. try { if (args != null) { ((AbstractSession) this.session) .log( SessionLog.FINEST, SessionLog.CONNECTION, "proxy_connection_customizer_already_proxy_session", args); } oracleConnection.close(OracleConnection.PROXY_SESSION); } catch (SQLException exception) { // Ignore this.session .getSessionLog() .logThrowable(SessionLog.WARNING, SessionLog.CONNECTION, exception); } } oracleConnection.openProxySession(proxyType, proxyProperties); // 12c driver will default to an autoCommit setting of true on calling openProxySession oracleConnection.setAutoCommit(false); if (args != null) { ((AbstractSession) this.session) .log( SessionLog.FINEST, SessionLog.CONNECTION, "proxy_connection_customizer_opened_proxy_session", args); } } catch (SQLException exception) { oracleConnection = null; throw DatabaseException.sqlException(exception); } catch (NoSuchMethodError noSuchMethodError) { oracleConnection = null; throw ValidationException.oracleJDBC10_1_0_2ProxyConnectorRequiresOracleConnectionVersion(); } }
/** * INTERNAL: Build and return the nested rows from the specified field value. This method allows * the field value to be an ARRAY containing other structures such as arrays or Struct, or direct * values. */ public static Object buildContainerFromArray( Array fieldValue, ObjectRelationalDatabaseField arrayField, AbstractSession session) throws DatabaseException { if (arrayField.getType() == null) { return fieldValue; } Object[] objects = null; try { objects = (Object[]) fieldValue.getArray(); } catch (java.sql.SQLException ex) { throw DatabaseException.sqlException(ex, session, false); } if (objects == null) { return null; } boolean isNestedStructure = false; ObjectRelationalDataTypeDescriptor ord = null; DatabaseField nestedType = null; if (arrayField != null) { nestedType = arrayField.getNestedTypeField(); if ((nestedType != null) && nestedType.getSqlType() == Types.STRUCT) { ClassDescriptor descriptor = session.getDescriptor(nestedType.getType()); if ((descriptor != null) && (descriptor.isObjectRelationalDataTypeDescriptor())) { // this is used to convert non-null objects passed through stored procedures and custom // SQL to structs ord = (ObjectRelationalDataTypeDescriptor) descriptor; } } else if ((nestedType != null) && (nestedType instanceof ObjectRelationalDatabaseField)) { isNestedStructure = true; } } // handle ARRAY conversions ReadObjectQuery query = new ReadObjectQuery(); query.setSession(session); ContainerPolicy cp = ContainerPolicy.buildPolicyFor(arrayField.getType()); Object container = cp.containerInstance(objects.length); for (int i = 0; i < objects.length; i++) { Object arrayValue = objects[i]; if (arrayValue == null) { return null; } if (ord != null) { AbstractRecord nestedRow = ord.buildRowFromStructure((Struct) arrayValue); ClassDescriptor descriptor = ord; if (descriptor.hasInheritance()) { Class newElementClass = descriptor.getInheritancePolicy().classFromRow(nestedRow, session); if (!descriptor.getJavaClass().equals(newElementClass)) { descriptor = session.getDescriptor(newElementClass); if (descriptor == null) { descriptor = ord; } } } arrayValue = descriptor.getObjectBuilder().buildNewInstance(); descriptor .getObjectBuilder() .buildAttributesIntoObject(arrayValue, nestedRow, query, null, false); } else if (isNestedStructure && (arrayValue instanceof Array)) { arrayValue = buildContainerFromArray( (Array) arrayValue, (ObjectRelationalDatabaseField) nestedType, session); } cp.addInto(arrayValue, container, session); } return container; }