blob: 556768f761fa660ff607e0fd619379123253af0f [file] [log] [blame]
/*
* Copyright (c) 2013, 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:
// 01/23/2013-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
package org.eclipse.persistence.testing.tests.jpa21.advanced;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Parameter;
import jakarta.persistence.ParameterMode;
import jakarta.persistence.StoredProcedureQuery;
import jakarta.persistence.TransactionRequiredException;
import junit.framework.TestSuite;
import junit.framework.Test;
import org.eclipse.persistence.queries.ResultSetMappingQuery;
import org.eclipse.persistence.queries.ColumnResult;
import org.eclipse.persistence.queries.ConstructorResult;
import org.eclipse.persistence.queries.EntityResult;
import org.eclipse.persistence.queries.FieldResult;
import org.eclipse.persistence.queries.SQLResultSetMapping;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.testing.models.jpa21.advanced.Address;
import org.eclipse.persistence.testing.models.jpa21.advanced.AdvancedTableCreator;
import org.eclipse.persistence.testing.models.jpa21.advanced.EmployeeDetails;
import org.eclipse.persistence.testing.models.jpa21.advanced.EmployeePopulator;
import org.eclipse.persistence.testing.models.jpa21.advanced.LargeProject;
import org.eclipse.persistence.testing.models.jpa21.advanced.Project;
import org.eclipse.persistence.testing.models.jpa21.advanced.SmallProject;
import org.eclipse.persistence.testing.models.jpa21.advanced.Employee;
import org.eclipse.persistence.testing.framework.junit.JUnitTestCase;
public class StoredProcedureQueryTestSuite extends JUnitTestCase {
public StoredProcedureQueryTestSuite() {}
public StoredProcedureQueryTestSuite(String name) {
super(name);
setPuName("MulitPU-1");
}
@Override
public String getPersistenceUnitName() {
return "MulitPU-1";
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("StoredProcedureQueryTestSuite");
suite.addTest(new StoredProcedureQueryTestSuite("testSetup"));
// Add the EM level stored procedure query tests.
suite.addTest(new StoredProcedureQueryTestSuite("testQueryExecute1"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryExecute2"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryExecuteUpdate"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryGetResultList"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryWithMultipleResultsFromCode"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryWithNamedFieldResult"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryWithNumberedFieldResult"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryWithResultClass"));
suite.addTest(new StoredProcedureQueryTestSuite("testQueryWithOutParam"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureParameterAPI"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQuerySysCursor_Named"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQuerySysCursor_Positional"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQuerySysCursor_ResultList_Named"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQuerySysCursor_ResultList_Positional"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQueryExceptionWrapping1"));
suite.addTest(new StoredProcedureQueryTestSuite("testStoredProcedureQueryExceptionWrapping2"));
// Add the named Annotation query tests.
suite.addTest(NamedStoredProcedureQueryTestSuite.suite());
// These are EM API validation tests. These tests delete and update so
// be careful where you introduce new tests.
suite.addTest(new StoredProcedureQueryTestSuite("testClassCastExceptionOnExecuteWithNoOutputParameters"));
suite.addTest(new StoredProcedureQueryTestSuite("testGetResultListOnDeleteQuery"));
suite.addTest(new StoredProcedureQueryTestSuite("testGetResultListOnUpdateQuery"));
suite.addTest(new StoredProcedureQueryTestSuite("testGetSingleResultOnDeleteQuery"));
suite.addTest(new StoredProcedureQueryTestSuite("testGetSingleResultOnUpdateQuery"));
return suite;
}
/**
* The setup is done as a test, both to record its failure, and to allow execution in the server.
*/
public void testSetup() {
new AdvancedTableCreator().replaceTables(getPersistenceUnitServerSession());
EmployeePopulator employeePopulator = new EmployeePopulator();
employeePopulator.buildExamples();
employeePopulator.persistExample(getPersistenceUnitServerSession());
clearCache();
}
/**
* Test a class cast exception.
*/
public void testClassCastExceptionOnExecuteWithNoOutputParameters() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_All_Employees");
boolean returnValue = query.execute();
assertTrue("Execute didn't return true", returnValue);
List<Employee> employees = query.getResultList();
assertFalse("No employees were returned", employees.isEmpty());
} catch (ClassCastException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
fail("ClassCastException caught" + e);
} finally {
closeEntityManager(em);
}
}
}
/**
* Test an expected exception.
*/
public void testGetResultListOnDeleteQuery() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
boolean exceptionCaught = false;
try {
Object result = em.createStoredProcedureQuery("Delete_All_Responsibilities").getResultList();
} catch (IllegalStateException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
exceptionCaught = true;
} finally {
closeEntityManager(em);
}
assertTrue("Expected Illegal state exception was not caught", exceptionCaught);
}
}
/**
* Test an expected exception.
*/
public void testGetResultListOnUpdateQuery() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
boolean exceptionCaught = false;
try {
String postalCodeTypo = "R3 1B9";
String postalCodeCorrection = "R3B 1B9";
StoredProcedureQuery query = em.createStoredProcedureQuery("Update_Address_Postal_Code");
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
Object results = query.setParameter("new_p_code_v", postalCodeCorrection).setParameter("old_p_code_v", postalCodeTypo).getResultList();
} catch (IllegalStateException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
exceptionCaught = true;
} finally {
closeEntityManager(em);
}
assertTrue("Expected Illegal state exception was not caught", exceptionCaught);
}
}
/**
* Test an expected exception.
*/
public void testGetSingleResultOnDeleteQuery() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
boolean exceptionCaught = false;
try {
Object result = em.createStoredProcedureQuery("Delete_All_Responsibilities").getSingleResult();
} catch (IllegalStateException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
exceptionCaught = true;
} finally {
closeEntityManager(em);
}
assertTrue("Expected Illegal state exception was not caught", exceptionCaught);
}
}
/**
* Test an expected exception.
*/
public void testGetSingleResultOnUpdateQuery() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
boolean exceptionCaught = false;
try {
String postalCodeTypo = "R3 1B9";
String postalCodeCorrection = "R3B 1B9";
StoredProcedureQuery query = em.createStoredProcedureQuery("Update_Address_Postal_Code");
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
query.setParameter("new_p_code_v", postalCodeCorrection);
query.setParameter("old_p_code_v", postalCodeTypo);
// Make these calls to test the getParameter call with a name.
Parameter<?> paramNew = query.getParameter("new_p_code_v");
Parameter<?> paramOld = query.getParameter("old_p_code_v");
Object results = query.getSingleResult();
} catch (IllegalStateException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
exceptionCaught = true;
} finally {
closeEntityManager(em);
}
assertTrue("Expected Illegal state exception was not caught", exceptionCaught);
}
}
/**
* Tests a StoredProcedureQuery that does an update though EM API
*/
public void testQueryExecute1() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
// Create some data (with errors)
String postalCodeTypo = "K2J 0L8";
String postalCodeCorrection = "K2G 6W2";
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Winnipeg");
address1.setPostalCode(postalCodeTypo);
address1.setProvince("MB");
address1.setStreet("510 Main Street");
address1.setCountry("Canada");
em.persist(address1);
Address address2 = new Address();
address2.setCity("Winnipeg");
address2.setPostalCode(postalCodeTypo);
address2.setProvince("MB");
address2.setStreet("512 Main Street");
address2.setCountry("Canada");
em.persist(address2);
Address address3 = new Address();
address3.setCity("Winnipeg");
address3.setPostalCode(postalCodeCorrection);
address3.setProvince("MB");
address3.setStreet("514 Main Street");
address3.setCountry("Canada");
em.persist(address3);
commitTransaction(em);
// Clear the cache
em.clear();
clearCache();
// Build the named stored procedure query, execute and test.
StoredProcedureQuery query = em.createStoredProcedureQuery("Result_Set_And_Update_Address", Address.class, Employee.class);
assertTrue("Parameter list was not empty.", query.getParameters().size() == 0);
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("employee_count_v", Integer.class, ParameterMode.OUT);
query.setParameter("new_p_code_v", postalCodeCorrection);
query.setParameter("old_p_code_v", postalCodeTypo);
boolean result = query.execute();
assertTrue("Parameter list size was incorrect, actual: " + query.getParameters().size() + ", expecting 3.", query.getParameters().size() == 3);
Object parameterValue = query.getParameterValue("new_p_code_v");
assertTrue("The IN parameter value was not preserved, expected: " + postalCodeCorrection + ", actual: " + parameterValue, parameterValue.equals(postalCodeCorrection));
assertTrue("Result did not return true for a result set.", result);
List<Address> addressResults = query.getResultList();
assertTrue("The query didn't have any more results.", query.hasMoreResults());
List<Employee> employeeResults = query.getResultList();
int numberOfEmployes = employeeResults.size();
// Should return false (no more results)
assertFalse("The query had more results.", query.hasMoreResults());
// Get the update count.
int updateCount = query.getUpdateCount();
assertTrue("Update count incorrect: " + updateCount, updateCount == 2);
// Update count should return -1 now.
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
// Check output parameters by name.
Object outputParamValueFromName = query.getOutputParameterValue("employee_count_v");
assertNotNull("The output parameter was null.", outputParamValueFromName);
// TODO: to investigate. This little bit is hacky. For some
// reason MySql returns a Long here. By position is ok, that is,
// it returns an Integer (as we registered)
if (outputParamValueFromName instanceof Long) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromName, outputParamValueFromName.equals((long) numberOfEmployes));
} else if (outputParamValueFromName instanceof Integer) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromName, outputParamValueFromName.equals(numberOfEmployes));
}
// TODO: else, don't worry about it for now ...
// Do some negative tests ...
try {
query.getOutputParameterValue(null);
fail("No IllegalArgumentException was caught with a null parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue("emp_count");
fail("No IllegalArgumentException was caught with invalid parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue("new_p_code_v");
fail("No IllegalArgumentException was caught with IN parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
// Check output parameters by position.
Object outputParamValueFromPosition = query.getOutputParameterValue(3);
// TODO: See previous investigate todo. A Long is returned here instead of an Integer on MySQL.
// This test also mixes index and named parameters, so this test my be invalid to begin with.
assertNotNull("The output parameter was null.", outputParamValueFromPosition);
if (outputParamValueFromName instanceof Long) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromPosition, outputParamValueFromPosition.equals((long) numberOfEmployes));
} else if (outputParamValueFromName instanceof Integer) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromPosition, outputParamValueFromPosition.equals(numberOfEmployes));
}
// Do some negative tests ...
try {
query.getOutputParameterValue(8);
fail("No IllegalArgumentException was caught with position out of bounds.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue(1);
fail("No IllegalArgumentException was caught with an IN parameter position.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
// Just because we don't trust anyone ... :-)
Address a1 = em.find(Address.class, address1.getId());
assertTrue("The postal code was not updated for address 1.", a1.getPostalCode().equals(postalCodeCorrection));
Address a2 = em.find(Address.class, address2.getId());
assertTrue("The postal code was not updated for address 2.", a2.getPostalCode().equals(postalCodeCorrection));
Address a3 = em.find(Address.class, address3.getId());
assertTrue("The postal code was not updated for address 3.", a3.getPostalCode().equals(postalCodeCorrection));
} finally {
// The open statement/connection will be closed here.
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery that does an update though EM API
* This is the same test as above except different retrieval path.
*/
public void testQueryExecute2() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
// Create some data (with errors)
String postalCodeTypo = "K2J 0L8";
String postalCodeCorrection = "K2G 6W2";
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Winnipeg");
address1.setPostalCode(postalCodeTypo);
address1.setProvince("MB");
address1.setStreet("510 Main Street");
address1.setCountry("Canada");
em.persist(address1);
Address address2 = new Address();
address2.setCity("Winnipeg");
address2.setPostalCode(postalCodeTypo);
address2.setProvince("MB");
address2.setStreet("512 Main Street");
address2.setCountry("Canada");
em.persist(address2);
Address address3 = new Address();
address3.setCity("Winnipeg");
address3.setPostalCode(postalCodeCorrection);
address3.setProvince("MB");
address3.setStreet("514 Main Street");
address3.setCountry("Canada");
em.persist(address3);
commitTransaction(em);
// Clear the cache
em.clear();
clearCache();
// Build the named stored procedure query, execute and test.
StoredProcedureQuery query = em.createStoredProcedureQuery("Result_Set_And_Update_Address", Address.class, Employee.class);
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("employee_count_v", Integer.class, ParameterMode.OUT);
boolean result = query.setParameter("new_p_code_v", postalCodeCorrection).setParameter("old_p_code_v", postalCodeTypo).execute();
assertTrue("Result did not return true for a result set.", result);
// This shouldn't affect where we are in the retrieval of the query.
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
assertTrue("We have didn't have any more results", query.hasMoreResults());
List<Address> addressResults = query.getResultList();
// We know there should be more results so ask for them without checking for has more results.
List<Employee> employeeResults = query.getResultList();
int numberOfEmployes = employeeResults.size();
// Should return false (no more results)
assertFalse("The query had more results.", query.hasMoreResults());
assertFalse("The query had more results.", query.hasMoreResults());
assertFalse("The query had more results.", query.hasMoreResults());
assertFalse("The query had more results.", query.hasMoreResults());
assertNull("getResultList after no results did not return null", query.getResultList());
// Get the update count.
int updateCount = query.getUpdateCount();
assertTrue("Update count incorrect: " + updateCount, updateCount == 2);
// Update count should return -1 now.
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
assertTrue("Update count should be -1.", query.getUpdateCount() == -1);
// Check output parameters by name.
Object outputParamValueFromName = query.getOutputParameterValue("employee_count_v");
assertNotNull("The output parameter was null.", outputParamValueFromName);
// TODO: to investigate. This little bit is hacky. For some
// reason MySql returns a Long here. By position is ok, that is,
// it returns an Integer (as we registered)
if (outputParamValueFromName instanceof Long) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromName, outputParamValueFromName.equals((long) numberOfEmployes));
} else if (outputParamValueFromName instanceof Integer) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromName, outputParamValueFromName.equals(numberOfEmployes));
}
// TODO: else, don't worry about it for now ...
// Do some negative tests ...
try {
query.getOutputParameterValue(null);
fail("No IllegalArgumentException was caught with a null parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue("emp_count");
fail("No IllegalArgumentException was caught with invalid parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue("new_p_code_v");
fail("No IllegalArgumentException was caught with IN parameter name.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
// Check output parameters by position.
Object outputParamValueFromPosition = query.getOutputParameterValue(3);
// TODO: See previous investigate todo. A Long is returned here instead of an Integer on MySQL.
// This test also mixes index and named parameters, so this test my be invalid to begin with.
assertNotNull("The output parameter was null.", outputParamValueFromPosition);
if (outputParamValueFromName instanceof Long) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromPosition, outputParamValueFromPosition.equals((long) numberOfEmployes));
} else if (outputParamValueFromName instanceof Integer) {
assertTrue("Incorrect value returned, expected " + numberOfEmployes + ", got: " + outputParamValueFromPosition, outputParamValueFromPosition.equals(numberOfEmployes));
}
// Do some negative tests ...
try {
query.getOutputParameterValue(8);
fail("No IllegalArgumentException was caught with position out of bounds.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
try {
query.getOutputParameterValue(1);
fail("No IllegalArgumentException was caught with an IN parameter position.");
} catch (IllegalArgumentException e) {
// Expected, swallow.
}
// Just because we don't trust anyone ... :-)
Address a1 = em.find(Address.class, address1.getId());
assertTrue("The postal code was not updated for address 1.", a1.getPostalCode().equals(postalCodeCorrection));
Address a2 = em.find(Address.class, address2.getId());
assertTrue("The postal code was not updated for address 2.", a2.getPostalCode().equals(postalCodeCorrection));
Address a3 = em.find(Address.class, address3.getId());
assertTrue("The postal code was not updated for address 3.", a3.getPostalCode().equals(postalCodeCorrection));
} finally {
// The open statement/connection will be closed here.
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery that does an update though EM API
*/
public void testQueryExecuteUpdate() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
String postalCodeTypo = "R3 1B9";
String postalCodeCorrection = "R3B 1B9";
StoredProcedureQuery query = em.createStoredProcedureQuery("Update_Address_Postal_Code");
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
try {
query.setParameter("new_p_code_v", postalCodeCorrection).setParameter("old_p_code_v", postalCodeTypo).executeUpdate();
fail("TransactionRequiredException not caught");
} catch (TransactionRequiredException e) {
// ignore since expected exception.
}
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Winnipeg");
address1.setPostalCode(postalCodeTypo);
address1.setProvince("MB");
address1.setStreet("510 Main Street");
address1.setCountry("Canada");
em.persist(address1);
Address address2 = new Address();
address2.setCity("Winnipeg");
address2.setPostalCode(postalCodeTypo);
address2.setProvince("MB");
address2.setStreet("512 Main Street");
address2.setCountry("Canada");
em.persist(address2);
em.flush();
// Clear the cache
em.clear();
clearCache();
query = em.createStoredProcedureQuery("Update_Address_Postal_Code");
query.registerStoredProcedureParameter("new_p_code_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("old_p_code_v", String.class, ParameterMode.IN);
int results = query.setParameter("new_p_code_v", postalCodeCorrection).setParameter("old_p_code_v", postalCodeTypo).executeUpdate();
assertTrue("Update count incorrect.", results == 2);
// Just because we don't trust anyone ... :-)
Address a1 = em.find(Address.class, address1.getId());
assertTrue("The postal code was not updated for address 1.", a1.getPostalCode().equals(postalCodeCorrection));
Address a2 = em.find(Address.class, address2.getId());
assertTrue("The postal code was not updated for address 2.", a2.getPostalCode().equals(postalCodeCorrection));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery that does an select though EM API
*/
public void testQueryGetResultList() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Edmonton");
address1.setPostalCode("T5B 4M9");
address1.setProvince("AB");
address1.setStreet("7424 118 Avenue");
address1.setCountry("Canada");
em.persist(address1);
em.flush();
// Clear the cache
em.clear();
clearCache();
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Address");
query.registerStoredProcedureParameter("address_id_v", Integer.class, ParameterMode.IN);
List addresses = query.setParameter("address_id_v", address1.getId()).getResultList();
assertTrue("Incorrect number of addresses returned", addresses.size() == 1);
Object[] addressContent = (Object[]) addresses.get(0);
assertTrue("Incorrect data content size", addressContent.length == 6);
assertTrue("Id content incorrect", addressContent[0].equals((long) address1.getId()));
assertTrue("Steet content incorrect", addressContent[1].equals(address1.getStreet()));
assertTrue("City content incorrect", addressContent[2].equals(address1.getCity()));
assertTrue("Country content incorrect", addressContent[3].equals(address1.getCountry()));
assertTrue("Province content incorrect", addressContent[4].equals(address1.getProvince()));
assertTrue("Postal Code content incorrect", addressContent[5].equals(address1.getPostalCode()));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Test multiple result sets by setting the SQL results set mapping from code.
*/
public void testQueryWithMultipleResultsFromCode() throws Exception {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
// SQL result set mapping for employee.
SQLResultSetMapping employeeResultSetMapping = new SQLResultSetMapping("EmployeeResultSetMapping");
employeeResultSetMapping.addResult(new EntityResult(Employee.class));
// SQL result set mapping for address.
SQLResultSetMapping addressResultSetMapping = new SQLResultSetMapping("AddressResultSetMapping");
addressResultSetMapping.addResult(new EntityResult(Address.class));
// SQL result set mapping for project (using inheritance and more complex result)
SQLResultSetMapping projectResultSetMapping = new SQLResultSetMapping("ProjectResultSetMapping");
EntityResult projectEntityResult = new EntityResult(Project.class);
projectResultSetMapping.addResult(projectEntityResult);
projectEntityResult = new EntityResult(SmallProject.class);
projectEntityResult.addFieldResult(new FieldResult("id", "SMALL_ID"));
projectEntityResult.addFieldResult(new FieldResult("name", "SMALL_NAME"));
projectEntityResult.addFieldResult(new FieldResult("description", "SMALL_DESCRIPTION"));
projectEntityResult.addFieldResult(new FieldResult("teamLeader", "SMALL_TEAMLEAD"));
projectEntityResult.addFieldResult(new FieldResult("version", "SMALL_VERSION"));
projectEntityResult.setDiscriminatorColumn("SMALL_DESCRIM");
projectResultSetMapping.addResult(projectEntityResult);
projectResultSetMapping.addResult(new ColumnResult("BUDGET_SUM"));
// SQL result set mapping for employee using constructor results.
SQLResultSetMapping employeeConstrustorResultSetMapping = new SQLResultSetMapping("EmployeeConstructorResultSetMapping");
ConstructorResult constructorResult = new ConstructorResult(EmployeeDetails.class);
ColumnResult columnResult = new ColumnResult("EMP_ID");
columnResult.getColumn().setType(Integer.class);
constructorResult.addColumnResult(columnResult);
columnResult = new ColumnResult("F_NAME");
columnResult.getColumn().setType(String.class);
constructorResult.addColumnResult(columnResult);
columnResult = new ColumnResult("L_NAME");
columnResult.getColumn().setType(String.class);
constructorResult.addColumnResult(columnResult);
columnResult = new ColumnResult("R_COUNT");
columnResult.getColumn().setType(Integer.class);
constructorResult.addColumnResult(columnResult);
employeeConstrustorResultSetMapping.addResult(constructorResult);
StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("Read_Multiple_Result_Sets");
call.setHasMultipleResultSets(true);
call.setReturnMultipleResultSetCollections(true);
ResultSetMappingQuery query = new ResultSetMappingQuery(call);
query.addSQLResultSetMapping(employeeResultSetMapping);
query.addSQLResultSetMapping(addressResultSetMapping);
query.addSQLResultSetMapping(projectResultSetMapping);
query.addSQLResultSetMapping(employeeConstrustorResultSetMapping);
List allResults = (List)getPersistenceUnitServerSession().executeQuery(query);
assertNotNull("No results returned", allResults);
assertTrue("Incorrect number of results returned", allResults.size() == 4);
// Verify first result set mapping --> Employee
List results0 = (List) allResults.get(0);
assertNotNull("No Employee results returned", results0);
assertTrue("Empty Employee results returned", results0.size() > 0);
// Verify second result set mapping --> Address
List results1 = (List) allResults.get(1);
assertNotNull("No Address results returned", results1);
assertTrue("Empty Address results returned", results1.size() > 0);
// Verify third result set mapping --> Project
List results2 = (List) allResults.get(2);
assertNotNull("No Project results returned", results2);
assertTrue("Empty Project results returned", results2.size() > 0);
for (Object result2 : results2) {
Object[] result2Element = (Object[]) result2;
assertTrue("Failed to Return 3 items", (result2Element.length == 3));
// Using Number as Different db/drivers can return different types
// e.g. Oracle with ijdbc14.jar returns BigDecimal where as Derby
// with derbyclient.jar returns Double. NOTE: the order of checking
// here is valid and as defined by the spec.
assertTrue("Failed to return LargeProject", (result2Element[0] instanceof LargeProject));
assertTrue("Failed To Return SmallProject", (result2Element[1] instanceof SmallProject));
assertTrue("Failed to return column",(result2Element[2] instanceof Number));
assertFalse("Returned same data in both result elements",((SmallProject) result2Element[1]).getName().equals(((LargeProject) result2Element[0]).getName()));
}
// Verify fourth result set mapping --> Employee Constructor Result
List results3 = (List) allResults.get(3);
assertNotNull("No Employee constructor results returned", results3);
assertTrue("Empty Employee constructor results returned", results3.size() > 0);
}
}
/**
* Tests a StoredProcedureQuery using a result-set mapping though EM API
*/
public void testQueryWithNamedFieldResult() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Address address = new Address();
address.setCity("Winnipeg");
address.setPostalCode("R3B 1B9");
address.setProvince("MB");
address.setStreet("510 Main Street");
address.setCountry("Canada");
em.persist(address);
em.flush();
// Clear the cache
em.clear();
clearCache();
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Address_Mapped_Named", "address-column-result-map");
query.registerStoredProcedureParameter("address_id_v", Integer.class, ParameterMode.IN);
Object[] values = (Object[]) query.setParameter("address_id_v", address.getId()).getSingleResult();
assertTrue("Address data not found or returned using stored procedure", ((values != null) && (values.length == 6)));
assertNotNull("No results returned from store procedure call", values[1]);
assertTrue("Address not found using stored procedure", address.getStreet().equals(values[1]));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a NamedStoredProcedureQuery using a result-set-mapping using
* positional parameters (and more than the procedure expects).
*/
public void testQueryWithNumberedFieldResult() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Ottawa");
address1.setPostalCode("K2J 0L7");
address1.setProvince("ON");
address1.setStreet("321 Main");
address1.setCountry("Canada");
em.persist(address1);
em.flush();
// Clear the cache
em.clear();
clearCache();
StoredProcedureQuery query = em.createNamedStoredProcedureQuery("ReadAddressMappedNumberedFieldResult");
List<Address> addresses = query.setParameter(1, address1.getId()).getResultList();
assertTrue("Too many addresses returned", addresses.size() == 1);
Address address2 = addresses.get(0);
assertNotNull("Address returned from stored procedure is null", address2);
assertTrue("Address didn't build correctly using stored procedure", (address1.getId() == address2.getId()));
assertTrue("Address didn't build correctly using stored procedure", (address1.getStreet().equals(address2.getStreet())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getCountry().equals(address2.getCountry())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getProvince().equals(address2.getProvince())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getPostalCode().equals(address2.getPostalCode())));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a class though EM API
*/
public void testQueryWithResultClass() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Address address1 = new Address();
address1.setCity("Victoria");
address1.setPostalCode("V9A 6A9");
address1.setProvince("BC");
address1.setStreet("785 Lampson Street");
address1.setCountry("Canada");
em.persist(address1);
em.flush();
// Clear the cache
em.clear();
clearCache();
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Address", org.eclipse.persistence.testing.models.jpa21.advanced.Address.class);
query.registerStoredProcedureParameter("address_id_v", Integer.class, ParameterMode.IN);
Address address2 = (Address) query.setParameter("address_id_v", address1.getId()).getSingleResult();
assertNotNull("Address returned from stored procedure is null", address2);
assertTrue("Address didn't build correctly using stored procedure", (address1.getId() == address2.getId()));
assertTrue("Address didn't build correctly using stored procedure", (address1.getStreet().equals(address2.getStreet())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getCountry().equals(address2.getCountry())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getProvince().equals(address2.getProvince())));
assertTrue("Address didn't build correctly using stored procedure", (address1.getPostalCode().equals(address2.getPostalCode())));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a class though EM API
*/
public void testQueryWithOutParam() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
beginTransaction(em);
Address address = new Address();
address.setCity("TestCity");
address.setPostalCode("V4U 1P2");
address.setProvince("Nunavut");
address.setStreet("269 Lust Lane");
address.setCountry("Canada");
em.persist(address);
em.flush();
// Clear the cache
em.clear();
clearCache();
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Address_City");
query.registerStoredProcedureParameter("address_id_v", Integer.class, ParameterMode.IN);
query.registerStoredProcedureParameter("city_v", String.class, ParameterMode.OUT);
boolean result = query.setParameter("address_id_v", address.getId()).execute();
String city = (String) query.getOutputParameterValue("city_v");
assertTrue("Incorrect city was returned.", (address.getCity().equals(city)));
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Test stored procedure parameter API.
*/
public void testStoredProcedureParameterAPI() {
if (supportsStoredProcedures() && getPlatform().isMySQL()) {
EntityManager em = createEntityManager();
try {
StoredProcedureQuery query = em.createStoredProcedureQuery("Parameter_Testing");
query.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
query.registerStoredProcedureParameter(2, Integer.class, ParameterMode.INOUT);
query.registerStoredProcedureParameter(3, Integer.class, ParameterMode.OUT);
query.setParameter(1, "1");
query.setParameter(2, 2);
// Make this call to test the getParameter call with a position.
Parameter<?> param1 = query.getParameter(1);
Parameter<?> param2 = query.getParameter(2);
Parameter<?> param3 = query.getParameter(3);
} catch (IllegalArgumentException e) {
if (isTransactionActive(em)){
rollbackTransaction(em);
}
fail("IllegalArgumentException was caught");
} finally {
closeEntityManager(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a system cursor. Also tests
* getParameters call BEFORE query execution.
*/
public void testStoredProcedureQuerySysCursor_Named() {
if (supportsStoredProcedures() && getPlatform().isOracle() ) {
EntityManager em = createEntityManager();
try {
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Using_Sys_Cursor", Employee.class);
query.registerStoredProcedureParameter("f_name_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("p_recordset", void.class, ParameterMode.REF_CURSOR);
// Test the getParameters call BEFORE query execution.
assertTrue("The number of parameters returned was incorrect, actual: " + query.getParameters().size() + ", expected 2", query.getParameters().size() == 2);
query.setParameter("f_name_v", "Fred");
boolean execute = query.execute();
assertTrue("Execute returned false.", execute);
List<Employee> employees = (List<Employee>) query.getOutputParameterValue("p_recordset");
assertFalse("No employees were returned", employees.isEmpty());
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a system cursor. Also tests
* getParameters call BEFORE query execution.
*/
public void testStoredProcedureQuerySysCursor_Positional() {
if (supportsStoredProcedures() && getPlatform().isOracle() ) {
EntityManager em = createEntityManager();
try {
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Using_Sys_Cursor", Employee.class);
query.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
query.registerStoredProcedureParameter(2, void.class, ParameterMode.REF_CURSOR);
// Test the getParameters call BEFORE query execution.
assertTrue("The number of parameters returned was incorrect, actual: " + query.getParameters().size() + ", expected 2", query.getParameters().size() == 2);
query.setParameter(1, "Fred");
boolean execute = query.execute();
assertTrue("Execute returned false.", execute);
List<Employee> employees = (List<Employee>) query.getOutputParameterValue(2);
assertFalse("No employees were returned", employees.isEmpty());
} finally {
closeEntityManager(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a system cursor. Also tests
* getParameters call AFTER query execution. Parameters are passed via name.
*/
public void testStoredProcedureQuerySysCursor_ResultList_Named() {
if (supportsStoredProcedures() && getPlatform().isOracle() ) {
EntityManager em = createEntityManager();
try {
// Test stored procedure query created through API. //
beginTransaction(em);
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Using_Sys_Cursor");
query.registerStoredProcedureParameter("f_name_v", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("p_recordset", void.class, ParameterMode.REF_CURSOR);
query.setParameter("f_name_v", "Fred");
boolean execute = query.execute();
assertTrue("Execute returned false.", execute);
// Test the getParameters call AFTER query execution.
assertTrue("The number of paramters returned was incorrect, actual: " + query.getParameters().size() + ", expected 2", query.getParameters().size() == 2);
List<Employee> employees = (List<Employee>)query.getResultList();
assertFalse("No employees were returned", employees.isEmpty());
commitTransaction(em);
// Test now with the named stored procedure. //
beginTransaction(em);
StoredProcedureQuery query2 = em.createNamedStoredProcedureQuery("ReadUsingNamedSysCursor");
query2.setParameter("f_name_v", "Fred");
boolean execute2 = query2.execute();
List<Employee> employees2 = (List<Employee>)query2.getResultList();
assertFalse("No employees were returned from name stored procedure query.", employees2.isEmpty());
commitTransaction(em);
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests a StoredProcedureQuery using a system cursor. Also tests
* getParameters call AFTER query execution. Parameters are passed via position.
*/
public void testStoredProcedureQuerySysCursor_ResultList_Positional() {
if (supportsStoredProcedures() && getPlatform().isOracle() ) {
EntityManager em = createEntityManager();
try {
// Test stored procedure query created through API. //
beginTransaction(em);
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Using_Sys_Cursor");
query.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
query.registerStoredProcedureParameter(2, void.class, ParameterMode.REF_CURSOR);
query.setParameter(1, "Fred");
boolean execute = query.execute();
assertTrue("Execute returned false.", execute);
// Test the getParameters call AFTER query execution.
assertTrue("The number of paramters returned was incorrect, actual: " + query.getParameters().size() + ", expected 2", query.getParameters().size() == 2);
List<Employee> employees = (List<Employee>)query.getResultList();
assertFalse("No employees were returned", employees.isEmpty());
commitTransaction(em);
// Test now with the named stored procedure. //
beginTransaction(em);
StoredProcedureQuery query2 = em.createNamedStoredProcedureQuery("ReadUsingUnNamedSysCursor");
query2.setParameter(1, "Fred");
boolean execute2 = query2.execute();
List<Employee> employees2 = (List<Employee>)query2.getResultList();
assertFalse("No employees were returned from name stored procedure query.", employees2.isEmpty());
commitTransaction(em);
} finally {
closeEntityManagerAndTransaction(em);
}
}
}
/**
* Tests StoredProcedureQuery exception wrapping.
*/
public void testStoredProcedureQueryExceptionWrapping1() {
EntityManager em = createEntityManager();
try {
jakarta.persistence.Query query = em.createNativeQuery("DoesNotExist", Employee.class);
Object execute = query.getResultList();
fail("Executing a bad native SQL query did not throw a PersistenceException and instead returned: "+execute);
} catch (jakarta.persistence.PersistenceException pe) {
//expected.
} catch (RuntimeException re) {
fail("Executing a bad native SQL query did not throw a PersistenceException and instead threw: "+re);
} finally {
closeEntityManager(em);
}
}
/**
* Tests StoredProcedureQuery exception wrapping.
*/
public void testStoredProcedureQueryExceptionWrapping2() {
EntityManager em = createEntityManager();
try {
StoredProcedureQuery query = em.createStoredProcedureQuery("DoesNotExist", Employee.class);
boolean execute = query.execute();
fail("Executing a non-existent stored procedure did not throw a PersistenceException and instead returned: "+execute);
} catch (jakarta.persistence.PersistenceException pe) {
//expected.
} catch (RuntimeException re) {
fail("Executing a non-existent stored procedure did not throw a PersistenceException and instead threw: "+re);
} finally {
closeEntityManager(em);
}
}
}