com.arcadedb.query.sql.parser.BaseExpression 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. OBaseExpression.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.exception.CommandSQLParsingException;
import com.arcadedb.query.sql.executor.AggregationContext;
import com.arcadedb.query.sql.executor.CommandContext;
import com.arcadedb.query.sql.executor.Result;
import com.arcadedb.query.sql.executor.ResultInternal;
import com.arcadedb.utility.NumberUtils;
import java.util.*;
public class BaseExpression extends MathExpression {
protected PNumber number;
protected BaseIdentifier identifier;
protected InputParameter inputParam;
protected String string;
protected Modifier modifier;
protected boolean isNull = false;
public BaseExpression(final int id) {
super(id);
}
public BaseExpression(final Identifier identifier) {
super(-1);
this.identifier = new BaseIdentifier(identifier);
}
public BaseExpression(final String string) {
super(-1);
this.string = "\"" + encode(string) + "\"";
}
public BaseExpression(final Identifier identifier, final Modifier modifier) {
this(identifier);
if (modifier != null) {
this.modifier = modifier;
}
}
public BaseExpression(final RecordAttribute attr, final Modifier modifier) {
super(-1);
this.identifier = new BaseIdentifier(attr);
if (modifier != null) {
this.modifier = modifier;
}
}
public void setModifier(final Modifier modifier) {
this.modifier = modifier;
if (identifier != null && modifier != null && identifier.isExpand())
throw new CommandSQLParsingException("Invalid modifier after special function expand()");
}
public void toString(final Map params, final StringBuilder builder) {
if (isNull)
builder.append("NULL");
else if (number != null) {
number.toString(params, builder);
} else if (identifier != null) {
identifier.toString(params, builder);
} else if (string != null) {
builder.append(string);
} else if (inputParam != null) {
inputParam.toString(params, builder);
}
if (modifier != null) {
modifier.toString(params, builder);
}
}
public Object execute(final Identifiable iCurrentRecord, final CommandContext context) {
Object result = null;
if (isNull)
result = null;
else if (number != null)
result = number.getValue();
else if (identifier != null)
result = identifier.execute(iCurrentRecord != null ? iCurrentRecord.getRecord() : null, context);
else if (string != null && string.length() > 1)
result = decode(string.substring(1, string.length() - 1));
else if (inputParam != null)
result = inputParam.getValue(context.getInputParameters());
if (modifier != null)
result = modifier.execute(iCurrentRecord, result, context);
return result;
}
public Object execute(final Result iCurrentRecord, final CommandContext context) {
Object result = null;
if (isNull)
result = null;
if (number != null) {
result = number.getValue();
} else {
final Map params = context != null ? context.getInputParameters() : null;
if (identifier != null) {
// CHECK FOR SPECIAL CASE FOR POSTGRES DRIVER THAT TRANSLATES POSITIONAL PARAMETERS (?) WITH $N
// THIS IS DIFFERENT FROM ORIENTDB CODE BASE
// @author Luca Garulli
// @see Postgres Driver
if (params != null && !params.isEmpty() && //
identifier.getSuffix() != null && identifier.getSuffix().identifier != null) {
final String v = identifier.getSuffix().identifier.getValue();
if (v.startsWith("$") && v.length() > 1) {
final String toParse = v.substring(1);
final Integer pos = NumberUtils.parsePositiveInteger(toParse);
if (pos != null && params.containsKey(String.valueOf(pos - 1)))
// POSTGRES PARAMETERS JDBC DRIVER START FROM 1
result = params.get(String.valueOf(pos - 1));
else
result = identifier.execute(iCurrentRecord, context);
} else
result = identifier.execute(iCurrentRecord, context);
} else
result = identifier.execute(iCurrentRecord, context);
} else if (string != null && string.length() > 1) {
result = decode(string.substring(1, string.length() - 1));
} else if (inputParam != null) {
result = inputParam.getValue(params);
}
}
if (modifier != null) {
result = modifier.execute(iCurrentRecord, result, context);
}
return result;
}
@Override
public boolean isIndexedFunctionCall(final CommandContext context) {
if (this.identifier == null)
return false;
return identifier.isIndexedFunctionCall(context);
}
public long estimateIndexedFunction(final FromClause target, final CommandContext context, final BinaryCompareOperator operator, final Object right) {
if (this.identifier == null)
return -1;
return identifier.estimateIndexedFunction(target, context, operator, right);
}
public Iterable executeIndexedFunction(final FromClause target, final CommandContext context, final BinaryCompareOperator operator,
final Object right) {
if (this.identifier == null)
return null;
return identifier.executeIndexedFunction(target, context, operator, right);
}
/**
* tests if current expression 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 expression 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) {
if (this.identifier == null)
return false;
return identifier.canExecuteIndexedFunctionWithoutIndex(target, context, operator, right);
}
/**
* tests if current expression 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 expression 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) {
if (this.identifier == null)
return false;
return identifier.allowsIndexedFunctionExecutionOnTarget(target, context, operator, right);
}
/**
* 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) {
if (this.identifier == null)
return false;
return identifier.executeIndexedFunctionAfterIndexSearch(target, context, operator, right);
}
@Override
public boolean isBaseIdentifier() {
return identifier != null && modifier == null && identifier.isBaseIdentifier();
}
public boolean isEarlyCalculated(CommandContext context) {
if (number != null || inputParam != null || string != null)
return true;
return identifier != null && identifier.isEarlyCalculated(context);
}
@Override
public boolean isExpand() {
if (identifier != null)
return identifier.isExpand();
return false;
}
@Override
public Expression getExpandContent() {
return this.identifier.getExpandContent();
}
@Override
public boolean isAggregate(final CommandContext context) {
return identifier != null && identifier.isAggregate(context);
}
@Override
public boolean isCount() {
return identifier != null && identifier.isCount();
}
public SimpleNode splitForAggregation(final AggregateProjectionSplit aggregateProj, final CommandContext context) {
if (isAggregate(context)) {
final SimpleNode splitResult = identifier.splitForAggregation(aggregateProj, context);
if (splitResult instanceof BaseIdentifier) {
final BaseExpression result = new BaseExpression(-1);
result.identifier = (BaseIdentifier) splitResult;
return result;
}
return splitResult;
} else {
return this;
}
}
public AggregationContext getAggregationContext(final CommandContext context) {
if (identifier != null) {
return identifier.getAggregationContext(context);
} else {
throw new CommandExecutionException("cannot aggregate on " + this);
}
}
@Override
public BaseExpression copy() {
final BaseExpression result = new BaseExpression(-1);
result.isNull = isNull;
result.number = number == null ? null : number.copy();
result.identifier = identifier == null ? null : identifier.copy();
result.inputParam = inputParam == null ? null : inputParam.copy();
result.string = string;
result.setModifier(modifier == null ? null : modifier.copy());
result.cachedStringForm = cachedStringForm;
return result;
}
public boolean refersToParent() {
if (identifier != null && identifier.refersToParent())
return true;
return modifier != null && modifier.refersToParent();
}
public void setIdentifier(final BaseIdentifier identifier) {
this.identifier = identifier;
}
public BaseIdentifier getIdentifier() {
return identifier;
}
public Modifier getModifier() {
return modifier;
}
public List getMatchPatternInvolvedAliases() {
if (this.identifier != null && this.identifier.toString().equals("$matched")) {
if (modifier != null && modifier.suffix != null && modifier.suffix.identifier != null) {
return Collections.singletonList(modifier.suffix.identifier.toString());
}
}
return Collections.emptyList();
}
@Override
public void applyRemove(final ResultInternal result, final CommandContext context) {
if (identifier != null) {
if (modifier == null) {
identifier.applyRemove(result, context);
} else {
final Object val = identifier.execute(result, context);
modifier.applyRemove(val, result, context);
}
}
}
@Override
public boolean isDefinedFor(final Result currentRecord) {
if (this.identifier != null) {
if (modifier == null) {
return identifier.isDefinedFor(currentRecord);
}
}
return true;
}
@Override
public boolean isDefinedFor(final Record currentRecord) {
if (this.identifier != null) {
if (modifier == null) {
return identifier.isDefinedFor(currentRecord);
}
}
return true;
}
public void extractSubQueries(final Identifier letAlias, final SubQueryCollector collector) {
if (this.identifier != null)
this.identifier.extractSubQueries(letAlias, collector);
}
public void extractSubQueries(final SubQueryCollector collector) {
if (this.identifier != null)
this.identifier.extractSubQueries(collector);
}
@Override
protected Object[] getIdentityElements() {
return new Object[] { identifier, inputParam, string, modifier, isNull };
}
@Override
protected SimpleNode[] getCacheableElements() {
return new SimpleNode[] { modifier, identifier };
}
public void setInputParam(final InputParameter inputParam) {
this.inputParam = inputParam;
}
/**
* Transforms, only if needed, the source string escaping the characters \ and ".
*
* @param iText Input String
*
* @return Modified string if needed, otherwise the same input object
*/
public static String encode(final String iText) {
int pos = -1;
final int newSize = iText.length();
for (int i = 0; i < newSize; ++i) {
final char c = iText.charAt(i);
if (c == '"' || c == '\\') {
pos = i;
break;
}
}
if (pos > -1) {
// CHANGE THE INPUT STRING
final StringBuilder iOutput = new StringBuilder((int) ((float) newSize * 1.5f));
char c;
for (int i = 0; i < newSize; ++i) {
c = iText.charAt(i);
if (c == '"' || c == '\\')
iOutput.append('\\');
iOutput.append(c);
}
return iOutput.toString();
}
return iText;
}
/**
* Transforms, only if needed, the source string un-escaping the characters \ and ".
*
* @param iText Input String
*
* @return Modified string if needed, otherwise the same input object
*/
public static String decode(final String iText) {
int pos = -1;
final int textSize = iText.length();
for (int i = 0; i < textSize; ++i)
if (iText.charAt(i) == '"' || iText.charAt(i) == '\\') {
pos = i;
break;
}
if (pos == -1)
// NOT FOUND, RETURN THE SAME STRING (AVOID COPIES)
return iText;
// CHANGE THE INPUT STRING
final StringBuilder buffer = new StringBuilder(textSize);
buffer.append(iText, 0, pos);
boolean escaped = false;
for (int i = pos; i < textSize; ++i) {
final char c = iText.charAt(i);
if (escaped) {
escaped = false;
if (c == 'n')
buffer.append('\n');
else if (c == 't')
buffer.append('\t');
else if (c == 'r')
buffer.append('\r');
else if (c == '%')
buffer.append("\\%");
else
buffer.append(c);
continue;
} else if (c == '\\') {
escaped = true;
continue;
}
buffer.append(c);
}
return buffer.toString();
}
}
/* JavaCC - OriginalChecksum=71b3e2d1b65c923dc7cfe11f9f449d2b (do not edit this line) */
© 2015 - 2024 Weber Informatics LLC | Privacy Policy