org.eclipse.persistence.jpa.jpql.parser.FunctionExpression Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation
//
package org.eclipse.persistence.jpa.jpql.parser;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.WordParser;
import org.eclipse.persistence.jpa.jpql.parser.FunctionExpressionFactory.ParameterCount;
/**
* This expression adds support to call native database functions.
*
* New to JPA 2.1.
*
*
BNF: func_expression ::= <identifier>('function_name' {, func_item}*)
*
* @version 2.5
* @since 2.4
* @author James
*/
public final class FunctionExpression extends AbstractSingleEncapsulatedExpression {
/**
* The name of the SQL function.
*/
private String functionName;
/**
* Determines whether the comma separating the function name and the first expression.
*/
private boolean hasComma;
/**
* Determines whether a whitespace is following the comma.
*/
private boolean hasSpaceAfterComma;
/**
* The number of {@link ParameterCount parameters} a {@link FunctionExpression} can have.
*
* @since 2.4
*/
private ParameterCount parameterCount;
/**
* The unique identifier of the {@link JPQLQueryBNF} that will be used to parse the arguments of
* the function expression.
*
* @since 2.4
*/
private String parameterQueryBNFId;
/**
* Creates a new FuncExpression
.
*
* @param parent The parent of this expression
* @param identifier The JPQL identifier
*/
public FunctionExpression(AbstractExpression parent, String identifier) {
super(parent, identifier);
}
/**
* Creates a new FunctionExpression
.
*
* @param parent The parent of this expression
* @param identifier The JPQL identifier
* @param parameterCount The number of {@link ParameterCount parameters} a {@link
* FunctionExpression} can have
* @param parameterQueryBNFId The unique identifier of the {@link JPQLQueryBNF} that will be used
* to parse the arguments of the function expression
*/
public FunctionExpression(AbstractExpression parent,
String identifier,
ParameterCount parameterCount,
String parameterQueryBNFId) {
this(parent, identifier);
this.parameterCount = parameterCount;
this.parameterQueryBNFId = parameterQueryBNFId;
}
@Override
public void accept(ExpressionVisitor visitor) {
visitor.visit(this);
}
@Override
protected void addOrderedEncapsulatedExpressionTo(List children) {
children.add(buildStringExpression(functionName));
if (hasComma) {
children.add(buildStringExpression(COMMA));
}
if (hasSpaceAfterComma) {
children.add(buildStringExpression(SPACE));
}
super.addOrderedEncapsulatedExpressionTo(children);
}
@Override
public String getEncapsulatedExpressionQueryBNFId() {
return parameterQueryBNFId;
}
/**
* Returns the name of the SQL function.
*
* @return The name of the SQL function
*/
public String getFunctionName() {
return functionName;
}
/**
* Returns the number of parameters a {@link FunctionExpression} can have, which will be during
* validation.
*
* @return The number of parameters (encapsulated expressions) allowed by this expression
* @since 2.4
*/
public ParameterCount getParameterCount() {
return parameterCount;
}
@Override
public JPQLQueryBNF getQueryBNF() {
return getQueryBNF(FunctionExpressionBNF.ID);
}
/**
* Returns the name of the SQL function.
*
* @return The name of the SQL function
*/
public String getUnquotedFunctionName() {
return ExpressionTools.unquote(functionName);
}
/**
* Determines whether the comma was parsed after the function name.
*
* @return true
if a comma was parsed after the function name and the first
* expression; false
otherwise
*/
public boolean hasComma() {
return hasComma;
}
@Override
public boolean hasEncapsulatedExpression() {
return hasFunctionName() || hasComma || super.hasEncapsulatedExpression();
}
/**
* Determines whether the function name was parsed.
*
* @return true
if the function name was parsed; false
otherwise
*/
public boolean hasFunctionName() {
return ExpressionTools.stringIsNotEmpty(functionName);
}
/**
* Determines whether a whitespace was parsed after the comma.
*
* @return true
if there was a whitespace after the comma; false
otherwise
*/
public boolean hasSpaceAfterComma() {
return hasSpaceAfterComma;
}
@Override
protected void parseEncapsulatedExpression(WordParser wordParser,
int whitespaceCount,
boolean tolerant) {
int count = 0;
// Parse the function name outside of a CollectionExpression so we can retrieve it
// with getFunctionName()
if (wordParser.startsWith(SINGLE_QUOTE)) {
functionName = wordParser.word();
wordParser.moveForward(functionName);
count = wordParser.skipLeadingWhitespace();
}
else {
functionName = ExpressionTools.EMPTY_STRING;
}
hasComma = wordParser.startsWith(COMMA);
if (hasComma) {
wordParser.moveForward(1);
count = wordParser.skipLeadingWhitespace();
hasSpaceAfterComma = count > 0;
}
// Parse the arguments
if (!wordParser.isTail() &&
wordParser.character() != RIGHT_PARENTHESIS) {
super.parseEncapsulatedExpression(wordParser, whitespaceCount, tolerant);
}
// A space was parsed but no expression, let the space belong to the parent
if (count > 0 &&
!hasExpression() &&
!wordParser.isTail() &&
wordParser.character() != RIGHT_PARENTHESIS) {
hasSpaceAfterComma = false;
wordParser.moveBackward(count);
}
}
@Override
protected void toParsedTextEncapsulatedExpression(StringBuilder writer, boolean actual) {
writer.append(functionName);
if (hasComma) {
writer.append(COMMA);
}
if (hasSpaceAfterComma) {
writer.append(SPACE);
}
super.toParsedTextEncapsulatedExpression(writer, actual);
}
}