Bug 463042: Concurrency issue with Case expression operator (#1359)
Signed-off-by: Will Dazey <dazeydev.3@gmail.com>
diff --git a/foundation/eclipselink.core.test/src/it/java/org/eclipse/persistence/testing/tests/expressions/ExpressionOperatorUnitTestSuite.java b/foundation/eclipselink.core.test/src/it/java/org/eclipse/persistence/testing/tests/expressions/ExpressionOperatorUnitTestSuite.java
index a553afc..aa90456 100644
--- a/foundation/eclipselink.core.test/src/it/java/org/eclipse/persistence/testing/tests/expressions/ExpressionOperatorUnitTestSuite.java
+++ b/foundation/eclipselink.core.test/src/it/java/org/eclipse/persistence/testing/tests/expressions/ExpressionOperatorUnitTestSuite.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021 IBM Corporation. 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
@@ -84,6 +85,158 @@
}
}
+ public void _testDefaultCaseOperatorDatabaseStringsTest() {
+ ExpressionOperator caseOp = ExpressionOperator.caseStatement();
+
+ String[] databaseStrings = caseOp.getDatabaseStrings(0);
+ String[] expectedStrings = new String[] {"CASE ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(1);
+ expectedStrings = new String[] {"CASE ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(2);
+ expectedStrings = new String[] {"CASE ", " ELSE ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(3);
+ expectedStrings = new String[] {"CASE ", " WHEN ", " THEN ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(4);
+ expectedStrings = new String[] {"CASE ", " WHEN ", " THEN ", " ELSE ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(5);
+ expectedStrings = new String[] {"CASE ", " WHEN ", " THEN ", " WHEN ", " THEN ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseOp.getDatabaseStrings(6);
+ expectedStrings = new String[] {"CASE ", " WHEN ", " THEN ", " WHEN ", " THEN ", " ELSE ", " END"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+ }
+
+ public void _testDefaultCaseConditionOperatorDatabaseStringsTest() {
+ ExpressionOperator caseConditionOp = ExpressionOperator.caseConditionStatement();
+
+ String[] databaseStrings = caseConditionOp.getDatabaseStrings(0);
+ String[] expectedStrings = new String[] {"CASE WHEN ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(1);
+ expectedStrings = new String[] {"CASE WHEN ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(2);
+ expectedStrings = new String[] {"CASE WHEN ", " THEN ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(3);
+ expectedStrings = new String[] {"CASE WHEN ", " THEN ", " ELSE ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(4);
+ expectedStrings = new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(5);
+ expectedStrings = new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " ELSE ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(6);
+ expectedStrings = new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " WHEN ", " THEN ", " END "};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+ }
+
+ public void _testDefaultCoalesceOperatorDatabaseStringsTest() {
+ ExpressionOperator coalesceOp = ExpressionOperator.coalesce();
+
+ String[] databaseStrings = coalesceOp.getDatabaseStrings(0);
+ String[] expectedStrings = new String[] {"COALESCE(", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = coalesceOp.getDatabaseStrings(1);
+ expectedStrings = new String[] {"COALESCE(", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = coalesceOp.getDatabaseStrings(2);
+ expectedStrings = new String[] {"COALESCE(", ", ", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = coalesceOp.getDatabaseStrings(3);
+ expectedStrings = new String[] {"COALESCE(", ", ", ", ", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = coalesceOp.getDatabaseStrings(4);
+ expectedStrings = new String[] {"COALESCE(", ", ", ", ", ", ", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+
+ databaseStrings = coalesceOp.getDatabaseStrings(5);
+ expectedStrings = new String[] {"COALESCE(", ", ", ", ", ", ", ", ", ")"};
+ if(!(Arrays.equals(expectedStrings, databaseStrings))) {
+ throw new TestErrorException("Expected " + Arrays.toString(expectedStrings) +
+ " but was " + Arrays.toString(databaseStrings));
+ }
+ }
+
@Override
public void addTests() {
setManager(PopulationManager.getDefaultManager());
@@ -95,5 +248,9 @@
addTest(new UnitTestCase("IsComparisonOperatorTest"));
addTest(new UnitTestCase("IsFunctionOperatorTest"));
addTest(new UnitTestCase("IsLogicalOperatorTest"));
+
+ addTest(new UnitTestCase("DefaultCaseOperatorDatabaseStringsTest"));
+ addTest(new UnitTestCase("DefaultCaseConditionOperatorDatabaseStringsTest"));
+ addTest(new UnitTestCase("DefaultCoalesceOperatorDatabaseStringsTest"));
}
}
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ExpressionOperator.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ExpressionOperator.java
index 09c1f4e..be93a0c 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ExpressionOperator.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ExpressionOperator.java
@@ -56,7 +56,10 @@
static final long serialVersionUID = -7066100204792043980L;
protected int selector;
protected String name;
- protected String[] databaseStrings;
+
+ // ListExpressionOperator uses its own start/separator/terminator strings
+ private String[] databaseStrings;
+
protected boolean isPrefix = false;
protected boolean isRepeating = false;
protected Class<?> nodeClass;
@@ -317,7 +320,7 @@
}
ExpressionOperator operator = (ExpressionOperator) object;
if (getSelector() == 0) {
- return Arrays.equals(getDatabaseStrings(), operator.getDatabaseStrings());
+ return Arrays.equals(getDatabaseStrings(0), operator.getDatabaseStrings(0));
} else {
return getSelector() == operator.getSelector();
}
@@ -1232,6 +1235,13 @@
/**
* INTERNAL:
*/
+ public String[] getDatabaseStrings(int arguments) {
+ return databaseStrings;
+ }
+
+ /**
+ * INTERNAL:
+ */
public String[] getJavaStrings() {
return javaStrings;
}
@@ -2166,16 +2176,11 @@
if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && !isBindingSupported()) {
printer.getCall().setUsesBinding(false);
}
+
int dbStringIndex = 0;
- try {
- if (isPrefix()) {
- printer.getWriter().write(getDatabaseStrings()[0]);
- dbStringIndex = 1;
- } else {
- dbStringIndex = 0;
- }
- } catch (IOException e) {
- e.printStackTrace();
+ if (isPrefix()) {
+ printer.printString(getDatabaseStrings()[0]);
+ dbStringIndex = 1;
}
if (argumentIndices == null) {
@@ -2185,6 +2190,7 @@
}
}
+ String[] dbStrings = getDatabaseStrings(items.size());
for (final int index : argumentIndices) {
Expression item = (Expression)items.get(index);
if ((this.selector == Ref) || ((this.selector == Deref) && (item.isObjectExpression()))) {
@@ -2195,8 +2201,8 @@
} else {
item.printSQL(printer);
}
- if (dbStringIndex < getDatabaseStrings().length) {
- printer.printString(getDatabaseStrings()[dbStringIndex++]);
+ if (dbStringIndex < dbStrings.length) {
+ printer.printString(dbStrings[dbStringIndex++]);
}
}
}
@@ -2225,12 +2231,11 @@
if (printer.getPlatform().isDynamicSQLRequiredForFunctions() && !isBindingSupported()) {
printer.getCall().setUsesBinding(false);
}
- int dbStringIndex;
+
+ int dbStringIndex = 0;
if (isPrefix()) {
printer.printString(getDatabaseStrings()[0]);
dbStringIndex = 1;
- } else {
- dbStringIndex = 0;
}
first.printSQL(printer);
@@ -2996,11 +3001,12 @@
*/
@Override
public String toString() {
- if ((getDatabaseStrings() == null) || (getDatabaseStrings().length == 0)) {
+ String[] dbStrings = getDatabaseStrings();
+ if ((dbStrings == null) || (dbStrings.length == 0)) {
//CR#... Print a useful name for the missing platform operator.
return "platform operator - " + getPlatformOperatorName(this.selector);
} else {
- return "operator " + Arrays.asList(getDatabaseStrings());
+ return "operator " + Arrays.asList(dbStrings);
}
}
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ListExpressionOperator.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ListExpressionOperator.java
index ba32a46..6093a93 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ListExpressionOperator.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/expressions/ListExpressionOperator.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021 IBM Corporation. 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
@@ -14,6 +15,8 @@
// tware - initial API and implementation from for JPA 2.0 criteria API
package org.eclipse.persistence.expressions;
+import java.util.List;
+
import org.eclipse.persistence.internal.helper.Helper;
/**
@@ -39,7 +42,6 @@
protected String[] startStrings = null;
protected String[] separators = null;
protected String[] terminationStrings = null;
- protected int numberOfItems = 0;
protected boolean isComplete = false;
@Override
@@ -61,35 +63,50 @@
*/
@Override
public String[] getDatabaseStrings() {
- databaseStrings = new String[numberOfItems + 1];
+ return getDatabaseStrings(0);
+ }
+
+ /**
+ * Returns an array of Strings that expects a query argument between each String in the array to form the Expression.
+ * The array is built from the defined startStrings, separators, and terminationStrings.
+ * Start strings and termination strings take precedence over separator strings.
+ *
+ * The first defined start string will be added to the array.
+ * All subsequent start strings are optional, meaning they will only be added to the array if there are argument spaces available.
+ *
+ * The defined set of separator strings will be repeated, as a complete set, as long as there are argument spaces available.
+ *
+ * The last defined termination string will be added to the array.
+ * All antecedent termination strings are optional, meaning they will only be added to the array if there are argument spaces available.
+ */
+ @Override
+ public String[] getDatabaseStrings(int arguments) {
int i = 0;
- while (i < startStrings.length){
- databaseStrings[i] = startStrings[i];
+ String[] databaseStrings = new String[(arguments == 0) ? 2 : arguments + 1];
+
+ int start = (arguments < (startStrings.length)) ? databaseStrings.length - 1 : startStrings.length;
+ for (int j = 0; j < start; j++) {
+ databaseStrings[i] = startStrings[j];
i++;
}
- while (i < numberOfItems - (terminationStrings.length - 1)){
- for (int j=0;j<separators.length;j++){
- databaseStrings[i] = separators[j];
+
+ // '- 1' to save a spot for the guaranteed 1 terminator
+ int separ = ((databaseStrings.length - start - 1) / separators.length);
+ for (int j = 0; j < separ; j++) {
+ for (int k = 0; k < separators.length; k++) {
+ databaseStrings[i] = separators[k];
i++;
}
}
- while (i <= numberOfItems){
- for (int j=0;j<terminationStrings.length;j++){
- databaseStrings[i] = terminationStrings[j];
- i++;
- }
+
+ int termi = databaseStrings.length - (start + (separ * separators.length));
+ for (int j = (terminationStrings.length - termi); j < terminationStrings.length; j++) {
+ databaseStrings[i] = terminationStrings[j];
+ i++;
}
return databaseStrings;
}
- public int getNumberOfItems(){
- return numberOfItems;
- }
-
- public void setNumberOfItems(int numberOfItems){
- this.numberOfItems = numberOfItems;
- }
-
public String[] getStartStrings() {
return startStrings;
}
@@ -126,10 +143,6 @@
this.terminationStrings = terminationStrings;
}
- public void incrementNumberOfItems(){
- numberOfItems++;
- }
-
public void setIsComplete(boolean isComplete){
this.isComplete = isComplete;
}
@@ -138,6 +151,4 @@
public boolean isComplete() {
return isComplete;
}
-
-
}
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java
index e91fff9..2bf2c2a 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ArgumentListFunctionExpression.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021 IBM Corporation. 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
@@ -56,7 +57,6 @@
super.addChild(argument);
}
setBaseExpression(getChildren().firstElement());
- ((ListExpressionOperator)operator).incrementNumberOfItems();
}
/**
@@ -86,7 +86,6 @@
public void setOperator(ExpressionOperator theOperator) {
assert(theOperator instanceof ListExpressionOperator);
super.setOperator(theOperator);
- ((ListExpressionOperator)theOperator).setNumberOfItems(0);
}
/**
@@ -104,7 +103,6 @@
@Override
protected void postCopyIn(Map alreadyDone) {
- ((ListExpressionOperator)operator).setNumberOfItems(0);
Boolean hasLastChildCopy = hasLastChild;
hasLastChild = null;
super.postCopyIn(alreadyDone);
@@ -117,7 +115,6 @@
@Override
public void initializePlatformOperator(DatabasePlatform platform) {
super.initializePlatformOperator(platform);
- ((ListExpressionOperator)platformOperator).setNumberOfItems(((ListExpressionOperator)operator).getNumberOfItems());
}
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ExpressionOperatorConverter.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ExpressionOperatorConverter.java
index 72d4734..b268ad5 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ExpressionOperatorConverter.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/expressions/ExpressionOperatorConverter.java
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021 IBM Corporation. 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
@@ -43,10 +44,11 @@
} else {
fieldValue = getAttributeToFieldValues().get(attributeValue);
if (fieldValue == null) {
- //Custom function. Remove "(".
- if (((ExpressionOperator)attributeValue).getDatabaseStrings() != null) {
- String databaseString = ((ExpressionOperator)attributeValue).getDatabaseStrings()[0];
- fieldValue = databaseString.substring(0, databaseString.length()-1);
+ // Custom function. Remove "(".
+ String[] dbStrings = ((ExpressionOperator)attributeValue).getDatabaseStrings();
+ if (dbStrings != null) {
+ String databaseString = dbStrings[0];
+ fieldValue = databaseString.substring(0, databaseString.length() - 1);
} else {
throw DescriptorException.noAttributeValueConversionToFieldValueProvided(attributeValue, getMapping());
}
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/TestConcurrencyPersistence.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/TestConcurrencyPersistence.java
index 11070fd..e22a34e 100644
--- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/TestConcurrencyPersistence.java
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/TestConcurrencyPersistence.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 IBM Corporation. All rights reserved.
+ * Copyright (c) 2018, 2021 IBM Corporation. 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
@@ -19,7 +19,10 @@
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
@@ -75,7 +78,51 @@
}
Assert.assertTrue(errors.toString(), errors.isEmpty());
+ }
+ /**
+ * Bug 463042: Executing the same query simultaneously on separate threads has the possibility of
+ * causing an ArrayOutOfBoundsException to be thrown. This test spins up multiple threads, executes
+ * the same query on each and validates that none of the threads failed.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCaseExpressionOperatorConcurrency() throws Exception {
+ final AtomicInteger count = new AtomicInteger();
+ final AtomicInteger error = new AtomicInteger();
+
+ final int threads = 100;
+ final ExecutorService taskExecutor = Executors.newFixedThreadPool(threads);
+
+ // Spawn 100 threads
+ for (int i = 0; i < threads; i++) {
+ taskExecutor.execute(new Runnable() {
+ public void run() {
+ count.incrementAndGet();
+
+ final EntityManager em = emf.createEntityManager();
+ try {
+ // Executing the Query
+ em.createNamedQuery("CONCURR_CASE_QUERY", Integer.class).setParameter("id", 1).getSingleResult();
+ } catch (Exception e) {
+ error.incrementAndGet();
+ System.out.println(e.getMessage());
+ } finally {
+ if (em != null) {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+ }
+ });
+ }
+ taskExecutor.shutdown();
+ taskExecutor.awaitTermination(5, TimeUnit.SECONDS);
+
+ Assert.assertEquals("Expected no failures, but " + error.intValue() + "/" + count.intValue() + " threads failed", 0, error.intValue());
}
/**
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/model/User.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/model/User.java
index d349b12..bbf775a 100644
--- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/model/User.java
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/concurrency/model/User.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 IBM Corporation. All rights reserved.
+ * Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2021 IBM Corporation. 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
@@ -25,10 +25,12 @@
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
+import jakarta.persistence.NamedQuery;
import jakarta.persistence.Table;
@Entity
@Table(name="CONCURR_USER")
+@NamedQuery(name = "CONCURR_CASE_QUERY", query = "SELECT CASE WHEN (COUNT(e) > 0) THEN true ELSE false END FROM User e WHERE e.id = :id")
public class User {
@Id private int id;
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestQueryCase.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestQueryCase.java
index 3971db9..33dc427 100644
--- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestQueryCase.java
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestQueryCase.java
@@ -28,6 +28,7 @@
import jakarta.persistence.criteria.ParameterExpression;
import jakarta.persistence.criteria.Root;
+import org.eclipse.persistence.expressions.ExpressionOperator;
import org.eclipse.persistence.jpa.test.framework.DDLGen;
import org.eclipse.persistence.jpa.test.framework.Emf;
import org.eclipse.persistence.jpa.test.framework.EmfRunner;
@@ -35,6 +36,7 @@
import org.eclipse.persistence.jpa.test.query.model.Dto01;
import org.eclipse.persistence.jpa.test.query.model.EntityTbl01;
import org.eclipse.persistence.jpa.test.query.model.EntityTbl01_;
+import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,6 +50,32 @@
private static boolean POPULATED = false;
@Test
+ public void testDefaultCaseConditionOperatorDatabaseStrings() {
+ ExpressionOperator caseConditionOp = ExpressionOperator.caseConditionStatement();
+
+ String[] databaseStrings = caseConditionOp.getDatabaseStrings(0);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(1);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(2);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " THEN ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(3);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " THEN ", " ELSE ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(4);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(5);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " ELSE ", " END "}, databaseStrings);
+
+ databaseStrings = caseConditionOp.getDatabaseStrings(6);
+ Assert.assertArrayEquals(new String[] {"CASE WHEN ", " THEN ", " WHEN ", " THEN ", " WHEN ", " THEN ", " END "}, databaseStrings);
+ }
+
+ @Test
public void testQuery_JPQL_Case_Literals_1() {
if (emf == null)
return;