| /* |
| |
| Derby - Class org.apache.derby.impl.sql.GenericParameterValueSet |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| */ |
| |
| package org.apache.derby.impl.sql; |
| |
| import org.apache.derby.iapi.error.StandardException; |
| import org.apache.derby.iapi.services.loader.ClassInspector; |
| import org.apache.derby.shared.common.sanity.SanityManager; |
| import org.apache.derby.iapi.reference.SQLState; |
| import org.apache.derby.iapi.sql.ParameterValueSet; |
| import org.apache.derby.iapi.types.DataTypeDescriptor; |
| import org.apache.derby.iapi.types.DataValueDescriptor; |
| import org.apache.derby.iapi.types.UserDataValue; |
| import org.apache.derby.impl.jdbc.Util; |
| |
| import java.io.InputStream; |
| import java.sql.ParameterMetaData; |
| import java.sql.Types; |
| |
| /** |
| * Implementation of ParameterValueSet |
| * |
| * @see ParameterValueSet |
| * |
| */ |
| |
| final class GenericParameterValueSet implements ParameterValueSet |
| { |
| //all this has to be copied in the clone constructor |
| private final GenericParameter[] parms; |
| final ClassInspector ci; |
| private final boolean hasReturnOutputParam; |
| |
| |
| /** |
| * Constructor for a GenericParameterValueSet |
| * |
| * @param numParms The number of parameters in the new ParameterValueSet |
| * @param hasReturnOutputParam if we have a ? = call syntax. Note that |
| * this is NOT the same thing as an output parameter -- return |
| * output parameters are special cases of output parameters. |
| */ |
| GenericParameterValueSet(ClassInspector ci, int numParms, boolean hasReturnOutputParam) |
| { |
| this.ci = ci; |
| this.hasReturnOutputParam = hasReturnOutputParam; |
| parms = new GenericParameter[numParms]; |
| for (int i = 0; i < numParms; i++) |
| { |
| /* |
| ** Last param is if this is a return output param. True if |
| ** we have an output param and we are on the 1st parameter. |
| */ |
| parms[i] = new GenericParameter(this, (hasReturnOutputParam && i == 0)); |
| } |
| } |
| |
| /* |
| ** Construct a pvs by cloning a pvs. |
| */ |
| private GenericParameterValueSet(int numParms, GenericParameterValueSet pvs) |
| { |
| this.hasReturnOutputParam = pvs.hasReturnOutputParam; |
| this.ci = pvs.ci; |
| parms = new GenericParameter[numParms]; |
| for (int i = 0; i < numParms; i++) |
| { |
| parms[i] = pvs.getGenericParameter(i).getClone(this); |
| } |
| } |
| |
| /* |
| ** ParameterValueSet interface methods |
| */ |
| |
| /** |
| * Initialize the set by allocating a holder DataValueDescriptor object |
| * for each parameter. |
| */ |
| public void initialize(DataTypeDescriptor[] types) throws StandardException |
| { |
| for (int i = 0; i < parms.length; i++) |
| { |
| DataTypeDescriptor dtd = types[i]; |
| |
| parms[i].initialize(dtd.getNull(), |
| dtd.getJDBCTypeId(), dtd.getTypeId().getCorrespondingJavaTypeName()); |
| } |
| } |
| |
| public void setParameterMode(int position, int mode) { |
| parms[position].parameterMode = (short) mode; |
| } |
| |
| /** |
| * @see ParameterValueSet#clearParameters |
| */ |
| public void clearParameters() |
| { |
| for (int i = 0; i < parms.length; i++) |
| { |
| parms[i].clear(); |
| } |
| } |
| |
| /** |
| * Returns the number of parameters in this set. |
| * |
| * @return The number of parameters in this set. |
| */ |
| public int getParameterCount() |
| { |
| return parms.length; |
| } |
| |
| /** |
| * Returns the parameter value at the given position. |
| * |
| * @return The parameter at the given position. |
| * @exception StandardException Thrown on error |
| */ |
| public DataValueDescriptor getParameter( int position ) throws StandardException |
| { |
| try { |
| return parms[position].getValue(); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| checkPosition(position); |
| return null; |
| } |
| } |
| |
| |
| |
| public DataValueDescriptor getParameterForSet(int position) throws StandardException { |
| |
| try { |
| |
| GenericParameter gp = parms[position]; |
| if (gp.parameterMode == (ParameterMetaData.parameterModeOut)) |
| throw StandardException.newException(SQLState.LANG_RETURN_OUTPUT_PARAM_CANNOT_BE_SET); |
| |
| gp.isSet = true; |
| |
| return gp.getValue(); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| checkPosition(position); |
| return null; |
| } |
| |
| } |
| |
| public DataValueDescriptor getParameterForGet(int position) throws StandardException { |
| |
| try { |
| |
| GenericParameter gp = parms[position]; |
| |
| switch (gp.parameterMode) { |
| case (ParameterMetaData.parameterModeIn): |
| case (ParameterMetaData.parameterModeUnknown): |
| throw StandardException.newException(SQLState.LANG_NOT_OUTPUT_PARAMETER, Integer.toString(position + 1)); |
| } |
| |
| return gp.getValue(); |
| } catch (ArrayIndexOutOfBoundsException e) { |
| checkPosition(position); |
| return null; |
| } |
| } |
| |
| public void setParameterAsObject(int position, Object value) throws StandardException { |
| |
| UserDataValue dvd = (UserDataValue) getParameterForSet(position); |
| |
| GenericParameter gp = parms[position]; |
| if (value != null) { |
| |
| { |
| |
| boolean throwError; |
| ClassNotFoundException t = null; |
| try { |
| throwError = !ci.instanceOf(gp.declaredClassName, value); |
| } catch (ClassNotFoundException cnfe) { |
| t = cnfe; |
| throwError = true; |
| } |
| |
| if (throwError) { |
| throw StandardException.newException(SQLState.LANG_DATA_TYPE_SET_MISMATCH, t, |
| ClassInspector.readableClassName(value.getClass()), gp.declaredClassName); |
| } |
| } |
| |
| } |
| |
| dvd.setValue(value); |
| } |
| |
| /** |
| * @see ParameterValueSet#allAreSet |
| */ |
| public boolean allAreSet() |
| { |
| for (int i = 0; i < parms.length; i++) |
| { |
| GenericParameter gp = parms[i]; |
| if (!gp.isSet) |
| { |
| switch (gp.parameterMode) { |
| case (ParameterMetaData.parameterModeOut): |
| break; |
| case (ParameterMetaData.parameterModeInOut): |
| case (ParameterMetaData.parameterModeUnknown): |
| case (ParameterMetaData.parameterModeIn): |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @see ParameterValueSet#transferDataValues |
| */ |
| public void transferDataValues(ParameterValueSet pvstarget) throws StandardException |
| { |
| // don't take application's values for return output parameters |
| int firstParam = pvstarget.hasReturnOutputParameter() ? 1 : 0; |
| for (int i = firstParam; i < parms.length;i++) |
| { |
| |
| GenericParameter oldp = parms[i]; |
| |
| if (oldp.registerOutType != Types.NULL) { |
| |
| pvstarget.registerOutParameter(i, oldp.registerOutType, oldp.registerOutScale); |
| |
| } |
| |
| if (oldp.isSet) |
| { |
| DataValueDescriptor dvd = oldp.getValue(); |
| InputStream is = null; |
| // See if the value type can hold a stream. |
| if (dvd.hasStream()) { |
| // DERBY-4455: Don't materialize the stream when |
| // transferring it. If the stream has been drained already, |
| // and the user doesn't set a new value before executing |
| // the prepared statement again, Derby will fail. |
| pvstarget.getParameterForSet(i).setValue(dvd.getStream(), |
| DataValueDescriptor.UNKNOWN_LOGICAL_LENGTH); |
| } else { |
| pvstarget.getParameterForSet(i).setValue(dvd); |
| } |
| } |
| } |
| } |
| |
| GenericParameter getGenericParameter(int position) |
| { |
| return(parms[position]); |
| } |
| |
| /* Class implementation */ |
| public String toString() |
| { |
| /* This method needed for derby.language.logStatementText=true. |
| * Do not put under SanityManager.DEBUG. |
| */ |
| StringBuffer strbuf = new StringBuffer(); |
| |
| for (int ctr = 0; ctr < parms.length; ctr++) |
| { |
| strbuf.append("begin parameter #" + (ctr + 1) + ": "); |
| strbuf.append(parms[ctr].toString()); |
| strbuf.append(" :end parameter "); |
| } |
| |
| return strbuf.toString(); |
| } |
| |
| /** |
| * Check the position number for a parameter and throw an exception if |
| * it is out of range. |
| * |
| * @param position The position number to check |
| * |
| * @exception StandardException Thrown if position number is |
| * out of range. |
| */ |
| private void checkPosition(int position) throws StandardException |
| { |
| if (position < 0 || position >= parms.length) |
| { |
| |
| if (parms.length == 0) |
| throw StandardException.newException(SQLState.NO_INPUT_PARAMETERS); |
| |
| throw StandardException.newException(SQLState.LANG_INVALID_PARAM_POSITION, |
| String.valueOf(position+1), |
| String.valueOf(parms.length)); |
| } |
| } |
| |
| |
| public ParameterValueSet getClone() |
| { |
| return(new GenericParameterValueSet(parms.length, this)); |
| } |
| |
| ////////////////////////////////////////////////////////////////// |
| // |
| // CALLABLE STATEMENT |
| // |
| ////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Mark the parameter as an output parameter. |
| * |
| * @param parameterIndex The ordinal parameterIndex of a parameter to set |
| * to the given value. |
| * @param jdbcType A type from java.sql.Types |
| * @param scale the scale to use. -1 means ignore scale |
| * |
| * @exception StandardException on error |
| */ |
| public void registerOutParameter(int parameterIndex, int jdbcType, int scale) |
| throws StandardException |
| { |
| checkPosition( parameterIndex ); |
| Util.checkSupportedRaiseStandard( jdbcType ); |
| parms[ parameterIndex ].setOutParameter( jdbcType, scale ); |
| } |
| |
| /** |
| * Validate the parameters. This is done for situations where |
| * we cannot validate everything in the setXXX() calls. In |
| * particular, before we do an execute() on a CallableStatement, |
| * we need to go through the parameters and make sure that |
| * all parameters are set up properly. The motivator for this |
| * is that setXXX() can be called either before or after |
| * registerOutputParamter(), we cannot be sure we have the types |
| * correct until we get to execute(). |
| * |
| * @exception StandardException if the parameters aren't valid |
| */ |
| public void validate() throws StandardException |
| { |
| for (int i = 0; i < parms.length; i++) |
| { |
| parms[i].validate(); |
| } |
| } |
| |
| |
| /** |
| * Return the parameter number (in jdbc lingo, i.e. 1 based) |
| * for the given parameter. Linear search. |
| * |
| * @return the parameter number, or 0 if not found |
| */ |
| public int getParameterNumber(GenericParameter theParam) |
| { |
| for (int i = 0; i < parms.length; i++) |
| { |
| if (parms[i] == theParam) |
| { |
| return i+1; |
| } |
| } |
| return 0; |
| } |
| |
| /** |
| Check that there are not output parameters defined |
| by the parameter set. If there are unknown parameter |
| types they are forced to input types. i.e. Derby static method |
| calls with parameters that are array. |
| |
| @return true if a declared Java Procedure INOUT or OUT parameter is in the set, false otherwise. |
| */ |
| public boolean checkNoDeclaredOutputParameters() { |
| |
| boolean hasDeclaredOutputParameter = false; |
| for (int i=0; i<parms.length; i++) { |
| |
| GenericParameter gp = parms[i]; |
| |
| switch (gp.parameterMode) { |
| case (ParameterMetaData.parameterModeIn): |
| break; |
| case (ParameterMetaData.parameterModeInOut): |
| case (ParameterMetaData.parameterModeOut): |
| hasDeclaredOutputParameter = true; |
| break; |
| case (ParameterMetaData.parameterModeUnknown): |
| gp.parameterMode = (ParameterMetaData.parameterModeIn); |
| break; |
| } |
| } |
| return hasDeclaredOutputParameter; |
| } |
| |
| /** |
| Return the mode of the parameter according to JDBC 3.0 ParameterMetaData |
| * @param parameterIndex the first parameter is 1, the second is 2, ... |
| * |
| */ |
| public short getParameterMode(int parameterIndex) |
| { |
| short mode = parms[parameterIndex - 1].parameterMode; |
| //if (mode == (short) JDBC30Translation.PARAMETER_MODE_UNKNOWN) |
| // mode = (short) JDBC30Translation.PARAMETER_MODE_IN; |
| return mode; |
| } |
| |
| /** |
| * Is there a return output parameter in this pvs. A return |
| * parameter is from a CALL statement of the following |
| * syntax: ? = CALL myMethod() |
| * |
| * @return true if it has a return parameter |
| * |
| */ |
| public boolean hasReturnOutputParameter() |
| { |
| return hasReturnOutputParam; |
| } |
| |
| /** |
| * Get the value of the return parameter in order to set it. |
| * |
| * |
| * @exception StandardException if a database-access error occurs. |
| */ |
| public DataValueDescriptor getReturnValueForSet() throws StandardException |
| { |
| checkPosition(0); |
| |
| if (SanityManager.DEBUG) |
| { |
| if (!hasReturnOutputParam) |
| SanityManager.THROWASSERT("getReturnValueForSet called on non-return parameter"); |
| } |
| |
| return parms[0].getValue(); |
| } |
| |
| /** |
| * Return the scale of the given parameter index in this pvs. |
| * |
| * @param parameterIndex the first parameter is 1, the second is 2, ... |
| * |
| * @return scale |
| */ |
| public int getScale(int parameterIndex) |
| { |
| return parms[parameterIndex-1].getScale(); |
| } |
| |
| /** |
| * Return the precision of the given parameter index in this pvs. |
| * |
| * @param parameterIndex the first parameter is 1, the second is 2, ... |
| * |
| * @return precision |
| */ |
| public int getPrecision(int parameterIndex) |
| { |
| return parms[parameterIndex-1].getPrecision(); |
| } |
| |
| } |