KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > Function


1 /* Copyright (c) 1995-2000, The Hypersonic SQL 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 Hypersonic SQL 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 THE HYPERSONIC SQL GROUP,
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  * This software consists of voluntary contributions made by many individuals
31  * on behalf of the Hypersonic SQL Group.
32  *
33  *
34  * For work added by the HSQL Development Group:
35  *
36  * Copyright (c) 2001-2005, The HSQL Development Group
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions are met:
41  *
42  * Redistributions of source code must retain the above copyright notice, this
43  * list of conditions and the following disclaimer.
44  *
45  * Redistributions in binary form must reproduce the above copyright notice,
46  * this list of conditions and the following disclaimer in the documentation
47  * and/or other materials provided with the distribution.
48  *
49  * Neither the name of the HSQL Development Group nor the names of its
50  * contributors may be used to endorse or promote products derived from this
51  * software without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */

65
66
67 package org.hsqldb;
68
69 import java.lang.reflect.InvocationTargetException JavaDoc;
70 import java.lang.reflect.Method JavaDoc;
71 import java.lang.reflect.Modifier JavaDoc;
72 import java.sql.Connection JavaDoc;
73
74 import org.hsqldb.lib.HashMap;
75 import org.hsqldb.lib.HsqlArrayList;
76 import org.hsqldb.lib.StringConverter;
77 import org.hsqldb.types.Binary;
78 import org.hsqldb.types.JavaObject;
79
80 // fredt@users 20020912 - patch 1.7.1 - shortcut treatment of identity() call
81
// fredt@users 20020912 - patch 1.7.1 - cache java.lang.reflect.Method objects
82
// fredt@users 20021013 - patch 1.7.1 - ignore non-static methods
83
// boucherb@users 20030201 - patch 1.7.2 - direct calls for org.hsqldb.Library
84
// fredt@users 20030621 - patch 1.7.2 - shortcut treatment of session calls
85
// boucherb@users 200404xx - doc 1.7.2 - updates toward 1.7.2 final
86

87 /**
88  * Provides services to evaluate SQL function and stored procedure calls,
89  * by invoking Java methods.
90  *
91  * Extended in successive versions of HSQLDB.
92  *
93  * @author Thomas Mueller (Hypersonic SQL Group)
94  * @version 1.8.0
95  * @since Hypersonic SQL
96  */

