Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.arcadedb.query.sql.parser.FunctionCall Maven / Gradle / Ivy
/*
* Copyright © 2021-present Arcade Data Ltd ([email protected] )
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: 2021-present Arcade Data Ltd ([email protected] )
* SPDX-License-Identifier: Apache-2.0
*/
/* Generated By:JJTree: Do not edit this line. OFunctionCall.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=O,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_USERTYPE_VISIBILITY_PUBLIC=true */
package com.arcadedb.query.sql.parser;
import com.arcadedb.database.Identifiable;
import com.arcadedb.database.Record;
import com.arcadedb.exception.CommandExecutionException;
import com.arcadedb.query.sql.SQLQueryEngine;
import com.arcadedb.query.sql.executor.AggregationContext;
import com.arcadedb.query.sql.executor.CommandContext;
import com.arcadedb.query.sql.executor.FunctionAggregationContext;
import com.arcadedb.query.sql.executor.IndexableSQLFunction;
import com.arcadedb.query.sql.executor.Result;
import com.arcadedb.query.sql.executor.SQLFunction;
import com.arcadedb.query.sql.function.graph.SQLFunctionMove;
import java.util.*;
import java.util.stream.*;
public class FunctionCall extends SimpleNode {
protected Identifier name;
protected List params = new ArrayList<>();
private SQLFunction cachedFunction;
public FunctionCall(final int id) {
super(id);
}
public boolean isStar() {
if (this.params.size() != 1)
return false;
final Expression param = params.get(0);
if (param.mathExpression == null || !(param.mathExpression instanceof BaseExpression))
return false;
final BaseExpression base = (BaseExpression) param.mathExpression;
if (base.identifier == null || base.identifier.suffix == null)
return false;
return base.identifier.suffix.star;
}
public List getParams() {
return params;
}
public void setParams(final List params) {
this.params = params;
}
public void toString(final Map params, final StringBuilder builder) {
name.toString(params, builder);
builder.append("(");
boolean first = true;
for (final Expression expr : this.params) {
if (!first) {
builder.append(", ");
}
expr.toString(params, builder);
first = false;
}
builder.append(")");
}
public Object execute(final Object targetObjects, final CommandContext context) {
return execute(targetObjects, context, name.getStringValue());
}
private Object execute(final Object targetObjects, final CommandContext context, final String name) {
final List paramValues = new ArrayList<>();
Object record;
if (targetObjects instanceof Identifiable) {
record = targetObjects;
} else if (targetObjects instanceof Result) {
if (((Result) targetObjects).isElement())
record = ((Result) targetObjects).toElement();
else
record = targetObjects;
} else {
record = targetObjects;
}
if (record == null) {
final Object current = context == null ? null : context.getVariable("current");
if (current != null) {
if (current instanceof Identifiable) {
record = current;
} else if (current instanceof Result) {
record = ((Result) current).toElement();
} else {
record = current;
}
}
}
for (final Expression expr : this.params) {
if (record instanceof Identifiable) {
paramValues.add(expr.execute((Identifiable) record, context));
} else if (record instanceof Result) {
paramValues.add(expr.execute((Result) record, context));
} else if (record == null) {
paramValues.add(expr.execute((Result) record, context));
} else {
throw new CommandExecutionException("Invalid value for $current: " + record);
}
}
final SQLFunction function = ((SQLQueryEngine) context.getDatabase().getQueryEngine("sql")).getFunction(name);
if (function != null) {
if (record instanceof Identifiable) {
return function.execute(targetObjects, (Identifiable) record, null, paramValues.toArray(), context);
} else if (record instanceof Result) {
return function.execute(targetObjects, ((Result) record).getElement().orElse(null), null, paramValues.toArray(), context);
} else if (record == null) {
return function.execute(targetObjects, null, null, paramValues.toArray(), context);
} else {
throw new CommandExecutionException("Invalid value for $current: " + record);
}
} else {
throw new CommandExecutionException("Function not found: " + name);
}
}
public boolean isIndexedFunctionCall(final CommandContext context) {
final SQLFunction function = getCachedFunction(context);
return (function instanceof IndexableSQLFunction);
}
/**
* see OIndexableSQLFunction.searchFromTarget()
*
* @param target
* @param context
* @param operator
* @param rightValue
*
* @return
*/
public Iterable executeIndexedFunction(final FromClause target, final CommandContext context, final BinaryCompareOperator operator,
final Object rightValue) {
final SQLFunction function = getFunction(context);
if (function instanceof IndexableSQLFunction)
return ((IndexableSQLFunction) function).searchFromTarget(target, operator, rightValue, context, this.getParams().toArray(new Expression[] {}));
return null;
}
/**
* @param target query target
* @param context execution context
* @param operator operator at the right of the function
* @param rightValue value to compare to function result
*
* @return the approximate number of items returned by the condition execution, -1 if the estimation cannot be executed
*/
public long estimateIndexedFunction(final FromClause target, final CommandContext context, final BinaryCompareOperator operator, final Object rightValue) {
final SQLFunction function = getFunction(context);
if (function instanceof IndexableSQLFunction)
return ((IndexableSQLFunction) function).estimate(target, operator, rightValue, context, this.getParams().toArray(new Expression[] {}));
return -1;
}
/**
* tests if current function is an indexed function AND that function can also be executed without using the index
*
* @param target the query target
* @param context the execution context
* @param operator
* @param right
*
* @return true if current function is an indexed function AND that function can also be executed without using the index, false
* otherwise
*/
public boolean canExecuteIndexedFunctionWithoutIndex(final FromClause target, final CommandContext context, final BinaryCompareOperator operator,
final Object right) {
final SQLFunction function = getCachedFunction(context);
if (function instanceof IndexableSQLFunction)
return ((IndexableSQLFunction) function).canExecuteInline(target, operator, right, context, this.getParams().toArray(new Expression[] {}));
return false;
}
/**
* tests if current function is an indexed function AND that function can be used on this target
*
* @param target the query target
* @param context the execution context
* @param operator
* @param right
*
* @return true if current function is an indexed function AND that function can be used on this target, false otherwise
*/
public boolean allowsIndexedFunctionExecutionOnTarget(final FromClause target, final CommandContext context, final BinaryCompareOperator operator,
final Object right) {
final SQLFunction function = getCachedFunction(context);
if (function instanceof IndexableSQLFunction)
return ((IndexableSQLFunction) function).allowsIndexedExecution(target, operator, right, context, this.getParams().toArray(new Expression[] {}));
return false;
}
/**
* tests if current expression is an indexed function AND the function has also to be executed after the index search. In some
* cases, the index search is accurate, so this condition can be excluded from further evaluation. In other cases the result from
* the index is a superset of the expected result, so the function has to be executed anyway for further filtering
*
* @param target the query target
* @param context the execution context
*
* @return true if current expression is an indexed function AND the function has also to be executed after the index search.
*/
public boolean executeIndexedFunctionAfterIndexSearch(final FromClause target, final CommandContext context, final BinaryCompareOperator operator,
final Object right) {
final SQLFunction function = getFunction(context);
if (function instanceof IndexableSQLFunction)
return ((IndexableSQLFunction) function).shouldExecuteAfterSearch(target, operator, right, context, this.getParams().toArray(new Expression[] {}));
return false;
}
public boolean isExpand() {
return name.getStringValue().equals("expand");
}
public boolean isAggregate(final CommandContext context) {
if (isAggregateFunction(context)) {
return true;
}
for (final Expression exp : params) {
if (exp.isAggregate(context)) {
return true;
}
}
return false;
}
public SimpleNode splitForAggregation(final AggregateProjectionSplit aggregateProj, final CommandContext context) {
if (isAggregate(context)) {
final FunctionCall newFunct = new FunctionCall(-1);
newFunct.name = this.name;
final Identifier functionResultAlias = aggregateProj.getNextAlias();
if (isAggregateFunction(context)) {
if (isStar()) {
for (final Expression param : params) {
newFunct.getParams().add(param);
}
} else {
for (final Expression param : params) {
if (param.isAggregate(context)) {
throw new CommandExecutionException("Cannot calculate an aggregate function of another aggregate function " + this);
}
final Identifier nextAlias = aggregateProj.getNextAlias();
final ProjectionItem paramItem = new ProjectionItem(-1);
paramItem.alias = nextAlias;
paramItem.expression = param;
aggregateProj.getPreAggregate().add(paramItem);
newFunct.params.add(new Expression(nextAlias));
}
}
aggregateProj.getAggregate().add(createProjection(newFunct, functionResultAlias));
return new Expression(functionResultAlias);
} else {
if (isStar()) {
for (final Expression param : params) {
newFunct.getParams().add(param);
}
} else {
for (final Expression param : params) {
newFunct.getParams().add(param.splitForAggregation(aggregateProj, context));
}
}
}
return newFunct;
}
return this;
}
private boolean isAggregateFunction(final CommandContext context) {
return getCachedFunction(context).aggregateResults();
}
private ProjectionItem createProjection(final FunctionCall newFunct, final Identifier alias) {
final LevelZeroIdentifier l0 = new LevelZeroIdentifier(-1);
l0.functionCall = newFunct;
final BaseIdentifier l1 = new BaseIdentifier(-1);
l1.levelZero = l0;
final BaseExpression l2 = new BaseExpression(-1);
l2.identifier = l1;
final Expression l3 = new Expression(-1);
l3.mathExpression = l2;
final ProjectionItem item = new ProjectionItem(-1);
item.alias = alias;
item.expression = l3;
return item;
}
public boolean isEarlyCalculated(final CommandContext context) {
if (isTraverseFunction(context))
return false;
for (final Expression param : params) {
if (!param.isEarlyCalculated(context)) {
return false;
}
}
return true;
}
private boolean isTraverseFunction(final CommandContext context) {
if (name == null)
return false;
final SQLFunction function = getFunction(context);
return function instanceof SQLFunctionMove;
}
public AggregationContext getAggregationContext(final CommandContext context) {
return new FunctionAggregationContext(getFunction(context), this.params);
}
public FunctionCall copy() {
final FunctionCall result = new FunctionCall(-1);
result.name = name;
result.params = params.stream().map(x -> x.copy()).collect(Collectors.toList());
return result;
}
@Override
protected Object[] getIdentityElements() {
return new Object[] { name, params };
}
@Override
public boolean refersToParent() {
if (params != null) {
for (final Expression param : params) {
if (param != null && param.refersToParent()) {
return true;
}
}
}
return false;
}
public Identifier getName() {
return name;
}
public MethodCall toMethod() {
final MethodCall result = new MethodCall(-1);
result.methodName = name.copy();
result.params = params.stream().map(x -> x.copy()).collect(Collectors.toList());
return result;
}
public void extractSubQueries(final Identifier letAlias, final SubQueryCollector collector) {
for (final Expression param : this.params) {
param.extractSubQueries(letAlias, collector);
}
}
public void extractSubQueries(final SubQueryCollector collector) {
for (final Expression param : this.params)
param.extractSubQueries(collector);
}
public boolean isCacheable() {
return isGraphFunction();
}
private boolean isGraphFunction() {
final String string = name.getStringValue();
if (string.equalsIgnoreCase("out"))
return true;
else if (string.equalsIgnoreCase("outE"))
return true;
else if (string.equalsIgnoreCase("outV"))
return true;
else if (string.equalsIgnoreCase("in"))
return true;
else if (string.equalsIgnoreCase("inE"))
return true;
else if (string.equalsIgnoreCase("inV"))
return true;
else if (string.equalsIgnoreCase("both"))
return true;
else if (string.equalsIgnoreCase("bothE"))
return true;
else
return string.equalsIgnoreCase("bothV");
}
private SQLFunction getFunction(final CommandContext context) {
return ((SQLQueryEngine) context.getDatabase().getQueryEngine("sql")).getFunction(name.getStringValue()).config(params.toArray());
}
private SQLFunction getCachedFunction(CommandContext context) {
if (cachedFunction == null)
cachedFunction = getFunction(context);
return cachedFunction;
}
}
/* JavaCC - OriginalChecksum=290d4e1a3f663299452e05f8db718419 (do not edit this line) */