| /* |
| * Copyright (c) 1998, 2020 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; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.internal.expressions.ConstantExpression; |
| import org.eclipse.persistence.internal.queries.ReportItem; |
| import org.eclipse.persistence.queries.ReportQuery; |
| |
| /** |
| * INTERNAL |
| * <p><b>Purpose</b>: Represent an EXISTS subquery. |
| */ |
| public class ExistsNode extends Node { |
| |
| /** True in case of a NOT EXISTS (...) query. */ |
| private boolean notIndicated = false; |
| |
| /** |
| * Return a new ExistsNode. |
| */ |
| public ExistsNode() { |
| super(); |
| } |
| |
| /** |
| * INTERNAL |
| * Validate node and calculate its type. |
| * Change subquery SELECT clause. |
| */ |
| @Override |
| public void validate(ParseTreeContext context) { |
| if (left != null) { |
| |
| // change SELECT clause of subquery |
| SubqueryNode subqueryNode = (SubqueryNode)getLeft(); |
| // validate changed subquery |
| subqueryNode.validate(context); |
| |
| TypeHelper typeHelper = context.getTypeHelper(); |
| setType(typeHelper.getBooleanType()); |
| } |
| } |
| |
| /** |
| * INTERNAL |
| * Generate the EclipseLink expression for this node |
| */ |
| @Override |
| public Expression generateExpression(GenerationContext context) { |
| SubqueryNode subqueryNode = (SubqueryNode)getLeft(); |
| ReportQuery reportQuery = subqueryNode.getReportQuery(context); |
| // Replace the SELECT clause of the exists subquery by SELECT 1 to |
| // avoid problems with databases not supporting multiple columns in the |
| // subquery SELECT clause in SQL. |
| // The original select clause expressions might include relationship |
| // navigations which should result in FK joins in the generated SQL, |
| // e.g. ... EXISTS (SELECT o.customer FROM Order o ...). Add the |
| // select clause expressions as non fetch join attributes to the |
| // ReportQuery representing the subquery. This make sure the FK joins |
| // get generated. |
| List items = reportQuery.getItems(); |
| for (Iterator i = items.iterator(); i.hasNext();) { |
| ReportItem item = (ReportItem)i.next(); |
| Expression expr = item.getAttributeExpression(); |
| reportQuery.addNonFetchJoinedAttribute(expr); |
| } |
| reportQuery.clearItems(); |
| Expression one = new ConstantExpression(Integer.valueOf(1), new ExpressionBuilder()); |
| reportQuery.addItem("one", one); |
| reportQuery.dontUseDistinct(); |
| Expression expr = context.getBaseExpression(); |
| return notIndicated() ? expr.notExists(reportQuery) : |
| expr.exists(reportQuery); |
| } |
| |
| /** |
| * INTERNAL |
| * Indicate if a NOT was found in the WHERE clause. |
| * Examples: WHERE ... NOT EXISTS(...) |
| */ |
| public void indicateNot() { |
| notIndicated = true; |
| } |
| |
| public boolean notIndicated() { |
| return notIndicated; |
| } |
| |
| } |