| /* |
| * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2015, 2021 IBM Corporation. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // 03/19/2015 - Rick Curtis |
| // - 462586 : Add national character support for z/OS. |
| package org.eclipse.persistence.platform.database; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.CharArrayReader; |
| import java.io.StringWriter; |
| import java.lang.reflect.Method; |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.sql.CallableStatement; |
| import java.sql.SQLException; |
| import java.util.Calendar; |
| import java.util.Hashtable; |
| |
| import org.eclipse.persistence.internal.databaseaccess.BindCallCustomParameter; |
| import org.eclipse.persistence.internal.databaseaccess.DatasourceCall; |
| import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.internal.helper.DatabaseField; |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedClassForName; |
| import org.eclipse.persistence.internal.security.PrivilegedGetContextClassLoader; |
| import org.eclipse.persistence.internal.security.PrivilegedGetMethod; |
| import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.logging.AbstractSessionLog; |
| import org.eclipse.persistence.logging.SessionLog; |
| import org.eclipse.persistence.mappings.structures.ObjectRelationalDatabaseField; |
| import org.eclipse.persistence.platform.database.converters.StructConverter; |
| import org.eclipse.persistence.queries.StoredProcedureCall; |
| |
| /** |
| * <b>Purpose</b>: Provides DB2 z/OS specific behavior. |
| * <p> |
| * This provides for some additional compatibility in certain DB2 versions. |
| * <p> |
| * <b>Responsibilities</b>: |
| * <ul> |
| * <li>Support creating tables that handle multibyte characters |
| * </ul> |
| */ |
| public class DB2ZPlatform extends DB2Platform { |
| private static String DB2_CALLABLESTATEMENT_CLASS = "com.ibm.db2.jcc.DB2CallableStatement"; |
| private static String DB2_PREPAREDSTATEMENT_CLASS = "com.ibm.db2.jcc.DB2PreparedStatement"; |
| |
| public DB2ZPlatform() { |
| super(); |
| this.pingSQL = "SELECT COUNT(*) from SYSIBM.SYSDUMMY1 WHERE 1 = 0"; |
| } |
| |
| @Override |
| protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() { |
| Hashtable<Class<?>, FieldTypeDefinition> res = super.buildFieldTypes(); |
| if (getUseNationalCharacterVaryingTypeForString()) { |
| res.put(String.class, new FieldTypeDefinition("VARCHAR", DEFAULT_VARCHAR_SIZE)); |
| } |
| return res; |
| } |
| |
| @Override |
| public String getTableCreationSuffix() { |
| // If we're on Z and using unicode support we need to append CCSID |
| // UNICODE on the table rather than FOR MIXED DATA on each column |
| if (getUseNationalCharacterVaryingTypeForString()) { |
| return " CCSID UNICODE"; |
| } |
| return super.getTableCreationSuffix(); |
| } |
| |
| @Override |
| public String getProcedureArgument(String name, Object parameter, Integer parameterType, |
| StoredProcedureCall call, AbstractSession session) { |
| if (name != null && shouldPrintStoredProcedureArgumentNameInCall()) { |
| return ":" + name; |
| } |
| return "?"; |
| } |
| |
| /** |
| * DB2 on Z uses ":" as prefix for procedure arguments. |
| */ |
| @Override |
| public String getProcedureOptionList() { |
| return " DISABLE DEBUG MODE "; |
| } |
| |
| @Override |
| public boolean isDB2Z() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: Used for sp calls. PostGreSQL uses a different method for executing StoredProcedures than other platforms. |
| */ |
| @Override |
| public String buildProcedureCallString(StoredProcedureCall call, AbstractSession session, AbstractRecord row) { |
| StringWriter writer = new StringWriter(); |
| writer.write(call.getCallHeader(this)); |
| writer.write(call.getProcedureName()); |
| if (requiresProcedureCallBrackets()) { |
| writer.write("("); |
| } else { |
| writer.write(" "); |
| } |
| |
| int indexFirst = call.getFirstParameterIndexForCallString(); |
| int size = call.getParameters().size(); |
| for (int index = indexFirst; index < size; index++) { |
| String name = call.getProcedureArgumentNames().get(index); |
| Object parameter = call.getParameters().get(index); |
| Integer parameterType = call.getParameterTypes().get(index); |
| // If the argument is optional and null, ignore it. |
| if (!call.hasOptionalArguments() || !call.getOptionalArguments().contains(parameter) || (row.get(parameter) != null)) { |
| |
| writer.write(getProcedureArgument(name, parameter, parameterType, call, session)); |
| |
| if (DatasourceCall.isOutputParameterType(parameterType) && requiresProcedureCallOuputToken()) { |
| writer.write(" "); |
| writer.write(getOutputProcedureToken()); |
| } |
| if ((index + 1) < call.getParameters().size()) { |
| writer.write(", "); |
| } |
| } |
| } |
| |
| if (requiresProcedureCallBrackets()) { |
| writer.write(")"); |
| } |
| writer.write(getProcedureCallTail()); |
| |
| return writer.toString(); |
| } |
| |
| /** |
| * This method is used to register output parameter on Callable Statements for Stored Procedures |
| * as each database seems to have a different method. |
| */ |
| @Override |
| public void registerOutputParameter(CallableStatement statement, String name, int jdbcType) throws SQLException { |
| try { |
| Class<?> clazz; |
| Method method; |
| String methodName = "registerJccOutParameterAtName"; |
| Class<?>[] methodArgs = new Class<?>[] {String.class, int.class}; |
| Object[] parameters = new Object[] {name, jdbcType}; |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| ClassLoader cl = AccessController.doPrivileged(new PrivilegedGetContextClassLoader(Thread.currentThread())); |
| clazz = AccessController.doPrivileged(new PrivilegedClassForName<>(DB2_CALLABLESTATEMENT_CLASS, true, cl)); |
| method = AccessController.doPrivileged(new PrivilegedGetMethod(clazz, methodName, methodArgs, true)); |
| Object o = statement.unwrap(clazz); |
| AccessController.doPrivileged(new PrivilegedMethodInvoker<>(method, o, parameters)); |
| } catch (PrivilegedActionException ex) { |
| if (ex.getCause() instanceof ClassNotFoundException) { |
| throw (ClassNotFoundException) ex.getCause(); |
| } |
| throw (RuntimeException) ex.getCause(); |
| } |
| } else { |
| ClassLoader cl = PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread()); |
| clazz = PrivilegedAccessHelper.getClassForName(DB2_CALLABLESTATEMENT_CLASS, true, cl); |
| method = PrivilegedAccessHelper.getMethod(clazz, methodName, methodArgs, true); |
| Object o = statement.unwrap(clazz); |
| PrivilegedAccessHelper.invokeMethod(method, o, parameters); |
| } |
| } catch (ReflectiveOperationException e) { |
| AbstractSessionLog.getLog().logThrowable(SessionLog.WARNING, null, e); |
| //Didn't work, fall back. This most likely still won't work, but the driver exception from there will be helpful. |
| super.registerOutputParameter(statement, name, jdbcType); |
| } |
| } |
| |
| /** |
| * This method is used to register output parameter on Callable Statements for Stored Procedures |
| * as each database seems to have a different method. |
| */ |
| @Override |
| public void registerOutputParameter(CallableStatement statement, String name, int jdbcType, String typeName) throws SQLException { |
| try { |
| Class<?> clazz; |
| Method method; |
| String methodName = "registerJccOutParameterAtName"; |
| Class<?>[] methodArgs = new Class<?>[] {String.class, int.class, String.class}; |
| Object[] parameters = new Object[] {name, jdbcType, typeName}; |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| ClassLoader cl = AccessController.doPrivileged(new PrivilegedGetContextClassLoader(Thread.currentThread())); |
| clazz = AccessController.doPrivileged(new PrivilegedClassForName<>(DB2_CALLABLESTATEMENT_CLASS, true, cl)); |
| method = AccessController.doPrivileged(new PrivilegedGetMethod(clazz, methodName, methodArgs, true)); |
| Object o = statement.unwrap(clazz); |
| AccessController.doPrivileged(new PrivilegedMethodInvoker<>(method, o, parameters)); |
| } catch (PrivilegedActionException ex) { |
| if (ex.getCause() instanceof ClassNotFoundException) { |
| throw (ClassNotFoundException) ex.getCause(); |
| } |
| throw (RuntimeException) ex.getCause(); |
| } |
| } else { |
| ClassLoader cl = PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread()); |
| clazz = PrivilegedAccessHelper.getClassForName(DB2_CALLABLESTATEMENT_CLASS, true, cl); |
| method = PrivilegedAccessHelper.getMethod(clazz, methodName, methodArgs, true); |
| Object o = statement.unwrap(clazz); |
| PrivilegedAccessHelper.invokeMethod(method, o, parameters); |
| } |
| } catch (ReflectiveOperationException e) { |
| AbstractSessionLog.getLog().logThrowable(SessionLog.WARNING, null, e); |
| //Didn't work, fall back. This most likely still won't work, but the driver exception from there will be helpful. |
| super.registerOutputParameter(statement, name, jdbcType, typeName); |
| } |
| } |
| |
| @Override |
| @SuppressWarnings({"rawtypes"}) |
| public void setParameterValueInDatabaseCall(Object parameter, |
| CallableStatement statement, String name, AbstractSession session) |
| throws SQLException { |
| |
| String methodName = null; |
| Class<?>[] methodArgs = null; |
| Object[] parameters = null; |
| |
| // Process common types first. |
| if (parameter instanceof String) { |
| // Check for stream binding of large strings. |
| if (usesStringBinding() && (((String)parameter).length() > getStringBindingSize())) { |
| CharArrayReader reader = new CharArrayReader(((String)parameter).toCharArray()); |
| methodName = "setJccCharacterStreamAtName"; |
| methodArgs = new Class<?>[] {String.class, java.io.Reader.class, int.class}; |
| parameters = new Object[] {name, reader, ((String)parameter).length()}; |
| } else { |
| //TODO find shouldUseGetSetNString() support for DB2/Z |
| methodName = "setJccStringAtName"; |
| methodArgs = new Class<?>[] {String.class, String.class}; |
| parameters = new Object[] {name, parameter}; |
| } |
| } else if (parameter instanceof Number) { |
| Number number = (Number) parameter; |
| if (number instanceof Integer) { |
| methodName = "setJccIntAtName"; |
| methodArgs = new Class<?>[] {String.class, int.class}; |
| parameters = new Object[] {name, number.intValue()}; |
| } else if (number instanceof Long) { |
| methodName = "setJccLongAtName"; |
| methodArgs = new Class<?>[] {String.class, long.class}; |
| parameters = new Object[] {name, number.longValue()}; |
| } else if (number instanceof BigDecimal) { |
| methodName = "setJccBigDecimalAtName"; |
| methodArgs = new Class<?>[] {String.class, BigDecimal.class}; |
| parameters = new Object[] {name, number}; |
| } else if (number instanceof Double) { |
| methodName = "setJccDoubleAtName"; |
| methodArgs = new Class<?>[] {String.class, double.class}; |
| parameters = new Object[] {name, number.doubleValue()}; |
| } else if (number instanceof Float) { |
| methodName = "setJccFloatAtName"; |
| methodArgs = new Class<?>[] {String.class, float.class}; |
| parameters = new Object[] {name, number.floatValue()}; |
| } else if (number instanceof Short) { |
| methodName = "setJccShortAtName"; |
| methodArgs = new Class<?>[] {String.class, short.class}; |
| parameters = new Object[] {name, number.shortValue()}; |
| } else if (number instanceof Byte) { |
| methodName = "setJccByteAtName"; |
| methodArgs = new Class<?>[] {String.class, byte.class}; |
| parameters = new Object[] {name, number.byteValue()}; |
| } else if (number instanceof BigInteger) { |
| // Convert to BigDecimal. |
| methodName = "setJccBigDecimalAtName"; |
| methodArgs = new Class<?>[] {String.class, BigDecimal.class}; |
| parameters = new Object[] {name, new BigDecimal((BigInteger) number)}; |
| } else { |
| methodName = "setJccObjectAtName"; |
| methodArgs = new Class<?>[] {String.class, Object.class}; |
| parameters = new Object[] {name, parameter}; |
| } |
| } else if (parameter instanceof java.sql.Date){ |
| methodName = "setJccDateAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Date.class}; |
| parameters = new Object[] {name, parameter}; |
| } else if (parameter instanceof java.time.LocalDate){ |
| // Convert to java.sql.Date |
| methodName = "setJccDateAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Date.class}; |
| parameters = new Object[] {name, java.sql.Date.valueOf((java.time.LocalDate) parameter)}; |
| } else if (parameter instanceof java.sql.Timestamp){ |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, parameter}; |
| } else if (parameter instanceof java.time.LocalDateTime){ |
| // Convert to java.sql.Timestamp |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, java.sql.Timestamp.valueOf((java.time.LocalDateTime) parameter)}; |
| } else if (parameter instanceof java.time.OffsetDateTime) { |
| // Convert to java.sql.Timestamp |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, java.sql.Timestamp.from(((java.time.OffsetDateTime) parameter).toInstant())}; |
| } else if (parameter instanceof java.sql.Time){ |
| methodName = "setJccTimeAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Time.class}; |
| parameters = new Object[] {name, parameter}; |
| } else if (parameter instanceof java.time.LocalTime){ |
| java.time.LocalTime lt = (java.time.LocalTime) parameter; |
| java.sql.Timestamp ts = java.sql.Timestamp.valueOf(java.time.LocalDateTime.of(java.time.LocalDate.ofEpochDay(0), lt)); |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, ts}; |
| } else if (parameter instanceof java.time.OffsetTime) { |
| java.time.OffsetTime ot = (java.time.OffsetTime) parameter; |
| java.sql.Timestamp ts = java.sql.Timestamp.valueOf(java.time.LocalDateTime.of(java.time.LocalDate.ofEpochDay(0), ot.toLocalTime())); |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, ts}; |
| } else if (parameter instanceof Boolean) { |
| methodName = "setJccBooleanAtName"; |
| methodArgs = new Class<?>[] {String.class, boolean.class}; |
| parameters = new Object[] {name, parameter}; |
| } else if (parameter == null) { |
| // Normally null is passed as a DatabaseField so the type is included, but in some case may be passed directly. |
| methodName = "setJccNullAtName"; |
| methodArgs = new Class<?>[] {String.class, int.class}; |
| parameters = new Object[] {name, getJDBCType((Class)null)}; |
| } else if (parameter instanceof DatabaseField) { |
| setNullFromDatabaseField((DatabaseField)parameter, statement, name); |
| } else if (parameter instanceof byte[]) { |
| if (usesStreamsForBinding()) { |
| ByteArrayInputStream inputStream = new ByteArrayInputStream((byte[])parameter); |
| methodName = "setJccBinaryStreamAtName"; |
| methodArgs = new Class<?>[] {String.class, java.io.InputStream.class, int.class}; |
| parameters = new Object[] {name, inputStream, ((byte[])parameter).length}; |
| } else { |
| methodName = "setJccBytesAtName"; |
| methodArgs = new Class<?>[] {String.class, byte[].class}; |
| parameters = new Object[] {name, parameter}; |
| } |
| } |
| // Next process types that need conversion. |
| else if (parameter instanceof Calendar) { |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, Helper.timestampFromDate(((Calendar)parameter).getTime())}; |
| } else if (parameter.getClass() == ClassConstants.UTILDATE) { |
| methodName = "setJccTimestampAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.Timestamp.class}; |
| parameters = new Object[] {name, Helper.timestampFromDate((java.util.Date) parameter)}; |
| } else if (parameter instanceof Character) { |
| methodName = "setJccStringAtName"; |
| methodArgs = new Class<?>[] {String.class, String.class}; |
| parameters = new Object[] {name, ((Character)parameter).toString()}; |
| } else if (parameter instanceof char[]) { |
| methodName = "setJccStringAtName"; |
| methodArgs = new Class<?>[] {String.class, String.class}; |
| parameters = new Object[] {name, new String((char[])parameter)}; |
| } else if (parameter instanceof Character[]) { |
| methodName = "setJccStringAtName"; |
| methodArgs = new Class<?>[] {String.class, String.class}; |
| parameters = new Object[] {name, convertObject(parameter, ClassConstants.STRING)}; |
| } else if (parameter instanceof Byte[]) { |
| methodName = "setJccBytesAtName"; |
| methodArgs = new Class<?>[] {String.class, byte[].class}; |
| parameters = new Object[] {name, convertObject(parameter, ClassConstants.APBYTE)}; |
| } else if (parameter instanceof java.sql.SQLXML) { |
| methodName = "setJccSQLXMLAtName"; |
| methodArgs = new Class<?>[] {String.class, java.sql.SQLXML.class}; |
| parameters = new Object[] {name, parameter}; |
| } else if (parameter instanceof BindCallCustomParameter) { |
| ((BindCallCustomParameter)(parameter)).set(this, statement, name, session); |
| } else if (typeConverters != null && typeConverters.containsKey(parameter.getClass())){ |
| StructConverter converter = typeConverters.get(parameter.getClass()); |
| java.sql.Struct struct = converter.convertToStruct(parameter, getConnection(session, statement.getConnection())); |
| methodName = "setJccObjectAtName"; |
| methodArgs = new Class<?>[] {String.class, Object.class}; |
| parameters = new Object[] {name, struct}; |
| } else { |
| methodName = "setJccObjectAtName"; |
| methodArgs = new Class<?>[] {String.class, Object.class}; |
| parameters = new Object[] {name, parameter}; |
| } |
| |
| if(methodName != null) { |
| try { |
| Class<?> clazz; |
| Method method; |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| ClassLoader cl = AccessController.doPrivileged(new PrivilegedGetContextClassLoader(Thread.currentThread())); |
| clazz = AccessController.doPrivileged(new PrivilegedClassForName<>(DB2_PREPAREDSTATEMENT_CLASS, true, cl)); |
| method = AccessController.doPrivileged(new PrivilegedGetMethod(clazz, methodName, methodArgs, true)); |
| Object o = statement.unwrap(clazz); |
| AccessController.doPrivileged(new PrivilegedMethodInvoker<>(method, o, parameters)); |
| } catch (PrivilegedActionException ex) { |
| if (ex.getCause() instanceof ClassNotFoundException) { |
| throw (ClassNotFoundException) ex.getCause(); |
| } |
| throw (RuntimeException) ex.getCause(); |
| } |
| } else { |
| ClassLoader cl = PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread()); |
| clazz = PrivilegedAccessHelper.getClassForName(DB2_PREPAREDSTATEMENT_CLASS, true, cl); |
| method = PrivilegedAccessHelper.getMethod(clazz, methodName, methodArgs, true); |
| Object o = statement.unwrap(clazz); |
| PrivilegedAccessHelper.invokeMethod(method, o, parameters); |
| } |
| } catch (ReflectiveOperationException e) { |
| AbstractSessionLog.getLog().logThrowable(SessionLog.WARNING, null, e); |
| //Didn't work, fall back. This most likely still won't work, but the driver exception from there will be helpful. |
| super.setParameterValueInDatabaseCall(parameter, statement, name, session); |
| } |
| } |
| } |
| |
| @Override |
| protected void setNullFromDatabaseField(DatabaseField databaseField, CallableStatement statement, String name) throws SQLException { |
| String methodName; |
| Class<?>[] methodArgs; |
| Object[] parameters; |
| if (databaseField instanceof ObjectRelationalDatabaseField) { |
| ObjectRelationalDatabaseField field = (ObjectRelationalDatabaseField)databaseField; |
| methodName = "setJccNullAtName"; |
| methodArgs = new Class<?>[] {String.class, int.class, String.class}; |
| parameters = new Object[] {name, field.getSqlType(), field.getSqlTypeName()}; |
| } else { |
| int jdbcType = getJDBCTypeForSetNull(databaseField); |
| methodName = "setJccNullAtName"; |
| methodArgs = new Class<?>[] {String.class, int.class}; |
| parameters = new Object[] {name, jdbcType}; |
| } |
| |
| try { |
| Class<?> clazz; |
| Method method; |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| ClassLoader cl = AccessController.doPrivileged(new PrivilegedGetContextClassLoader(Thread.currentThread())); |
| clazz = AccessController.doPrivileged(new PrivilegedClassForName<>(DB2_PREPAREDSTATEMENT_CLASS, true, cl)); |
| method = AccessController.doPrivileged(new PrivilegedGetMethod(clazz, methodName, methodArgs, true)); |
| Object o = statement.unwrap(clazz); |
| AccessController.doPrivileged(new PrivilegedMethodInvoker<>(method, o, parameters)); |
| } catch (PrivilegedActionException ex) { |
| if (ex.getCause() instanceof ClassNotFoundException) { |
| throw (ClassNotFoundException) ex.getCause(); |
| } |
| throw (RuntimeException) ex.getCause(); |
| } |
| } else { |
| ClassLoader cl = PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread()); |
| clazz = PrivilegedAccessHelper.getClassForName(DB2_PREPAREDSTATEMENT_CLASS, true, cl); |
| method = PrivilegedAccessHelper.getMethod(clazz, methodName, methodArgs, true); |
| Object o = statement.unwrap(clazz); |
| PrivilegedAccessHelper.invokeMethod(method, o, parameters); |
| } |
| } catch (ReflectiveOperationException e) { |
| AbstractSessionLog.getLog().logThrowable(SessionLog.WARNING, null, e); |
| //Didn't work, fall back. This most likely still won't work, but the driver exception from there will be helpful. |
| super.setNullFromDatabaseField(databaseField, statement, name); |
| } |
| } |
| |
| @Override |
| public Object getParameterValueFromDatabaseCall(CallableStatement statement, String name, AbstractSession session) |
| throws SQLException { |
| String methodName; |
| Class<?>[] methodArgs; |
| Object[] parameters; |
| |
| methodName = "getJccObjectAtName"; |
| methodArgs = new Class<?>[] {String.class}; |
| parameters = new Object[] {name}; |
| |
| try { |
| Class<?> clazz; |
| Method method; |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| try { |
| ClassLoader cl = AccessController.doPrivileged(new PrivilegedGetContextClassLoader(Thread.currentThread())); |
| clazz = AccessController.doPrivileged(new PrivilegedClassForName<>(DB2_CALLABLESTATEMENT_CLASS, true, cl)); |
| method = AccessController.doPrivileged(new PrivilegedGetMethod(clazz, methodName, methodArgs, true)); |
| Object o = statement.unwrap(clazz); |
| return AccessController.doPrivileged(new PrivilegedMethodInvoker<>(method, o, parameters)); |
| } catch (PrivilegedActionException ex) { |
| if (ex.getCause() instanceof ClassNotFoundException) { |
| throw (ClassNotFoundException) ex.getCause(); |
| } |
| throw (RuntimeException) ex.getCause(); |
| } |
| } else { |
| ClassLoader cl = PrivilegedAccessHelper.getContextClassLoader(Thread.currentThread()); |
| clazz = PrivilegedAccessHelper.getClassForName(DB2_CALLABLESTATEMENT_CLASS, true, cl); |
| method = PrivilegedAccessHelper.getMethod(clazz, methodName, methodArgs, true); |
| Object o = statement.unwrap(clazz); |
| return PrivilegedAccessHelper.invokeMethod(method, o, parameters); |
| } |
| } catch (ReflectiveOperationException e) { |
| AbstractSessionLog.getLog().logThrowable(SessionLog.WARNING, null, e); |
| } |
| //Didn't work, fall back. This most likely still won't work, but the driver exception from there will be helpful. |
| return super.getParameterValueFromDatabaseCall(statement, name, session); |
| } |
| } |