Package org.hsqldb

Source Code of org.hsqldb.Routine

/* Copyright (c) 2001-2010, 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 org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.HsqlNameManager.SimpleName;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.jdbc.JDBCResultSet;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.result.Result;
import org.hsqldb.rights.Grantee;
import org.hsqldb.store.BitMap;
import org.hsqldb.types.RowType;
import org.hsqldb.types.Type;
import org.hsqldb.types.Types;

/**
* Implementation of specific routine
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
*
* @version 1.9.0
* @since 1.9.0
*/
public class Routine implements SchemaObject {

    public final static int NO_SQL       = 1;
    public final static int CONTAINS_SQL = 2;
    public final static int READS_SQL    = 3;
    public final static int MODIFIES_SQL = 4;

    //
    public final static int LANGUAGE_JAVA = 1;
    public final static int LANGUAGE_SQL  = 2;

    //
    public static final int PARAM_STYLE_JAVA = 1;
    public static final int PARAM_STYLE_SQL  = 2;

    //
    final static Routine[] emptyArray = new Routine[]{};

    //
    RoutineSchema    routineSchema;
    private HsqlName name;
    private HsqlName specificName;
    Type[]           parameterTypes;
    int              typeGroups;
    Type             returnType;
    Type[]           tableType;
    Table            returnTable;
    final int        routineType;
    int              language   = LANGUAGE_SQL;
    int              dataImpact = CONTAINS_SQL;
    int              parameterStyle;
    boolean          isDeterministic;
    boolean          isNullInputOutput;
    boolean          isNewSavepointLevel = true;
    boolean          isPSM;
    boolean          returnsTable;
    Statement        statement;

    //
    boolean isAggregate;

    //
    private String  methodName;
    Method          javaMethod;
    boolean         javaMethodWithConnection;
    private boolean isLibraryRoutine;

    //
    HashMappedList  parameterList = new HashMappedList();
    int             scopeVariableCount;
    RangeVariable[] ranges;

    //
    int variableCount;

    //
    OrderedHashSet references;

    //
    Table triggerTable;
    int   triggerType;
    int   triggerOperation;

    public Routine(int type) {

        routineType = type;
        returnType  = Type.SQL_ALL_TYPES;
        ranges = new RangeVariable[]{
            new RangeVariable(parameterList, false) };
    }

    public Routine(Table table, RangeVariable[] ranges, int impact,
                   int triggerType, int operationType) {

        routineType           = SchemaObject.TRIGGER;
        returnType            = Type.SQL_ALL_TYPES;
        dataImpact            = impact;
        this.ranges           = ranges;
        this.triggerTable     = table;
        this.triggerType      = triggerType;
        this.triggerOperation = operationType;
    }

    public int getType() {
        return routineType;
    }

    public HsqlName getName() {
        return name;
    }

    public HsqlName getSchemaName() {
        return name.schema;
    }

    public HsqlName getCatalogName() {
        return name.schema.schema;
    }

    public Grantee getOwner() {
        return name.schema.owner;
    }

    public OrderedHashSet getReferences() {
        return references;
    }

    public OrderedHashSet getComponents() {
        return null;
    }

    public void compile(Session session, SchemaObject parentObject) {

        ParserRoutine p = new ParserRoutine(session,
                                            new Scanner(statement.getSQL()));

        p.read();
        p.startRecording();

        Statement statement = p.compileSQLProcedureStatementOrNull(this, null);
        Token[]   tokenisedStatement = p.getRecordedStatement();
        String    sql                = Token.getSQL(tokenisedStatement);

        statement.setSQL(sql);
        setProcedure(statement);
        statement.resolve(session);
        setReferences();
    }

