1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.jdbc.core.metadata;
18
19 import java.util.ArrayList;
20 import java.util.LinkedHashMap;
21 import java.util.LinkedHashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import javax.sql.DataSource;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.springframework.dao.InvalidDataAccessApiUsageException;
31 import org.springframework.jdbc.core.SqlTypeValue;
32 import org.springframework.jdbc.core.namedparam.SqlParameterSource;
33 import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
34 import org.springframework.jdbc.support.JdbcUtils;
35 import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
36
37
38
39
40
41
42
43
44
45 public class TableMetaDataContext {
46
47
48 protected final Log logger = LogFactory.getLog(getClass());
49
50
51 private String tableName;
52
53
54 private String catalogName;
55
56
57 private String schemaName;
58
59
60 private List<String> tableColumns = new ArrayList<String>();
61
62
63 private boolean accessTableColumnMetaData = true;
64
65
66 private boolean overrideIncludeSynonymsDefault = false;
67
68
69 private TableMetaDataProvider metaDataProvider;
70
71
72 private boolean generatedKeyColumnsUsed = false;
73
74
75 NativeJdbcExtractor nativeJdbcExtractor;
76
77
78
79
80
81 public void setTableName(String tableName) {
82 this.tableName = tableName;
83 }
84
85
86
87
88 public String getTableName() {
89 return this.tableName;
90 }
91
92
93
94
95 public void setCatalogName(String catalogName) {
96 this.catalogName = catalogName;
97 }
98
99
100
101
102 public String getCatalogName() {
103 return this.catalogName;
104 }
105
106
107
108
109 public void setSchemaName(String schemaName) {
110 this.schemaName = schemaName;
111 }
112
113
114
115
116 public String getSchemaName() {
117 return this.schemaName;
118 }
119
120
121
122
123 public void setAccessTableColumnMetaData(boolean accessTableColumnMetaData) {
124 this.accessTableColumnMetaData = accessTableColumnMetaData;
125 }
126
127
128
129
130 public boolean isAccessTableColumnMetaData() {
131 return this.accessTableColumnMetaData;
132 }
133
134
135
136
137
138 public void setOverrideIncludeSynonymsDefault(boolean override) {
139 this.overrideIncludeSynonymsDefault = override;
140 }
141
142
143
144
145 public boolean isOverrideIncludeSynonymsDefault() {
146 return this.overrideIncludeSynonymsDefault;
147 }
148
149
150
151
152 public List<String> getTableColumns() {
153 return this.tableColumns;
154 }
155
156
157
158
159
160 public boolean isGetGeneratedKeysSupported() {
161 return this.metaDataProvider.isGetGeneratedKeysSupported();
162 }
163
164
165
166
167
168
169 public boolean isGetGeneratedKeysSimulated() {
170 return this.metaDataProvider.isGetGeneratedKeysSimulated();
171 }
172
173
174
175
176
177
178 public String getSimulationQueryForGetGeneratedKey(String tableName, String keyColumnName) {
179 return this.metaDataProvider.getSimpleQueryForGetGeneratedKey(tableName, keyColumnName);
180 }
181
182
183
184
185
186 public boolean isGeneratedKeysColumnNameArraySupported() {
187 return this.metaDataProvider.isGeneratedKeysColumnNameArraySupported();
188 }
189
190
191
192
193 public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
194 this.nativeJdbcExtractor = nativeJdbcExtractor;
195 }
196
197
198
199
200
201
202
203
204 public void processMetaData(DataSource dataSource, List<String> declaredColumns, String[] generatedKeyNames) {
205 this.metaDataProvider = TableMetaDataProviderFactory.createMetaDataProvider(dataSource, this, this.nativeJdbcExtractor);
206 this.tableColumns = reconcileColumnsToUse(declaredColumns, generatedKeyNames);
207 }
208
209
210
211
212
213
214 protected List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
215 if (generatedKeyNames.length > 0) {
216 this.generatedKeyColumnsUsed = true;
217 }
218 if (declaredColumns.size() > 0) {
219 return new ArrayList<String>(declaredColumns);
220 }
221 Set<String> keys = new LinkedHashSet<String>(generatedKeyNames.length);
222 for (String key : generatedKeyNames) {
223 keys.add(key.toUpperCase());
224 }
225 List<String> columns = new ArrayList<String>();
226 for (TableParameterMetaData meta : metaDataProvider.getTableParameterMetaData()) {
227 if (!keys.contains(meta.getParameterName().toUpperCase())) {
228 columns.add(meta.getParameterName());
229 }
230 }
231 return columns;
232 }
233
234
235
236
237
238 public List<Object> matchInParameterValuesWithInsertColumns(SqlParameterSource parameterSource) {
239 List<Object> values = new ArrayList<Object>();
240
241
242 Map<String, String> caseInsensitiveParameterNames =
243 SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);
244 for (String column : this.tableColumns) {
245 if (parameterSource.hasValue(column)) {
246 values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, column));
247 }
248 else {
249 String lowerCaseName = column.toLowerCase();
250 if (parameterSource.hasValue(lowerCaseName)) {
251 values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, lowerCaseName));
252 }
253 else {
254 String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
255 if (parameterSource.hasValue(propertyName)) {
256 values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName));
257 }
258 else {
259 if (caseInsensitiveParameterNames.containsKey(lowerCaseName)) {
260 values.add(
261 SqlParameterSourceUtils.getTypedValue(parameterSource,
262 caseInsensitiveParameterNames.get(lowerCaseName)));
263 }
264 else {
265 values.add(null);
266 }
267 }
268 }
269 }
270 }
271 return values;
272 }
273
274
275
276
277
278 public List<Object> matchInParameterValuesWithInsertColumns(Map<String, ?> inParameters) {
279 List<Object> values = new ArrayList<Object>();
280 Map<String, Object> source = new LinkedHashMap<String, Object>(inParameters.size());
281 for (String key : inParameters.keySet()) {
282 source.put(key.toLowerCase(), inParameters.get(key));
283 }
284 for (String column : this.tableColumns) {
285 values.add(source.get(column.toLowerCase()));
286 }
287 return values;
288 }
289
290
291
292
293
294
295 public String createInsertString(String... generatedKeyNames) {
296 Set<String> keys = new LinkedHashSet<String>(generatedKeyNames.length);
297 for (String key : generatedKeyNames) {
298 keys.add(key.toUpperCase());
299 }
300 StringBuilder insertStatement = new StringBuilder();
301 insertStatement.append("INSERT INTO ");
302 if (this.getSchemaName() != null) {
303 insertStatement.append(this.getSchemaName());
304 insertStatement.append(".");
305 }
306 insertStatement.append(this.getTableName());
307 insertStatement.append(" (");
308 int columnCount = 0;
309 for (String columnName : this.getTableColumns()) {
310 if (!keys.contains(columnName.toUpperCase())) {
311 columnCount++;
312 if (columnCount > 1) {
313 insertStatement.append(", ");
314 }
315 insertStatement.append(columnName);
316 }
317 }
318 insertStatement.append(") VALUES(");
319 if (columnCount < 1) {
320 if (this.generatedKeyColumnsUsed) {
321 logger.info("Unable to locate non-key columns for table '" +
322 this.getTableName() + "' so an empty insert statement is generated");
323 }
324 else {
325 throw new InvalidDataAccessApiUsageException("Unable to locate columns for table '" +
326 this.getTableName() + "' so an insert statement can't be generated");
327 }
328 }
329 for (int i = 0; i < columnCount; i++) {
330 if (i > 0) {
331 insertStatement.append(", ");
332 }
333 insertStatement.append("?");
334 }
335 insertStatement.append(")");
336 return insertStatement.toString();
337 }
338
339
340
341
342
343 public int[] createInsertTypes() {
344 int[] types = new int[this.getTableColumns().size()];
345 List<TableParameterMetaData> parameters = this.metaDataProvider.getTableParameterMetaData();
346 Map<String, TableParameterMetaData> parameterMap =
347 new LinkedHashMap<String, TableParameterMetaData>(parameters.size());
348 for (TableParameterMetaData tpmd : parameters) {
349 parameterMap.put(tpmd.getParameterName().toUpperCase(), tpmd);
350 }
351 int typeIndx = 0;
352 for (String column : this.getTableColumns()) {
353 if (column == null) {
354 types[typeIndx] = SqlTypeValue.TYPE_UNKNOWN;
355 }
356 else {
357 TableParameterMetaData tpmd = parameterMap.get(column.toUpperCase());
358 if (tpmd != null) {
359 types[typeIndx] = tpmd.getSqlType();
360 }
361 else {
362 types[typeIndx] = SqlTypeValue.TYPE_UNKNOWN;
363 }
364 }
365 typeIndx++;
366 }
367 return types;
368 }
369
370 }