1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.jdbc.core;
18
19 import java.sql.CallableStatement;
20 import java.sql.Connection;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.util.HashMap;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.springframework.dao.InvalidDataAccessApiUsageException;
29 import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
30
31
32
33
34
35
36
37
38
39
40 public class CallableStatementCreatorFactory {
41
42
43 private final String callString;
44
45
46 private final List<SqlParameter> declaredParameters;
47
48 private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
49
50 private boolean updatableResults = false;
51
52 private NativeJdbcExtractor nativeJdbcExtractor;
53
54
55
56
57
58
59 public CallableStatementCreatorFactory(String callString) {
60 this.callString = callString;
61 this.declaredParameters = new LinkedList<SqlParameter>();
62 }
63
64
65
66
67
68
69 public CallableStatementCreatorFactory(String callString, List<SqlParameter> declaredParameters) {
70 this.callString = callString;
71 this.declaredParameters = declaredParameters;
72 }
73
74
75
76
77
78
79
80 public void addParameter(SqlParameter param) {
81 this.declaredParameters.add(param);
82 }
83
84
85
86
87
88
89
90
91
92 public void setResultSetType(int resultSetType) {
93 this.resultSetType = resultSetType;
94 }
95
96
97
98
99 public void setUpdatableResults(boolean updatableResults) {
100 this.updatableResults = updatableResults;
101 }
102
103
104
105
106 public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
107 this.nativeJdbcExtractor = nativeJdbcExtractor;
108 }
109
110
111
112
113
114
115 public CallableStatementCreator newCallableStatementCreator(Map<String, ?> params) {
116 return new CallableStatementCreatorImpl(params != null ? params : new HashMap<String, Object>());
117 }
118
119
120
121
122
123 public CallableStatementCreator newCallableStatementCreator(ParameterMapper inParamMapper) {
124 return new CallableStatementCreatorImpl(inParamMapper);
125 }
126
127
128
129
130
131 private class CallableStatementCreatorImpl implements CallableStatementCreator, SqlProvider, ParameterDisposer {
132
133 private ParameterMapper inParameterMapper;
134
135 private Map<String, ?> inParameters;
136
137
138
139
140
141 public CallableStatementCreatorImpl(ParameterMapper inParamMapper) {
142 this.inParameterMapper = inParamMapper;
143 }
144
145
146
147
148
149 public CallableStatementCreatorImpl(Map<String, ?> inParams) {
150 this.inParameters = inParams;
151 }
152
153 @Override
154 public CallableStatement createCallableStatement(Connection con) throws SQLException {
155
156 if (this.inParameterMapper != null) {
157 this.inParameters = this.inParameterMapper.createMap(con);
158 }
159 else {
160 if (this.inParameters == null) {
161 throw new InvalidDataAccessApiUsageException(
162 "A ParameterMapper or a Map of parameters must be provided");
163 }
164 }
165
166 CallableStatement cs = null;
167 if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && !updatableResults) {
168 cs = con.prepareCall(callString);
169 }
170 else {
171 cs = con.prepareCall(callString, resultSetType,
172 updatableResults ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY);
173 }
174
175
176 CallableStatement csToUse = cs;
177 if (nativeJdbcExtractor != null) {
178 csToUse = nativeJdbcExtractor.getNativeCallableStatement(cs);
179 }
180
181 int sqlColIndx = 1;
182 for (SqlParameter declaredParam : declaredParameters) {
183 if (!declaredParam.isResultsParameter()) {
184
185
186 Object inValue = this.inParameters.get(declaredParam.getName());
187 if (declaredParam instanceof ResultSetSupportingSqlParameter) {
188
189
190 if (declaredParam instanceof SqlOutParameter) {
191 if (declaredParam.getTypeName() != null) {
192 cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType(), declaredParam.getTypeName());
193 }
194 else {
195 if (declaredParam.getScale() != null) {
196 cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType(), declaredParam.getScale());
197 }
198 else {
199 cs.registerOutParameter(sqlColIndx, declaredParam.getSqlType());
200 }
201 }
202 if (declaredParam.isInputValueProvided()) {
203 StatementCreatorUtils.setParameterValue(csToUse, sqlColIndx, declaredParam, inValue);
204 }
205 }
206 }
207 else {
208
209 if (!this.inParameters.containsKey(declaredParam.getName())) {
210 throw new InvalidDataAccessApiUsageException(
211 "Required input parameter '" + declaredParam.getName() + "' is missing");
212 }
213 StatementCreatorUtils.setParameterValue(csToUse, sqlColIndx, declaredParam, inValue);
214 }
215 sqlColIndx++;
216 }
217 }
218
219 return cs;
220 }
221
222 @Override
223 public String getSql() {
224 return callString;
225 }
226
227 @Override
228 public void cleanupParameters() {
229 if (this.inParameters != null) {
230 StatementCreatorUtils.cleanupParameters(this.inParameters.values());
231 }
232 }
233
234 @Override
235 public String toString() {
236 StringBuilder sb = new StringBuilder();
237 sb.append("CallableStatementCreatorFactory.CallableStatementCreatorImpl: sql=[");
238 sb.append(callString).append("]; parameters=").append(this.inParameters);
239 return sb.toString();
240 }
241 }
242
243 }