    public String getSQL() {

        StringBuffer sb = new StringBuffer();

        sb.append(Tokens.T_CREATE).append(' ');

        if (isAggregate) {
            sb.append(Tokens.T_AGGREGATE).append(' ');
        }

        if (routineType == SchemaObject.PROCEDURE) {
            sb.append(Tokens.T_PROCEDURE);
        } else {
            sb.append(Tokens.T_FUNCTION);
        }

        sb.append(' ');
        sb.append(name.getSchemaQualifiedStatementName());
        sb.append('(');

        for (int i = 0; i < parameterList.size(); i++) {
            if (i > 0) {
                sb.append(',');
            }

            ColumnSchema param = (ColumnSchema) parameterList.get(i);

            // in - out
            sb.append(param.getSQL());
        }

        sb.append(')');
        sb.append(' ');

        if (routineType == SchemaObject.FUNCTION) {
            sb.append(Tokens.T_RETURNS);
            sb.append(' ');

            if (returnsTable) {
                sb.append(Tokens.T_TABLE);
                sb.append(returnTable.getColumnListWithTypeSQL());
            } else {
                sb.append(returnType.getTypeDefinition());
            }

            sb.append(' ');
        }

        // SPECIFIC
        if (specificName != null) {
            sb.append(Tokens.T_SPECIFIC);
            sb.append(' ');
            sb.append(specificName.getStatementName());
            sb.append(' ');
        }

        //
        sb.append(Tokens.T_LANGUAGE);
        sb.append(' ');

        if (language == LANGUAGE_JAVA) {
            sb.append(Tokens.T_JAVA);
        } else {
            sb.append(Tokens.T_SQL);
        }

        sb.append(' ');

        //
        if (!isDeterministic) {
            sb.append(Tokens.T_NOT);
            sb.append(' ');
        }

        sb.append(Tokens.T_DETERMINISTIC);
        sb.append(' ');

        //
        sb.append(getDataImpactString());
        sb.append(' ');

        //
        if (routineType == SchemaObject.FUNCTION) {
            if (isNullInputOutput) {
                sb.append(Tokens.T_RETURNS).append(' ').append(Tokens.T_NULL);
            } else {
                sb.append(Tokens.T_CALLED);
            }

            sb.append(' ').append(Tokens.T_ON).append(' ');
            sb.append(Tokens.T_NULL).append(' ').append(Tokens.T_INPUT);
            sb.append(' ');
        } else {
            if (isNewSavepointLevel) {
                sb.append(Tokens.T_NEW);
            } else {
                sb.append(Tokens.T_OLD);
            }

            sb.append(' ').append(Tokens.T_SAVEPOINT).append(' ');
            sb.append(Tokens.T_LEVEL).append(' ');
        }

        if (language == LANGUAGE_JAVA) {
            sb.append(Tokens.T_EXTERNAL).append(' ').append(Tokens.T_NAME);
            sb.append(' ').append('\'').append(methodName).append('\'');
        } else {
            sb.append(statement.getSQL());
        }

        return sb.toString();
    }

    public long getChangeTimestamp() {
        return 0;
    }

    public void addParameter(ColumnSchema param) {

        HsqlName name = param.getName();
        String paramName =
            name == null
            ? HsqlNameManager.getAutoNoNameColumnString(parameterList.size())
            : name.name;

        parameterList.add(paramName, param);
    }

    public void setLanguage(int lang) {
        language = lang;
        isPSM    = language == LANGUAGE_SQL;
    }

    public int getLanguage() {
        return language;
    }

    boolean isPSM() {
        return isPSM;
    }

    public void setDataImpact(int impact) {
        dataImpact = impact;
    }

    public int getDataImpact() {
        return dataImpact;
    }

    public String getDataImpactString() {

        StringBuffer sb = new StringBuffer();

        switch (this.dataImpact) {

            case NO_SQL :
                sb.append(Tokens.T_NO).append(' ').append(Tokens.T_SQL);
                break;

            case CONTAINS_SQL :
                sb.append(Tokens.T_CONTAINS).append(' ').append(Tokens.T_SQL);
                break;

            case READS_SQL :
                sb.append(Tokens.T_READS).append(' ').append(
                    Tokens.T_SQL).append(' ').append(Tokens.T_DATA);
                break;

            case MODIFIES_SQL :
                sb.append(Tokens.T_MODIFIES).append(' ').append(
                    Tokens.T_SQL).append(' ').append(Tokens.T_DATA);
                break;
        }

        return sb.toString();
    }

    public void setReturnType(Type type) {
        returnType = type;
    }

    public Type getReturnType() {
        return returnType;
    }

    public void setTableType(Type[] types) {
        tableType = types;
    }

    public Type[] getTableType() {
        return tableType;
    }

    public Table getTable() {
        return returnTable;
    }

    public void setProcedure(Statement statement) {
        this.statement = statement;
    }

    public Statement getProcedure() {
        return statement;
    }

