001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.GenericParameterValueSet
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql;
023:
024: import org.apache.derby.iapi.services.loader.ClassFactory;
025: import org.apache.derby.iapi.services.loader.ClassInspector;
026: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
027:
028: import org.apache.derby.iapi.sql.ParameterValueSet;
029:
030: import org.apache.derby.iapi.types.DataTypeDescriptor;
031: import org.apache.derby.iapi.types.DataValueFactory;
032: import org.apache.derby.iapi.types.DataValueDescriptor;
033: import org.apache.derby.iapi.types.UserDataValue;
034:
035: import org.apache.derby.iapi.reference.SQLState;
036:
037: import org.apache.derby.iapi.error.StandardException;
038:
039: import org.apache.derby.iapi.services.sanity.SanityManager;
040:
041: import java.io.InputStream;
042: import java.sql.Date;
043: import java.sql.Time;
044: import java.sql.Timestamp;
045: import java.sql.Types;
046: import org.apache.derby.iapi.reference.JDBC30Translation;
047:
048: /**
049: * Implementation of ParameterValueSet
050: *
051: * @see ParameterValueSet
052: *
053: * @author Jeff Lichtman
054: */
055:
056: final class GenericParameterValueSet implements ParameterValueSet {
057: //all this has to be copied in the clone constructor
058: private final GenericParameter[] parms;
059: final ClassInspector ci;
060: private final boolean hasReturnOutputParam;
061:
062: /**
063: * Constructor for a GenericParameterValueSet
064: *
065: * @param numParms The number of parameters in the new ParameterValueSet
066: * @param hasReturnOutputParam if we have a ? = call syntax. Note that
067: * this is NOT the same thing as an output parameter -- return
068: * output parameters are special cases of output parameters.
069: */
070: GenericParameterValueSet(ClassInspector ci, int numParms,
071: boolean hasReturnOutputParam) {
072: this .ci = ci;
073: this .hasReturnOutputParam = hasReturnOutputParam;
074: parms = new GenericParameter[numParms];
075: for (int i = 0; i < numParms; i++) {
076: /*
077: ** Last param is if this is a return output param. True if
078: ** we have an output param and we are on the 1st parameter.
079: */
080: parms[i] = new GenericParameter(this ,
081: (hasReturnOutputParam && i == 0));
082: }
083: }
084:
085: /*
086: ** Construct a pvs by cloning a pvs.
087: */
088: private GenericParameterValueSet(int numParms,
089: GenericParameterValueSet pvs) {
090: this .hasReturnOutputParam = pvs.hasReturnOutputParam;
091: this .ci = pvs.ci;
092: parms = new GenericParameter[numParms];
093: for (int i = 0; i < numParms; i++) {
094: parms[i] = pvs.getGenericParameter(i).getClone(this );
095: }
096: }
097:
098: /*
099: ** ParameterValueSet interface methods
100: */
101:
102: /**
103: * Initialize the set by allocating a holder DataValueDescriptor object
104: * for each parameter.
105: */
106: public void initialize(DataTypeDescriptor[] types) {
107: for (int i = 0; i < parms.length; i++) {
108: DataTypeDescriptor dtd = types[i];
109:
110: parms[i].initialize(dtd.getNull(), dtd.getJDBCTypeId(), dtd
111: .getTypeId().getCorrespondingJavaTypeName());
112: }
113: }
114:
115: public void setParameterMode(int position, int mode) {
116: parms[position].parameterMode = (short) mode;
117: }
118:
119: /**
120: * @see ParameterValueSet#clearParameters
121: */
122: public void clearParameters() {
123: for (int i = 0; i < parms.length; i++) {
124: parms[i].clear();
125: }
126: }
127:
128: /**
129: * Returns the number of parameters in this set.
130: *
131: * @return The number of parameters in this set.
132: */
133: public int getParameterCount() {
134: return parms.length;
135: }
136:
137: /**
138: * Returns the parameter value at the given position.
139: *
140: * @return The parameter at the given position.
141: * @exception StandardException Thrown on error
142: */
143: public DataValueDescriptor getParameter(int position)
144: throws StandardException {
145: try {
146: return parms[position].getValue();
147: } catch (ArrayIndexOutOfBoundsException e) {
148: checkPosition(position);
149: return null;
150: }
151: }
152:
153: public DataValueDescriptor getParameterForSet(int position)
154: throws StandardException {
155:
156: try {
157:
158: GenericParameter gp = parms[position];
159: if (gp.parameterMode == JDBC30Translation.PARAMETER_MODE_OUT)
160: throw StandardException
161: .newException(SQLState.LANG_RETURN_OUTPUT_PARAM_CANNOT_BE_SET);
162:
163: gp.isSet = true;
164:
165: return gp.getValue();
166: } catch (ArrayIndexOutOfBoundsException e) {
167: checkPosition(position);
168: return null;
169: }
170:
171: }
172:
173: public DataValueDescriptor getParameterForGet(int position)
174: throws StandardException {
175:
176: try {
177:
178: GenericParameter gp = parms[position];
179:
180: switch (gp.parameterMode) {
181: case JDBC30Translation.PARAMETER_MODE_IN:
182: case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
183: throw StandardException.newException(
184: SQLState.LANG_NOT_OUTPUT_PARAMETER, Integer
185: .toString(position + 1));
186: }
187:
188: return gp.getValue();
189: } catch (ArrayIndexOutOfBoundsException e) {
190: checkPosition(position);
191: return null;
192: }
193: }
194:
195: public void setParameterAsObject(int position, Object value)
196: throws StandardException {
197:
198: UserDataValue dvd = (UserDataValue) getParameterForSet(position);
199:
200: GenericParameter gp = parms[position];
201: if (value != null) {
202:
203: {
204:
205: boolean throwError;
206: ClassNotFoundException t = null;
207: try {
208: throwError = !ci.instanceOf(gp.declaredClassName,
209: value);
210: } catch (ClassNotFoundException cnfe) {
211: t = cnfe;
212: throwError = true;
213: }
214:
215: if (throwError) {
216: throw StandardException.newException(
217: SQLState.LANG_DATA_TYPE_SET_MISMATCH, t,
218: ClassInspector.readableClassName(value
219: .getClass()), gp.declaredClassName);
220: }
221: }
222:
223: }
224:
225: dvd.setValue(value);
226: }
227:
228: /**
229: * @see ParameterValueSet#allAreSet
230: */
231: public boolean allAreSet() {
232: for (int i = 0; i < parms.length; i++) {
233: GenericParameter gp = parms[i];
234: if (!gp.isSet) {
235: switch (gp.parameterMode) {
236: case JDBC30Translation.PARAMETER_MODE_OUT:
237: break;
238: case JDBC30Translation.PARAMETER_MODE_IN_OUT:
239: case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
240: case JDBC30Translation.PARAMETER_MODE_IN:
241: return false;
242: }
243: }
244: }
245:
246: return true;
247: }
248:
249: /**
250: * @see ParameterValueSet#transferDataValues
251: */
252: public void transferDataValues(ParameterValueSet pvstarget)
253: throws StandardException {
254: // don't take application's values for return output parameters
255: int firstParam = pvstarget.hasReturnOutputParameter() ? 1 : 0;
256: for (int i = firstParam; i < parms.length; i++) {
257:
258: GenericParameter oldp = parms[i];
259:
260: if (oldp.registerOutType != Types.NULL) {
261:
262: pvstarget.registerOutParameter(i, oldp.registerOutType,
263: oldp.registerOutScale);
264:
265: }
266:
267: if (oldp.isSet) {
268: pvstarget.getParameterForSet(i).setValue(
269: oldp.getValue());
270: }
271: }
272: }
273:
274: GenericParameter getGenericParameter(int position) {
275: return (parms[position]);
276: }
277:
278: /* Class implementation */
279: public String toString() {
280: /* This method needed for derby.language.logStatementText=true.
281: * Do not put under SanityManager.DEBUG.
282: */
283: StringBuffer strbuf = new StringBuffer();
284:
285: for (int ctr = 0; ctr < parms.length; ctr++) {
286: strbuf.append("begin parameter #" + (ctr + 1) + ": ");
287: strbuf.append(parms[ctr].toString());
288: strbuf.append(" :end parameter ");
289: }
290:
291: return strbuf.toString();
292: }
293:
294: /**
295: * Check the position number for a parameter and throw an exception if
296: * it is out of range.
297: *
298: * @param position The position number to check
299: *
300: * @exception StandardException Thrown if position number is
301: * out of range.
302: */
303: private void checkPosition(int position) throws StandardException {
304: if (position < 0 || position >= parms.length) {
305:
306: if (parms.length == 0)
307: throw StandardException
308: .newException(SQLState.NO_INPUT_PARAMETERS);
309:
310: throw StandardException.newException(
311: SQLState.LANG_INVALID_PARAM_POSITION, String
312: .valueOf(position + 1), String
313: .valueOf(parms.length));
314: }
315: }
316:
317: public ParameterValueSet getClone() {
318: return (new GenericParameterValueSet(parms.length, this ));
319: }
320:
321: //////////////////////////////////////////////////////////////////
322: //
323: // CALLABLE STATEMENT
324: //
325: //////////////////////////////////////////////////////////////////
326:
327: /**
328: * Mark the parameter as an output parameter.
329: *
330: * @param parameterIndex The ordinal parameterIndex of a parameter to set
331: * to the given value.
332: * @param sqlType A type from java.sql.Types
333: * @param scale the scale to use. -1 means ignore scale
334: *
335: * @exception StandardException on error
336: */
337: public void registerOutParameter(int parameterIndex, int sqlType,
338: int scale) throws StandardException {
339: checkPosition(parameterIndex);
340: parms[parameterIndex].setOutParameter(sqlType, scale);
341: }
342:
343: /**
344: * Validate the parameters. This is done for situations where
345: * we cannot validate everything in the setXXX() calls. In
346: * particular, before we do an execute() on a CallableStatement,
347: * we need to go through the parameters and make sure that
348: * all parameters are set up properly. The motivator for this
349: * is that setXXX() can be called either before or after
350: * registerOutputParamter(), we cannot be sure we have the types
351: * correct until we get to execute().
352: *
353: * @exception StandardException if the parameters aren't valid
354: */
355: public void validate() throws StandardException {
356: for (int i = 0; i < parms.length; i++) {
357: parms[i].validate();
358: }
359: }
360:
361: /**
362: * Return the parameter number (in jdbc lingo, i.e. 1 based)
363: * for the given parameter. Linear search.
364: *
365: * @return the parameter number, or 0 if not found
366: */
367: public int getParameterNumber(GenericParameter theParam) {
368: for (int i = 0; i < parms.length; i++) {
369: if (parms[i] == theParam) {
370: return i + 1;
371: }
372: }
373: return 0;
374: }
375:
376: /**
377: Check that there are not output parameters defined
378: by the parameter set. If there are unknown parameter
379: types they are forced to input types. i.e. Cloudscape static method
380: calls with parameters that are array.
381:
382: @return true if a declared Java Procedure INOUT or OUT parameter is in the set, false otherwise.
383: */
384: public boolean checkNoDeclaredOutputParameters() {
385:
386: boolean hasDeclaredOutputParameter = false;
387: for (int i = 0; i < parms.length; i++) {
388:
389: GenericParameter gp = parms[i];
390:
391: switch (gp.parameterMode) {
392: case JDBC30Translation.PARAMETER_MODE_IN:
393: break;
394: case JDBC30Translation.PARAMETER_MODE_IN_OUT:
395: case JDBC30Translation.PARAMETER_MODE_OUT:
396: hasDeclaredOutputParameter = true;
397: break;
398: case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
399: gp.parameterMode = JDBC30Translation.PARAMETER_MODE_IN;
400: break;
401: }
402: }
403: return hasDeclaredOutputParameter;
404: }
405:
406: /**
407: Return the mode of the parameter according to JDBC 3.0 ParameterMetaData
408: * @param parameterIndex the first parameter is 1, the second is 2, ...
409: *
410: */
411: public short getParameterMode(int parameterIndex) {
412: short mode = parms[parameterIndex - 1].parameterMode;
413: //if (mode == (short) JDBC30Translation.PARAMETER_MODE_UNKNOWN)
414: // mode = (short) JDBC30Translation.PARAMETER_MODE_IN;
415: return mode;
416: }
417:
418: /**
419: * Is there a return output parameter in this pvs. A return
420: * parameter is from a CALL statement of the following
421: * syntax: ? = CALL myMethod()
422: *
423: * @return true if it has a return parameter
424: *
425: */
426: public boolean hasReturnOutputParameter() {
427: return hasReturnOutputParam;
428: }
429:
430: /**
431: * Get the value of the return parameter in order to set it.
432: *
433: *
434: * @exception StandardException if a database-access error occurs.
435: */
436: public DataValueDescriptor getReturnValueForSet()
437: throws StandardException {
438: checkPosition(0);
439:
440: if (SanityManager.DEBUG) {
441: if (!hasReturnOutputParam)
442: SanityManager
443: .THROWASSERT("getReturnValueForSet called on non-return parameter");
444: }
445:
446: return parms[0].getValue();
447: }
448:
449: /**
450: * Return the scale of the given parameter index in this pvs.
451: *
452: * @param parameterIndex the first parameter is 1, the second is 2, ...
453: *
454: * @return scale
455: */
456: public int getScale(int parameterIndex) {
457: return parms[parameterIndex - 1].getScale();
458: }
459:
460: /**
461: * Return the precision of the given parameter index in this pvs.
462: *
463: * @param parameterIndex the first parameter is 1, the second is 2, ...
464: *
465: * @return precision
466: */
467: public int getPrecision(int parameterIndex) {
468: return parms[parameterIndex - 1].getPrecision();
469: }
470:
471: }
|