97 class Function {
98
99     private String JavaDoc sFunction;
100     private Method JavaDoc mMethod;
101     private String JavaDoc returnClassName;
102     private Class JavaDoc[] aArgClasses;
103     private int iReturnType;
104     private int iArgCount;
105     private int iSqlArgCount;
106     private int iSqlArgStart;
107     private int[] iArgType;
108     private boolean[] bArgNullable;
109     Expression[] eArg;
110     private boolean bConnection;
111     private static HashMap methodCache = new HashMap();
112     private int fID;
113     String JavaDoc name; // name used to call function
114
boolean isSimple; //CURRENT_TIME, NOW etc.
115
boolean hasAggregate;
116
117     /**
118      * Constructs a new Function object with the given function call name
119      * and using the specified Session context. <p>
120      *
121      * The call name is the fully qualified name of a static Java method, in
122      * the form "package.class.method." This implies that Java
123      * methods with the same fully qualified name but different signatures
124      * cannot be used properly as HSQLDB SQL functions or stored procedures.
125      * For instance, it is impossible to call both System.getProperty(String)
126      * and System.getProperty(String,String) under this arrangement, because
127      * the HSQLDB Function object is unable to differentiate between the two;
128      * it simply chooses the first method matching the FQN in the array of
129      * methods obtained from calling getMethods() on an instance of the
130      * Class indicated in the FQN, hiding all other methods with the same
131      * FQN. <p>
132      *
133      * The function FQN must match at least one static Java method FQN in the
134      * specified class or construction cannot procede and an HsqlException is
135      * thrown. <p>
136      *
137      * The isSimple parameter is true when certain SQL standard functions
138      * that are used without brackets are invokded.
139      *
140      * @param name this Function object's call name
141      * @param fqn the fully qualified name of a Java method
142      * @param isSimple if true, used to evalate CURRENT_TIME, NOW etc.
143      * evaluate
144      * @throws HsqlException if the specified function FQN corresponds to no
145      * Java method
146      */

147     Function(String JavaDoc name, String JavaDoc fqn, boolean isSimple) throws HsqlException {
148
149         this.name = name;
150         this.isSimple = isSimple;
151
152 // cSession = session;
153
sFunction = fqn;
154         fID = Library.functionID(fqn);
155
156         int i = fqn.lastIndexOf('.');
157
158         Trace.check(i != -1, Trace.UNEXPECTED_TOKEN, fqn);
159
160         String JavaDoc classname = fqn.substring(0, i);
161
162         mMethod = (Method JavaDoc) methodCache.get(fqn);
163
164         if (mMethod == null) {
165             String JavaDoc methodname = fqn.substring(i + 1);
166             Class JavaDoc classinstance = null;
167
168             try {
169                 classinstance = Class.forName(classname);
170             } catch (Exception JavaDoc e) {
171                 throw Trace.error(Trace.FUNCTION_NOT_FOUND,
172                                   Trace.Message_Pair, new Object JavaDoc[] {
173                     classname, e
174                 });
175             }
176
177             // public only, but includes those inherited from
178
// superclasses and superinterfaces. List is unordered.
179
Method JavaDoc[] methods = classinstance.getMethods();
180
181             for (i = 0; i < methods.length; i++) {
182                 Method JavaDoc m = methods[i];
183
184                 if (m.getName().equals(methodname)
185                         && Modifier.isStatic(m.getModifiers())) {
186                     mMethod = m;
187
188                     break;
189                 }
190             }
191
192             Trace.check(mMethod != null, Trace.UNKNOWN_FUNCTION, methodname);
193             methodCache.put(fqn, mMethod);
194         }
195
196         Class JavaDoc returnClass = mMethod.getReturnType();
197
198         if (returnClass.equals(org.hsqldb.Result.class)) {
199
200             // For now, we can write stored procedures whose
201
// descriptor explicitly specifies the above return type.
202
// Later, this will be modified or replaced to provide proper
203
// support for jdbcCallableStatement OUT mode return parameter,
204
// multiple results (Result.MULTI etc.)
205
iReturnType = Types.OTHER;
206         } else {
207
208             // Now we support the following construction-time return type
209
// Classes, as specified by the method descriptor:
210
//
211
// 1.) any primitive or primitive wrapper type, except Byte(.TYPE),
212
// Short(.TYPE) and Float(.TYPE) (TBD; narrow if no truncation)
213
//
214
// 2.) any primitive array type
215
//
216
// 3.) any non-primitive array whose base component implements
217
// java.io.Serializable
218
//
219
// 4.) any class implementing java.io.Serializable, except those
220
// described in 1.) as currently unsupported
221
//
222
// 5.) java.lang.Object
223
//
224
// For java.lang.Object, checking is deferred from the construction
225
// stage to the evaluation stage. In general, for the evaluation
226
// to succeed, the runtime class of the retrieved Object must be
227
//
228
// 1.) any primitive or primitive wrapper type, except Byte(.TYPE),
229
// Short(.TYPE) and Float(.TYPE) (TBD; narrow if no trunction)
230
//
231
// 2.) any primitive array type
232
// 3.) any non-primitive array whose base component implements
233
// java.io.Serializable
234
//
235
// 4.) any class implementing java.io.Serializable, except those
236
// described in 1.) as currently unsupported
237
//
238
// Additionally, it is possible for the evaluation to succeed under
239
// an SQL CALL if the runtime Class of the returned Object is not
240
// from the list above but is from the list below:
241
//
242
// 1.) is org.hsqldb.Result
243
// 2.) is org.hsqldb.jdbc.jdbcResultSet
244
//
245
// In these special cases, the statement executor notices the
246
// types and presents the client with a view the underlying result
247
// rather than with a view of the object as an opaque scalar value
248
//
249
iReturnType = Types.getParameterTypeNr(returnClass);
250         }
251
252         returnClassName =
253             Types.getFunctionReturnClassName(returnClass.getName());
254         aArgClasses = mMethod.getParameterTypes();
255         iArgCount = aArgClasses.length;
256         iArgType = new int[iArgCount];
257         bArgNullable = new boolean[iArgCount];
258
259         for (i = 0; i < aArgClasses.length; i++) {
260             Class JavaDoc a = aArgClasses[i];
261             String JavaDoc type = a.getName();
262
263             if ((i == 0) && a.equals(Connection JavaDoc.class)) {
264
265                 // TODO: provide jdbc:default:connection url functionality
266
//
267
// only the first parameter can be a Connection
268
bConnection = true;
269             } else {
270
271                 // see discussion above for iReturnType
272
iArgType[i] = Types.getParameterTypeNr(a);
273                 bArgNullable[i] = !a.isPrimitive();
274             }
275         }
276
277         iSqlArgCount = iArgCount;
278
279         if (bConnection) {
280             iSqlArgCount--;
281
282             iSqlArgStart = 1;
283         } else {
284             iSqlArgStart = 0;
285         }
286
287         eArg = new Expression[iArgCount];
288     }
289
290     /**
291      * Evaluates and returns this Function in the context of the session.<p>
292      */

293     Object JavaDoc getValue(Session session) throws HsqlException {
294
295         switch (fID) {
296
297             case Library.curtime :
298                 return session.getCurrentTime();
299
300             case Library.curdate :
301                 return session.getCurrentDate();
302
303             case Library.database :
304                 return session.getDatabase().getPath();
305
306             case Library.getAutoCommit :
307                 return session.isAutoCommit() ? Boolean.TRUE
308                                               : Boolean.FALSE;
309
310             case Library.identity :
311                 return session.getLastIdentity();
312
313             case Library.isReadOnlyDatabase :
314                 return session.getDatabase().databaseReadOnly ? Boolean.TRUE
315                                                               : Boolean.FALSE;
316
317             case Library.isReadOnlyConnection :
318                 return session.isReadOnly() ? Boolean.TRUE
319                                             : Boolean.FALSE;
320
321             case Library.isReadOnlyDatabaseFiles :
322                 return session.getDatabase().isFilesReadOnly() ? Boolean.TRUE
323                                                                : Boolean
324                                                                .FALSE;
325
326             case Library.now :
327                 return session.getCurrentTimestamp();
328
329             case Library.user :
330                 return session.getUsername();
331         }
332
333         Object JavaDoc[] oArg = getArguments(session);
334
335         if (oArg == null) {
336             return null;
337         }
338
339         return getValue(session, oArg);
340     }
341
342     /**
343      * Evaluates the Function with the given arguments in the session context.
344      */

345     Object JavaDoc getValue(Session session,
346                     Object JavaDoc[] arguments) throws HsqlException {
347
348         if (bConnection) {
349             arguments[0] = session.getInternalConnection();
350         }
351
352         try {
353             Object JavaDoc ret = (fID >= 0) ? Library.invoke(fID, arguments)
354                                     : mMethod.invoke(null, arguments);
355
356             return Column.convertObject(ret, iReturnType);
357         } catch (InvocationTargetException JavaDoc e) {
358
359             // thrown by user functions
360
Throwable JavaDoc t = e.getTargetException();
361             String JavaDoc s = sFunction + " : " + t.toString();
362
363             throw Trace.error(Trace.FUNCTION_CALL_ERROR, s);
364         } catch (IllegalAccessException JavaDoc e) {
365
366             // never thrown in this method
367
throw Trace.error(Trace.FUNCTION_CALL_ERROR);
368         }
369
370         // Library function throw HsqlException
371
}
372
373     private Object JavaDoc[] getArguments(Session session) throws HsqlException {
374
375         int i = bConnection ? 1
376                                     : 0;
377         Object JavaDoc[] oArg = new Object JavaDoc[iArgCount];
378
379         for (; i < iArgCount; i++) {
380             Expression e = eArg[i];
381             Object JavaDoc o = null;
382
383             if (e != null) {
384
385                 // no argument: null
386
o = e.getValue(session, iArgType[i]);
387             }
388
389             if ((o == null) &&!bArgNullable[i]) {
390
391                 // null argument for primitive datatype: don't call
392
return null;
393             }
394
395             if (o instanceof JavaObject) {
396                 o = ((JavaObject) o).getObject();
397             } else if (o instanceof Binary) {
398                 o = ((Binary) o).getBytes();
399             }
400
401             oArg[i] = o;
402         }
403
404         return oArg;
405     }
406
407     /**
408      * returns null if any non-nullable element of values is null
409      */

410     private Object JavaDoc[] getNotNull(Object JavaDoc[] values) throws HsqlException {
411
412         int i = bConnection ? 1
413                             : 0;
414
415         for (; i < iArgCount; i++) {
416             Object JavaDoc o = values[i];
417
418             if (o == null &&!bArgNullable[i]) {
419
420                 // null argument for primitive datatype: don't call
421
return null;
422             }
423         }
424
425         return values;
426     }
427
428     void collectInGroupByExpressions(HsqlArrayList colExps) {
429
430         for (int i = 0; i < iArgCount; i++) {
431             Expression e = eArg[i];
432
433             if (e != null) {
434                 e.collectInGroupByExpressions(colExps);
435             }
436         }
437     }
438
439     Object JavaDoc getAggregatedValue(Session session,
440                               Object JavaDoc currValue) throws HsqlException {
441
442         Object JavaDoc[] valueArray = (Object JavaDoc[]) currValue;
443
444         if (valueArray == null) {
445             valueArray = new Object JavaDoc[iArgCount];
446         }
447
448         for (int i = 0; i < iArgCount; i++) {
449             Expression e = eArg[i];
450
451             if (eArg[i] != null) {
452                 if (eArg[i].isAggregate()) {
453                     valueArray[i] = Column.convertObject(
454                         e.getAggregatedValue(session, valueArray[i]),
455                         iArgType[i]);
456                 } else {
457                     valueArray[i] = e.getValue(session, iArgType[i]);
458                 }
459             }
460         }
461
462         valueArray = getNotNull(valueArray);
463
464         if (valueArray == null) {
465             return null;
466         }
467
468         return getValue(session, valueArray);
469     }
470
471     Object JavaDoc updateAggregatingValue(Session session,
472                                   Object JavaDoc currValue) throws HsqlException {
473
474         Object JavaDoc[] valueArray = (Object JavaDoc[]) currValue;
475
476         if (valueArray == null) {
477             valueArray = new Object JavaDoc[iArgCount];
478         }
479
480         for (int i = 0; i < iArgCount; i++) {
481             Expression e = eArg[i];
482
483             if (eArg[i] != null) {
484                 valueArray[i] = e.updateAggregatingValue(session,
485                         valueArray[i]);
486             }
487         }
488
489         return valueArray;
490     }
491
492     /**
493      * Returns the number of parameters that must be supplied to evaluate
494      * this Function object from SQL. <p>
495      *
496      * This value may be different than the number of parameters of the
497      * underlying Java method. This is because HSQLDB automatically detects
498      * if the first parameter is of type java.sql.Connection, and supplies a
499      * live Connection object constructed from the evaluating session context
500      * if so.
501      */

502     int getArgCount() {
503         return iSqlArgCount;
504     }
505
506     /**
507      * Remnoves the Table filters from Expression parameters to this Function.
508      *
509      * @throws HsqlException if there is a problem resolving a parameter
510      * against the specified TableFilter
511      */

512 /*
513     void removeFilters() throws HsqlException {
514
515         Expression e;
516
517         for (int i = iSqlArgStart; i < iArgCount; i++) {
518             e = eArg[i];
519
520             if (e != null) {
521                 e.removeFilters();
522             }
523         }
524     }
525 */

526     void replaceAliases(Expression[] columns,
527                         int length) throws HsqlException {
528
529         Expression e;
530
531         for (int i = iSqlArgStart; i < iArgCount; i++) {
532             e = eArg[i];
533
534             if (e != null) {
535                 if (e.exprType == Expression.COLUMN) {
536                     eArg[i] = e.getExpressionForAlias(columns, length);
537                 } else {
538                     e.replaceAliases(columns, length);
539                 }
540             }
541         }
542     }
543
544     /**
545      * Checks the Expresion parameters to this Function object against the
546      * set of TableFilter.
547      */

548     void checkTables(HsqlArrayList fa) throws HsqlException {
549
550         Expression e;
551
552         for (int i = iSqlArgStart; i < iArgCount; i++) {
553             e = eArg[i];
554
555             if (e != null) {
556                 e.checkTables(fa);
557             }
558         }
559     }
560
561     /**
562      * Resolves the Expression parameters to this Function object against the
563      * specified TableFilter.
564      */

565     void resolveTables(TableFilter f) throws HsqlException {
566
567         Expression e;
568
569         for (int i = iSqlArgStart; i < iArgCount; i++) {
570             e = eArg[i];
571
572             if (e != null) {
573                 e.resolveTables(f);
574             }
575         }
576     }
577
578     /**
579      * Resolves the type of this expression and performs certain
580      * transformations and optimisations of the expression tree.
581      */

582     void resolveType(Session session) throws HsqlException {
583
584         Expression e;
585
586         for (int i = iSqlArgStart; i < iArgCount; i++) {
587             e = eArg[i];
588
589             if (e != null) {
590                 if (e.isParam()) {
591                     e.setDataType(iArgType[i]);
592
593                     e.nullability = getArgNullability(i);
594                     e.valueClassName = getArgClass(i).getName();
595                 } else {
596                     e.resolveTypes(session);
597                 }
598             }
599         }
600     }
601
602     /**
603      * Checks each of this object's arguments for resolution, throwing an
604      * HsqlException if any arguments have not yet been resolved. <p>
605      * The check boolean argument is passed on to further check calls.<p>
606      */

607     boolean checkResolved(boolean check) throws HsqlException {
608
609         boolean result = true;
610
611         for (int i = iSqlArgStart; i < iArgCount; i++) {
612             if (eArg[i] != null) {
613                 result = result && eArg[i].checkResolved(check);
614             }
615         }
616
617         return result;
618     }
619
620     /**
621      * Returns the type of the argument at the specified
622      * offset in this Function object's paramter list. <p>
623      */

624     int getArgType(int i) {
625         return iArgType[i];
626     }
627
628     /**
629      * Returns the type of this Function
630      * object's return type. <p>
631      */

632     int getReturnType() {
633         return iReturnType;
634     }
635
636     /**
637      * Binds the specified expression to the specified position in this
638      * Function object's parameter list. <p>
639      */

640     void setArgument(int i, Expression e) {
641
642         if (bConnection) {
643             i++;
644         }
645
646         eArg[i] = e;
647         hasAggregate = hasAggregate || (e != null && e.isAggregate());
648     }
649
650     /**
651      * Returns a DDL representation of this object. <p>
652      */

653     String JavaDoc getDLL() throws HsqlException {
654
655         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
656
657         // get the name as used by the CHECK statement
658
String JavaDoc ddlName = name;
659
660         if (isSimple) {
661             return name;
662         } else if (Token.T_TRIM.equals(name)) {
663
664             // special case for TRIM
665
sb.append(name).append('(');
666
667             boolean leading = eArg[2].testCondition(null);
668             boolean trailing = eArg[3].testCondition(null);
669
670             if (leading && trailing) {
671                 sb.append(Token.T_BOTH);
672             } else {
673                 sb.append(leading ? Token.T_LEADING
674                                   : Token.T_TRAILING);
675             }
676
677             // to do change to string
678
sb.append(' ');
679
680             String JavaDoc charval = (String JavaDoc) eArg[1].getValue(null);
681
682             sb.append(Column.createSQLString(charval)).append(' ');
683             sb.append(Token.T_FROM).append(' ');
684             sb.append(eArg[0].getDDL()).append(')');
685
686             return sb.toString();
687         }
688
689         if (sFunction.equals(name)) {
690             ddlName = StringConverter.toQuotedString(name, '"', true);
691         }
692
693         sb.append(ddlName).append('(');
694
695         for (int i = iSqlArgStart; i < eArg.length; i++) {
696             sb.append(eArg[i].getDDL());
697
698             if (i < eArg.length - 1) {
699                 sb.append(',');
700             }
701         }
702
703         sb.append(')');
704
705         return sb.toString();
706     }
707
708     /**
709      * Returns a String representation of this object. <p>
710      */

711     public String JavaDoc describe(Session session) {
712
713         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
714
715         sb.append(super.toString()).append("=[\n");
716         sb.append(sFunction).append("(");
717
718         for (int i = iSqlArgStart; i < eArg.length; i++) {
719             sb.append("[").append(eArg[i].describe(session)).append("]");
720         }
721
722         sb.append(") returns ").append(Types.getTypeString(getReturnType()));
723         sb.append("]\n");
724
725         return sb.toString();
726     }
727
728     /**
729      * Returns the Java Class of the object returned by getValue(). <p>
730      */

731     String JavaDoc getReturnClassName() {
732         return returnClassName;
733     }
734
735     /**
736      * Returns the Java Class of the i'th argument. <p>
737      */

738     Class JavaDoc getArgClass(int i) {
739         return aArgClasses[i];
740     }
741
742     /**
743      * Returns the SQL nullability code of the i'th argument. <p>
744      */

745     int getArgNullability(int i) {
746         return bArgNullable[i] ? Expression.NULLABLE
747                                : Expression.NO_NULLS;
748     }
749
750     Method JavaDoc getMethod() {
751         return mMethod;
752     }
753 }
754
Popular Tags