blob: ef1e8c93713185736bb9f951d135e13423ca0a75 [file] [log] [blame]
/*
* Copyright (c) 2018, 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
*/
package org.eclipse.persistence.jpa.tests.jpql;
import org.eclipse.persistence.jpa.jpql.tools.model.DefaultActualJPQLQueryFormatter;
import org.eclipse.persistence.jpa.jpql.tools.model.DefaultJPQLQueryFormatter;
import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryBuilder;
import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryFormatter;
import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryFormatter.IdentifierStyle;
import org.eclipse.persistence.jpa.jpql.tools.model.query.JPQLQueryStateObject;
import org.eclipse.persistence.jpa.jpql.tools.model.query.SelectStatementStateObject;
import org.eclipse.persistence.jpa.tests.jpql.tools.model.IJPQLQueryBuilderTestHelper;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Illustrates possible bugs in the Hermes 2.0 parser.
*/
@UniqueSignature
@SuppressWarnings("nls")
public final class HermesBugsTest extends JPQLCoreTest {
@IJPQLQueryBuilderTestHelper
private IJPQLQueryBuilder queryBuilder;
/**
* missing space before WHERE statement
*/
@Test
public void testAddWhereClauseMissingSpace() throws Exception {
String jpql = "SELECT a FROM Artifact a";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, true);
SelectStatementStateObject selectSO = (SelectStatementStateObject) so.getQueryStatement();
assertFalse(selectSO.hasWhereClause());
selectSO.addWhereClause("a.relativeURI LIKE '%bar'");
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(false);
assertEquals("SELECT a FROM Artifact a WHERE a.relativeURI LIKE '%bar'", formatter.toString(so));
// instead we get
// SELECT a FROM Artifact aWHERE a.relativeURI LIKE '%bar'
// this only happens with DefaultActualJPQLQueryFormatter with exactMatch=false.
// doesn't happen for DefaultJPQLQueryFormatter
}
/**
* WhereClauseStateObject.andParse() doesn't preserve order of operations. I think it should?
*/
@Test
public void testAndParseOrderOfOperations() throws Exception {
String jpql = "SELECT r FROM AnyRelationshipType r WHERE r.name = a OR r.name = b";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
SelectStatementStateObject selectSO = (SelectStatementStateObject) so.getQueryStatement();
selectSO.getWhereClause().andParse("r.name = c OR r.name = d");
IJPQLQueryFormatter formatter = new DefaultJPQLQueryFormatter(IdentifierStyle.UPPERCASE);
assertEquals("SELECT r FROM AnyRelationshipType r WHERE (r.name = a OR r.name = b) AND (r.name = c OR r.name = d)", formatter.toString(so));
// instead formatter.toString(so) returns:
// SELECT r FROM AnyRelationshipType r WHERE r.name = a OR r.name = b
// AND r.name = c OR r.name = d
// which is logically different
}
/**
* formatter throws StackOverflowError on "IS NULL"
*/
@Test
public void testFormatterIsNullOrderStackOverflow() throws Exception {
String jpql = "SELECT r FROM AnyRelationshipType r WHERE r.groupUUID IS NULL";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, true);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(false);
assertEquals(jpql, formatter.toString(so)); // fails with
// StackOverflowError
}
/**
* Default formatter still throws StackOverflowError on "IS NULL"
*/
@Test
public void testFormatterIsNullStackOverflow() throws Exception {
String jpql = "SELECT r FROM AnyRelationshipType r WHERE r.groupUUID IS NULL";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, true);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(false);
assertEquals(jpql, formatter.toString(so)); // passes
formatter = new DefaultJPQLQueryFormatter(IdentifierStyle.UPPERCASE);
assertEquals(jpql, formatter.toString(so)); // fails with StackOverflowError
}
/**
* DefaultJPQLQueryFormatter omits important space after LIKE
*/
@Test
public void testFormatterLikeMissingSpace() throws Exception {
String jpql = "SELECT a FROM Asset a WHERE a.name LIKE a.address";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
IJPQLQueryFormatter formatter = new DefaultJPQLQueryFormatter(IdentifierStyle.UPPERCASE);
assertEquals(jpql, formatter.toString(so));
// instead formatter.toString(so) returns:
// SELECT a FROM Asset a WHERE a.name LIKEa.address'
}
/**
* lowercase 'true" is formatted as NULL
*/
@Test
public void testFormatterLowercaseTrue() throws Exception {
String jpql = "SELECT a FROM Asset a WHERE a.good = TRUE";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(true);
assertEquals(jpql, formatter.toString(so)); // this works
jpql = "SELECT a FROM Asset a WHERE a.good = true";
so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
formatter = new DefaultActualJPQLQueryFormatter(true);
assertEquals(jpql, formatter.toString(so));
// instead formatter.toString(so) returns:
// SELECT a FROM Asset a WHERE a.good = NULL
}
/**
* Not causes StackOverflow
*/
@Test
public void testFormatterNot() throws Exception {
String jpql = "SELECT a FROM Artifact a WHERE NOT (a.name = 'fred')";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(true);
assertEquals(jpql, formatter.toString(so));
// fails with DefaultJPQLQueryFormatter too
}
/**
* DefaultActualJPQLQueryFormatter with exactMatch=true omits important space before ORDER BY
*/
@Test
public void testFormatterOrderByMissingSpace() throws Exception {
String jpql = "SELECT a FROM Asset a WHERE a.good = TRUE ORDER BY a.size";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(true);
assertEquals(jpql, formatter.toString(so));
// instead formatter.toString(so) returns: TRUEORDER BY a.size
}
/**
* "IS EMPTY" is formatted as "null"
*/
@Test
public void testFormatterOrderStackOverflow() throws Exception {
String jpql = "SELECT r FROM AnyRelationshipType r WHERE r.groupUUID IS EMPTY";
JPQLQueryStateObject so = queryBuilder.buildStateObject(getPersistenceUnit(), jpql, false);
IJPQLQueryFormatter formatter = new DefaultActualJPQLQueryFormatter(false);
assertEquals(jpql, formatter.toString(so));
// instead formatter.toString(so) returns:
// SELECT r FROM AnyRelationshipType r WHERE r.groupUUID null
}
}