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.initialize(this.getValue().getClone(), jdbcTypeId, declaredClassName); |
149 | gpClone.isSet = true; |
150 | |
151 | return gpClone; |
152 | } |
153 | |
154 | /** |
155 | * Set the DataValueDescriptor and type information for this parameter |
156 | * |
157 | */ |
158 | void initialize(DataValueDescriptor value, int jdbcTypeId, String className) |
159 | { |
160 | this.value = value; |
161 | this.jdbcTypeId = jdbcTypeId; |
162 | this.declaredClassName = className; |
163 | } |
164 | |
165 | |
166 | /** |
167 | * Clear the parameter, unless it is a return |
168 | * output parameter |
169 | */ |
170 | void clear() |
171 | { |
172 | isSet = false; |
173 | } |
174 | |
175 | |
176 | /** |
177 | * Get the parameter value. Doesn't check to |
178 | * see if it has been initialized or not. |
179 | * |
180 | * @return the parameter value, may return null |
181 | */ |
182 | DataValueDescriptor getValue() |
183 | { |
184 | return value; |
185 | } |
186 | |
187 | |
188 | ////////////////////////////////////////////////////////////////// |
189 | // |
190 | // CALLABLE STATEMENT |
191 | // |
192 | ////////////////////////////////////////////////////////////////// |
193 | |
194 | /** |
195 | * Mark the parameter as an output parameter. |
196 | * |
197 | * @param sqlType A type from java.sql.Types |
198 | * @param scale scale, -1 if no scale arg |
199 | * |
200 | * @exception StandardException on error |
201 | */ |
202 | void setOutParameter(int sqlType, int scale) |
203 | throws StandardException |
204 | { |
205 | // fast case duplicate registrations. |
206 | if (registerOutType == sqlType) { |
207 | if (scale == registerOutScale) |
208 | return; |
209 | } |
210 | |
211 | switch (parameterMode) { |
212 | case JDBC30Translation.PARAMETER_MODE_IN: |
213 | case JDBC30Translation.PARAMETER_MODE_UNKNOWN: |
214 | default: |
215 | throw StandardException.newException(SQLState.LANG_NOT_OUT_PARAM, getJDBCParameterNumberStr()); |
216 | |
217 | case JDBC30Translation.PARAMETER_MODE_IN_OUT: |
218 | case JDBC30Translation.PARAMETER_MODE_OUT: |
219 | // Declared/Java procedure parameter. |
220 | if (!DataTypeDescriptor.isJDBCTypeEquivalent(jdbcTypeId, sqlType)) |
221 | throw throwInvalidOutParamMap(sqlType); |
222 | break; |
223 | |
224 | } |
225 | |
226 | registerOutType = sqlType; |
227 | |
228 | } |
229 | |
230 | private StandardException throwInvalidOutParamMap(int sqlType) { |
231 | |
232 | //TypeId typeId = TypeId.getBuiltInTypeId(sqlType); |
233 | // String sqlTypeName = typeId == null ? "OTHER" : typeId.getSQLTypeName(); |
234 | |
235 | |
236 | String jdbcTypesName = org.apache.derby.impl.jdbc.Util.typeName(sqlType); |
237 | |
238 | TypeId typeId = TypeId.getBuiltInTypeId(jdbcTypeId); |
239 | String thisTypeName = typeId == null ? declaredClassName : typeId.getSQLTypeName(); |
240 | |
241 | StandardException e = StandardException.newException(SQLState.LANG_INVALID_OUT_PARAM_MAP, |
242 | getJDBCParameterNumberStr(), |
243 | jdbcTypesName, thisTypeName); |
244 | |
245 | return e; |
246 | } |
247 | |
248 | |
249 | |
250 | /** |
251 | * Validate the parameters. This is done for situations where |
252 | * we cannot validate everything in the setXXX() calls. In |
253 | * particular, before we do an execute() on a CallableStatement, |
254 | * we need to go through the parameters and make sure that |
255 | * all parameters are set up properly. The motivator for this |
256 | * is that setXXX() can be called either before or after |
257 | * registerOutputParamter(), we cannot be sure we have the types |
258 | * correct until we get to execute(). |
259 | * |
260 | * @exception StandardException if the parameters aren't valid |
261 | */ |
262 | void validate() throws StandardException |
263 | { |
264 | switch (parameterMode) { |
265 | case JDBC30Translation.PARAMETER_MODE_UNKNOWN: |
266 | break; |
267 | case JDBC30Translation.PARAMETER_MODE_IN: |
268 | break; |
269 | case JDBC30Translation.PARAMETER_MODE_IN_OUT: |
270 | case JDBC30Translation.PARAMETER_MODE_OUT: |
271 | if (registerOutType == Types.NULL) { |
272 | throw StandardException.newException(SQLState.NEED_TO_REGISTER_PARAM, |
273 | getJDBCParameterNumberStr(), |
274 | org.apache.derby.catalog.types.RoutineAliasInfo.parameterMode(parameterMode)); |
275 | } |
276 | break; |
277 | } |
278 | } |
279 | |
280 | /** |
281 | * Return the scale of the parameter. |
282 | * |
283 | * @return scale |
284 | */ |
285 | int getScale() |
286 | { |
287 | //when the user doesn't pass any scale, the registerOutScale gets set to -1 |
288 | return (registerOutScale == -1 ? 0 : registerOutScale); |
289 | } |
290 | |
291 | |
292 | int getPrecision() |
293 | { |
294 | return registerOutPrecision; |
295 | |
296 | } |
297 | |
298 | //////////////////////////////////////////////////// |
299 | // |
300 | // CLASS IMPLEMENTATION |
301 | // |
302 | //////////////////////////////////////////////////// |
303 | |
304 | /** |
305 | * get string for param number |
306 | */ |
307 | String getJDBCParameterNumberStr() |
308 | { |
309 | return Integer.toString(pvs.getParameterNumber(this)); |
310 | } |
311 | |
312 | public String toString() |
313 | { |
314 | /* This method is used for debugging. |
315 | * It is called when derby.language.logStatementText=true, |
316 | * so there is no check of SanityManager.DEBUG. |
317 | * Anyway, we need to call value.getString() instead of |
318 | * value.toString() because the user may have done a |
319 | * a setStream() on the parameter. (toString() could get |
320 | * an assertion failure in that case as it would be in an |
321 | * unexpected state since this is a very weird codepath.) |
322 | * getString() can throw an exception which we eat and |
323 | * and reflect in the returned string. |
324 | */ |
325 | if (value == null) |
326 | { |
327 | return "null"; |
328 | } |
329 | else |
330 | { |
331 | try |
332 | { |
333 | return value.getString(); |
334 | } |
335 | catch (StandardException se) |
336 | { |
337 | return "unexpected exception from getString() - " + se; |
338 | } |
339 | } |
340 | } |
341 | } |