1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.sqlfederation.resultset;
19
20 import org.apache.calcite.avatica.SqlType;
21 import org.apache.calcite.rel.type.RelDataType;
22 import org.apache.calcite.rel.type.RelDataTypeFactory;
23 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl.JavaType;
24 import org.apache.calcite.schema.Schema;
25 import org.apache.calcite.schema.Table;
26 import org.apache.calcite.sql.type.SqlTypeName;
27 import org.apache.shardingsphere.database.connector.core.DefaultDatabase;
28 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
29 import org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
30 import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
31 import org.apache.shardingsphere.sqlfederation.compiler.sql.type.SQLFederationDataTypeFactory;
32 import org.apache.shardingsphere.sqlfederation.resultset.converter.DialectSQLFederationColumnTypeConverter;
33
34 import java.math.BigInteger;
35 import java.sql.ResultSetMetaData;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Optional;
39
40
41
42
43 public final class SQLFederationResultSetMetaData extends SQLFederationWrapperAdapter implements ResultSetMetaData {
44
45 private final Schema sqlFederationSchema;
46
47 private final RelDataTypeFactory typeFactory;
48
49 private final List<Projection> expandProjections;
50
51 private final DatabaseType databaseType;
52
53 private final RelDataType resultColumnType;
54
55 private final Map<Integer, String> indexAndColumnLabels;
56
57 private final DialectSQLFederationColumnTypeConverter columnTypeConverter;
58
59 public SQLFederationResultSetMetaData(final Schema sqlFederationSchema, final List<Projection> expandProjections, final DatabaseType databaseType, final RelDataType resultColumnType,
60 final Map<Integer, String> indexAndColumnLabels, final DialectSQLFederationColumnTypeConverter columnTypeConverter) {
61 this.sqlFederationSchema = sqlFederationSchema;
62 typeFactory = SQLFederationDataTypeFactory.getInstance();
63 this.expandProjections = expandProjections;
64 this.databaseType = databaseType;
65 this.resultColumnType = resultColumnType;
66 this.indexAndColumnLabels = indexAndColumnLabels;
67 this.columnTypeConverter = columnTypeConverter;
68 }
69
70 @Override
71 public int getColumnCount() {
72 return indexAndColumnLabels.size();
73 }
74
75 @Override
76 public boolean isAutoIncrement(final int column) {
77 return false;
78 }
79
80 @Override
81 public boolean isCaseSensitive(final int column) {
82 return false;
83 }
84
85 @Override
86 public boolean isSearchable(final int column) {
87 return false;
88 }
89
90 @Override
91 public boolean isCurrency(final int column) {
92 return false;
93 }
94
95 @Override
96 public int isNullable(final int column) {
97 Optional<Table> table = findTableName(column).flatMap(optional -> Optional.ofNullable(sqlFederationSchema.tables().get(optional)));
98 return !table.isPresent() || table.get().getRowType(typeFactory).isNullable() ? columnNullable : columnNoNulls;
99 }
100
101 @Override
102 public boolean isSigned(final int column) {
103 return true;
104 }
105
106 @Override
107 public int getColumnDisplaySize(final int column) {
108 return findTableName(column).flatMap(optional -> Optional.ofNullable(sqlFederationSchema.tables().get(optional))).map(optional -> optional.getRowType(typeFactory).getPrecision()).orElse(0);
109 }
110
111 @Override
112 public String getColumnLabel(final int column) {
113 return indexAndColumnLabels.size() < column ? resultColumnType.getFieldList().get(column - 1).getName() : indexAndColumnLabels.get(column);
114 }
115
116 @Override
117 public String getColumnName(final int column) {
118 return expandProjections.size() < column ? resultColumnType.getFieldList().get(column - 1).getName() : expandProjections.get(column - 1).getColumnName();
119 }
120
121 @Override
122 public String getSchemaName(final int column) {
123 return DefaultDatabase.LOGIC_NAME;
124 }
125
126 @Override
127 public int getPrecision(final int column) {
128 Optional<Table> table = findTableName(column).flatMap(optional -> Optional.ofNullable(sqlFederationSchema.tables().get(optional)));
129 return !table.isPresent() || RelDataType.PRECISION_NOT_SPECIFIED == table.get().getRowType(typeFactory).getPrecision() ? 0 : table.get().getRowType(typeFactory).getPrecision();
130 }
131
132 @Override
133 public int getScale(final int column) {
134 Optional<Table> table = findTableName(column).flatMap(optional -> Optional.ofNullable(sqlFederationSchema.tables().get(optional)));
135 return !table.isPresent() || RelDataType.SCALE_NOT_SPECIFIED == table.get().getRowType(typeFactory).getScale() ? 0 : table.get().getRowType(typeFactory).getScale();
136 }
137
138 @Override
139 public String getTableName(final int column) {
140 return findTableName(column).orElse("");
141 }
142
143 @Override
144 public String getCatalogName(final int column) {
145 return DefaultDatabase.LOGIC_NAME;
146 }
147
148 @Override
149 public int getColumnType(final int column) {
150 RelDataType relDataType = resultColumnType.getFieldList().get(column - 1).getType();
151
152 if (relDataType instanceof JavaType && BigInteger.class.isAssignableFrom(((JavaType) relDataType).getJavaClass())) {
153 return SqlType.BIGINT.id;
154 }
155 return null == columnTypeConverter ? relDataType.getSqlTypeName().getJdbcOrdinal() : columnTypeConverter.convertColumnType(relDataType.getSqlTypeName());
156 }
157
158 @Override
159 public String getColumnTypeName(final int column) {
160 SqlTypeName originalSqlTypeName = resultColumnType.getFieldList().get(column - 1).getType().getSqlTypeName();
161 SqlTypeName convertSqlTypeName = SqlTypeName.getNameForJdbcType(
162 null == columnTypeConverter ? originalSqlTypeName.getJdbcOrdinal() : columnTypeConverter.convertColumnType(originalSqlTypeName));
163 return null == convertSqlTypeName ? originalSqlTypeName.getName() : convertSqlTypeName.getName();
164 }
165
166 @Override
167 public boolean isReadOnly(final int column) {
168 return false;
169 }
170
171 @Override
172 public boolean isWritable(final int column) {
173 return false;
174 }
175
176 @Override
177 public boolean isDefinitelyWritable(final int column) {
178 return false;
179 }
180
181 @Override
182 public String getColumnClassName(final int column) {
183 return resultColumnType.getFieldList().get(column - 1).getType().getSqlTypeName().getClass().getName();
184 }
185
186 private Optional<String> findTableName(final int column) {
187 Projection projection = expandProjections.size() < column
188 ? new ColumnProjection(null, resultColumnType.getFieldList().get(column - 1).getName(), null, databaseType)
189 : expandProjections.get(column - 1);
190 return projection instanceof ColumnProjection ? Optional.ofNullable(((ColumnProjection) projection).getOriginalTable().getValue()) : Optional.empty();
191 }
192 }