KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > DIProcedureInfo


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb;
33
34 import java.io.Serializable JavaDoc;
35 import java.lang.reflect.Method JavaDoc;
36
37 import org.hsqldb.lib.HashMap;
38 import org.hsqldb.lib.HsqlArrayList;
39 import org.hsqldb.resources.BundleHandler;
40 import org.hsqldb.store.ValuePool;
41 import org.hsqldb.types.Binary;
42
43 /**@todo fredt - move Trace.doAssert() literals to Trace*/
44
45 /**
46  * Provides information about HSQLDB SQL-invoked routines and SQL functions. <p>
47  *
48  * In particular, this class provides information about Java Methods in a form
49  * compatible with presentation via the related HSQLDB system tables,
50  * SYSTEM_PROCEDURES and SYSTEM_PROCEDURECOLUMNS, involved in the production of
51  * the DatabaseMetaData getProcedures and getProcedureColumns result sets.
52  *
53  * @author boucherb@users
54  * @version 1.7.2
55  * @since 1.7.2
56  */

57 final class DIProcedureInfo {
58
59     // java.sql dependencies mostly removed
60
static final String JavaDoc conClsName = "java.sql.Connection";
61     static final int procedureResultUnknown = 0;
62     static final int procedureNoResult = 1;
63     static final int procedureReturnsResult = 2;
64     static final int procedureColumnUnknown = 0;
65     static final int procedureColumnIn = 1;
66     static final int procedureColumnInOut = 2;
67     static final int procedureColumnResult = 3;
68     static final int procedureColumnOut = 4;
69     static final int procedureColumnReturn = 5;
70     static final int procedureNoNulls = 0;
71     static final int procedureNullable = 1;
72     static final int procedureNullableUnknown = 2;
73     private Class JavaDoc clazz;
74     private Class JavaDoc[] colClasses;
75     private int[] colTypes;
76     private int colOffset;
77     private int colCount;
78     private boolean colsResolved;
79     private String JavaDoc fqn;
80     private String JavaDoc specificName;
81     private int hnd_remarks;
82     private Method JavaDoc method;
83     private String JavaDoc sig;
84     private DINameSpace nameSpace;
85     private final HashMap typeMap = new HashMap();
86
87     public DIProcedureInfo(DINameSpace ns) throws HsqlException {
88         setNameSpace(ns);
89     }
90
91     private int colOffset() {
92
93         if (!colsResolved) {
94             resolveCols();
95         }
96
97         return colOffset;
98     }
99
100     HsqlArrayList getAliases() {
101         return (HsqlArrayList) nameSpace.getInverseAliasMap().get(getFQN());
102     }
103
104     Class JavaDoc getColClass(int i) {
105         return colClasses[i + colOffset()];
106     }
107
108     int getColCount() {
109
110         if (!colsResolved) {
111             resolveCols();
112         }
113
114         return colCount;
115     }
116
117     Integer JavaDoc getColDataType(int i) {
118         return ValuePool.getInt(getColTypeCode(i));
119     }
120
121     Integer JavaDoc getColLen(int i) {
122
123         int size;
124         int type;
125
126         type = getColTypeCode(i);
127
128         switch (type) {
129
130             case Types.BINARY :
131             case Types.LONGVARBINARY :
132             case Types.VARBINARY : {
133                 size = Integer.MAX_VALUE;
134
135                 break;
136             }
137             case Types.BIGINT :
138             case Types.DOUBLE :
139             case Types.DATE :
140             case Types.FLOAT :
141             case Types.TIME : {
142                 size = 8;
143
144                 break;
145             }
146             case Types.TIMESTAMP : {
147                 size = 12;
148
149                 break;
150             }
151             case Types.REAL :
152             case Types.INTEGER : {
153                 size = 4;
154
155                 break;
156             }
157             case Types.SMALLINT : {
158                 size = 2;
159
160                 break;
161             }
162             case Types.TINYINT :
163             case Types.BOOLEAN : {
164                 size = 1;
165
166                 break;
167             }
168             default :
169                 size = 0;
170         }
171
172         return (size == 0) ? null
173                            : ValuePool.getInt(size);
174     }
175
176     String JavaDoc getColName(int i) {
177         return CompiledStatement.PCOL_PREFIX + (i + colOffset());
178     }
179
180     Integer JavaDoc getColNullability(int i) {
181
182         int cn;
183
184         cn = getColClass(i).isPrimitive() ? procedureNoNulls
185                                           : procedureNullable;
186
187         return ValuePool.getInt(cn);
188     }
189
190     String JavaDoc getColRemark(int i) {
191
192         String JavaDoc key;
193         StringBuffer JavaDoc sb;
194
195         sb = new StringBuffer JavaDoc(getSignature());
196         key = sb.append('@').append(i + colOffset()).toString();
197
198         return BundleHandler.getString(hnd_remarks, key);
199     }
200
201     // JDBC sort-contract:
202
// out return value column, then in/in out/out parameter columns
203
// in formal order, then result columns in column order
204
//
205
// Currently, we materialize the java method return value, if
206
// any, as a result column, not as an OUT return value column, so
207
// it should actually appear _after_ the other procedure columns
208
// in the row order returned by the JDBC getProcedureColumns() method
209
int getColSequence(int i) {
210
211         // colOffset has the side-effect of setting colCount properly
212
return (i + colOffset() == 0) ? colCount
213                                       : i;
214     }
215
216     int getColTypeCode(int i) {
217
218         i += colOffset();
219
220         return colTypes[i];
221     }
222
223     Integer JavaDoc getColUsage(int i) {
224
225         switch (i + colOffset()) {
226
227             case 0 : {
228
229                 // Currently, we materialize the java method return value, if
230
// any, as a result column, not as an OUT return column
231
return ValuePool.getInt(procedureColumnResult);
232             }
233
234             // todo: registration and reporting on result columns for routines
235
// that generate real" result sets
236
default : {
237
238                 // We could get religious here and maybe report IN OUT
239
// for newRow of before update for each row trigger methods,
240
// but there's not really any added value
241
return ValuePool.getInt(procedureColumnIn);
242             }
243         }
244     }
245
246     Class JavaDoc getDeclaringClass() {
247         return this.clazz;
248     }
249
250     String JavaDoc getFQN() {
251
252         StringBuffer JavaDoc sb;
253
254         if (fqn == null) {
255             sb = new StringBuffer JavaDoc();
256             fqn = sb.append(clazz.getName()).append('.').append(
257                 method.getName()).toString();
258         }
259
260         return fqn;
261     }
262
263     String JavaDoc getSpecificName() {
264
265         if (specificName == null) {
266             specificName = clazz.getName() + "." + getSignature();
267         }
268
269         return specificName;
270     }
271
272     Integer JavaDoc getInputParmCount() {
273         return ValuePool.getInt(method.getParameterTypes().length);
274     }
275
276     Method JavaDoc getMethod() {
277         return this.method;
278     }
279
280     String JavaDoc getOrigin(String JavaDoc srcType) {
281         return (nameSpace.isBuiltin(clazz) ? "BUILTIN "
282                                            : "USER DEFINED ") + srcType;
283     }
284
285     Integer JavaDoc getOutputParmCount() {
286
287         // no support for IN OUT or OUT columns yet
288
return ValuePool.getInt(0);
289     }
290
291     String JavaDoc getRemark() {
292         return BundleHandler.getString(hnd_remarks, getSignature());
293     }
294
295     Integer JavaDoc getResultSetCount() {
296         return (method.getReturnType() == Void.TYPE) ? ValuePool.getInt(0)
297                                                      : ValuePool.getInt(1);
298     }
299
300     Integer JavaDoc getResultType(String JavaDoc origin) {
301
302         int type;
303
304         type = !"ROUTINE".equals(origin) ? procedureResultUnknown
305                                          : method.getReturnType()
306                                            == Void.TYPE ? procedureNoResult
307                                                         : procedureReturnsResult;
308
309         return ValuePool.getInt(type);
310     }
311
312     String JavaDoc getSignature() {
313
314         if (sig == null) {
315             sig = DINameSpace.getSignature(method);
316         }
317
318         return sig;
319     }
320
321     /**
322      * Retrieves the specific name of the given Method object. <p>
323      *
324      * @param m The Method object for which to retreive the specific name
325      * @return the specific name of the specified Method object.
326      */

327     static String JavaDoc getMethodSpecificName(Method JavaDoc m) {
328
329         return m == null ? null
330                          : m.getDeclaringClass().getName() + '.'
331                            + DINameSpace.getSignature(m);
332     }
333
334     DINameSpace getNameSpace() {
335         return nameSpace;
336     }
337
338     void setNameSpace(DINameSpace ns) throws HsqlException {
339
340         nameSpace = ns;
341
342         Class JavaDoc c;
343         Integer JavaDoc type;
344
345         // can only speed up test significantly for java.lang.Object,
346
// final classes, primitive types and hierachy parents.
347
// Must still check later if assignable from candidate classes, where
348
// hierarchy parent is not final.
349
//ARRAY
350
try {
351             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcArray");
352
353             typeMap.put(c, ValuePool.getInt(Types.ARRAY));
354         } catch (Exception JavaDoc e) {}
355
356         // BIGINT
357
type = ValuePool.getInt(Types.BIGINT);
358
359         typeMap.put(Long.TYPE, type);
360         typeMap.put(Long JavaDoc.class, type);
361
362         // BOOLEAN
363
type = ValuePool.getInt(Types.BOOLEAN);
364
365         typeMap.put(Boolean.TYPE, type);
366         typeMap.put(Boolean JavaDoc.class, type);
367
368         // BLOB
369
type = ValuePool.getInt(Types.BLOB);
370
371         try {
372             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcBlob");
373
374             typeMap.put(c, type);
375         } catch (Exception JavaDoc e) {}
376
377         // CHAR
378
type = ValuePool.getInt(Types.CHAR);
379
380         typeMap.put(Character.TYPE, type);
381         typeMap.put(Character JavaDoc.class, type);
382         typeMap.put(Character JavaDoc[].class, type);
383         typeMap.put(char[].class, type);
384
385         // CLOB
386
type = ValuePool.getInt(Types.CLOB);
387
388         try {
389             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcClob");
390
391             typeMap.put(c, type);
392         } catch (Exception JavaDoc e) {}
393
394         // DATALINK
395
type = ValuePool.getInt(Types.DATALINK);
396
397         typeMap.put(java.net.URL JavaDoc.class, type);
398
399         // DATE
400
type = ValuePool.getInt(Types.DATE);
401
402         typeMap.put(java.util.Date JavaDoc.class, type);
403         typeMap.put(java.sql.Date JavaDoc.class, type);
404
405         // DECIMAL
406
type = ValuePool.getInt(Types.DECIMAL);
407
408         try {
409             c = nameSpace.classForName("java.math.BigDecimal");
410
411             typeMap.put(c, type);
412         } catch (Exception JavaDoc e) {}
413
414         // DISTINCT
415
try {
416             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcDistinct");
417
418             typeMap.put(c, ValuePool.getInt(Types.DISTINCT));
419         } catch (Exception JavaDoc e) {}
420
421         // DOUBLE
422
type = ValuePool.getInt(Types.DOUBLE);
423
424         typeMap.put(Double.TYPE, type);
425         typeMap.put(Double JavaDoc.class, type);
426
427         // FLOAT : Not actually a legal IN parameter type yet
428
type = ValuePool.getInt(Types.FLOAT);
429
430         typeMap.put(Float.TYPE, type);
431         typeMap.put(Float JavaDoc.class, type);
432
433         // INTEGER
434
type = ValuePool.getInt(Types.INTEGER);
435
436         typeMap.put(Integer.TYPE, type);
437         typeMap.put(Integer JavaDoc.class, type);
438
439         // JAVA_OBJECT
440
type = ValuePool.getInt(Types.JAVA_OBJECT);
441
442         typeMap.put(Object JavaDoc.class, type);
443
444         // LONGVARBINARY
445
type = ValuePool.getInt(Types.LONGVARBINARY);
446
447         typeMap.put(byte[].class, type);
448         typeMap.put(Binary.class, type);
449
450         // LONGVARCHAR
451
type = ValuePool.getInt(Types.LONGVARCHAR);
452
453         typeMap.put(String JavaDoc.class, type);
454
455         // NULL
456
type = ValuePool.getInt(Types.NULL);
457
458         typeMap.put(Void.TYPE, type);
459         typeMap.put(Void JavaDoc.class, type);
460
461         // REF
462
type = ValuePool.getInt(Types.REF);
463
464         try {
465             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcRef");
466
467             typeMap.put(c, type);
468         } catch (Exception JavaDoc e) {}
469
470         // SMALLINT : Not actually a legal IN parameter type yet
471
type = ValuePool.getInt(Types.SMALLINT);
472
473         typeMap.put(Short.TYPE, type);
474         typeMap.put(Short JavaDoc.class, type);
475
476         // STRUCT :
477
type = ValuePool.getInt(Types.STRUCT);
478
479         try {
480             c = nameSpace.classForName("org.hsqldb.jdbc.jdbcStruct");
481
482             typeMap.put(c, type);
483         } catch (Exception JavaDoc e) {}
484
485         // TIME
486
type = ValuePool.getInt(Types.TIME);
487
488         typeMap.put(java.sql.Time JavaDoc.class, type);
489
490         // TIMESTAMP
491
type = ValuePool.getInt(Types.TIMESTAMP);
492
493         typeMap.put(java.sql.Timestamp JavaDoc.class, type);
494
495         // TINYINT : Not actually a legal IN parameter type yet
496
type = ValuePool.getInt(Types.TINYINT);
497
498         typeMap.put(Byte.TYPE, type);
499         typeMap.put(Byte JavaDoc.class, type);
500
501         // XML : Not actually a legal IN parameter type yet
502
type = ValuePool.getInt(Types.XML);
503
504         try {
505             c = nameSpace.classForName("org.w3c.dom.Document");
506
507             typeMap.put(c, type);
508
509             c = nameSpace.classForName("org.w3c.dom.DocumentFragment");
510
511             typeMap.put(c, type);
512         } catch (Exception JavaDoc e) {}
513     }
514
515     private void resolveCols() {
516
517         Class JavaDoc rType;
518         Class JavaDoc[] pTypes;
519         Class JavaDoc clazz;
520         int ptlen;
521         int pclen;
522         boolean isFPCON;
523
524         rType = method.getReturnType();
525         pTypes = method.getParameterTypes();
526         ptlen = pTypes.length;
527         isFPCON = ptlen > 0 && pTypes[0].getName().equals(conClsName);
528         pclen = 1 + ptlen - (isFPCON ? 1
529                                              : 0);
530         colClasses = new Class JavaDoc[pclen];
531         colTypes = new int[pclen];
532         colClasses[0] = rType;
533         colTypes[0] = typeForClass(rType);
534
535         for (int i = isFPCON ? 1
536                              : 0, idx = 1; i < ptlen; i++, idx++) {
537             clazz = pTypes[i];
538             colClasses[idx] = clazz;
539             colTypes[idx] = typeForClass(clazz);
540         }
541
542         colOffset = rType == Void.TYPE ? 1
543                                        : 0;
544         colCount = pclen - colOffset;
545     }
546
547     /**
548      * This requires the following properties files:
549      *
550      * org_hsqldb_Library.properties
551      * java_math.properties
552      */

553     void setMethod(Method JavaDoc m) {
554
555         String JavaDoc remarkKey;
556
557         method = m;
558         clazz = method.getDeclaringClass();
559         fqn = null;
560         specificName = null;
561         sig = null;
562         colsResolved = false;
563         remarkKey = clazz.getName().replace('.', '_');
564         hnd_remarks = BundleHandler.getBundleHandle(remarkKey, null);
565     }
566
567     int typeForClass(Class JavaDoc c) {
568
569         Class JavaDoc to;
570         Integer JavaDoc type = (Integer JavaDoc) typeMap.get(c);
571
572         if (type != null) {
573             return type.intValue();
574         }
575
576         // ARRAY (dimension 1)
577
// HSQLDB does not yet support ARRAY for SQL, but
578
// Trigger.fire takes Object[] row, which we report.
579
// Also, it's just friendly to show what "would"
580
// be required if/when we support ARRAY in a broader
581
// sense
582
if (c.isArray() &&!c.getComponentType().isArray()) {
583             return Types.ARRAY;
584         }
585
586         try {
587             to = Class.forName("java.sql.Array");
588
589             if (to.isAssignableFrom(c)) {
590                 return Types.ARRAY;
591             }
592         } catch (Exception JavaDoc e) {}
593
594         // NUMERIC
595
// All java.lang.Number impls and BigDecimal have
596
// already been covered by lookup in typeMap.
597
// They are all final, so this is OK.
598
if (Number JavaDoc.class.isAssignableFrom(c)) {
599             return Types.NUMERIC;
600         }
601
602         // TIMESTAMP
603
try {
604             to = Class.forName("java.sql.Timestamp");
605
606             if (to.isAssignableFrom(c)) {
607                 return Types.TIMESTAMP;
608             }
609         } catch (Exception JavaDoc e) {}
610
611         // TIME
612
try {
613             to = Class.forName("java.sql.Time");
614
615             if (to.isAssignableFrom(c)) {
616                 return Types.TIMESTAMP;
617             }
618         } catch (Exception JavaDoc e) {}
619
620         // DATE
621
try {
622             to = Class.forName("java.sql.Date");
623
624             if (to.isAssignableFrom(c)) {
625                 return Types.DATE;
626             }
627         } catch (Exception JavaDoc e) {}
628
629         // BLOB
630
try {
631             to = Class.forName("java.sql.Blob");
632
633             if (to.isAssignableFrom(c)) {
634                 return Types.BLOB;
635             }
636         } catch (Exception JavaDoc e) {}
637
638         // CLOB
639
try {
640             to = Class.forName("java.sql.Clob");
641
642             if (to.isAssignableFrom(c)) {
643                 return Types.CLOB;
644             }
645         } catch (Exception JavaDoc e) {}
646
647         // REF
648
try {
649             to = Class.forName("java.sql.Ref");
650
651             if (to.isAssignableFrom(c)) {
652                 return Types.REF;
653             }
654         } catch (Exception JavaDoc e) {}
655
656         // STRUCT
657
try {
658             to = Class.forName("java.sql.Struct");
659
660             if (to.isAssignableFrom(c)) {
661                 return Types.STRUCT;
662             }
663         } catch (Exception JavaDoc e) {}
664
665         // LONGVARBINARY : org.hsqldb.Binary is not final
666
if (Binary.class.isAssignableFrom(c)) {
667             return Types.LONGVARBINARY;
668         }
669
670         // LONGVARCHAR : really OTHER at this point
671
try {
672
673             // @since JDK1.4
674
to = Class.forName("java.lang.CharSequence");
675
676             if (to.isAssignableFrom(c)) {
677                 return Types.LONGVARCHAR;
678             }
679         } catch (Exception JavaDoc e) {}
680
681         // we have no standard mapping for the specified class
682
// at this point...is it even storable?
683
if (Serializable JavaDoc.class.isAssignableFrom(c)) {
684
685             // Yes: it is storable, as an OTHER.
686
return Types.OTHER;
687         }
688
689         // It may (in future, say using bean contract) or may not be storable
690
// (by HSQLDB)...
691
// but then it may be possible to pass to an in-process routine,
692
// so be lenient and just return the most generic type.
693
return Types.JAVA_OBJECT;
694     }
695 }
696
Popular Tags