1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.driver.jdbc.core.resultset;
19
20 import com.cedarsoftware.util.CaseInsensitiveMap;
21 import lombok.EqualsAndHashCode;
22 import org.apache.shardingsphere.driver.exception.ResultSetClosedException;
23 import org.apache.shardingsphere.infra.exception.kernel.syntax.ColumnIndexOutOfRangeException;
24 import org.apache.shardingsphere.infra.exception.kernel.syntax.ColumnLabelNotFoundException;
25 import org.apache.shardingsphere.driver.jdbc.unsupported.AbstractUnsupportedDatabaseMetaDataResultSet;
26 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.util.ResultSetUtils;
27 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
28 import org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
29
30 import java.math.BigDecimal;
31 import java.net.URL;
32 import java.sql.Date;
33 import java.sql.ResultSet;
34 import java.sql.ResultSetMetaData;
35 import java.sql.SQLException;
36 import java.sql.Statement;
37 import java.sql.Time;
38 import java.sql.Timestamp;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.HashSet;
42 import java.util.Iterator;
43 import java.util.LinkedList;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Optional;
47
48
49
50
51 public final class DatabaseMetaDataResultSet extends AbstractUnsupportedDatabaseMetaDataResultSet {
52
53 private static final String TABLE_NAME = "TABLE_NAME";
54
55 private static final String INDEX_NAME = "INDEX_NAME";
56
57 private final int type;
58
59 private final int concurrency;
60
61 private final Collection<ShardingSphereRule> rules;
62
63 private final ResultSetMetaData resultSetMetaData;
64
65 private final Map<String, Integer> columnLabelIndexMap;
66
67 private final Iterator<DatabaseMetaDataObject> databaseMetaDataObjectIterator;
68
69 private final ResultSet resultSet;
70
71 private volatile boolean closed;
72
73 private DatabaseMetaDataObject currentDatabaseMetaDataObject;
74
75 public DatabaseMetaDataResultSet(final ResultSet resultSet, final Collection<ShardingSphereRule> rules) throws SQLException {
76 this.resultSet = resultSet;
77 this.rules = rules;
78 type = resultSet.getType();
79 concurrency = resultSet.getConcurrency();
80 resultSetMetaData = resultSet.getMetaData();
81 columnLabelIndexMap = initIndexMap();
82 databaseMetaDataObjectIterator = initIterator(resultSet);
83 }
84
85 private Map<String, Integer> initIndexMap() throws SQLException {
86 Map<String, Integer> result = new CaseInsensitiveMap<>();
87 for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
88 result.put(resultSetMetaData.getColumnLabel(i), i);
89 }
90 return result;
91 }
92
93 private Iterator<DatabaseMetaDataObject> initIterator(final ResultSet resultSet) throws SQLException {
94 Collection<DatabaseMetaDataObject> result = new LinkedList<>();
95 Collection<DatabaseMetaDataObject> removeDuplicationSet = new HashSet<>();
96 int tableNameColumnIndex = columnLabelIndexMap.getOrDefault(TABLE_NAME, -1);
97 int indexNameColumnIndex = columnLabelIndexMap.getOrDefault(INDEX_NAME, -1);
98 while (resultSet.next()) {
99 DatabaseMetaDataObject databaseMetaDataObject = generateDatabaseMetaDataObject(tableNameColumnIndex, indexNameColumnIndex, resultSet);
100 if (!removeDuplicationSet.contains(databaseMetaDataObject)) {
101 result.add(databaseMetaDataObject);
102 removeDuplicationSet.add(databaseMetaDataObject);
103 }
104 }
105 return result.iterator();
106 }
107
108 private DatabaseMetaDataObject generateDatabaseMetaDataObject(final int tableNameColumnIndex, final int indexNameColumnIndex, final ResultSet resultSet) throws SQLException {
109 DatabaseMetaDataObject result = new DatabaseMetaDataObject(resultSetMetaData.getColumnCount());
110 Optional<DataNodeRuleAttribute> ruleAttribute = findDataNodeRuleAttribute();
111 for (int i = 1; i <= columnLabelIndexMap.size(); i++) {
112 if (tableNameColumnIndex == i) {
113 String tableName = resultSet.getString(i);
114 Optional<String> logicTableName = ruleAttribute.isPresent() ? ruleAttribute.get().findLogicTableByActualTable(tableName) : Optional.empty();
115 result.addObject(logicTableName.orElse(tableName));
116 } else if (indexNameColumnIndex == i) {
117 String tableName = resultSet.getString(tableNameColumnIndex);
118 String indexName = resultSet.getString(i);
119 result.addObject(null != indexName && indexName.endsWith(tableName) ? indexName.substring(0, indexName.length() - tableName.length() - 1) : indexName);
120 } else {
121 result.addObject(resultSet.getObject(i));
122 }
123 }
124 return result;
125 }
126
127 private Optional<DataNodeRuleAttribute> findDataNodeRuleAttribute() {
128 for (ShardingSphereRule each : rules) {
129 Optional<DataNodeRuleAttribute> ruleAttribute = each.getAttributes().findAttribute(DataNodeRuleAttribute.class);
130 if (ruleAttribute.isPresent()) {
131 return ruleAttribute;
132 }
133 }
134 return Optional.empty();
135 }
136
137 @Override
138 public boolean next() throws SQLException {
139 checkClosed();
140 if (databaseMetaDataObjectIterator.hasNext()) {
141 currentDatabaseMetaDataObject = databaseMetaDataObjectIterator.next();
142 return true;
143 }
144 return false;
145 }
146
147 @Override
148 public void close() throws SQLException {
149 checkClosed();
150 closed = true;
151 }
152
153 @Override
154 public boolean wasNull() throws SQLException {
155 checkClosed();
156 return false;
157 }
158
159 @Override
160 public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException {
161 return getBigDecimal(columnIndex, true, scale);
162 }
163
164 @Override
165 public BigDecimal getBigDecimal(final String columnLabel, final int scale) throws SQLException {
166 return getBigDecimal(findColumn(columnLabel), scale);
167 }
168
169 @Override
170 public BigDecimal getBigDecimal(final int columnIndex) throws SQLException {
171 return getBigDecimal(columnIndex, false, 0);
172 }
173
174 private BigDecimal getBigDecimal(final int columnIndex, final boolean needScale, final int scale) throws SQLException {
175 checkClosed();
176 checkColumnIndex(columnIndex);
177 return (BigDecimal) ResultSetUtils.convertBigDecimalValue(currentDatabaseMetaDataObject.getObject(columnIndex), needScale, scale);
178 }
179
180 @Override
181 public BigDecimal getBigDecimal(final String columnLabel) throws SQLException {
182 return getBigDecimal(findColumn(columnLabel));
183 }
184
185 @Override
186 public Statement getStatement() throws SQLException {
187 return resultSet.getStatement();
188 }
189
190 @Override
191 public String getString(final int columnIndex) throws SQLException {
192 checkClosed();
193 checkColumnIndex(columnIndex);
194 return (String) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), String.class);
195 }
196
197 @Override
198 public String getString(final String columnLabel) throws SQLException {
199 return getString(findColumn(columnLabel));
200 }
201
202 @Override
203 public String getNString(final int columnIndex) throws SQLException {
204 return getString(columnIndex);
205 }
206
207 @Override
208 public String getNString(final String columnLabel) throws SQLException {
209 return getString(columnLabel);
210 }
211
212 @Override
213 public boolean getBoolean(final int columnIndex) throws SQLException {
214 checkClosed();
215 checkColumnIndex(columnIndex);
216 return (boolean) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), boolean.class);
217 }
218
219 @Override
220 public boolean getBoolean(final String columnLabel) throws SQLException {
221 return getBoolean(findColumn(columnLabel));
222 }
223
224 @Override
225 public byte getByte(final int columnIndex) throws SQLException {
226 checkClosed();
227 checkColumnIndex(columnIndex);
228 return (byte) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), byte.class);
229 }
230
231 @Override
232 public byte getByte(final String columnLabel) throws SQLException {
233 return getByte(findColumn(columnLabel));
234 }
235
236 @Override
237 public short getShort(final int columnIndex) throws SQLException {
238 checkClosed();
239 checkColumnIndex(columnIndex);
240 return (short) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), short.class);
241 }
242
243 @Override
244 public short getShort(final String columnLabel) throws SQLException {
245 return getShort(findColumn(columnLabel));
246 }
247
248 @Override
249 public int getInt(final int columnIndex) throws SQLException {
250 checkClosed();
251 checkColumnIndex(columnIndex);
252 return (int) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), int.class);
253 }
254
255 @Override
256 public int getInt(final String columnLabel) throws SQLException {
257 return getInt(findColumn(columnLabel));
258 }
259
260 @Override
261 public long getLong(final int columnIndex) throws SQLException {
262 checkClosed();
263 checkColumnIndex(columnIndex);
264 return (long) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), long.class);
265 }
266
267 @Override
268 public long getLong(final String columnLabel) throws SQLException {
269 return getLong(findColumn(columnLabel));
270 }
271
272 @Override
273 public float getFloat(final int columnIndex) throws SQLException {
274 checkClosed();
275 checkColumnIndex(columnIndex);
276 return (float) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), float.class);
277 }
278
279 @Override
280 public float getFloat(final String columnLabel) throws SQLException {
281 return getFloat(findColumn(columnLabel));
282 }
283
284 @Override
285 public double getDouble(final int columnIndex) throws SQLException {
286 checkClosed();
287 checkColumnIndex(columnIndex);
288 return (double) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), double.class);
289 }
290
291 @Override
292 public double getDouble(final String columnLabel) throws SQLException {
293 return getDouble(findColumn(columnLabel));
294 }
295
296 @Override
297 public byte[] getBytes(final int columnIndex) throws SQLException {
298 checkClosed();
299 checkColumnIndex(columnIndex);
300 return (byte[]) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), byte[].class);
301 }
302
303 @Override
304 public byte[] getBytes(final String columnLabel) throws SQLException {
305 return getBytes(findColumn(columnLabel));
306 }
307
308 @Override
309 public Date getDate(final int columnIndex) throws SQLException {
310 checkClosed();
311 checkColumnIndex(columnIndex);
312 return (Date) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), Date.class);
313 }
314
315 @Override
316 public Date getDate(final String columnLabel) throws SQLException {
317 return getDate(findColumn(columnLabel));
318 }
319
320 @Override
321 public Time getTime(final int columnIndex) throws SQLException {
322 checkClosed();
323 checkColumnIndex(columnIndex);
324 return (Time) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), Time.class);
325 }
326
327 @Override
328 public Time getTime(final String columnLabel) throws SQLException {
329 return getTime(findColumn(columnLabel));
330 }
331
332 @Override
333 public Timestamp getTimestamp(final int columnIndex) throws SQLException {
334 checkClosed();
335 checkColumnIndex(columnIndex);
336 return (Timestamp) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), Timestamp.class);
337 }
338
339 @Override
340 public Timestamp getTimestamp(final String columnLabel) throws SQLException {
341 return getTimestamp(findColumn(columnLabel));
342 }
343
344 @Override
345 public URL getURL(final int columnIndex) throws SQLException {
346 checkClosed();
347 checkColumnIndex(columnIndex);
348 return (URL) ResultSetUtils.convertValue(currentDatabaseMetaDataObject.getObject(columnIndex), URL.class);
349 }
350
351 @Override
352 public URL getURL(final String columnLabel) throws SQLException {
353 return getURL(findColumn(columnLabel));
354 }
355
356 @Override
357 public ResultSetMetaData getMetaData() throws SQLException {
358 checkClosed();
359 return resultSetMetaData;
360 }
361
362 @Override
363 public Object getObject(final int columnIndex) throws SQLException {
364 checkClosed();
365 checkColumnIndex(columnIndex);
366 return currentDatabaseMetaDataObject.getObject(columnIndex);
367 }
368
369 @Override
370 public Object getObject(final String columnLabel) throws SQLException {
371 return getObject(findColumn(columnLabel));
372 }
373
374 @Override
375 public int findColumn(final String columnLabel) throws SQLException {
376 checkClosed();
377 if (!columnLabelIndexMap.containsKey(columnLabel)) {
378 throw new ColumnLabelNotFoundException(columnLabel).toSQLException();
379 }
380 return columnLabelIndexMap.get(columnLabel);
381 }
382
383 @Override
384 public int getType() throws SQLException {
385 checkClosed();
386 return type;
387 }
388
389 @Override
390 public int getConcurrency() throws SQLException {
391 checkClosed();
392 return concurrency;
393 }
394
395 @Override
396 public void setFetchDirection(final int direction) throws SQLException {
397 resultSet.setFetchDirection(direction);
398 }
399
400 @Override
401 public int getFetchDirection() throws SQLException {
402 return resultSet.getFetchDirection();
403 }
404
405 @Override
406 public int getFetchSize() throws SQLException {
407 return resultSet.getFetchSize();
408 }
409
410 @Override
411 public void setFetchSize(final int rows) throws SQLException {
412 resultSet.setFetchSize(rows);
413 }
414
415 @Override
416 public boolean isClosed() {
417 return closed;
418 }
419
420 private void checkClosed() throws SQLException {
421 if (closed) {
422 throw new ResultSetClosedException().toSQLException();
423 }
424 }
425
426 private void checkColumnIndex(final int columnIndex) throws SQLException {
427 if (columnIndex < 1 || columnIndex > resultSetMetaData.getColumnCount()) {
428 throw new ColumnIndexOutOfRangeException(columnIndex).toSQLException();
429 }
430 }
431
432 @EqualsAndHashCode
433 private static final class DatabaseMetaDataObject {
434
435 private final List<Object> objects;
436
437 private DatabaseMetaDataObject(final int columnCount) {
438 objects = new ArrayList<>(columnCount);
439 }
440
441 public void addObject(final Object object) {
442 objects.add(object);
443 }
444
445 public Object getObject(final int index) {
446 return objects.get(index - 1);
447 }
448 }
449 }