|
4 | 4 | */ |
5 | 5 | package org.hibernate.community.dialect; |
6 | 6 |
|
7 | | -import java.util.List; |
8 | | - |
9 | | -import org.hibernate.HibernateException; |
10 | | -import org.hibernate.dialect.type.AbstractPostgreSQLStructJdbcType; |
11 | | -import org.hibernate.procedure.internal.AbstractStandardCallableStatementSupport; |
12 | | -import org.hibernate.procedure.spi.FunctionReturnImplementor; |
13 | | -import org.hibernate.procedure.spi.ProcedureCallImplementor; |
| 7 | +import org.hibernate.procedure.internal.StandardCallableStatementSupport; |
14 | 8 | import org.hibernate.procedure.spi.ProcedureParameterImplementor; |
15 | | -import org.hibernate.type.OutputableType; |
16 | | -import org.hibernate.query.spi.ProcedureParameterMetadataImplementor; |
17 | | -import org.hibernate.sql.exec.internal.JdbcCallImpl; |
18 | 9 | import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration; |
19 | | -import org.hibernate.sql.exec.spi.JdbcOperationQueryCall; |
20 | | -import org.hibernate.type.SqlTypes; |
21 | | - |
22 | | -import jakarta.persistence.ParameterMode; |
23 | 10 |
|
24 | 11 | /** |
25 | 12 | * GaussDB implementation of CallableStatementSupport. |
|
28 | 15 | * |
29 | 16 | * Notes: Original code of this class is based on PostgreSQLCallableStatementSupport. |
30 | 17 | */ |
31 | | -public class GaussDBCallableStatementSupport extends AbstractStandardCallableStatementSupport { |
32 | | - /** |
33 | | - * Singleton access |
34 | | - */ |
35 | | - public static final GaussDBCallableStatementSupport INSTANCE = new GaussDBCallableStatementSupport( true ); |
| 18 | +public class GaussDBCallableStatementSupport extends StandardCallableStatementSupport { |
36 | 19 |
|
37 | | - private final boolean supportsProcedures; |
| 20 | + public static final StandardCallableStatementSupport INSTANCE = new GaussDBCallableStatementSupport( |
| 21 | + true ); |
38 | 22 |
|
39 | 23 | private GaussDBCallableStatementSupport(boolean supportsProcedures) { |
40 | | - this.supportsProcedures = supportsProcedures; |
| 24 | + super( supportsProcedures ); |
41 | 25 | } |
42 | 26 |
|
43 | 27 | @Override |
44 | | - public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedureCall) { |
45 | | - final String procedureName = procedureCall.getProcedureName(); |
46 | | - final FunctionReturnImplementor<?> functionReturn = procedureCall.getFunctionReturn(); |
47 | | - final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata(); |
48 | | - final boolean firstParamIsRefCursor = parameterMetadata.getParameterCount() != 0 |
49 | | - && isFirstParameterModeRefCursor( parameterMetadata ); |
50 | | - |
51 | | - final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList(); |
52 | | - final int paramStringSizeEstimate; |
53 | | - if ( functionReturn == null && parameterMetadata.hasNamedParameters() ) { |
54 | | - // That's just a rough estimate. I guess most params will have fewer than 8 chars on average |
55 | | - paramStringSizeEstimate = registrations.size() * 10; |
56 | | - } |
57 | | - else { |
58 | | - // For every param rendered as '?' we have a comma, hence the estimate |
59 | | - paramStringSizeEstimate = registrations.size() * 2; |
60 | | - } |
61 | | - final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder(); |
62 | | - |
63 | | - final int jdbcParameterOffset; |
64 | | - final int startIndex; |
65 | | - final CallMode callMode; |
66 | | - if ( functionReturn != null ) { |
67 | | - if ( functionReturn.getJdbcTypeCode() == SqlTypes.REF_CURSOR ) { |
68 | | - if ( firstParamIsRefCursor ) { |
69 | | - // validate that the parameter strategy is positional (cannot mix, and REF_CURSOR is inherently positional) |
70 | | - if ( parameterMetadata.hasNamedParameters() ) { |
71 | | - throw new HibernateException( "Cannot mix named parameters and REF_CURSOR parameter on GaussDB" ); |
72 | | - } |
73 | | - callMode = CallMode.CALL_RETURN; |
74 | | - startIndex = 1; |
75 | | - jdbcParameterOffset = 1; |
76 | | - builder.addParameterRegistration( registrations.get( 0 ).toJdbcParameterRegistration( 1, procedureCall ) ); |
77 | | - } |
78 | | - else { |
79 | | - callMode = CallMode.TABLE_FUNCTION; |
80 | | - startIndex = 0; |
81 | | - jdbcParameterOffset = 1; |
82 | | - } |
83 | | - } |
84 | | - else { |
85 | | - callMode = CallMode.FUNCTION; |
86 | | - startIndex = 0; |
87 | | - jdbcParameterOffset = 1; |
88 | | - } |
89 | | - } |
90 | | - else if ( supportsProcedures ) { |
91 | | - jdbcParameterOffset = 1; |
92 | | - startIndex = 0; |
93 | | - callMode = CallMode.NATIVE_CALL; |
94 | | - } |
95 | | - else if ( firstParamIsRefCursor ) { |
96 | | - // validate that the parameter strategy is positional (cannot mix, and REF_CURSOR is inherently positional) |
97 | | - if ( parameterMetadata.hasNamedParameters() ) { |
98 | | - throw new HibernateException( "Cannot mix named parameters and REF_CURSOR parameter on GaussDB" ); |
99 | | - } |
100 | | - jdbcParameterOffset = 1; |
101 | | - startIndex = 1; |
102 | | - callMode = CallMode.CALL_RETURN; |
103 | | - builder.addParameterRegistration( registrations.get( 0 ).toJdbcParameterRegistration( 1, procedureCall ) ); |
104 | | - } |
105 | | - else { |
106 | | - jdbcParameterOffset = 1; |
107 | | - startIndex = 0; |
108 | | - callMode = CallMode.CALL; |
109 | | - } |
110 | | - |
111 | | - final StringBuilder buffer = new StringBuilder( callMode.start.length() + callMode.end.length() + procedureName.length() + paramStringSizeEstimate ) |
112 | | - .append( callMode.start ); |
113 | | - buffer.append( procedureName ); |
114 | | - |
115 | | - if ( startIndex == registrations.size() ) { |
116 | | - buffer.append( '(' ); |
117 | | - } |
118 | | - else { |
119 | | - char sep = '('; |
120 | | - for ( int i = startIndex; i < registrations.size(); i++ ) { |
121 | | - final ProcedureParameterImplementor<?> parameter = registrations.get( i ); |
122 | | - if ( !supportsProcedures && parameter.getMode() == ParameterMode.REF_CURSOR ) { |
123 | | - throw new HibernateException( |
124 | | - "GaussDB supports only one REF_CURSOR parameter, but multiple were registered" ); |
125 | | - } |
126 | | - buffer.append( sep ); |
127 | | - final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration( |
128 | | - i + jdbcParameterOffset, |
129 | | - procedureCall |
130 | | - ); |
131 | | - final OutputableType<?> type = registration.getParameterType(); |
132 | | - final String castType; |
133 | | - if ( parameter.getName() != null ) { |
134 | | - buffer.append( parameter.getName() ).append( " => " ); |
135 | | - } |
136 | | - if ( type != null && type.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) { |
137 | | - // We have to cast struct type parameters so that GaussDB understands nulls |
138 | | - castType = ( (AbstractPostgreSQLStructJdbcType) type.getJdbcType() ).getStructTypeName(); |
139 | | - buffer.append( "cast(" ); |
140 | | - } |
141 | | - else { |
142 | | - castType = null; |
143 | | - } |
144 | | - buffer.append( "?" ); |
145 | | - if ( castType != null ) { |
146 | | - buffer.append( " as " ).append( castType ).append( ')' ); |
147 | | - } |
148 | | - sep = ','; |
149 | | - builder.addParameterRegistration( registration ); |
150 | | - } |
151 | | - } |
152 | | - |
153 | | - buffer.append( callMode.end ); |
154 | | - builder.setCallableName( buffer.toString() ); |
155 | | - return builder.buildJdbcCall(); |
156 | | - } |
157 | | - |
158 | | - private static boolean isFirstParameterModeRefCursor(ProcedureParameterMetadataImplementor parameterMetadata) { |
159 | | - return parameterMetadata.getRegistrationsAsList().get( 0 ).getMode() == ParameterMode.REF_CURSOR; |
160 | | - } |
161 | | - |
162 | | - enum CallMode { |
163 | | - TABLE_FUNCTION("select * from ", ")"), |
164 | | - FUNCTION("select ", ")"), |
165 | | - NATIVE_CALL("call ", ")"), |
166 | | - CALL_RETURN("{?=call ", ")}"), |
167 | | - CALL("{call ", ")}"); |
168 | | - |
169 | | - private final String start; |
170 | | - private final String end; |
171 | | - |
172 | | - CallMode(String start, String end) { |
173 | | - this.start = start; |
174 | | - this.end = end; |
175 | | - } |
| 28 | + protected void appendNameParameter( |
| 29 | + StringBuilder buffer, |
| 30 | + ProcedureParameterImplementor parameter, |
| 31 | + JdbcCallParameterRegistration registration) { |
| 32 | + buffer.append( parameter.getName() ).append( " => ?" ); |
176 | 33 | } |
177 | 34 | } |
0 commit comments