Skip to content

Commit 8766a8e

Browse files
dreab8sebersole
authored andcommitted
HHH-18280 Support named procedure parameters down to the JDBC level
1 parent 79480ab commit 8766a8e

File tree

11 files changed

+110
-38
lines changed

11 files changed

+110
-38
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,12 +1501,6 @@ public int registerResultSetOutParameter(CallableStatement statement, String nam
15011501
return 1;
15021502
}
15031503

1504-
@Override
1505-
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
1506-
// Not sure if it's a JDBC driver issue, but it doesn't work
1507-
return false;
1508-
}
1509-
15101504
@Override
15111505
public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException {
15121506
return (ResultSet) statement.getObject( name );

hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
import org.hibernate.metamodel.mapping.EntityMappingType;
5555
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
5656
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
57-
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
57+
import org.hibernate.procedure.internal.OracleCallableStatementSupport;
5858
import org.hibernate.procedure.spi.CallableStatementSupport;
5959
import org.hibernate.query.SemanticException;
6060
import org.hibernate.query.spi.QueryOptions;
@@ -1314,7 +1314,7 @@ public int getMaxIdentifierLength() {
13141314
@Override
13151315
public CallableStatementSupport getCallableStatementSupport() {
13161316
// Oracle supports returning cursors
1317-
return StandardCallableStatementSupport.REF_CURSOR_INSTANCE;
1317+
return OracleCallableStatementSupport.REF_CURSOR_INSTANCE;
13181318
}
13191319

13201320
@Override

hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
import org.hibernate.internal.util.JdbcExceptionHelper;
5555
import org.hibernate.mapping.Column;
5656
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
57+
import org.hibernate.procedure.internal.SQLServerCallableStatementSupport;
58+
import org.hibernate.procedure.spi.CallableStatementSupport;
5759
import org.hibernate.query.sqm.CastType;
5860
import org.hibernate.query.sqm.FetchClauseType;
5961
import org.hibernate.query.sqm.IntervalType;
@@ -1122,7 +1124,6 @@ protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata m
11221124

11231125
@Override
11241126
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) {
1125-
// Not sure if it's a JDBC driver issue, but it doesn't work
11261127
return false;
11271128
}
11281129

@@ -1168,4 +1169,10 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
11681169
public boolean supportsFromClauseInUpdate() {
11691170
return true;
11701171
}
1172+
1173+
@Override
1174+
public CallableStatementSupport getCallableStatementSupport() {
1175+
return SQLServerCallableStatementSupport.INSTANCE;
1176+
}
1177+
11711178
}

