Source Code Cross Referenced for MethodCallNode.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » sql » compile » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.sql.compile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.sql.compile.MethodCallNode
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.sql.compile;
0023:
0024:        import org.apache.derby.iapi.services.loader.ClassInspector;
0025:
0026:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
0027:
0028:        import org.apache.derby.iapi.services.sanity.SanityManager;
0029:
0030:        import org.apache.derby.iapi.error.StandardException;
0031:
0032:        import org.apache.derby.iapi.types.TypeId;
0033:        import org.apache.derby.iapi.types.JSQLType;
0034:
0035:        import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0036:
0037:        import org.apache.derby.iapi.sql.compile.Visitable;
0038:        import org.apache.derby.iapi.sql.compile.Visitor;
0039:        import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0040:        import org.apache.derby.iapi.sql.compile.CompilerContext;
0041:
0042:        import org.apache.derby.iapi.types.DataTypeDescriptor;
0043:
0044:        import org.apache.derby.iapi.sql.compile.TypeCompiler;
0045:        import org.apache.derby.catalog.TypeDescriptor;
0046:
0047:        import org.apache.derby.iapi.reference.SQLState;
0048:        import org.apache.derby.iapi.reference.JDBC30Translation;
0049:
0050:        import org.apache.derby.iapi.store.access.Qualifier;
0051:
0052:        import org.apache.derby.iapi.util.JBitSet;
0053:
0054:        import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0055:        import org.apache.derby.catalog.types.RoutineAliasInfo;
0056:
0057:        import java.lang.reflect.Modifier;
0058:        import java.lang.reflect.Member;
0059:
0060:        import java.util.StringTokenizer;
0061:        import java.util.Vector;
0062:
0063:        /**
0064:         * A MethodCallNode represents a Java method call.  Method calls can be done
0065:         * through DML (as expressions) or through the CALL statement.
0066:         *
0067:         * @author Jeff Lichtman
0068:         */
0069:
0070:        abstract class MethodCallNode extends JavaValueNode {
0071:            /*
0072:             ** Name of the method.
0073:             */
0074:            String methodName;
0075:
0076:            /** The name of the class containing the method. May not be known until bindExpression() has been called.
0077:             * @see #bindExpression
0078:             * @see #getJavaClassName()
0079:             */
0080:            String javaClassName;
0081:
0082:            /**
0083:            	For a procedure or function call
0084:             */
0085:            RoutineAliasInfo routineInfo;
0086:
0087:            /**
0088:            	True if this is an internal call, just used to set up a generated method call.
0089:             */
0090:            boolean internalCall;
0091:
0092:            /**
0093:            	For resolution of procedure INOUT/OUT parameters to the primitive
0094:            	form, such as int[]. May be null.
0095:             */
0096:            private String[] procedurePrimitiveArrayType;
0097:
0098:            // bound signature of arguments, stated in universal types (JSQLType)
0099:            protected JSQLType[] signature;
0100:
0101:            /*
0102:             ** Parameters to the method, if any.  No elements if no parameters.
0103:             */
0104:            protected JavaValueNode[] methodParms;
0105:
0106:            /* The method call */
0107:            protected Member method;
0108:
0109:            protected String actualMethodReturnType;
0110:
0111:            /**
0112:             *	Gets the signature of JSQLTypes needed to propagate a work unit from
0113:             *	target to source.
0114:             *
0115:             *	@return	the JSQLType signature
0116:             */
0117:            public JSQLType[] getSignature() {
0118:                return signature;
0119:            }
0120:
0121:            /**
0122:            	The parameter types for the resolved method.
0123:             */
0124:            String[] methodParameterTypes;
0125:
0126:            /**
0127:             * Initializer for a MethodCallNode
0128:             *
0129:             * @param	methodName	The name of the method to call
0130:             */
0131:            public void init(Object methodName) {
0132:                this .methodName = (String) methodName;
0133:            }
0134:
0135:            public String getMethodName() {
0136:                return methodName;
0137:            }
0138:
0139:            /**
0140:             * @return the name of the class that contains the method, null if not known. It may not be known
0141:             *         until this node has been bound.
0142:             */
0143:            public String getJavaClassName() {
0144:                return javaClassName;
0145:            }
0146:
0147:            /**
0148:             * Set the clause that this node appears in.
0149:             *
0150:             * @param clause	The clause that this node appears in.
0151:             */
0152:            public void setClause(int clause) {
0153:                super .setClause(clause);
0154:                if (methodParms != null) {
0155:                    for (int parm = 0; parm < methodParms.length; parm++) {
0156:                        if (methodParms[parm] != null) {
0157:                            methodParms[parm].setClause(clause);
0158:                        }
0159:                    }
0160:                }
0161:            }
0162:
0163:            /**
0164:             * Add the parameter list.
0165:             * (This flavor is useful when transforming a non-static method call node
0166:             * to a static method call node.)
0167:             *
0168:             * @param methodParms		JavaValueNode[]
0169:             */
0170:
0171:            public void addParms(JavaValueNode[] methodParms) {
0172:                this .methodParms = methodParms;
0173:            }
0174:
0175:            /**
0176:             * Add the parameter list
0177:             *
0178:             * @param parameterList		A Vector of the parameters
0179:             *
0180:             * @exception StandardException		Thrown on error
0181:             */
0182:            public void addParms(Vector parameterList) throws StandardException {
0183:                methodParms = new JavaValueNode[parameterList.size()];
0184:
0185:                int plSize = parameterList.size();
0186:                for (int index = 0; index < plSize; index++) {
0187:                    QueryTreeNode qt;
0188:
0189:                    qt = (QueryTreeNode) parameterList.elementAt(index);
0190:
0191:                    /*
0192:                     ** Since we need the parameter to be in Java domain format, put a
0193:                     ** SQLToJavaValueNode on top of the parameter node if it is a 
0194:                     ** SQLValueNode. But if the parameter is already in Java domain 
0195:                     ** format, then we don't need to do anything.
0196:                     */
0197:                    if (!(qt instanceof  JavaValueNode)) {
0198:                        qt = (SQLToJavaValueNode) getNodeFactory().getNode(
0199:                                C_NodeTypes.SQL_TO_JAVA_VALUE_NODE, qt,
0200:                                getContextManager());
0201:                    }
0202:
0203:                    methodParms[index] = (JavaValueNode) qt;
0204:                }
0205:            }
0206:
0207:            /**
0208:             * Prints the sub-nodes of this object.  See QueryTreeNode.java for
0209:             * how tree printing is supposed to work.
0210:             *
0211:             * @param depth		The depth of this node in the tree
0212:             */
0213:
0214:            public void printSubNodes(int depth) {
0215:                if (SanityManager.DEBUG) {
0216:                    int parm;
0217:
0218:                    super .printSubNodes(depth);
0219:                    if (methodParms != null) {
0220:                        for (parm = 0; parm < methodParms.length; parm++) {
0221:                            if (methodParms[parm] != null) {
0222:                                printLabel(depth, "methodParms[" + parm + "] :");
0223:                                methodParms[parm].treePrint(depth + 1);
0224:                            }
0225:                        }
0226:                    }
0227:                }
0228:            }
0229:
0230:            /**
0231:             * Convert this object to a String.  See comments in QueryTreeNode.java
0232:             * for how this should be done for tree printing.
0233:             *
0234:             * @return	This object as a String
0235:             */
0236:
0237:            public String toString() {
0238:                if (SanityManager.DEBUG) {
0239:                    return "methodName: "
0240:                            + (methodName != null ? methodName : "null") + "\n"
0241:                            + super .toString();
0242:                } else {
0243:                    return "";
0244:                }
0245:            }
0246:
0247:            /**
0248:             * Bind this expression.  This means binding the sub-expressions,
0249:             * as well as figuring out what the return type is for this expression.
0250:             *
0251:             * @param fromList		The FROM list for the query this
0252:             *				expression is in, for binding columns.
0253:             * @param subqueryList		The subquery list being built as we find SubqueryNodes
0254:             * @param aggregateVector	The aggregate vector being built as we find AggregateNodes
0255:             *
0256:             * @exception StandardException		Thrown on error
0257:             */
0258:
0259:            final void bindParameters(FromList fromList,
0260:                    SubqueryList subqueryList, Vector aggregateVector)
0261:                    throws StandardException {
0262:                /* Bind the parameters */
0263:                if (methodParms != null) {
0264:                    int count = methodParms.length;
0265:
0266:                    // with a procedure call the signature
0267:                    // is preformed in StaticMethodCall from
0268:                    // the procedures signature.
0269:                    if (signature == null)
0270:                        signature = new JSQLType[count];
0271:
0272:                    for (int parm = 0; parm < count; parm++) {
0273:                        if (methodParms[parm] != null) {
0274:                            methodParms[parm] = methodParms[parm]
0275:                                    .bindExpression(fromList, subqueryList,
0276:                                            aggregateVector);
0277:
0278:                            if (routineInfo == null)
0279:                                signature[parm] = methodParms[parm]
0280:                                        .getJSQLType();
0281:
0282:                            // prohibit LOB columns/types
0283:                            if (signature[parm] != null) {
0284:                                String type = signature[parm].getSQLType()
0285:                                        .getTypeId().getSQLTypeName();
0286:                                if (type.equals("BLOB") || type.equals("CLOB")
0287:                                        || type.equals("NCLOB")) {
0288:                                    throw StandardException
0289:                                            .newException(SQLState.LOB_AS_METHOD_ARGUMENT_OR_RECEIVER);
0290:                                }
0291:                            }
0292:                        }
0293:                    }
0294:                }
0295:            }
0296:
0297:            /**
0298:             * Return whether or not all of the parameters to this node are
0299:             * QUERY_INVARIANT or CONSTANT.  This is useful for VTIs - a VTI is a candidate
0300:             * for materialization if all of its parameters are QUERY_INVARIANT or CONSTANT
0301:             *
0302:             * @return Whether or not all of the parameters to this node are QUERY_INVARIANT or CONSTANT
0303:             * @exception StandardException	thrown on error
0304:             */
0305:            protected boolean areParametersQueryInvariant()
0306:                    throws StandardException {
0307:                return (getVariantTypeOfParams() == Qualifier.QUERY_INVARIANT);
0308:            }
0309:
0310:            /**
0311:             * Build parameters for error message and throw the exception when there
0312:             * is no matching signature found.
0313:             *
0314:             * @param receiverTypeName	Type name for receiver
0315:             * @param parmTypeNames		Type names for parameters as object types
0316:             * @param primParmTypeNames	Type names for parameters as primitive types
0317:             *
0318:             * @exception StandardException		Thrown on error
0319:             */
0320:            void throwNoMethodFound(String receiverTypeName,
0321:                    String[] parmTypeNames, String[] primParmTypeNames)
0322:                    throws StandardException {
0323:                /* Put the parameter type names into a single string */
0324:                StringBuffer parmTypes = new StringBuffer();
0325:                for (int i = 0; i < parmTypeNames.length; i++) {
0326:                    if (i != 0)
0327:                        parmTypes.append(", ");
0328:                    /* RESOLVE - shouldn't be using hard coded strings for output */
0329:                    parmTypes
0330:                            .append((parmTypeNames[i].length() != 0 ? parmTypeNames[i]
0331:                                    : "UNTYPED"));
0332:                    if ((primParmTypeNames != null)
0333:                            && !primParmTypeNames[i].equals(parmTypeNames[i])) // has primitive
0334:                        parmTypes.append("(" + primParmTypeNames[i] + ")");
0335:                }
0336:
0337:                throw StandardException.newException(
0338:                        SQLState.LANG_NO_METHOD_FOUND, receiverTypeName,
0339:                        methodName, parmTypes);
0340:            }
0341:
0342:            /**
0343:             * Preprocess an expression tree.  We do a number of transformations
0344:             * here (including subqueries, IN lists, LIKE and BETWEEN) plus
0345:             * subquery flattening.
0346:             * NOTE: This is done before the outer ResultSetNode is preprocessed.
0347:             *
0348:             * @param	numTables			Number of tables in the DML Statement
0349:             * @param	outerFromList		FromList from outer query block
0350:             * @param	outerSubqueryList	SubqueryList from outer query block
0351:             * @param	outerPredicateList	PredicateList from outer query block
0352:             *
0353:             * @exception StandardException		Thrown on error
0354:             */
0355:            public void preprocess(int numTables, FromList outerFromList,
0356:                    SubqueryList outerSubqueryList,
0357:                    PredicateList outerPredicateList) throws StandardException {
0358:                int parm;
0359:
0360:                /* Preprocess the parameters */
0361:                if (methodParms != null) {
0362:                    for (parm = 0; parm < methodParms.length; parm++) {
0363:                        if (methodParms[parm] != null) {
0364:                            methodParms[parm].preprocess(numTables,
0365:                                    outerFromList, outerSubqueryList,
0366:                                    outerPredicateList);
0367:                        }
0368:                    }
0369:                }
0370:            }
0371:
0372:            /**
0373:             * Categorize this predicate.  Initially, this means
0374:             * building a bit map of the referenced tables for each predicate.
0375:             * If the source of this ColumnReference (at the next underlying level) 
0376:             * is not a ColumnReference or a VirtualColumnNode then this predicate
0377:             * will not be pushed down.
0378:             *
0379:             * For example, in:
0380:             *		select * from (select 1 from s) a (x) where x = 1
0381:             * we will not push down x = 1.
0382:             * NOTE: It would be easy to handle the case of a constant, but if the
0383:             * inner SELECT returns an arbitrary expression, then we would have to copy
0384:             * that tree into the pushed predicate, and that tree could contain
0385:             * subqueries and method calls.
0386:             * RESOLVE - revisit this issue once we have views.
0387:             *
0388:             * @param referencedTabs	JBitSet with bit map of referenced FromTables
0389:             * @param simplePredsOnly	Whether or not to consider method
0390:             *							calls, field references and conditional nodes
0391:             *							when building bit map
0392:             *
0393:             * @return boolean		Whether or not source.expression is a ColumnReference
0394:             *						or a VirtualColumnNode.
0395:             * @exception StandardException			Thrown on error
0396:             */
0397:            public boolean categorize(JBitSet referencedTabs,
0398:                    boolean simplePredsOnly) throws StandardException {
0399:                /* We stop here when only considering simple predicates
0400:                 *  as we don't consider method calls when looking
0401:                 * for null invariant predicates.
0402:                 */
0403:                if (simplePredsOnly) {
0404:                    return false;
0405:                }
0406:
0407:                boolean pushable = true;
0408:                int param;
0409:
0410:                if (methodParms != null) {
0411:                    for (param = 0; param < methodParms.length; param++) {
0412:                        if (methodParms[param] != null) {
0413:                            pushable = methodParms[param].categorize(
0414:                                    referencedTabs, simplePredsOnly)
0415:                                    && pushable;
0416:                        }
0417:                    }
0418:                }
0419:
0420:                /* We need to push down method call.  Then the predicate can be used for start/stop
0421:                 * key for index scan.  The fact that method call's cost is not predictable and can
0422:                 * be expensive doesn't mean we shouldn't push it down. Beetle 4826.
0423:                 */
0424:                return pushable;
0425:            }
0426:
0427:            /**
0428:             * Remap all ColumnReferences in this tree to be clones of the
0429:             * underlying expression.
0430:             *
0431:             * @return JavaValueNode			The remapped expression tree.
0432:             *
0433:             * @exception StandardException			Thrown on error
0434:             */
0435:            public JavaValueNode remapColumnReferencesToExpressions()
0436:                    throws StandardException {
0437:                int param;
0438:
0439:                if (methodParms != null) {
0440:                    for (param = 0; param < methodParms.length; param++) {
0441:                        if (methodParms[param] != null) {
0442:                            methodParms[param] = methodParms[param]
0443:                                    .remapColumnReferencesToExpressions();
0444:                        }
0445:                    }
0446:                }
0447:                return this ;
0448:            }
0449:
0450:            /**
0451:             * Generate the parameters to the given method call
0452:             *
0453:             * @param acb	The ExpressionClassBuilder for the class we're generating
0454:             * @param mb the method  the expression will go into
0455:             *
0456:             * @return	Count of arguments to the method.
0457:             *
0458:             * @exception StandardException		Thrown on error
0459:             */
0460:
0461:            public int generateParameters(ExpressionClassBuilder acb,
0462:                    MethodBuilder mb) throws StandardException {
0463:                int param;
0464:
0465:                String[] expectedTypes = methodParameterTypes;
0466:
0467:                ClassInspector classInspector = getClassFactory()
0468:                        .getClassInspector();
0469:
0470:                /* Generate the code for each user parameter, generating the appropriate
0471:                 * cast when the passed type needs to get widened to the expected type.
0472:                 */
0473:                for (param = 0; param < methodParms.length; param++) {
0474:                    generateOneParameter(acb, mb, param);
0475:
0476:                    // type from the SQL-J expression
0477:                    String argumentType = getParameterTypeName(methodParms[param]);
0478:
0479:                    // type of the method
0480:                    String parameterType = expectedTypes[param];
0481:
0482:                    if (!parameterType.equals(argumentType)) {
0483:                        // since we reached here through method resolution
0484:                        // casts are only required for primitive types.
0485:                        // In any other case the expression type must be assignable
0486:                        // to the parameter type.
0487:                        if (classInspector.primitiveType(parameterType)) {
0488:                            mb.cast(parameterType);
0489:                        } else {
0490:
0491:                            // for a prodcedure
0492:                            if (routineInfo != null) {
0493:                                continue; // probably should be only for INOUT/OUT parameters.
0494:                            }
0495:
0496:                            if (SanityManager.DEBUG) {
0497:                                SanityManager
0498:                                        .ASSERT(
0499:                                                classInspector.assignableTo(
0500:                                                        argumentType,
0501:                                                        parameterType),
0502:                                                "Argument type "
0503:                                                        + argumentType
0504:                                                        + " is not assignable to parameter "
0505:                                                        + parameterType);
0506:                            }
0507:
0508:                            /*
0509:                             ** Set the parameter type in case the argument type is narrower
0510:                             ** than the parameter type.
0511:                             */
0512:                            mb.upCast(parameterType);
0513:
0514:                        }
0515:                    }
0516:
0517:                }
0518:
0519:                return methodParms.length;
0520:            }
0521:
0522:            static public String getParameterTypeName(JavaValueNode param)
0523:                    throws StandardException {
0524:                String argumentType;
0525:
0526:                // RESOLVE - shouldn't this logic be inside JavaValueNode ??
0527:                // I.e. once the value is primitive then its java type name is its
0528:                // primitive type name.
0529:                if (param.isPrimitiveType()) {
0530:                    argumentType = param.getPrimitiveTypeName();
0531:                } else {
0532:                    argumentType = param.getJavaTypeName();
0533:                }
0534:
0535:                return argumentType;
0536:            }
0537:
0538:            /**
0539:             * Generate one parameter to the given method call. This method is overriden by
0540:             * RepStaticMethodCallNode.
0541:             *
0542:             * @param acb				The ExpressionClassBuilder for the class we're generating
0543:             * @param mb the method the expression will go into
0544:             * @param parameterNumber	Identifies which parameter to generate. 0 based.
0545:             *
0546:             * @exception StandardException		Thrown on error
0547:             */
0548:
0549:            public void generateOneParameter(ExpressionClassBuilder acb,
0550:                    MethodBuilder mb, int parameterNumber)
0551:                    throws StandardException {
0552:                methodParms[parameterNumber].generateExpression(acb, mb);
0553:            }
0554:
0555:            /**
0556:             * Set the appropriate type information for a null passed as a parameter.
0557:             * This method is called after method resolution, when a signature was
0558:             * successfully matched.
0559:             *
0560:             * @param parmTypeNames	String[] with the java type names for the parameters
0561:             *        as declared by the method
0562:             *
0563:             * @exception StandardException		Thrown on error
0564:             */
0565:            public void setNullParameterInfo(String[] parmTypeNames)
0566:                    throws StandardException {
0567:                for (int i = 0; i < methodParms.length; i++) {
0568:                    /* null parameters are represented by a java type name of "" */
0569:                    if (methodParms[i].getJavaTypeName().equals("")) {
0570:                        /* Set the type information in the null constant node */
0571:                        DataTypeDescriptor dts = DataTypeDescriptor
0572:                                .getSQLDataTypeDescriptor(parmTypeNames[i]);
0573:                        ((SQLToJavaValueNode) methodParms[i]).value
0574:                                .setType(dts);
0575:
0576:                        /* Set the correct java type name */
0577:                        methodParms[i].setJavaTypeName(parmTypeNames[i]);
0578:                        signature[i] = methodParms[i].getJSQLType();
0579:                    }
0580:                }
0581:            }
0582:
0583:            protected void resolveMethodCall(String javaClassName,
0584:                    boolean staticMethod) throws StandardException {
0585:                // only allow direct method calls through routines and internal SQL.
0586:                if (routineInfo == null && !internalCall) {
0587:                    // See if we are being executed in an internal context
0588:                    if ((getCompilerContext().getReliability() & CompilerContext.INTERNAL_SQL_ILLEGAL) != 0) {
0589:                        throw StandardException.newException(
0590:                                SQLState.LANG_SYNTAX_ERROR, javaClassName
0591:                                        + (staticMethod ? "::" : ".")
0592:                                        + methodName);
0593:                    }
0594:                }
0595:
0596:                int count = signature.length;
0597:
0598:                ClassInspector classInspector = getClassFactory()
0599:                        .getClassInspector();
0600:
0601:                String[] parmTypeNames;
0602:                String[] primParmTypeNames = null;
0603:                boolean[] isParam = getIsParam();
0604:
0605:                boolean hasDynamicResultSets = (routineInfo != null)
0606:                        && (count != 0) && (count != methodParms.length);
0607:
0608:                /*
0609:                 ** Find the matching method that is public.
0610:                 */
0611:
0612:                int signatureOffset = methodName.indexOf('(');
0613:
0614:                // support Java signatures by checking if the method name contains a '('
0615:                if (signatureOffset != -1) {
0616:                    parmTypeNames = parseValidateSignature(methodName,
0617:                            signatureOffset, hasDynamicResultSets);
0618:                    methodName = methodName.substring(0, signatureOffset);
0619:
0620:                    // If the signature is specified then Derby resolves to exactly
0621:                    // that method. Setting this flag to false disables the method
0622:                    // resolution from automatically optionally repeating the last
0623:                    // parameter as needed.
0624:                    hasDynamicResultSets = false;
0625:
0626:                } else {
0627:                    parmTypeNames = getObjectSignature();
0628:                }
0629:                try {
0630:                    method = classInspector.findPublicMethod(javaClassName,
0631:                            methodName, parmTypeNames, null, isParam,
0632:                            staticMethod, hasDynamicResultSets);
0633:
0634:                    // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE
0635:                    // and these are the only types that can map to a primitive or an object type according
0636:                    // to SQL part 13. So we never have a second chance match.
0637:                    // Also if the DDL specified a signature, then no alternate resolution
0638:                    if (signatureOffset == -1 && routineInfo == null) {
0639:
0640:                        /* If no match, then retry with combinations of object and
0641:                         * primitive types.
0642:                         */
0643:                        if (method == null) {
0644:                            primParmTypeNames = getPrimitiveSignature(false);
0645:
0646:                            method = classInspector.findPublicMethod(
0647:                                    javaClassName, methodName, parmTypeNames,
0648:                                    primParmTypeNames, isParam, staticMethod,
0649:                                    hasDynamicResultSets);
0650:                        }
0651:                    }
0652:                } catch (ClassNotFoundException e) {
0653:                    /*
0654:                     ** If one of the classes couldn't be found, just act like the
0655:                     ** method couldn't be found.  The error lists all the class names,
0656:                     ** which should give the user enough info to diagnose the problem.
0657:                     */
0658:                    method = null;
0659:                }
0660:                /* Throw exception if no matching signature found */
0661:                if (method == null) {
0662:                    throwNoMethodFound(javaClassName, parmTypeNames,
0663:                            primParmTypeNames);
0664:                }
0665:
0666:                String typeName = classInspector.getType(method);
0667:                actualMethodReturnType = typeName;
0668:
0669:                if (routineInfo == null) {
0670:
0671:                    /* void methods are only okay for CALL Statements */
0672:                    if (typeName.equals("void")) {
0673:                        if (!forCallStatement)
0674:                            throw StandardException
0675:                                    .newException(SQLState.LANG_VOID_METHOD_CALL);
0676:                    }
0677:                } else {
0678:                    String promoteName = null;
0679:                    TypeDescriptor returnType = routineInfo.getReturnType();
0680:                    String requiredType;
0681:                    if (returnType == null) {
0682:                        // must have a void method for a procedure call.
0683:                        requiredType = "void";
0684:                    } else {
0685:
0686:                        // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE
0687:                        // and these are the only types that can map to a primitive or an object type according
0688:                        // to SQL part 13. So always map to the primitive type. We can not use the getPrimitiveSignature()
0689:                        // as it (incorrectly but historically always has) maps a DECIMAL to a double. 
0690:
0691:                        TypeId returnTypeId = TypeId
0692:                                .getBuiltInTypeId(returnType.getJDBCTypeId());
0693:                        switch (returnType.getJDBCTypeId()) {
0694:                        case java.sql.Types.SMALLINT:
0695:                        case java.sql.Types.INTEGER:
0696:                        case java.sql.Types.BIGINT:
0697:                        case java.sql.Types.REAL:
0698:                        case java.sql.Types.DOUBLE:
0699:                            TypeCompiler tc = getTypeCompiler(returnTypeId);
0700:                            requiredType = tc
0701:                                    .getCorrespondingPrimitiveTypeName();
0702:                            if (!routineInfo.calledOnNullInput()
0703:                                    && routineInfo.getParameterCount() != 0) {
0704:                                promoteName = returnTypeId
0705:                                        .getCorrespondingJavaTypeName();
0706:                            }
0707:
0708:                            break;
0709:                        default:
0710:                            requiredType = returnTypeId
0711:                                    .getCorrespondingJavaTypeName();
0712:                            break;
0713:                        }
0714:
0715:                    }
0716:
0717:                    if (!requiredType.equals(typeName)) {
0718:                        throwNoMethodFound(requiredType + " " + javaClassName,
0719:                                parmTypeNames, primParmTypeNames);
0720:                    }
0721:
0722:                    // for a returns null on null input with a primitive
0723:                    // type we need to promote to an object so we can return null.
0724:                    if (promoteName != null)
0725:                        typeName = promoteName;
0726:                }
0727:                setJavaTypeName(typeName);
0728:
0729:                methodParameterTypes = classInspector.getParameterTypes(method);
0730:
0731:                for (int i = 0; i < methodParameterTypes.length; i++) {
0732:                    String methodParameter = methodParameterTypes[i];
0733:
0734:                    if (routineInfo != null) {
0735:                        if (i < routineInfo.getParameterCount()) {
0736:                            int parameterMode = routineInfo.getParameterModes()[i];
0737:
0738:                            switch (parameterMode) {
0739:                            case JDBC30Translation.PARAMETER_MODE_IN:
0740:                                break;
0741:                            case JDBC30Translation.PARAMETER_MODE_IN_OUT:
0742:                                // we need to see if the type of the array is
0743:                                // primitive, not the array itself.
0744:                                methodParameter = methodParameter.substring(0,
0745:                                        methodParameter.length() - 2);
0746:                                break;
0747:
0748:                            case JDBC30Translation.PARAMETER_MODE_OUT:
0749:                                // value is not obtained *from* parameter.
0750:                                continue;
0751:                            }
0752:                        }
0753:                    }
0754:
0755:                    if (ClassInspector.primitiveType(methodParameter))
0756:                        methodParms[i].castToPrimitive(true);
0757:                }
0758:
0759:                /* Set type info for any null parameters */
0760:                if (someParametersAreNull()) {
0761:                    setNullParameterInfo(methodParameterTypes);
0762:                }
0763:
0764:                /* bug 4450 - if the callable statement is ? = call form, generate the metadata
0765:                infor for the return parameter. We don't really need that info in order to
0766:                execute the callable statement. But with jdbc3.0, this information should be
0767:                made available for return parameter through ParameterMetaData class.
0768:                Parser sets a flag in compilercontext if ? = call. If the flag is set,
0769:                we generate the metadata info for the return parameter and reset the flag
0770:                in the compilercontext for future call statements*/
0771:                DataTypeDescriptor dts = DataTypeDescriptor
0772:                        .getSQLDataTypeDescriptor(typeName);
0773:                if (getCompilerContext().getReturnParameterFlag()) {
0774:                    getCompilerContext().getParameterTypes()[0] = dts;
0775:                }
0776:            }
0777:
0778:            /**
0779:             * Parse the user supplied signature for a method and validate
0780:             * it, need to match the number of parameters passed in and match
0781:             * the valid types for the parameter.
0782:             * @param offset Character offset of first paren
0783:             * @param hasDynamicResultSets Can ResultSet[] parameters be specified.
0784:             * @return The valid array of types for resolution.
0785:             * @throws StandardException
0786:             */
0787:            private String[] parseValidateSignature(String externalName,
0788:                    int offset, boolean hasDynamicResultSets)
0789:                    throws StandardException {
0790:                int siglen = externalName.length();
0791:
0792:                // Ensure the opening paren is not the last
0793:                // character and that the last character is a close paren
0794:                if (((offset + 1) == siglen)
0795:                        || (externalName.charAt(siglen - 1) != ')'))
0796:                    throw StandardException
0797:                            .newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid
0798:
0799:                StringTokenizer st = new StringTokenizer(externalName
0800:                        .substring(offset + 1, siglen - 1), ",", true);
0801:
0802:                String[] signatureTypes = new String[signature.length];
0803:                int count;
0804:                boolean seenClass = false;
0805:                for (count = 0; st.hasMoreTokens();) {
0806:                    String type = st.nextToken().trim();
0807:
0808:                    // check sequence is <class><comma>class> etc.
0809:                    if (",".equals(type)) {
0810:                        if (!seenClass)
0811:                            throw StandardException
0812:                                    .newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid
0813:                        seenClass = false;
0814:                        continue;
0815:                    } else {
0816:                        if (type.length() == 0)
0817:                            throw StandardException
0818:                                    .newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid
0819:                        seenClass = true;
0820:                        count++;
0821:                    }
0822:
0823:                    if (count > signature.length) {
0824:                        if (hasDynamicResultSets) {
0825:                            // Allow any number of dynamic result set holders
0826:                            // but they must match the exact type.
0827:                            String rsType = signature[signature.length - 1]
0828:                                    .getSQLType().getTypeId()
0829:                                    .getCorrespondingJavaTypeName();
0830:
0831:                            if (!type.equals(rsType))
0832:                                throw StandardException.newException(
0833:                                        SQLState.LANG_DATA_TYPE_GET_MISMATCH,
0834:                                        type, rsType);
0835:
0836:                            if (signatureTypes.length == signature.length) {
0837:                                // expand once
0838:                                String[] sigs = new String[st.countTokens()];
0839:                                System.arraycopy(signatureTypes, 0, sigs, 0,
0840:                                        signatureTypes.length);
0841:                                signatureTypes = sigs;
0842:                            }
0843:
0844:                            signatureTypes[count - 1] = type;
0845:                            continue;
0846:
0847:                        }
0848:                        throw StandardException.newException(
0849:                                SQLState.SQLJ_SIGNATURE_PARAMETER_COUNT,
0850:                                Integer.toString(count), Integer
0851:                                        .toString(signature.length)); // too many types
0852:                    }
0853:
0854:                    TypeId paramTypeId = signature[count - 1].getSQLType()
0855:                            .getTypeId();
0856:
0857:                    // Does it match the object name
0858:                    if (type.equals(paramTypeId.getCorrespondingJavaTypeName())) {
0859:                        signatureTypes[count - 1] = type;
0860:                        continue;
0861:                    }
0862:
0863:                    // how about the primitive name
0864:                    if ((paramTypeId.isNumericTypeId() && !paramTypeId
0865:                            .isDecimalTypeId())
0866:                            || paramTypeId.isBooleanTypeId()) {
0867:                        TypeCompiler tc = getTypeCompiler(paramTypeId);
0868:                        if (type.equals(tc.getCorrespondingPrimitiveTypeName())) {
0869:                            signatureTypes[count - 1] = type;
0870:                            continue;
0871:                        }
0872:                    }
0873:                    throw StandardException.newException(
0874:                            SQLState.LANG_DATA_TYPE_GET_MISMATCH, type,
0875:                            paramTypeId.getSQLTypeName()); // type conversion error
0876:                }
0877:
0878:                // Did signature end with trailing comma?
0879:                if (count != 0 && !seenClass)
0880:                    throw StandardException
0881:                            .newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid
0882:
0883:                if (count < signatureTypes.length) {
0884:                    if (hasDynamicResultSets) {
0885:                        // we can tolerate a count of one less than the
0886:                        // expected count, which means the procedure is declared
0887:                        // to have dynamic result sets, but the explict signature
0888:                        // doesn't have any ResultSet[] types.
0889:                        // So accept, and procedure will automatically have 0
0890:                        // dynamic results at runtime
0891:                        if (count == (signature.length - 1)) {
0892:                            String[] sigs = new String[count];
0893:                            System.arraycopy(signatureTypes, 0, sigs, 0, count);
0894:                            return sigs;
0895:                        }
0896:                    }
0897:                    throw StandardException.newException(
0898:                            SQLState.SQLJ_SIGNATURE_PARAMETER_COUNT, Integer
0899:                                    .toString(count), Integer
0900:                                    .toString(signature.length)); // too few types
0901:                }
0902:
0903:                return signatureTypes;
0904:            }
0905:
0906:            /**
0907:             *	Return true if some parameters are null, false otherwise.
0908:             */
0909:            protected boolean someParametersAreNull() {
0910:                int count = signature.length;
0911:
0912:                for (int ictr = 0; ictr < count; ictr++) {
0913:                    if (signature[ictr] == null) {
0914:                        return true;
0915:                    }
0916:                }
0917:
0918:                return false;
0919:            }
0920:
0921:            /**
0922:             *	Build an array of names of the argument types. These types are biased toward
0923:             *	Java objects. That is, if an argument is of SQLType, then we map it to the
0924:             *	corresponding Java synonym class (e.g., SQLINT is mapped to 'java.lang.Integer').
0925:             *
0926:             *
0927:             *	@return	array of type names
0928:             *
0929:             * @exception StandardException		Thrown on error
0930:             */
0931:            protected String[] getObjectSignature() throws StandardException {
0932:                int count = signature.length;
0933:                String parmTypeNames[] = new String[count];
0934:
0935:                for (int i = 0; i < count; i++) {
0936:                    parmTypeNames[i] = getObjectTypeName(signature[i]);
0937:                }
0938:
0939:                return parmTypeNames;
0940:            }
0941:
0942:            /**
0943:             * Build an array of booleans denoting whether or not a given method
0944:             * parameter is a ?.
0945:             *
0946:             * @return array of booleans denoting wheter or not a given method
0947:             * parameter is a ?.
0948:             */
0949:            protected boolean[] getIsParam() {
0950:                if (methodParms == null) {
0951:                    return new boolean[0];
0952:                }
0953:
0954:                boolean[] isParam = new boolean[methodParms.length];
0955:
0956:                for (int index = 0; index < methodParms.length; index++) {
0957:                    if (methodParms[index] instanceof  SQLToJavaValueNode) {
0958:                        SQLToJavaValueNode stjvn = (SQLToJavaValueNode) methodParms[index];
0959:                        if (stjvn.value.requiresTypeFromContext()) {
0960:                            isParam[index] = true;
0961:                        }
0962:                    }
0963:                }
0964:
0965:                return isParam;
0966:            }
0967:
0968:            private String getObjectTypeName(JSQLType jsqlType)
0969:                    throws StandardException {
0970:                if (jsqlType != null) {
0971:                    switch (jsqlType.getCategory()) {
0972:                    case JSQLType.SQLTYPE:
0973:
0974:                        TypeId ctid = mapToTypeID(jsqlType);
0975:
0976:                        if (ctid == null) {
0977:                            return null;
0978:                        } else {
0979:                            // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE
0980:                            // and these are the only types that can map to a primitive or an object type according
0981:                            // to SQL part 13. So always map to the primitive type. We can not use the getPrimitiveSignature()
0982:                            // as it (incorrectly but historically always has) maps a DECIMAL to a double. 
0983:
0984:                            switch (ctid.getJDBCTypeId()) {
0985:                            case java.sql.Types.SMALLINT:
0986:                            case java.sql.Types.INTEGER:
0987:                            case java.sql.Types.BIGINT:
0988:                            case java.sql.Types.REAL:
0989:                            case java.sql.Types.DOUBLE:
0990:                                if (routineInfo != null) {
0991:                                    TypeCompiler tc = getTypeCompiler(ctid);
0992:                                    return tc
0993:                                            .getCorrespondingPrimitiveTypeName();
0994:                                }
0995:                                // fall through
0996:                            default:
0997:                                return ctid.getCorrespondingJavaTypeName();
0998:                            }
0999:                        }
1000:
1001:                    case JSQLType.JAVA_CLASS:
1002:                        return jsqlType.getJavaClassName();
1003:
1004:                    case JSQLType.JAVA_PRIMITIVE:
1005:                        return JSQLType.primitiveNames[jsqlType
1006:                                .getPrimitiveKind()];
1007:
1008:                    default:
1009:
1010:                        if (SanityManager.DEBUG) {
1011:                            SanityManager.THROWASSERT("Unknown JSQLType: "
1012:                                    + jsqlType);
1013:                        }
1014:
1015:                    }
1016:                }
1017:
1018:                return "";
1019:            }
1020:
1021:            String[] getPrimitiveSignature(boolean castToPrimitiveAsNecessary)
1022:                    throws StandardException {
1023:                int count = signature.length;
1024:                String[] primParmTypeNames = new String[count];
1025:                JSQLType jsqlType;
1026:
1027:                for (int i = 0; i < count; i++) {
1028:                    jsqlType = signature[i];
1029:
1030:                    if (jsqlType == null) {
1031:                        primParmTypeNames[i] = "";
1032:                    } else {
1033:                        switch (jsqlType.getCategory()) {
1034:                        case JSQLType.SQLTYPE:
1035:
1036:                            if ((procedurePrimitiveArrayType != null)
1037:                                    && (i < procedurePrimitiveArrayType.length)
1038:                                    && (procedurePrimitiveArrayType[i] != null)) {
1039:
1040:                                primParmTypeNames[i] = procedurePrimitiveArrayType[i];
1041:
1042:                            } else {
1043:
1044:                                TypeId ctid = mapToTypeID(jsqlType);
1045:
1046:                                if ((ctid.isNumericTypeId() && !ctid
1047:                                        .isDecimalTypeId())
1048:                                        || ctid.isBooleanTypeId()) {
1049:                                    TypeCompiler tc = getTypeCompiler(ctid);
1050:                                    primParmTypeNames[i] = tc
1051:                                            .getCorrespondingPrimitiveTypeName();
1052:                                    if (castToPrimitiveAsNecessary) {
1053:                                        methodParms[i].castToPrimitive(true);
1054:                                    }
1055:                                } else {
1056:                                    primParmTypeNames[i] = ctid
1057:                                            .getCorrespondingJavaTypeName();
1058:                                }
1059:                            }
1060:
1061:                            break;
1062:
1063:                        case JSQLType.JAVA_CLASS:
1064:
1065:                            primParmTypeNames[i] = jsqlType.getJavaClassName();
1066:                            break;
1067:
1068:                        case JSQLType.JAVA_PRIMITIVE:
1069:
1070:                            primParmTypeNames[i] = JSQLType.primitiveNames[jsqlType
1071:                                    .getPrimitiveKind()];
1072:                            if (castToPrimitiveAsNecessary) {
1073:                                methodParms[i].castToPrimitive(true);
1074:                            }
1075:                            break;
1076:
1077:                        default:
1078:
1079:                            if (SanityManager.DEBUG) {
1080:                                SanityManager.THROWASSERT("Unknown JSQLType: "
1081:                                        + jsqlType);
1082:                            }
1083:
1084:                        } // end switch
1085:
1086:                    } // end if
1087:
1088:                } // end for
1089:
1090:                return primParmTypeNames;
1091:            }
1092:
1093:            /**
1094:             * Return the variant type for the underlying expression.
1095:             * The variant type can be:
1096:             *		VARIANT				- variant within a scan
1097:             *							  (non-static field access)
1098:             *		SCAN_INVARIANT		- invariant within a scan
1099:             *							  (column references from outer tables)
1100:             *		QUERY_INVARIANT		- invariant within the life of a query
1101:             *							  (constant expressions)
1102:             *
1103:             * @return	The variant type for the underlying expression.
1104:             */
1105:            protected int getOrderableVariantType() throws StandardException {
1106:                // beetle 4880. We return the most variant type of the parameters. If no
1107:                // params then query-invariant. This makes more sense, and we can evaluate
1108:                // only once per query (good for performance) because method call could be
1109:                // expensive.  And if we push down method qualifier to store, language
1110:                // can pre-evaluate the method call.  This avoids letting store evaluate
1111:                // the method while holding page latch, causing deadlock.
1112:
1113:                return getVariantTypeOfParams();
1114:            }
1115:
1116:            private int getVariantTypeOfParams() throws StandardException {
1117:                int variance = Qualifier.QUERY_INVARIANT;
1118:
1119:                if (methodParms != null) {
1120:                    for (int parm = 0; parm < methodParms.length; parm++) {
1121:                        if (methodParms[parm] != null) {
1122:                            int paramVariantType = methodParms[parm]
1123:                                    .getOrderableVariantType();
1124:                            if (paramVariantType < variance) //return the most variant type
1125:                                variance = paramVariantType;
1126:                        } else {
1127:                            variance = Qualifier.VARIANT;
1128:                        }
1129:                    }
1130:                }
1131:
1132:                return variance;
1133:            }
1134:
1135:            /////////////////////////////////////////////////////////////////////
1136:            //
1137:            //	ACCESSORS
1138:            //
1139:            /////////////////////////////////////////////////////////////////////
1140:            /**
1141:             * Get the method parameters.
1142:             * 
1143:             * @return	The method parameters
1144:             */
1145:            public JavaValueNode[] getMethodParms() {
1146:                return methodParms;
1147:            }
1148:
1149:            /**
1150:             * Accept a visitor, and call v.visit()
1151:             * on child nodes as necessary.  
1152:             * 
1153:             * @param v the visitor
1154:             *
1155:             * @exception StandardException on error
1156:             */
1157:            public Visitable accept(Visitor v) throws StandardException {
1158:                Visitable returnNode = v.visit(this );
1159:
1160:                if (v.skipChildren(this )) {
1161:                    return returnNode;
1162:                }
1163:
1164:                for (int parm = 0; !v.stopTraversal()
1165:                        && parm < methodParms.length; parm++) {
1166:                    if (methodParms[parm] != null) {
1167:                        methodParms[parm] = (JavaValueNode) methodParms[parm]
1168:                                .accept(v);
1169:                    }
1170:                }
1171:
1172:                return returnNode;
1173:            }
1174:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.