    public void setSpecificName(HsqlName name) {
        specificName = name;
    }

    public void setName(HsqlName name) {
        this.name = name;
    }

    public HsqlName getSpecificName() {
        return specificName;
    }

    public void setDeterministic(boolean value) {
        isDeterministic = value;
    }

    public boolean isDeterministic() {
        return isDeterministic;
    }

    public void setNullInputOutput(boolean value) {
        isNullInputOutput = value;
    }

    public boolean isNullInputOutput() {
        return isNullInputOutput;
    }

    public void setNewSavepointLevel(boolean value) {
        isNewSavepointLevel = value;
    }

    public void setParameterStyle(int style) {
        parameterStyle = style;
    }

    public void setMethodURL(String url) {
        this.methodName = url;
    }

    public Method getMethod() {
        return javaMethod;
    }

    public void setMethod(Method method) {
        this.javaMethod = method;
    }

    public void setReturnTable(TableDerived table) {

        this.returnTable  = table;
        this.returnsTable = true;

        SimpleName[] names = new SimpleName[table.getColumnCount()];
        Type[]       types = table.getColumnTypes();

        returnType = new RowType(types);
    }

    public boolean returnsTable() {
        return returnsTable;
    }

    public void setAggregate(boolean isAggregate) {
        this.isAggregate = isAggregate;
    }

    public boolean isAggregate() {
        return isAggregate;
    }

    public void resolve(Session session) {

        setLanguage(language);

        if (language == Routine.LANGUAGE_SQL) {
            if (dataImpact == NO_SQL) {
                throw Error.error(ErrorCode.X_42604);
            }

            if (parameterStyle == PARAM_STYLE_JAVA) {
                throw Error.error(ErrorCode.X_42604);
            }
        }

        if (language == Routine.LANGUAGE_SQL) {
            if (parameterStyle != 0 && parameterStyle != PARAM_STYLE_SQL) {
                throw Error.error(ErrorCode.X_42604);
            }
        }

        parameterTypes = new Type[parameterList.size()];
        typeGroups     = 0;

        for (int i = 0; i < parameterTypes.length; i++) {
            ColumnSchema param = (ColumnSchema) parameterList.get(i);

            parameterTypes[i] = param.dataType;

            if (i < 4) {
                BitMap.setByte(typeGroups,
                               (byte) param.dataType.typeComparisonGroup,
                               i * 8);
            }
        }

        if (statement != null) {
            statement.resolve(session);

            if (dataImpact == CONTAINS_SQL) {
                checkNoSQLData(session.database, statement.getReferences());
            }
        }

        if (methodName != null && javaMethod == null) {
            boolean[] hasConnection = new boolean[1];

            javaMethod = getMethod(methodName, this, hasConnection,
                                   returnsTable);

            if (javaMethod == null) {
                throw Error.error(ErrorCode.X_46103);
            }

            javaMethodWithConnection = hasConnection[0];

            String className = javaMethod.getDeclaringClass().getName();

            if (className.equals("java.lang.Math")) {
                isLibraryRoutine = true;
            }
        }

        if (isAggregate) {
            if (parameterTypes.length != 4) {
                throw Error.error(ErrorCode.X_42610);
            }

            boolean check = parameterTypes[1].typeCode == Types.BOOLEAN;

            //
            ColumnSchema param = (ColumnSchema) parameterList.get(0);

            check &= param.getParameterMode()
                     == SchemaObject.ParameterModes.PARAM_IN;
            param = (ColumnSchema) parameterList.get(1);
            check &= param.getParameterMode()
                     == SchemaObject.ParameterModes.PARAM_IN;
            param = (ColumnSchema) parameterList.get(2);
            check &= param.getParameterMode()
                     == SchemaObject.ParameterModes.PARAM_INOUT;
            param = (ColumnSchema) parameterList.get(3);
            check &= param.getParameterMode()
                     == SchemaObject.ParameterModes.PARAM_INOUT;

            if (!check) {
                throw Error.error(ErrorCode.X_42610);
            }
        }

        setReferences();
    }

    private void setReferences() {

        OrderedHashSet set = new OrderedHashSet();

        for (int i = 0; i < parameterTypes.length; i++) {
            ColumnSchema param = (ColumnSchema) parameterList.get(i);

            set.addAll(param.getReferences());
        }

        if (statement != null) {
            set.addAll(statement.getReferences());
        }

        references = set;
    }

