Source code: org/apache/derby/impl/sql/GenericParameter.java
1 /*
2
3 Derby - Class org.apache.derby.impl.sql.GenericParameter
4
5 Copyright 1999, 2004 The Apache Software Foundation or its licensors, as applicable.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 */
20
21 package org.apache.derby.impl.sql;
22
23 import org.apache.derby.iapi.services.loader.ClassInspector;
24
25 import org.apache.derby.iapi.sql.ParameterValueSet;
26
27 import org.apache.derby.iapi.types.DataValueDescriptor;
28 import org.apache.derby.iapi.types.BooleanDataValue;
29 import org.apache.derby.iapi.types.BitDataValue;
30 import org.apache.derby.iapi.types.DateTimeDataValue;
31 import org.apache.derby.iapi.types.NumberDataValue;
32 import org.apache.derby.iapi.types.StringDataValue;
33 import org.apache.derby.iapi.types.UserDataValue;
34 import org.apache.derby.iapi.types.TypeId;
35 import org.apache.derby.iapi.types.DataTypeDescriptor;
36 import org.apache.derby.iapi.types.*;
37
38 import org.apache.derby.iapi.reference.SQLState;
39
40 import org.apache.derby.iapi.reference.JDBC30Translation;
41
42 import org.apache.derby.iapi.error.StandardException;
43
44 import org.apache.derby.iapi.services.sanity.SanityManager;
45
46 import org.apache.derby.iapi.types.*;
47 import org.apache.derby.iapi.types.*;
48
49 import java.sql.Types;
50
51 import java.lang.reflect.Array;
52
53 /**
54 * A parameter. Originally lifted from ParameterValueSet.
55 *
56 * @author jamie
57 */
58 final class GenericParameter
59 {
60
61 // These defaults match the Network Server/ JCC max precision and
62 // The JCC "guessed" scale. They are used as the defaults for
63 // Decimal out params.
64 private static int DECIMAL_PARAMETER_DEFAULT_PRECISION = 31;
65 private static int DECIMAL_PARAMETER_DEFAULT_SCALE = 15;
66
67
68 /*
69 ** The parameter set we are part of
70 */
71 private final GenericParameterValueSet pvs;
72
73 /**
74 ** Our value
75 */
76 private DataValueDescriptor value;
77
78 /**
79 Compile time JDBC type identifier.
80 */
81 int jdbcTypeId;
82
83 /**
84 Compile time Java class name.
85 */
86 String declaredClassName;
87
88 /**
89 Mode of the parameter, from ParameterMetaData
90 */
91 short parameterMode;
92
93 /*
94 ** If we are set
95 */
96 boolean isSet;
97
98 /*
99 ** Output parameter values
100 */
101 private final boolean isReturnOutputParameter;
102
103 /**
104 Type that has been registered.
105 */
106 int registerOutType = Types.NULL;
107 /**
108 Scale that has been registered.
109 */
110 int registerOutScale = -1;
111
112 /**
113 * When a decimal output parameter is registered we give it a
114 * precision
115 */
116
117 int registerOutPrecision = -1;
118
119 /**
120 * Constructor for a Parameter
121 *
122 * @param pvs the parameter set that this is part of
123 * @param isReturnOutputParameter true if this is a return output parameter
124 */
125 GenericParameter
126 (
127 GenericParameterValueSet pvs,
128 boolean isReturnOutputParameter
129 )
130 {
131 this.pvs = pvs;
132 parameterMode = (this.isReturnOutputParameter = isReturnOutputParameter)
133 ? (short) JDBC30Translation.PARAMETER_MODE_OUT : (short) JDBC30Translation.PARAMETER_MODE_IN;
134 }
135
136 /**
137 * Clone myself. It is a shallow copy for everything but
138 * the underlying data wrapper and its value -- e.g. for
139 * everything but the underlying SQLInt and its int.
140 *
141 * @param pvs the parameter value set
142 *
143 * @return a new generic parameter.
144 */
145 public GenericParameter getClone(GenericParameterValueSet pvs)
146 {
147 GenericParameter gpClone = new GenericParameter(pvs, isReturnOutputParameter);
148 gpClone.setStorableDataValue(this.getValue().getClone(), jdbcTypeId, declaredClassName);
149 gpClone.isSet = true;
150
151 return gpClone;
152 }
153
154 /**
155 * Set the DataValueDescriptor for this parameter. If makrAsSet
156 * is set, then we consider this parameter both initialized and
157 * set. Otherwise, it is just initialized but not yet set.
158 *
159 * @param std the storable data value
160 * @param markAsSet whether we should mark as being set or not.
161 * The isSet() method will return this value.
162 */
163 void setStorableDataValue(DataValueDescriptor value, int jdbcTypeId, String className)
164 {
165 this.value = value;
166 this.jdbcTypeId = jdbcTypeId;
167 this.declaredClassName = className;
168 }
169
170
171 /**
172 * Clear the parameter, unless it is a return
173 * output parameter
174 */
175 void clear()
176 {
177 isSet = false;
178 }
179
180
181 /**
182 * Get the parameter value. Doesn't check to
183 * see if it has been initialized or not.
184 *
185 * @return the parameter value, may return null
186 */
187 DataValueDescriptor getValue()
188 {
189 return value;
190 }
191
192
193 //////////////////////////////////////////////////////////////////
194 //
195 // CALLABLE STATEMENT
196 //
197 //////////////////////////////////////////////////////////////////
198
199 /**
200 * Mark the parameter as an output parameter.
201 *
202 * @param sqlType A type from java.sql.Types
203 * @param scale scale, -1 if no scale arg
204 *
205 * @exception StandardException on error
206 */
207 void setOutParameter(int sqlType, int scale)
208 throws StandardException
209 {
210 // fast case duplicate registrations.
211 if (registerOutType == sqlType) {
212 if (scale == registerOutScale)
213 return;
214 }
215
216 switch (parameterMode) {
217 case JDBC30Translation.PARAMETER_MODE_IN:
218 case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
219 default:
220 throw StandardException.newException(SQLState.LANG_NOT_OUT_PARAM, getJDBCParameterNumberStr());
221
222 case JDBC30Translation.PARAMETER_MODE_IN_OUT:
223 case JDBC30Translation.PARAMETER_MODE_OUT:
224 // Declared/Java procedure parameter.
225 if (!DataTypeDescriptor.isJDBCTypeEquivalent(jdbcTypeId, sqlType))
226 throw throwInvalidOutParamMap(sqlType);
227 break;
228
229 }
230
231 registerOutType = sqlType;
232
233 }
234
235 private StandardException throwInvalidOutParamMap(int sqlType) {
236
237 //TypeId typeId = TypeId.getBuiltInTypeId(sqlType);
238 // String sqlTypeName = typeId == null ? "OTHER" : typeId.getSQLTypeName();
239
240
241 String jdbcTypesName = org.apache.derby.impl.jdbc.Util.typeName(sqlType);
242
243 TypeId typeId = TypeId.getBuiltInTypeId(jdbcTypeId);
244 String thisTypeName = typeId == null ? declaredClassName : typeId.getSQLTypeName();
245
246 StandardException e = StandardException.newException(SQLState.LANG_INVALID_OUT_PARAM_MAP,
247 getJDBCParameterNumberStr(),
248 jdbcTypesName, thisTypeName);
249
250 return e;
251 }
252
253
254
255 /**
256 * Validate the parameters. This is done for situations where
257 * we cannot validate everything in the setXXX() calls. In
258 * particular, before we do an execute() on a CallableStatement,
259 * we need to go through the parameters and make sure that
260 * all parameters are set up properly. The motivator for this
261 * is that setXXX() can be called either before or after
262 * registerOutputParamter(), we cannot be sure we have the types
263 * correct until we get to execute().
264 *
265 * @exception StandardException if the parameters aren't valid
266 */
267 void validate() throws StandardException
268 {
269 switch (parameterMode) {
270 case JDBC30Translation.PARAMETER_MODE_UNKNOWN:
271 break;
272 case JDBC30Translation.PARAMETER_MODE_IN:
273 break;
274 case JDBC30Translation.PARAMETER_MODE_IN_OUT:
275 case JDBC30Translation.PARAMETER_MODE_OUT:
276 if (registerOutType == Types.NULL) {
277 throw StandardException.newException(SQLState.NEED_TO_REGISTER_PARAM,
278 getJDBCParameterNumberStr(),
279 org.apache.derby.catalog.types.RoutineAliasInfo.parameterMode(parameterMode));
280 }
281 break;
282 }
283 }
284
285 /**
286 * Return the scale of the parameter.
287 *
288 * @return scale
289 */
290 int getScale()
291 {
292 //when the user doesn't pass any scale, the registerOutScale gets set to -1
293 return (registerOutScale == -1 ? 0 : registerOutScale);
294 }
295
296
297 int getPrecision()
298 {
299 return registerOutPrecision;
300
301 }
302
303 ////////////////////////////////////////////////////
304 //
305 // CLASS IMPLEMENTATION
306 //
307 ////////////////////////////////////////////////////
308
309 /**
310 * do a setValue on the particular field. Doesn't do
311 * checks on what it is being set to or on whether
312 * it is a return parameter or what. This is only
313 * called internally; it is not expected to be called
314 * directly as a result of some jdbc call (e.g. setObject()).
315 *
316 * @param newValue the value to set
317 *
318 * @exception StandardException on error
319 */
320 void stuffObject(Object newValue) throws StandardException
321 {
322 value.setValue(newValue);
323 isSet = true;
324 }
325
326 /**
327 * get string for param number
328 */
329 String getJDBCParameterNumberStr()
330 {
331 return Integer.toString(pvs.getParameterNumber(this));
332 }
333
334 public String toString()
335 {
336 /* This method is used for debugging.
337 * It is called when derby.language.logStatementText=true,
338 * so there is no check of SanityManager.DEBUG.
339 * Anyway, we need to call value.getString() instead of
340 * value.toString() because the user may have done a
341 * a setStream() on the parameter. (toString() could get
342 * an assertion failure in that case as it would be in an
343 * unexpected state since this is a very weird codepath.)
344 * getString() can throw an exception which we eat and
345 * and reflect in the returned string.
346 */
347 if (value == null)
348 {
349 return "null";
350 }
351 else
352 {
353 try
354 {
355 return value.getString();
356 }
357 catch (StandardException se)
358 {
359 return "unexpected exception from getString() - " + se;
360 }
361 }
362 }
363 }