| /* |
| * Copyright (c) 1998, 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 from Oracle TopLink |
| package org.eclipse.persistence.internal.jpa.parsing; |
| |
| |
| // Java imports |
| import java.util.*; |
| |
| // TopLink imports |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.queries.ReportQuery; |
| import org.eclipse.persistence.exceptions.JPQLException; |
| |
| /** |
| * INTERNAL |
| * <p><b>Purpose</b>: Represent an IN in EJBQL |
| * <p><b>Responsibilities</b>:<ul> |
| * <li> Generate the correct expression for an IN |
| * </ul> |
| * @author Jon Driscoll and Joel Lucuik |
| * @since TopLink 4.0 |
| */ |
| public class InNode extends SimpleConditionalExpressionNode { |
| |
| private List<Node> theObjects = null; |
| |
| //Was NOT indicated? "WHERE emp.lastName NOT IN (...) |
| private boolean notIndicated = false; |
| |
| private boolean isListParameterOrSubquery = false; |
| |
| /** |
| * InNode constructor comment. |
| */ |
| public InNode() { |
| super(); |
| } |
| |
| /** |
| * INTERNAL |
| * Add the passed node value to the collection of object for this node |
| */ |
| public void addNodeToTheObjects(Node theNode) { |
| getTheObjects().add(theNode); |
| } |
| |
| /** |
| * INTERNAL |
| * Validate the current node and calculates its type. |
| */ |
| @Override |
| public void validate(ParseTreeContext context) { |
| Object leftType = null; |
| TypeHelper typeHelper = context.getTypeHelper(); |
| |
| if (left != null) { |
| left.validate(context); |
| // check to see if the argument is a parameter |
| if (isListParameterOrSubquery && !getTheObjects().isEmpty() && getTheObjects().get(0).isParameterNode()){ |
| leftType = Collection.class; |
| } else { |
| leftType = left.getType(); |
| } |
| } |
| for (Iterator<Node> i = getTheObjects().iterator(); i.hasNext();) { |
| Node node = i.next(); |
| node.validate(context); |
| node.validateParameter(context, leftType); |
| Object nodeType = node.getType(); |
| if ((leftType != null) && !typeHelper.isAssignableFrom(leftType, nodeType)) |
| throw JPQLException.invalidExpressionArgument( |
| context.getQueryInfo(), node.getLine(), node.getColumn(), |
| "IN", node.getAsString(), typeHelper.getTypeName(leftType)); |
| } |
| |
| setType(typeHelper.getBooleanType()); |
| } |
| |
| /** |
| * INTERNAL |
| * Return the EclipseLink expression for this node |
| */ |
| @Override |
| public Expression generateExpression(GenerationContext context) { |
| Expression whereClause = getLeft().generateExpression(context); |
| List<Node> arguments = getTheObjects(); |
| Node firstArg = arguments.get(0); |
| if (firstArg.isSubqueryNode()) { |
| SubqueryNode subqueryNode = (SubqueryNode)firstArg; |
| ReportQuery reportQuery = subqueryNode.getReportQuery(context); |
| if (notIndicated()) { |
| whereClause = whereClause.notIn(reportQuery); |
| } |
| else { |
| whereClause = whereClause.in(reportQuery); |
| } |
| } else if (isListParameterOrSubquery && firstArg.isParameterNode()) { |
| if (notIndicated()) { |
| whereClause = whereClause.notIn(firstArg.generateExpression(context)); |
| } else { |
| whereClause = whereClause.in(firstArg.generateExpression(context)); |
| } |
| } else { |
| Vector<Expression> inArguments = new Vector<>(arguments.size()); |
| for (Iterator<Node> iter = arguments.iterator(); iter.hasNext();) { |
| Node nextNode = iter.next(); |
| inArguments.add(nextNode.generateExpression(context)); |
| } |
| if (inArguments.size() > 0) { |
| if (notIndicated()) { |
| whereClause = whereClause.notIn(inArguments); |
| } else { |
| whereClause = whereClause.in(inArguments); |
| } |
| } |
| } |
| return whereClause; |
| } |
| |
| /** |
| * INTERNAL |
| * Return the collection of the objects used as parameters for this node |
| */ |
| public List<Node> getTheObjects() { |
| if (theObjects == null) { |
| setTheObjects(new Vector<>()); |
| } |
| return theObjects; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method is called to indicate that the inNode has a single argument. This will be either a |
| * subquery or a single parameter that contains the list of items to test |
| */ |
| public void setIsListParameterOrSubquery(boolean isListParameterOrSubquery){ |
| this.isListParameterOrSubquery = isListParameterOrSubquery; |
| } |
| |
| /** |
| * INTERNAL |
| * Set this node's object collection to the passed value |
| */ |
| public void setTheObjects(List<Node> newTheObjects) { |
| theObjects = newTheObjects; |
| } |
| |
| /** |
| * INTERNAL |
| * Indicate if a NOT was found in the WHERE clause. |
| * Examples: |
| * ...WHERE ... NOT IN(...) |
| */ |
| public void indicateNot() { |
| notIndicated = true; |
| } |
| |
| public boolean notIndicated() { |
| return notIndicated; |
| } |
| } |