Skip to content

Commit

Permalink
Fix calling stored procs on Postgres, and enable some tests (#2308)
Browse files Browse the repository at this point in the history
  • Loading branch information
rdicroce authored Dec 20, 2024
1 parent 3e6f9b3 commit 452ffdd
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022 IBM Corporation. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2024 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
Expand Down Expand Up @@ -1443,6 +1443,7 @@ public boolean isInformixOuterJoin() {
*
* @see PostgreSQLPlatform
*/
@Deprecated(forRemoval = true)
public boolean isJDBCExecuteCompliant() {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,20 +305,6 @@ public boolean shouldPrintOutputTokenAtStart() {
return true;
}

/**
* Calling a stored procedure query on PostgreSQL with no output parameters
* always returns true from an execute call regardless if a result set is
* returned or not. This flag will help avoid throwing a JPA mandated
* exception on an executeUpdate call (which calls jdbc execute and checks
* the return value to ensure no results sets are returned (true))
*
* @see PostgreSQLPlatform
*/
@Override
public boolean isJDBCExecuteCompliant() {
return false;
}

/**
* INTERNAL: Answers whether platform is Postgres.
*/
Expand Down Expand Up @@ -522,63 +508,25 @@ public int getMaxFieldNameSize() {
*/
@Override
public String getProcedureBeginString() {
return "AS $$ BEGIN ";
return "$$ BEGIN ";
}

/**
* INTERNAL: Used for sp calls.
*/
@Override
public String getProcedureEndString() {
return "; END ; $$ LANGUAGE plpgsql;";
}

/**
* INTERNAL: Used for sp calls. PostGreSQL uses a different method for executing StoredProcedures than other platforms.
*/
@Override
public String buildProcedureCallString(StoredProcedureCall call, AbstractSession session, AbstractRecord row) {
StringWriter tailWriter = new StringWriter();
StringWriter writer = new StringWriter();
boolean outParameterFound = false;

tailWriter.write(call.getProcedureName());
tailWriter.write("(");

int indexFirst = call.getFirstParameterIndexForCallString();
int size = call.getParameters().size();
String nextBindString = "?";

for (int index = indexFirst; index < size; index++) {
String name = call.getProcedureArgumentNames().get(index);
Object parameter = call.getParameters().get(index);
ParameterType parameterType = call.getParameterTypes().get(index);
// If the argument is optional and null, ignore it.
if (!call.hasOptionalArguments() || !call.getOptionalArguments().contains(parameter) || (row.get(parameter) != null)) {
if (!DatasourceCall.isOutputParameterType(parameterType)) {
tailWriter.write(nextBindString);
nextBindString = ", ?";
} else {
if (outParameterFound) {
//multiple outs found
throw ValidationException.multipleOutParamsNotSupported(Helper.getShortClassName(this), call.getProcedureName());
}
outParameterFound = true; //PostGreSQL uses a very different header to execute when there are out params
}
}
}
tailWriter.write(")");

if (outParameterFound) {
writer.write("{?= CALL ");
tailWriter.write("}");
} else {
writer.write("SELECT * FROM ");
}
writer.write(tailWriter.toString());
return "END; $$ LANGUAGE plpgsql;";
}

return writer.toString();
/**
* INTERNAL: Used for sp calls.
*/
@Override
public String getProcedureCallHeader() {
return "CALL ";
}

/**
* INTERNAL Used for stored function calls.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand Down Expand Up @@ -30,6 +30,7 @@
import org.eclipse.persistence.jpa.test.framework.Property;
import org.eclipse.persistence.platform.database.DatabasePlatform;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
import org.eclipse.persistence.tools.schemaframework.SchemaManager;
import org.eclipse.persistence.tools.schemaframework.StoredProcedureDefinition;

Expand Down Expand Up @@ -121,6 +122,8 @@ public void testStoredProcedure_SetUnordered_IndexParameters() {
*/
@Test
public void testStoredProcedure_SetOrdered_NamedParameters() {
Assume.assumeFalse("pgjdbc does not support named parameters", getPlatform(storedProcedureEmf).isPostgreSQL());

EntityManager em = storedProcedureEmf.createEntityManager();
try {
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("simple_order_procedure");
Expand Down Expand Up @@ -152,6 +155,8 @@ public void testStoredProcedure_SetOrdered_NamedParameters() {
*/
@Test
public void testStoredProcedure_SetUnordered_NamedParameters() {
Assume.assumeFalse("pgjdbc does not support named parameters", getPlatform(storedProcedureEmf).isPostgreSQL());

EntityManager em = storedProcedureEmf.createEntityManager();
try {
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("simple_order_procedure");
Expand Down Expand Up @@ -186,22 +191,27 @@ private static boolean createSimpleStoredProcedure(EntityManagerFactory emf) {
//Setup a stored procedure
EntityManager em = emf.createEntityManager();
try {
DatabaseSession dbs = ((EntityManagerImpl)em).getDatabaseSession();
SchemaManager manager = new SchemaManager(dbs);
Platform platform = dbs.getDatasourcePlatform();

StoredProcedureDefinition proc = new StoredProcedureDefinition();
proc.setName("simple_order_procedure");

proc.addArgument("in_param_one", String.class, 10);
proc.addArgument("in_param_two", String.class, 10);
proc.addArgument("in_param_three", String.class, 10);
proc.addOutputArgument("out_param_one", String.class, 30);

DatabaseSession dbs = ((EntityManagerImpl)em).getDatabaseSession();
SchemaManager manager = new SchemaManager(dbs);
Platform platform = dbs.getDatasourcePlatform();
if (platform.isPostgreSQL()) {
// PG only supports OUT in 14+
proc.addInOutputArgument(new FieldDefinition("out_param_one", String.class, 30));
} else {
proc.addOutputArgument("out_param_one", String.class, 30);
}

//Add more platform specific diction to support more platforms
if(platform.isMySQL()) {
proc.addStatement("SET out_param_one = CONCAT('One: ',in_param_one,' Two: ',in_param_two,' Three: ',in_param_three)");
} else if(platform.isOracle()) {
} else if(platform.isOracle() || platform.isPostgreSQL()) {
proc.addStatement("out_param_one := 'One: ' || in_param_one || ' Two: ' || in_param_two || ' Three: ' || in_param_three");
} else if (platform.isDB2() || platform.isDB2Z()) {
proc.addStatement("SET out_param_one = 'One: ' || in_param_one || ' Two: ' || in_param_two || ' Three: ' || in_param_three");
Expand Down

0 comments on commit 452ffdd

Please sign in to comment.