hibernate-core/src/main/java/org/hibernate/procedure/internal/DB2CallableStatementSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
8484
i + offset,
8585
procedureCall
8686
);
87-
if ( registration.getName() != null ) {
88-
buffer.append( ':' ).append( registration.getName() );
87+
if ( parameter.getName() != null ) {
88+
buffer.append( ':' ).append( parameter.getName() );
8989
}
9090
else {
9191
buffer.append( "?" );

hibernate-core/src/main/java/org/hibernate/procedure/internal/JTDSCallableStatementSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
6969
i + offset,
7070
procedureCall
7171
);
72-
if ( registration.getName() != null ) {
73-
buffer.append( '@' ).append( registration.getName() ).append( "=?" );
72+
if ( parameter.getName() != null ) {
73+
buffer.append( '@' ).append( parameter.getName() ).append( "=?" );
7474
}
7575
else {
7676
buffer.append( "?" );
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.procedure.internal;
8+
9+
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
10+
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
11+
12+
/**
13+
* Standard implementation of {@link org.hibernate.procedure.spi.CallableStatementSupport}.
14+
*
15+
* @author Steve Ebersole
16+
*/
17+
public class OracleCallableStatementSupport extends StandardCallableStatementSupport {
18+
19+
public static final StandardCallableStatementSupport REF_CURSOR_INSTANCE = new OracleCallableStatementSupport( true );
20+
21+
22+
public OracleCallableStatementSupport(boolean supportsRefCursors) {
23+
super( supportsRefCursors );
24+
}
25+
26+
protected void appendNameParameter(
27+
StringBuilder buffer,
28+
ProcedureParameterImplementor parameter,
29+
JdbcCallParameterRegistration registration) {
30+
buffer.append( parameter.getName() ).append( " => ?" );
31+
}
32+
33+
}

hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ else if ( firstParamIsRefCursor ) {
156156
);
157157
final OutputableType<?> type = registration.getParameterType();
158158
final String castType;
159+
if ( parameter.getName() != null ) {
160+
buffer.append( parameter.getName() ).append( " => " );
161+
}
159162
if ( type != null && type.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) {
160163
// We have to cast struct type parameters so that PostgreSQL understands nulls
161164
castType = ( (AbstractPostgreSQLStructJdbcType) type.getJdbcType() ).getStructTypeName();
@@ -164,12 +167,7 @@ else if ( firstParamIsRefCursor ) {
164167
else {
165168
castType = null;
166169
}
167-
if ( registration.getName() != null ) {
168-
buffer.append( ':' ).append( registration.getName() );
169-
}
170-
else {
171-
buffer.append( "?" );
172-
}
170+
buffer.append( "?" );
173171
if ( castType != null ) {
174172
buffer.append( " as " ).append( castType ).append( ')' );
175173
}

hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterImpl.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package org.hibernate.procedure.internal;
88

99
import java.sql.CallableStatement;
10+
import java.sql.DatabaseMetaData;
1011
import java.sql.PreparedStatement;
1112
import java.sql.SQLException;
1213
import java.util.Locale;
@@ -144,36 +145,38 @@ else if ( binding != null ) {
144145
);
145146

146147
final String jdbcParamName;
147-
if ( isNamed && canDoNameParameterBinding( typeToUse, procedureCall ) ) {
148-
jdbcParamName = this.name;
149-
}
150-
else {
151-
jdbcParamName = null;
152-
}
153-
154148
final JdbcParameterBinder parameterBinder;
155149
final JdbcCallRefCursorExtractorImpl refCursorExtractor;
156150
final JdbcCallParameterExtractorImpl<T> parameterExtractor;
151+
final ExtractedDatabaseMetaData databaseMetaData = procedureCall.getSession()
152+
.getFactory()
153+
.getJdbcServices()
154+
.getJdbcEnvironment()
155+
.getExtractedDatabaseMetaData();
157156

158157
switch ( mode ) {
159158
case REF_CURSOR:
159+
jdbcParamName = this.name != null && databaseMetaData.supportsNamedParameters() ? this.name : null;
160160
refCursorExtractor = new JdbcCallRefCursorExtractorImpl( jdbcParamName, startIndex );
161161
parameterBinder = null;
162162
parameterExtractor = null;
163163
break;
164164
case IN:
165+
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
165166
validateBindableType( typeToUse, startIndex );
166167
parameterBinder = getParameterBinder( typeToUse, jdbcParamName );
167168
parameterExtractor = null;
168169
refCursorExtractor = null;
169170
break;
170171
case INOUT:
172+
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
171173
validateBindableType( typeToUse, startIndex );
172174
parameterBinder = getParameterBinder( typeToUse, jdbcParamName );
173175
parameterExtractor = new JdbcCallParameterExtractorImpl<>( procedureCall.getProcedureName(), jdbcParamName, startIndex, typeToUse );
174176
refCursorExtractor = null;
175177
break;
176178
default:
179+
jdbcParamName = getJdbcParamName( procedureCall, isNamed, typeToUse, databaseMetaData );
177180
validateBindableType( typeToUse, startIndex );
178181
parameterBinder = null;
179182
parameterExtractor = new JdbcCallParameterExtractorImpl<>( procedureCall.getProcedureName(), jdbcParamName, startIndex, typeToUse );
@@ -184,6 +187,14 @@ else if ( binding != null ) {
184187
return new JdbcCallParameterRegistrationImpl( jdbcParamName, startIndex, mode, typeToUse, parameterBinder, parameterExtractor, refCursorExtractor );
185188
}
186189

190+
private String getJdbcParamName(
191+
ProcedureCallImplementor<?> procedureCall,
192+
boolean isNamed,
193+
OutputableType<T> typeToUse,
194+
ExtractedDatabaseMetaData databaseMetaData) {
195+
return isNamed && canDoNameParameterBinding( typeToUse, procedureCall, databaseMetaData ) ? this.name : null;
196+
}
197+
187198
private void validateBindableType(BindableType<T> bindableType, int startIndex) {
188199
if ( bindableType == null ) {
189200
throw new ParameterTypeException(
@@ -210,7 +221,7 @@ private JdbcParameterBinder getParameterBinder(BindableType<T> typeToUse, String
210221
}
211222

212223
if ( typeToUse instanceof BasicType<?> ) {
213-
if ( name == null ) {
224+
if ( name == null ) {
214225
return new JdbcParameterImpl( (BasicType<T>) typeToUse );
215226
}
216227
else {
@@ -242,12 +253,8 @@ public String toString() {
242253

243254
private boolean canDoNameParameterBinding(
244255
BindableType<?> hibernateType,
245-
ProcedureCallImplementor<?> procedureCall) {
246-
final ExtractedDatabaseMetaData databaseMetaData = procedureCall.getSession()
247-
.getFactory()
248-
.getJdbcServices()
249-
.getJdbcEnvironment()
250-
.getExtractedDatabaseMetaData();
256+
ProcedureCallImplementor<?> procedureCall,
257+
ExtractedDatabaseMetaData databaseMetaData) {
251258
return procedureCall.getFunctionReturn() == null
252259
&& databaseMetaData.supportsNamedParameters()
253260
&& hibernateType instanceof ProcedureParameterNamedBinder
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.procedure.internal;
8+
9+
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
10+
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
11+
12+
public class SQLServerCallableStatementSupport extends StandardCallableStatementSupport {
13+
14+
public static final StandardCallableStatementSupport INSTANCE = new SQLServerCallableStatementSupport( );
15+
16+
17+
private SQLServerCallableStatementSupport() {
18+
super( false );
19+
}
20+
21+
protected void appendNameParameter(StringBuilder buffer, ProcedureParameterImplementor parameter, JdbcCallParameterRegistration registration) {
22+
buffer.append( '@' ).append( parameter.getName() ).append( " = ?" );
23+
}
24+
}

hibernate-core/src/main/java/org/hibernate/procedure/internal/StandardCallableStatementSupport.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
9191
i + offset,
9292
procedureCall
9393
);
94-
if ( registration.getName() != null ) {
95-
buffer.append( ':' ).append( registration.getName() );
94+
if ( parameter.getName() != null ) {
95+
appendNameParameter( buffer, parameter, registration );
9696
}
9797
else {
9898
buffer.append( "?" );
@@ -108,6 +108,13 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
108108
return builder.buildJdbcCall();
109109
}
110110

111+
protected void appendNameParameter(
112+
StringBuilder buffer,
113+
ProcedureParameterImplementor parameter,
114+
JdbcCallParameterRegistration registration) {
115+
buffer.append( '?' );
116+
}
117+
111118
private void verifyRefCursorSupport(Dialect dialect) {
112119
if ( ! supportsRefCursors ) {
113120
throw new QueryException( "Dialect [" + dialect.getClass().getName() + "] not known to support REF_CURSOR parameters" );

0 commit comments

Comments
 (0)