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