001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.jdbc;
032:
033: import java.lang.reflect.Method;
034: import java.lang.reflect.Modifier;
035: import java.sql.ParameterMetaData;
036: import java.sql.SQLException;
037:
038: import org.hsqldb.Result;
039: import org.hsqldb.Trace;
040: import org.hsqldb.Types;
041:
042: // fredt@users 20040412 - removed DITypeInfo dependencies
043: // TODO: implement internal support for at least OUT return parameter
044:
045: /**
046: * An object that can be used to get information about the types and
047: * properties of the parameters in a PreparedStatement object.
048: *
049: * @author boucherb@users
050: * @version 1.7.2
051: * @since JDK 1.4, HSQLDB 1.7.2
052: */
053: public class jdbcParameterMetaData implements ParameterMetaData {
054:
055: /** The metadata object with which this object is constructed */
056: Result.ResultMetaData rmd;
057:
058: /** The numeric data type codes of the parameters. */
059: int[] types;
060:
061: /** Parameter mode values */
062: int[] modes;
063:
064: /** whether param is assigned directly to identity column */
065: boolean[] isIdentity;
066:
067: /** nullability code for site to which param is bound */
068: int[] nullability;
069:
070: /**
071: * The fully-qualified name of the Java class whose instances should
072: * be passed to the method PreparedStatement.setObject. <p>
073: *
074: * Note that changes to Function.java and Types.java allow passing
075: * objects of any class implementing java.io.Serializable and that,
076: * as such, the parameter expression resolution mechanism has been
077: * upgraded to provide the precise FQN for SQL function and stored
078: * procedure arguments, rather than the more generic
079: * org.hsqldb.JavaObject class that is used internally to represent
080: * and transport objects whose class is not in the standard mapping.
081: */
082: String[] classNames;
083:
084: /** The number of parameters in the described statement */
085: int parameterCount;
086:
087: /**
088: * Creates a new instance of jdbcParameterMetaData. <p>
089: *
090: * @param r A Result object describing the statement parameters
091: * @throws SQLException never - reserved for future use
092: */
093: jdbcParameterMetaData(Result r) throws SQLException {
094:
095: if (r == null) {
096: parameterCount = 0;
097:
098: return;
099: }
100:
101: rmd = r.metaData;
102: types = rmd.colTypes;
103: parameterCount = types.length;
104: nullability = rmd.colNullable;
105: isIdentity = rmd.isIdentity;
106: classNames = rmd.classNames;
107: modes = rmd.paramMode;
108: }
109:
110: /**
111: * Checks if the value of the param argument is a valid parameter
112: * position. <p>
113: *
114: * @param param position to check
115: * @throws SQLException if the value of the param argument is not a
116: * valid parameter position
117: */
118: void checkRange(int param) throws SQLException {
119:
120: if (param < 1 || param > parameterCount) {
121: String msg = param + " is out of range";
122:
123: throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT, msg);
124: }
125: }
126:
127: /**
128: * Retrieves the fully-qualified name of the Java class whose instances
129: * should be passed to the method PreparedStatement.setObject. <p>
130: *
131: * @param param the first parameter is 1, the second is 2, ...
132: * @throws SQLException if a database access error occurs
133: * @return the fully-qualified name of the class in the
134: * Java programming language that would be
135: * used by the method PreparedStatement.setObject
136: * to set the value in the specified parameter.
137: * This is the class name used for custom mapping.
138: * @since JDK 1.4, HSQLDB 1.7.2
139: */
140: public String getParameterClassName(int param) throws SQLException {
141:
142: checkRange(param);
143:
144: return classNames[--param];
145: }
146:
147: /**
148: * Retrieves the number of parameters in the PreparedStatement object for
149: * which this ParameterMetaData object provides information. <p>
150: *
151: * @throws SQLException if a database access error occurs
152: * @return the number of parameters
153: * @since JDK 1.4, HSQLDB 1.7.2
154: */
155: public int getParameterCount() throws SQLException {
156: return parameterCount;
157: }
158:
159: /**
160: * Retrieves the designated parameter's mode. <p>
161: *
162: * @param param the first parameter is 1, the second is 2, ...
163: * @throws SQLException if a database access error occurs
164: * @return mode of the parameter; one of
165: * ParameterMetaData.parameterModeIn,
166: * ParameterMetaData.parameterModeOut,
167: * ParameterMetaData.parameterModeInOut,
168: * ParameterMetaData.parameterModeUnknown
169: * @since JDK 1.4, HSQLDB 1.7.2
170: */
171: public int getParameterMode(int param) throws SQLException {
172:
173: checkRange(param);
174:
175: return modes[--param];
176: }
177:
178: /**
179: * Retrieves the designated parameter's SQL type. <p>
180: *
181: * @param param the first parameter is 1, the second is 2, ...
182: * @throws SQLException if a database access error occurs
183: * @return SQL type from java.sql.Types
184: * @since JDK 1.4, HSQLDB 1.7.2
185: * @see java.sql.Types
186: */
187: public int getParameterType(int param) throws SQLException {
188:
189: int t;
190:
191: checkRange(param);
192:
193: t = types[--param];
194:
195: return t == Types.VARCHAR_IGNORECASE ? Types.VARCHAR : t;
196: }
197:
198: /**
199: * Retrieves the designated parameter's database-specific type name. <p>
200: *
201: * @param param the first parameter is 1, the second is 2, ...
202: * @throws SQLException if a database access error occurs
203: * @return type the name used by the database.
204: * If the parameter type is a user-defined
205: * type, then a fully-qualified type name is
206: * returned.
207: * @since JDK 1.4, HSQLDB 1.7.2
208: */
209: public String getParameterTypeName(int param) throws SQLException {
210:
211: int t;
212: int ts;
213:
214: checkRange(param);
215:
216: return Types.getTypeName(types[--param]);
217: }
218:
219: /**
220: * Retrieves the designated parameter's number of decimal digits. <p>
221: *
222: * @param param the first parameter is 1, the second is 2, ...
223: * @throws SQLException if a database access error occurs
224: * @return precision
225: * @since JDK 1.4, HSQLDB 1.7.2
226: */
227: public int getPrecision(int param) throws SQLException {
228:
229: checkRange(param);
230:
231: // TODO:
232: // parameters assigned directly to table columns
233: // should report the precision of the column if it is
234: // defined, otherwise the default (intrinsic) precision
235: // of the undecorated type
236: return Types.getPrecision(types[--param]);
237: }
238:
239: /**
240: * Retrieves the designated parameter's number of digits to right of
241: * the decimal point. <p>
242: *
243: * @param param the first parameter is 1, the second is 2, ...
244: * @throws SQLException if a database access error occurs
245: * @return scale
246: * @since JDK 1.4, HSQLDB 1.7.2
247: */
248: public int getScale(int param) throws SQLException {
249:
250: checkRange(param);
251:
252: // TODO:
253: // parameters assigned directly to DECIMAL/NUMERIC columns
254: // should report the declared scale of the column
255: // For now, to be taken as "default or unknown"
256: return 0;
257: }
258:
259: /**
260: * Retrieves whether null values are allowed in the designated parameter. <p>
261: *
262: * @param param the first parameter is 1, the second is 2, ...
263: * @throws SQLException if a database access error occurs
264: * @return the nullability status of the given parameter; one of
265: * ParameterMetaData.parameterNoNulls,
266: * ParameterMetaData.parameterNullable or
267: * ParameterMetaData.parameterNullableUnknown
268: * @since JDK 1.4, HSQLDB 1.7.2
269: */
270: public int isNullable(int param) throws SQLException {
271:
272: checkRange(param);
273:
274: return nullability[--param];
275: }
276:
277: /**
278: * Retrieves whether values for the designated parameter can be
279: * signed numbers. <p>
280: *
281: * @param param the first parameter is 1, the second is 2, ...
282: * @throws SQLException if a database access error occurs
283: * @return true if so; false otherwise
284: * @since JDK 1.4, HSQLDB 1.7.2
285: */
286: public boolean isSigned(int param) throws SQLException {
287:
288: checkRange(param);
289:
290: Boolean b = Types.isUnsignedAttribute(types[--param]);
291:
292: return b != null && !b.booleanValue() && !isIdentity[param];
293: }
294:
295: /**
296: * Retrieves a String repsentation of this object. <p>
297: *
298: * @return a String repsentation of this object
299: */
300: public String toString() {
301:
302: try {
303: return toStringImpl();
304: } catch (Throwable t) {
305: return super .toString() + "[toStringImpl_exception=" + t
306: + "]";
307: }
308: }
309:
310: /**
311: * Provides the implementation of the toString() method. <p>
312: *
313: * @return a String representation of this object
314: * @throws Exception if a reflection error occurs
315: */
316: private String toStringImpl() throws Exception {
317:
318: StringBuffer sb;
319: Method[] methods;
320: Method method;
321: int count;
322:
323: sb = new StringBuffer();
324:
325: sb.append(super .toString());
326:
327: count = getParameterCount();
328:
329: if (count == 0) {
330: sb.append("[parameterCount=0]");
331:
332: return sb.toString();
333: }
334:
335: methods = getClass().getDeclaredMethods();
336:
337: sb.append('[');
338:
339: int len = methods.length;
340:
341: for (int i = 0; i < count; i++) {
342: sb.append('\n');
343: sb.append(" parameter_");
344: sb.append(i + 1);
345: sb.append('=');
346: sb.append('[');
347:
348: for (int j = 0; j < len; j++) {
349: method = methods[j];
350:
351: if (!Modifier.isPublic(method.getModifiers())) {
352: continue;
353: }
354:
355: if (method.getParameterTypes().length != 1) {
356: continue;
357: }
358:
359: sb.append(method.getName());
360: sb.append('=');
361: sb.append(method.invoke(this ,
362: new Object[] { new Integer(i + 1) }));
363:
364: if (j + 1 < len) {
365: sb.append(',');
366: sb.append(' ');
367: }
368: }
369:
370: sb.append(']');
371:
372: if (i + 1 < count) {
373: sb.append(',');
374: sb.append(' ');
375: }
376: }
377:
378: sb.append('\n');
379: sb.append(']');
380:
381: return sb.toString();
382: }
383: }
|