    public boolean isTrigger() {
        return routineType == SchemaObject.TRIGGER;
    }

    public boolean isProcedure() {
        return routineType == SchemaObject.PROCEDURE;
    }

    public boolean isFunction() {
        return routineType == SchemaObject.FUNCTION;
    }

    public ColumnSchema getParameter(int i) {
        return (ColumnSchema) parameterList.get(i);
    }

    Type[] getParameterTypes() {
        return parameterTypes;
    }

    int getParameterSignature() {
        return typeGroups;
    }

    public int getParameterCount() {
        return parameterTypes.length;
    }

    public int getParameterCount(int type) {

        int count = 0;

        for (int i = 0; i < parameterList.size(); i++) {
            ColumnSchema col = (ColumnSchema) parameterList.get(i);

            if (col.getParameterMode() == type) {
                count++;
            }
        }

        return count;
    }

    public int getParameterIndex(String name) {
        return parameterList.getIndex(name);
    }

    public RangeVariable[] getParameterRangeVariables() {
        return ranges;
    }

    public int getVariableCount() {
        return variableCount;
    }

    public boolean isLibraryRoutine() {
        return isLibraryRoutine;
    }

    public HsqlName[] getTableNamesForRead() {

        if (statement == null) {
            return HsqlName.emptyArray;
        }

        return statement.getTableNamesForRead();
    }

    public HsqlName[] getTableNamesForWrite() {

        if (statement == null) {
            return HsqlName.emptyArray;
        }

        return statement.getTableNamesForWrite();
    }

    Object[] convertArgsToJava(Session session, Object[] callArguments) {

        int      extraArg = javaMethodWithConnection ? 1
                                                     : 0;
        Object[] data     = new Object[callArguments.length + extraArg];
        Type[]   types    = getParameterTypes();

        for (int i = 0; i < callArguments.length; i++) {
            Object       value = callArguments[i];
            ColumnSchema param = getParameter(i);

            if (param.parameterMode == SchemaObject.ParameterModes.PARAM_IN) {
                data[i + extraArg] = types[i].convertSQLToJava(session, value);
            } else {
                Object jdbcValue = types[i].convertSQLToJava(session, value);
                Class  cl        = types[i].getJDBCClass();
                Object array     = java.lang.reflect.Array.newInstance(cl, 1);

                java.lang.reflect.Array.set(array, 0, jdbcValue);

                data[i + extraArg] = array;
            }
        }

        return data;
    }

    void convertArgsToSQL(Session session, Object[] callArguments,
                          Object[] data) {

        int    extraArg = javaMethodWithConnection ? 1
                                                   : 0;
        Type[] types    = getParameterTypes();

        for (int i = 0; i < callArguments.length; i++) {
            Object       value = data[i + extraArg];
            ColumnSchema param = getParameter(i);

            if (param.parameterMode != SchemaObject.ParameterModes.PARAM_IN) {
                value = java.lang.reflect.Array.get(value, 0);
            }

            callArguments[i] = types[i].convertJavaToSQL(session, value);
        }
    }

    Result invokeJavaMethod(Session session, Object[] data) {

        Result result;

        try {
            if (dataImpact == Routine.NO_SQL) {
                session.sessionContext.isReadOnly = Boolean.TRUE;

                session.setNoSQL();
            } else if (dataImpact == Routine.CONTAINS_SQL) {
                session.sessionContext.isReadOnly = Boolean.TRUE;
            } else if (dataImpact == Routine.READS_SQL) {
                session.sessionContext.isReadOnly = Boolean.TRUE;
            }

            Object returnValue = javaMethod.invoke(null, data);

            if (returnsTable()) {
                if (returnValue instanceof JDBCResultSet) {
                    result = ((JDBCResultSet) returnValue).result;
                } else {

                    // convert ResultSet to table
                    throw Error.runtimeError(ErrorCode.U_S0500,
                                             "FunctionSQLInvoked");
                }
            } else {
                returnValue = returnType.convertJavaToSQL(session,
                        returnValue);
                result = Result.newPSMResult(returnValue);
            }
        } catch (InvocationTargetException e) {
            result = Result.newErrorResult(
                Error.error(ErrorCode.X_46000, getName().name), null);
        } catch (IllegalAccessException e) {
            result = Result.newErrorResult(
                Error.error(ErrorCode.X_46000, getName().name), null);
        } catch (Throwable e) {
            result = Result.newErrorResult(
                Error.error(ErrorCode.X_46000, getName().name), null);
        }

        return result;
    }

    static Method getMethod(String name, Routine routine,
                            boolean[] hasConnection, boolean returnsTable) {

        int i = name.indexOf(':');

        if (i != -1) {
            if (!name.substring(0, i).equals(SqlInvariants.CLASSPATH_NAME)) {
                throw Error.error(ErrorCode.X_46102, name);
            }

            name = name.substring(i + 1);
        }

        Method[] methods       = getMethods(name);
        int      firstMismatch = -1;

        for (i = 0; i < methods.length; i++) {
            int offset = 0;

            hasConnection[0] = false;

            Method  method = methods[i];
            Class[] params = method.getParameterTypes();

            if (params.length > 0
                    && params[0].equals(java.sql.Connection.class)) {
                offset           = 1;
                hasConnection[0] = true;
            }

            if (params.length - offset != routine.parameterTypes.length) {
                continue;
            }

            if (returnsTable) {
                if (!java.sql.ResultSet.class.isAssignableFrom(
                        method.getReturnType())) {
                    continue;
                }
            } else {
                Type methodReturnType =
                    Types.getParameterSQLType(method.getReturnType());

                if (methodReturnType == null) {
                    continue;
                }

                if (methodReturnType.typeCode != routine.returnType.typeCode) {
                    continue;
                }
            }

            for (int j = 0; j < routine.parameterTypes.length; j++) {
                boolean isInOut = false;
                Class   param   = params[j + offset];

                if (param.isArray()) {
                    if (!byte[].class.equals(param)) {
                        param = param.getComponentType();

                        if (param.isPrimitive()) {
                            method = null;

                            break;
                        }

                        isInOut = true;
                    }
                }

                Type methodParamType = Types.getParameterSQLType(param);

                if (methodParamType == null) {
                    method = null;

                    break;
                }

                boolean result = routine.parameterTypes[j].typeComparisonGroup
                                 == methodParamType.typeComparisonGroup;

                // exact type for number
                if (result && routine.parameterTypes[j].isNumberType()) {
                    result = routine.parameterTypes[j].typeCode
                             == methodParamType.typeCode;
                }

                if (isInOut
                        && routine.getParameter(j).parameterMode
                           == SchemaObject.ParameterModes.PARAM_IN) {
                    result = false;
                }

                if (!result) {
                    method = null;

                    if (j + offset > firstMismatch) {
                        firstMismatch = j + offset;
                    }

                    break;
                }
            }

            if (method != null) {
                for (int j = 0; j < routine.parameterTypes.length; j++) {
                    routine.getParameter(j).setNullable(
                        !params[j + offset].isPrimitive());
                }

                return method;
            }
        }

        if (firstMismatch >= 0) {
            ColumnSchema param = routine.getParameter(firstMismatch);

            throw Error.error(ErrorCode.X_46511, param.getNameString());
        }

        return null;
    }

    static Method[] getMethods(String name) {

        int i = name.lastIndexOf('.');

        if (i == -1) {
            throw Error.error(ErrorCode.X_42501, name);
        }

        String   className  = name.substring(0, i);
        String   methodname = name.substring(i + 1);
        Class    cl;
        Method[] methods = null;

        try {
            cl = Class.forName(className, true,
                               Thread.currentThread().getContextClassLoader());
        } catch (Throwable t1) {
            try {
                cl = Class.forName(className);
            } catch (Throwable t) {
                throw Error.error(t, ErrorCode.X_42501,
                                  ErrorCode.M_Message_Pair, new Object[] {
                    t.getMessage(), className
                });
            }
        }

        try {
            methods = cl.getMethods();
        } catch (Throwable t) {
            throw Error.error(t, ErrorCode.X_42501, ErrorCode.M_Message_Pair,
                              new Object[] {
                t.getMessage(), className
            });
        }

        HsqlArrayList list = new HsqlArrayList();

        for (i = 0; i < methods.length; i++) {
            int    offset    = 0;
            Method method    = methods[i];
            int    modifiers = method.getModifiers();

            if (!method.getName().equals(methodname)
                    || !Modifier.isStatic(modifiers)
                    || !Modifier.isPublic(modifiers)) {
                continue;
            }

            Class[] params = methods[i].getParameterTypes();

            if (params.length > 0
                    && params[0].equals(java.sql.Connection.class)) {
                offset = 1;
            }

            for (int j = offset; j < params.length; j++) {
                Class param = params[j];

                if (param.isArray()) {
                    if (!byte[].class.equals(param)) {
                        param = param.getComponentType();

                        if (param.isPrimitive()) {
                            method = null;

                            break;
                        }
                    }
                }

                Type methodParamType = Types.getParameterSQLType(param);

                if (methodParamType == null) {
                    method = null;

                    break;
                }
            }

            if (method == null) {
                continue;
            }

            if (java.sql.ResultSet.class.isAssignableFrom(
                    method.getReturnType())) {
                list.add(methods[i]);
            } else {
                Type methodReturnType =
                    Types.getParameterSQLType(method.getReturnType());

                if (methodReturnType != null) {
                    list.add(methods[i]);
                }
            }
        }

        methods = new Method[list.size()];

        list.toArray(methods);

        return methods;
    }

    public static Routine[] newRoutines(Session session, Method[] methods) {

        Routine[] routines = new Routine[methods.length];

        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];

            routines[i] = newRoutine(session, method);
        }

        return routines;
    }

    /**
     * Returns a new function Routine object based solely on a Java Method object.
     */
    public static Routine newRoutine(Session session, Method method) {

        Routine      routine   = new Routine(SchemaObject.FUNCTION);
        int          offset    = 0;
        Class[]      params    = method.getParameterTypes();
        String       className = method.getDeclaringClass().getName();
        StringBuffer sb        = new StringBuffer();

        sb.append("CLASSPATH:");
        sb.append(method.getDeclaringClass().getName()).append('.');
        sb.append(method.getName());

        if (params.length > 0 && params[0].equals(java.sql.Connection.class)) {
            offset = 1;
        }

        String name = sb.toString();

        if (className.equals("java.lang.Math")) {
            routine.isLibraryRoutine = true;
        }

        for (int j = offset; j < params.length; j++) {
            Type methodParamType = Types.getParameterSQLType(params[j]);
            ColumnSchema param = new ColumnSchema(null, methodParamType,
                                                  !params[j].isPrimitive(),
                                                  false, null);

            routine.addParameter(param);
        }

        routine.setLanguage(Routine.LANGUAGE_JAVA);
        routine.setMethod(method);
        routine.setMethodURL(name);
        routine.setDataImpact(Routine.NO_SQL);

        Type methodReturnType =
            Types.getParameterSQLType(method.getReturnType());

        routine.javaMethodWithConnection = offset == 1;;

        routine.setReturnType(methodReturnType);
        routine.resolve(session);

        return routine;
    }

    public static void createRoutines(Session session, HsqlName schema,
                                      String name) {

        Method[]  methods  = Routine.getMethods(name);
        Routine[] routines = Routine.newRoutines(session, methods);
        HsqlName routineName = session.database.nameManager.newHsqlName(schema,
            name, true, SchemaObject.FUNCTION);

        for (int i = 0; i < routines.length; i++) {
            routines[i].setName(routineName);
            session.database.schemaManager.addSchemaObject(routines[i]);
        }
    }

    static void checkNoSQLData(Database database, OrderedHashSet set) {

        for (int i = 0; i < set.size(); i++) {
            HsqlName name = (HsqlName) set.get(i);

            if (name.type == SchemaObject.SPECIFIC_ROUTINE) {
                Routine routine =
                    (Routine) database.schemaManager.getSchemaObject(name);

                if (routine.dataImpact == Routine.READS_SQL) {
                    throw Error.error(ErrorCode.X_42608,
                                      Tokens.T_READS + " " + Tokens.T_SQL);
                } else if (routine.dataImpact == Routine.MODIFIES_SQL) {
                    throw Error.error(ErrorCode.X_42608,
                                      Tokens.T_MODIFIES + " " + Tokens.T_SQL);
                } else if (name.type == SchemaObject.TABLE) {
                    throw Error.error(ErrorCode.X_42608,
                                      Tokens.T_READS + " " + Tokens.T_SQL);
                }
            }
        }
    }
}
TOP

Related Classes of org.hsqldb.Routine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.