📄 function.java
字号:
/* Copyright (c) 1995-2000, The Hypersonic SQL Group. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the Hypersonic SQL Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software consists of voluntary contributions made by many individuals * on behalf of the Hypersonic SQL Group. * * * For work added by the HSQL Development Group: * * Copyright (c) 2001-2005, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */package org.hsqldb;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.sql.Connection;import org.hsqldb.lib.HashMap;import org.hsqldb.lib.HsqlArrayList;import org.hsqldb.lib.StringConverter;import org.hsqldb.types.Binary;import org.hsqldb.types.JavaObject;// fredt@users 20020912 - patch 1.7.1 - shortcut treatment of identity() call// fredt@users 20020912 - patch 1.7.1 - cache java.lang.reflect.Method objects// fredt@users 20021013 - patch 1.7.1 - ignore non-static methods// boucherb@users 20030201 - patch 1.7.2 - direct calls for org.hsqldb.Library// fredt@users 20030621 - patch 1.7.2 - shortcut treatment of session calls// boucherb@users 200404xx - doc 1.7.2 - updates toward 1.7.2 final/** * Provides services to evaluate SQL function and stored procedure calls, * by invoking Java methods. * * Extended in successive versions of HSQLDB. * * @author Thomas Mueller (Hypersonic SQL Group) * @version 1.8.0 * @since Hypersonic SQL */class Function { private String sFunction; private Method mMethod; private String returnClassName; private Class[] aArgClasses; private int iReturnType; private int iArgCount; private int iSqlArgCount; private int iSqlArgStart; private int[] iArgType; private boolean[] bArgNullable; Expression[] eArg; private boolean bConnection; private static HashMap methodCache = new HashMap(); private int fID; String name; // name used to call function boolean isSimple; //CURRENT_TIME, NOW etc. boolean hasAggregate; /** * Constructs a new Function object with the given function call name * and using the specified Session context. <p> * * The call name is the fully qualified name of a static Java method, in * the form "package.class.method." This implies that Java * methods with the same fully qualified name but different signatures * cannot be used properly as HSQLDB SQL functions or stored procedures. * For instance, it is impossible to call both System.getProperty(String) * and System.getProperty(String,String) under this arrangement, because * the HSQLDB Function object is unable to differentiate between the two; * it simply chooses the first method matching the FQN in the array of * methods obtained from calling getMethods() on an instance of the * Class indicated in the FQN, hiding all other methods with the same * FQN. <p> * * The function FQN must match at least one static Java method FQN in the * specified class or construction cannot procede and an HsqlException is * thrown. <p> * * The isSimple parameter is true when certain SQL standard functions * that are used without brackets are invokded. * * @param name this Function object's call name * @param fqn the fully qualified name of a Java method * @param isSimple if true, used to evalate CURRENT_TIME, NOW etc. * evaluate * @throws HsqlException if the specified function FQN corresponds to no * Java method */ Function(String name, String fqn, boolean isSimple) throws HsqlException { this.name = name; this.isSimple = isSimple;// cSession = session; sFunction = fqn; fID = Library.functionID(fqn); int i = fqn.lastIndexOf('.'); Trace.check(i != -1, Trace.UNEXPECTED_TOKEN, fqn); String classname = fqn.substring(0, i); mMethod = (Method) methodCache.get(fqn); if (mMethod == null) { String methodname = fqn.substring(i + 1); Class classinstance = null; try { classinstance = Class.forName(classname); } catch (Exception e) { throw Trace.error(Trace.FUNCTION_NOT_FOUND, Trace.Message_Pair, new Object[] { classname, e }); } // public only, but includes those inherited from // superclasses and superinterfaces. List is unordered. Method[] methods = classinstance.getMethods(); for (i = 0; i < methods.length; i++) { Method m = methods[i]; if (m.getName().equals(methodname) && Modifier.isStatic(m.getModifiers())) { mMethod = m; break; } } Trace.check(mMethod != null, Trace.UNKNOWN_FUNCTION, methodname); methodCache.put(fqn, mMethod); } Class returnClass = mMethod.getReturnType(); if (returnClass.equals(org.hsqldb.Result.class)) { // For now, we can write stored procedures whose // descriptor explicitly specifies the above return type. // Later, this will be modified or replaced to provide proper // support for jdbcCallableStatement OUT mode return parameter, // multiple results (Result.MULTI etc.) iReturnType = Types.OTHER; } else { // Now we support the following construction-time return type // Classes, as specified by the method descriptor: // // 1.) any primitive or primitive wrapper type, except Byte(.TYPE), // Short(.TYPE) and Float(.TYPE) (TBD; narrow if no truncation) // // 2.) any primitive array type // // 3.) any non-primitive array whose base component implements // java.io.Serializable // // 4.) any class implementing java.io.Serializable, except those // described in 1.) as currently unsupported // // 5.) java.lang.Object // // For java.lang.Object, checking is deferred from the construction // stage to the evaluation stage. In general, for the evaluation // to succeed, the runtime class of the retrieved Object must be // // 1.) any primitive or primitive wrapper type, except Byte(.TYPE), // Short(.TYPE) and Float(.TYPE) (TBD; narrow if no trunction) // // 2.) any primitive array type // 3.) any non-primitive array whose base component implements // java.io.Serializable // // 4.) any class implementing java.io.Serializable, except those // described in 1.) as currently unsupported // // Additionally, it is possible for the evaluation to succeed under // an SQL CALL if the runtime Class of the returned Object is not // from the list above but is from the list below: // // 1.) is org.hsqldb.Result // 2.) is org.hsqldb.jdbc.jdbcResultSet // // In these special cases, the statement executor notices the // types and presents the client with a view the underlying result // rather than with a view of the object as an opaque scalar value // iReturnType = Types.getParameterTypeNr(returnClass); } returnClassName = Types.getFunctionReturnClassName(returnClass.getName()); aArgClasses = mMethod.getParameterTypes(); iArgCount = aArgClasses.length; iArgType = new int[iArgCount]; bArgNullable = new boolean[iArgCount]; for (i = 0; i < aArgClasses.length; i++) { Class a = aArgClasses[i]; String type = a.getName(); if ((i == 0) && a.equals(Connection.class)) { // TODO: provide jdbc:default:connection url functionality // // only the first parameter can be a Connection bConnection = true; } else { // see discussion above for iReturnType iArgType[i] = Types.getParameterTypeNr(a); bArgNullable[i] = !a.isPrimitive(); } } iSqlArgCount = iArgCount; if (bConnection) { iSqlArgCount--; iSqlArgStart = 1; } else { iSqlArgStart = 0; } eArg = new Expression[iArgCount]; } /** * Evaluates and returns this Function in the context of the session.<p> */ Object getValue(Session session) throws HsqlException { switch (fID) { case Library.curtime : return session.getCurrentTime(); case Library.curdate : return session.getCurrentDate(); case Library.database : return session.getDatabase().getPath(); case Library.getAutoCommit : return session.isAutoCommit() ? Boolean.TRUE : Boolean.FALSE; case Library.identity : return session.getLastIdentity(); case Library.isReadOnlyDatabase : return session.getDatabase().databaseReadOnly ? Boolean.TRUE : Boolean.FALSE; case Library.isReadOnlyConnection : return session.isReadOnly() ? Boolean.TRUE : Boolean.FALSE; case Library.isReadOnlyDatabaseFiles : return session.getDatabase().isFilesReadOnly() ? Boolean.TRUE : Boolean .FALSE; case Library.now : return session.getCurrentTimestamp(); case Library.user : return session.getUsername(); } Object[] oArg = getArguments(session); if (oArg == null) { return null; } return getValue(session, oArg); } /** * Evaluates the Function with the given arguments in the session context. */ Object getValue(Session session, Object[] arguments) throws HsqlException { if (bConnection) { arguments[0] = session.getInternalConnection(); } try { Object ret = (fID >= 0) ? Library.invoke(fID, arguments) : mMethod.invoke(null, arguments); return Column.convertObject(ret, iReturnType); } catch (InvocationTargetException e) { // thrown by user functions Throwable t = e.getTargetException(); String s = sFunction + " : " + t.toString(); throw Trace.error(Trace.FUNCTION_CALL_ERROR, s); } catch (IllegalAccessException e) { // never thrown in this method throw Trace.error(Trace.FUNCTION_CALL_ERROR); } // Library function throw HsqlException } private Object[] getArguments(Session session) throws HsqlException { int i = bConnection ? 1 : 0; Object[] oArg = new Object[iArgCount];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -