/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.expression.function;

import org.h2.command.Parser;
import org.h2.engine.Constants;
import org.h2.engine.FunctionAlias;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.expression.ValueExpression;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueCollectionBase;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;

This class wraps a user-defined function.
/** * This class wraps a user-defined function. */
public class JavaFunction extends Expression implements FunctionCall { private final FunctionAlias functionAlias; private final FunctionAlias.JavaMethod javaMethod; private final Expression[] args; public JavaFunction(FunctionAlias functionAlias, Expression[] args) { this.functionAlias = functionAlias; this.javaMethod = functionAlias.findJavaMethod(args); this.args = args; } @Override public Value getValue(Session session) { return javaMethod.getValue(session, args, false); } @Override public TypeInfo getType() { return TypeInfo.getTypeInfo(javaMethod.getDataType()); } @Override public int getValueType() { return javaMethod.getDataType(); } @Override public void mapColumns(ColumnResolver resolver, int level, int state) { for (Expression e : args) { e.mapColumns(resolver, level, state); } } @Override public Expression optimize(Session session) { boolean allConst = isDeterministic(); for (int i = 0, len = args.length; i < len; i++) { Expression e = args[i].optimize(session); args[i] = e; allConst &= e.isConstant(); } if (allConst) { return ValueExpression.get(getValue(session)); } return this; } @Override public void setEvaluatable(TableFilter tableFilter, boolean b) { for (Expression e : args) { if (e != null) { e.setEvaluatable(tableFilter, b); } } } @Override public StringBuilder getSQL(StringBuilder builder, boolean alwaysQuote) { // TODO always append the schema once FUNCTIONS_IN_SCHEMA is enabled if (functionAlias.getDatabase().getSettings().functionsInSchema || functionAlias.getSchema().getId() != Constants.MAIN_SCHEMA_ID) { Parser.quoteIdentifier(builder, functionAlias.getSchema().getName(), alwaysQuote).append('.'); } Parser.quoteIdentifier(builder, functionAlias.getName(), alwaysQuote).append('('); writeExpressions(builder, this.args, alwaysQuote); return builder.append(')'); } @Override public void updateAggregate(Session session, int stage) { for (Expression e : args) { if (e != null) { e.updateAggregate(session, stage); } } } @Override public String getName() { return functionAlias.getName(); } @Override public ValueResultSet getValueForColumnList(Session session, Expression[] argList) { Value v = javaMethod.getValue(session, argList, true); return v == ValueNull.INSTANCE ? null : (ValueResultSet) v; } @Override public Expression[] getArgs() { return args; } @Override public boolean isEverything(ExpressionVisitor visitor) { switch (visitor.getType()) { case ExpressionVisitor.DETERMINISTIC: if (!isDeterministic()) { return false; } // only if all parameters are deterministic as well break; case ExpressionVisitor.GET_DEPENDENCIES: visitor.addDependency(functionAlias); break; default: } for (Expression e : args) { if (e != null && !e.isEverything(visitor)) { return false; } } return true; } @Override public int getCost() { int cost = javaMethod.hasConnectionParam() ? 25 : 5; for (Expression e : args) { cost += e.getCost(); } return cost; } @Override public boolean isDeterministic() { return functionAlias.isDeterministic(); } @Override public Expression[] getExpressionColumns(Session session) { switch (getValueType()) { case Value.RESULT_SET: ValueResultSet rs = getValueForColumnList(session, getArgs()); return getExpressionColumns(session, rs.getResult()); case Value.ARRAY: case Value.ROW: return getExpressionColumns(session, (ValueCollectionBase) getValue(session)); } return super.getExpressionColumns(session); } @Override public boolean isBufferResultSetToLocalTemp() { return functionAlias.isBufferResultSetToLocalTemp(); } @Override public int getSubexpressionCount() { return args.length; } @Override public Expression getSubexpression(int index) { return args[index]; } }