Skip to content

Commit 943337d

Browse files
author
Thomas Darimont
committed
DATAJPA-652 - Added support for REF_CURSOR output parameters for procedures.
We now support detecting output parameters for stored-procedures with ParameterMode.REF_CURSOR. Previously we only considered parameters with OUT or INOUT mode as output parameters. Note that since it is a bit tricky to setup a proper test case with hsql / eclipselink, I had to verify this with a standalone spring boot app: https://gist.github.com/thomasdarimont/129bc15d0ccc459610c2 A proper test case will follow. Original pull request: #130.
1 parent 049fc45 commit 943337d

File tree

5 files changed

+75
-26
lines changed

5 files changed

+75
-26
lines changed

src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSource.java

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public StoredProcedureAttributes createFrom(Method method, JpaEntityMetadata<?>
5757
procedure);
5858

5959
if (namedStoredProc != null) {
60-
return newProcedureAttributesFrom(method, namedStoredProc);
60+
return newProcedureAttributesFrom(method, namedStoredProc, procedure);
6161
}
6262

6363
String procedureName = deriveProcedureNameFrom(method, procedure);
@@ -90,43 +90,63 @@ private String deriveProcedureNameFrom(Method method, Procedure procedure) {
9090
/**
9191
* @param method
9292
* @param namedStoredProc
93+
* @param procedure
9394
* @return
9495
*/
95-
private StoredProcedureAttributes newProcedureAttributesFrom(Method method, NamedStoredProcedureQuery namedStoredProc) {
96+
private StoredProcedureAttributes newProcedureAttributesFrom(Method method,
97+
NamedStoredProcedureQuery namedStoredProc, Procedure procedure) {
9698

9799
String outputParameterName = null;
98100
Class<?> outputParameterType = null;
99101

100-
int outputParameterCount = 0;
102+
if (!procedure.outputParameterName().isEmpty()) {
103+
104+
// we give the output parameter definition from the @Procedure annotation precedence
105+
outputParameterName = procedure.outputParameterName();
106+
} else {
107+
108+
// try to discover the output parameter
109+
List<StoredProcedureParameter> outputParameters = extractOutputParametersFrom(namedStoredProc);
110+
111+
if (outputParameters.size() != 1 && !void.class.equals(method.getReturnType())) {
112+
throw new IllegalStateException(String.format(
113+
"Could not create ProcedureAttributes from %s. We currently support exactly one output parameter!", method));
114+
}
115+
116+
if (!outputParameters.isEmpty()) {
117+
StoredProcedureParameter outputParameter = outputParameters.get(0);
118+
outputParameterName = outputParameter.name();
119+
outputParameterType = outputParameter.type();
120+
}
121+
}
122+
123+
if (outputParameterType == null || Object.class.equals(outputParameterType)
124+
|| void.class.equals(outputParameterType)) {
125+
outputParameterType = method.getReturnType();
126+
}
127+
128+
return new StoredProcedureAttributes(namedStoredProc.name(), outputParameterName, outputParameterType, true);
129+
}
130+
131+
private List<StoredProcedureParameter> extractOutputParametersFrom(NamedStoredProcedureQuery namedStoredProc) {
132+
133+
List<StoredProcedureParameter> outputParameters = new ArrayList<StoredProcedureParameter>();
101134

102135
for (StoredProcedureParameter param : namedStoredProc.parameters()) {
136+
103137
switch (param.mode()) {
104138
case OUT:
105139
case INOUT:
106-
107-
if (outputParameterCount > 0) {
108-
throw new IllegalStateException(
109-
String.format(
110-
"Could not create ProcedureAttributes from %s. We currently support only one output parameter!",
111-
method));
112-
}
113-
114-
outputParameterName = param.name();
115-
outputParameterType = param.type();
116-
117-
outputParameterCount++;
140+
case REF_CURSOR:
141+
outputParameters.add(param);
118142
break;
119143
case IN:
120144
default:
121145
continue;
122146
}
123147
}
124148

125-
if (outputParameterType == null) {
126-
outputParameterType = method.getReturnType();
127-
}
128-
129-
return new StoredProcedureAttributes(namedStoredProc.name(), outputParameterName, outputParameterType, true);
149+
return outputParameters;
130150
}
131151

132152
/**

src/test/java/org/springframework/data/jpa/domain/sample/User.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2014 the original author or authors.
2+
* Copyright 2008-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ public class User {
8484
@Lob private byte[] binaryData;
8585

8686
@ElementCollection private Set<String> attributes;
87-
87+
8888
@Temporal(TemporalType.DATE) private Date dateOfBirth;
8989

9090
/**
@@ -367,7 +367,7 @@ public Set<String> getAttributes() {
367367
public void setAttributes(Set<String> attributes) {
368368
this.attributes = attributes;
369369
}
370-
370+
371371
public Date getDateOfBirth() {
372372
return dateOfBirth;
373373
}

src/test/java/org/springframework/data/jpa/repository/UserRepositoryStoredProcedureTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -118,4 +118,17 @@ public void plainJpa21_entityAnnotatedCustomNamedProcedurePlus1IO() {
118118

119119
assertThat(proc.getOutputParameterValue("res"), is((Object) 2));
120120
}
121+
122+
/**
123+
* @see DATAJPA-652
124+
*/
125+
@Test
126+
public void executesProcedureWithNoOutput() {
127+
128+
assumeTrue(currentEntityManagerIsAJpa21EntityManager(em));
129+
130+
repository.executeNoOutputProcedure(1);
131+
132+
assertTrue(true);
133+
}
121134
}

src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2008-2014 the original author or authors.
2+
* Copyright 2008-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -549,4 +549,12 @@ List<User> findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
549549
* DATAJPA-606
550550
*/
551551
List<User> queryByAgeInOrFirstname(Integer[] ages, String firstname);
552+
553+
/**
554+
* Explicitly mapped to a procedure with name "nooutput" in database.
555+
*
556+
* @see DATAJPA-652
557+
*/
558+
@Procedure(procedureName = "nooutput")
559+
void executeNoOutputProcedure(Integer arg);
552560
}

src/test/resources/scripts/schema-stored-procedures.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@ CREATE procedure plus1inout (IN arg int, OUT res int)
55
BEGIN ATOMIC
66
set res = arg + 1;
77
END
8+
/;
9+
DROP procedure IF EXISTS nooutput
10+
/;
11+
CREATE procedure nooutput (IN arg int)
12+
BEGIN ATOMIC
13+
declare res int;
14+
set res = arg + 1;
15+
END
816
/;

0 commit comments

Comments
 (0)