View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.sqlfederation.resultset;
19  
20  import com.cedarsoftware.util.CaseInsensitiveMap;
21  import org.apache.calcite.linq4j.Enumerator;
22  import org.apache.calcite.rel.type.RelDataType;
23  import org.apache.calcite.schema.Schema;
24  import org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
25  import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
26  import org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader;
27  import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
28  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
29  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.util.ResultSetUtils;
30  import org.apache.shardingsphere.sqlfederation.resultset.converter.SQLFederationColumnTypeConverter;
31  
32  import java.io.InputStream;
33  import java.io.Reader;
34  import java.math.BigDecimal;
35  import java.net.URL;
36  import java.sql.Array;
37  import java.sql.Blob;
38  import java.sql.Clob;
39  import java.sql.Date;
40  import java.sql.ResultSetMetaData;
41  import java.sql.SQLException;
42  import java.sql.SQLFeatureNotSupportedException;
43  import java.sql.SQLWarning;
44  import java.sql.SQLXML;
45  import java.sql.Statement;
46  import java.sql.Time;
47  import java.sql.Timestamp;
48  import java.util.Arrays;
49  import java.util.Calendar;
50  import java.util.Collection;
51  import java.util.HashSet;
52  import java.util.List;
53  import java.util.Map;
54  
55  /**
56   * SQL federation result set.
57   */
58  public final class SQLFederationResultSet extends AbstractUnsupportedOperationResultSet {
59      
60      private static final String ASCII = "Ascii";
61      
62      private static final String UNICODE = "Unicode";
63      
64      private static final String BINARY = "Binary";
65      
66      private static final Collection<Class<?>> INVALID_FEDERATION_TYPES = new HashSet<>(Arrays.asList(Blob.class, Clob.class, Reader.class, InputStream.class, SQLXML.class));
67      
68      private final Enumerator<Object> enumerator;
69      
70      private final Map<String, Integer> columnLabelAndIndexes;
71      
72      private final SQLFederationResultSetMetaData resultSetMetaData;
73      
74      private final SQLFederationColumnTypeConverter columnTypeConverter;
75      
76      private Object[] currentRows;
77      
78      private boolean wasNull;
79      
80      private boolean closed;
81      
82      public SQLFederationResultSet(final Enumerator<Object> enumerator, final Schema sqlFederationSchema, final SelectStatementContext selectStatementContext, final RelDataType resultColumnType) {
83          this.enumerator = enumerator;
84          DatabaseType databaseType = selectStatementContext.getDatabaseType().getTrunkDatabaseType().orElse(selectStatementContext.getDatabaseType());
85          columnTypeConverter = DatabaseTypedSPILoader.getService(SQLFederationColumnTypeConverter.class, databaseType);
86          columnLabelAndIndexes = new CaseInsensitiveMap<>(selectStatementContext.getProjectionsContext().getExpandProjections().size(), 1F);
87          Map<Integer, String> indexAndColumnLabels = new CaseInsensitiveMap<>(selectStatementContext.getProjectionsContext().getExpandProjections().size(), 1F);
88          handleColumnLabelAndIndex(columnLabelAndIndexes, indexAndColumnLabels, selectStatementContext);
89          resultSetMetaData = new SQLFederationResultSetMetaData(sqlFederationSchema, selectStatementContext, resultColumnType, indexAndColumnLabels, columnTypeConverter);
90      }
91      
92      private void handleColumnLabelAndIndex(final Map<String, Integer> columnLabelAndIndexes, final Map<Integer, String> indexAndColumnLabels, final SelectStatementContext selectStatementContext) {
93          List<Projection> projections = selectStatementContext.getProjectionsContext().getExpandProjections();
94          for (int columnIndex = 1; columnIndex <= projections.size(); columnIndex++) {
95              Projection projection = projections.get(columnIndex - 1);
96              String columnLabel = projection.getColumnLabel();
97              columnLabelAndIndexes.put(columnLabel, columnIndex);
98              indexAndColumnLabels.put(columnIndex, columnLabel);
99          }
100     }
101     
102     @Override
103     public boolean next() {
104         boolean result = enumerator.moveNext();
105         if (result && null != enumerator.current()) {
106             currentRows = enumerator.current().getClass().isArray() ? (Object[]) enumerator.current() : new Object[]{enumerator.current()};
107         } else {
108             currentRows = new Object[]{};
109         }
110         return result;
111     }
112     
113     @Override
114     public void close() {
115         closed = true;
116         enumerator.close();
117         currentRows = null;
118     }
119     
120     @Override
121     public boolean wasNull() {
122         return wasNull;
123     }
124     
125     @Override
126     public String getString(final int columnIndex) throws SQLException {
127         return (String) ResultSetUtils.convertValue(getValue(columnIndex, String.class), String.class);
128     }
129     
130     @Override
131     public String getString(final String columnLabel) throws SQLException {
132         return getString(getIndexFromColumnLabelAndIndexMap(columnLabel));
133     }
134     
135     @Override
136     public boolean getBoolean(final int columnIndex) throws SQLException {
137         return (boolean) ResultSetUtils.convertValue(getValue(columnIndex, boolean.class), boolean.class);
138     }
139     
140     @Override
141     public boolean getBoolean(final String columnLabel) throws SQLException {
142         return getBoolean(getIndexFromColumnLabelAndIndexMap(columnLabel));
143     }
144     
145     @Override
146     public byte getByte(final int columnIndex) throws SQLException {
147         return (byte) ResultSetUtils.convertValue(getValue(columnIndex, byte.class), byte.class);
148     }
149     
150     @Override
151     public byte getByte(final String columnLabel) throws SQLException {
152         return getByte(getIndexFromColumnLabelAndIndexMap(columnLabel));
153     }
154     
155     @Override
156     public short getShort(final int columnIndex) throws SQLException {
157         return (short) ResultSetUtils.convertValue(getValue(columnIndex, short.class), short.class);
158     }
159     
160     @Override
161     public short getShort(final String columnLabel) throws SQLException {
162         return getShort(getIndexFromColumnLabelAndIndexMap(columnLabel));
163     }
164     
165     @Override
166     public int getInt(final int columnIndex) throws SQLException {
167         return (int) ResultSetUtils.convertValue(getValue(columnIndex, int.class), int.class);
168     }
169     
170     @Override
171     public int getInt(final String columnLabel) throws SQLException {
172         return getInt(getIndexFromColumnLabelAndIndexMap(columnLabel));
173     }
174     
175     @Override
176     public long getLong(final int columnIndex) throws SQLException {
177         return (long) ResultSetUtils.convertValue(getValue(columnIndex, long.class), long.class);
178     }
179     
180     @Override
181     public long getLong(final String columnLabel) throws SQLException {
182         return getLong(getIndexFromColumnLabelAndIndexMap(columnLabel));
183     }
184     
185     @Override
186     public float getFloat(final int columnIndex) throws SQLException {
187         return (float) ResultSetUtils.convertValue(getValue(columnIndex, float.class), float.class);
188     }
189     
190     @Override
191     public float getFloat(final String columnLabel) throws SQLException {
192         return getFloat(getIndexFromColumnLabelAndIndexMap(columnLabel));
193     }
194     
195     @Override
196     public double getDouble(final int columnIndex) throws SQLException {
197         return (double) ResultSetUtils.convertValue(getValue(columnIndex, double.class), double.class);
198     }
199     
200     @Override
201     public double getDouble(final String columnLabel) throws SQLException {
202         return getDouble(getIndexFromColumnLabelAndIndexMap(columnLabel));
203     }
204     
205     @Override
206     public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException {
207         return (BigDecimal) ResultSetUtils.convertValue(getValue(columnIndex, BigDecimal.class), BigDecimal.class);
208     }
209     
210     @Override
211     public BigDecimal getBigDecimal(final String columnLabel, final int scale) throws SQLException {
212         return getBigDecimal(getIndexFromColumnLabelAndIndexMap(columnLabel));
213     }
214     
215     @Override
216     public BigDecimal getBigDecimal(final int columnIndex) throws SQLException {
217         return (BigDecimal) ResultSetUtils.convertValue(getValue(columnIndex, BigDecimal.class), BigDecimal.class);
218     }
219     
220     @Override
221     public BigDecimal getBigDecimal(final String columnLabel) throws SQLException {
222         return getBigDecimal(getIndexFromColumnLabelAndIndexMap(columnLabel));
223     }
224     
225     @Override
226     public byte[] getBytes(final int columnIndex) throws SQLException {
227         return (byte[]) ResultSetUtils.convertValue(getValue(columnIndex, byte[].class), byte[].class);
228     }
229     
230     @Override
231     public byte[] getBytes(final String columnLabel) throws SQLException {
232         return getBytes(getIndexFromColumnLabelAndIndexMap(columnLabel));
233     }
234     
235     @Override
236     public Date getDate(final int columnIndex) throws SQLException {
237         return (Date) ResultSetUtils.convertValue(getValue(columnIndex, Date.class), Date.class);
238     }
239     
240     @Override
241     public Date getDate(final String columnLabel) throws SQLException {
242         return getDate(getIndexFromColumnLabelAndIndexMap(columnLabel));
243     }
244     
245     @Override
246     public Date getDate(final int columnIndex, final Calendar cal) throws SQLException {
247         return (Date) ResultSetUtils.convertValue(getCalendarValue(columnIndex), Date.class);
248     }
249     
250     @Override
251     public Date getDate(final String columnLabel, final Calendar cal) throws SQLException {
252         return getDate(getIndexFromColumnLabelAndIndexMap(columnLabel), cal);
253     }
254     
255     @Override
256     public Time getTime(final int columnIndex) throws SQLException {
257         return (Time) ResultSetUtils.convertValue(getValue(columnIndex, Time.class), Time.class);
258     }
259     
260     @Override
261     public Time getTime(final String columnLabel) throws SQLException {
262         return getTime(getIndexFromColumnLabelAndIndexMap(columnLabel));
263     }
264     
265     @Override
266     public Time getTime(final int columnIndex, final Calendar cal) throws SQLException {
267         return (Time) ResultSetUtils.convertValue(getCalendarValue(columnIndex), Time.class);
268     }
269     
270     @Override
271     public Time getTime(final String columnLabel, final Calendar cal) throws SQLException {
272         return getTime(getIndexFromColumnLabelAndIndexMap(columnLabel), cal);
273     }
274     
275     @Override
276     public Timestamp getTimestamp(final int columnIndex) throws SQLException {
277         return (Timestamp) ResultSetUtils.convertValue(getValue(columnIndex, Timestamp.class), Timestamp.class);
278     }
279     
280     @Override
281     public Timestamp getTimestamp(final String columnLabel) throws SQLException {
282         return getTimestamp(getIndexFromColumnLabelAndIndexMap(columnLabel));
283     }
284     
285     @Override
286     public Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException {
287         return (Timestamp) ResultSetUtils.convertValue(getCalendarValue(columnIndex), Timestamp.class);
288     }
289     
290     @Override
291     public Timestamp getTimestamp(final String columnLabel, final Calendar cal) throws SQLException {
292         return getTimestamp(getIndexFromColumnLabelAndIndexMap(columnLabel), cal);
293     }
294     
295     @Override
296     public InputStream getAsciiStream(final int columnIndex) throws SQLException {
297         return getInputStream(ASCII);
298     }
299     
300     @Override
301     public InputStream getAsciiStream(final String columnLabel) throws SQLException {
302         return getAsciiStream(getIndexFromColumnLabelAndIndexMap(columnLabel));
303     }
304     
305     @Override
306     public InputStream getUnicodeStream(final int columnIndex) throws SQLException {
307         return getInputStream(UNICODE);
308     }
309     
310     @Override
311     public InputStream getUnicodeStream(final String columnLabel) throws SQLException {
312         return getUnicodeStream(getIndexFromColumnLabelAndIndexMap(columnLabel));
313     }
314     
315     @Override
316     public InputStream getBinaryStream(final int columnIndex) throws SQLException {
317         return getInputStream(BINARY);
318     }
319     
320     @Override
321     public InputStream getBinaryStream(final String columnLabel) throws SQLException {
322         return getBinaryStream(getIndexFromColumnLabelAndIndexMap(columnLabel));
323     }
324     
325     @Override
326     public SQLWarning getWarnings() {
327         return null;
328     }
329     
330     @Override
331     public void clearWarnings() {
332     }
333     
334     @Override
335     public ResultSetMetaData getMetaData() {
336         return resultSetMetaData;
337     }
338     
339     @Override
340     public Object getObject(final int columnIndex) throws SQLException {
341         return getValue(columnIndex, Object.class);
342     }
343     
344     @Override
345     public Object getObject(final String columnLabel) throws SQLException {
346         return getObject(getIndexFromColumnLabelAndIndexMap(columnLabel));
347     }
348     
349     @Override
350     public int findColumn(final String columnLabel) throws SQLException {
351         return getIndexFromColumnLabelAndIndexMap(columnLabel);
352     }
353     
354     @Override
355     public Reader getCharacterStream(final int columnIndex) throws SQLException {
356         return (Reader) getValue(columnIndex, Reader.class);
357     }
358     
359     @Override
360     public Reader getCharacterStream(final String columnLabel) throws SQLException {
361         return getCharacterStream(getIndexFromColumnLabelAndIndexMap(columnLabel));
362     }
363     
364     @Override
365     public void setFetchDirection(final int direction) {
366     }
367     
368     @Override
369     public int getFetchDirection() {
370         return FETCH_FORWARD;
371     }
372     
373     @Override
374     public void setFetchSize(final int rows) {
375     }
376     
377     @Override
378     public int getFetchSize() {
379         return 0;
380     }
381     
382     @Override
383     public int getType() {
384         return TYPE_FORWARD_ONLY;
385     }
386     
387     @Override
388     public int getConcurrency() {
389         return CONCUR_READ_ONLY;
390     }
391     
392     @Override
393     public Statement getStatement() {
394         return null;
395     }
396     
397     @Override
398     public Blob getBlob(final int columnIndex) throws SQLException {
399         return (Blob) getValue(columnIndex, Blob.class);
400     }
401     
402     @Override
403     public Blob getBlob(final String columnLabel) throws SQLException {
404         return getBlob(getIndexFromColumnLabelAndIndexMap(columnLabel));
405     }
406     
407     @Override
408     public Clob getClob(final int columnIndex) throws SQLException {
409         return (Clob) getValue(columnIndex, Clob.class);
410     }
411     
412     @Override
413     public Clob getClob(final String columnLabel) throws SQLException {
414         return getClob(getIndexFromColumnLabelAndIndexMap(columnLabel));
415     }
416     
417     @Override
418     public Array getArray(final int columnIndex) throws SQLException {
419         return (Array) getValue(columnIndex, Array.class);
420     }
421     
422     @Override
423     public Array getArray(final String columnLabel) throws SQLException {
424         return getArray(getIndexFromColumnLabelAndIndexMap(columnLabel));
425     }
426     
427     @Override
428     public URL getURL(final int columnIndex) throws SQLException {
429         return (URL) getValue(columnIndex, URL.class);
430     }
431     
432     @Override
433     public URL getURL(final String columnLabel) throws SQLException {
434         return getURL(getIndexFromColumnLabelAndIndexMap(columnLabel));
435     }
436     
437     @Override
438     public boolean isClosed() {
439         return closed;
440     }
441     
442     @Override
443     public SQLXML getSQLXML(final int columnIndex) throws SQLException {
444         return (SQLXML) getValue(columnIndex, SQLXML.class);
445     }
446     
447     @Override
448     public SQLXML getSQLXML(final String columnLabel) throws SQLException {
449         return getSQLXML(getIndexFromColumnLabelAndIndexMap(columnLabel));
450     }
451     
452     @Override
453     public String getNString(final int columnIndex) throws SQLException {
454         return getString(columnIndex);
455     }
456     
457     @Override
458     public String getNString(final String columnLabel) throws SQLException {
459         return getString(columnLabel);
460     }
461     
462     private Integer getIndexFromColumnLabelAndIndexMap(final String columnLabel) throws SQLException {
463         Integer result = columnLabelAndIndexes.get(columnLabel);
464         ShardingSpherePreconditions.checkNotNull(result, () -> new SQLFeatureNotSupportedException(String.format("can not get index from column label `%s`", columnLabel)));
465         return result;
466     }
467     
468     private Object getValue(final int columnIndex, final Class<?> type) throws SQLException {
469         ShardingSpherePreconditions.checkNotContains(INVALID_FEDERATION_TYPES, type, () -> new SQLFeatureNotSupportedException(String.format("Get value from `%s`", type.getName())));
470         Object result = currentRows[columnIndex - 1];
471         wasNull = null == result;
472         return columnTypeConverter.convertColumnValue(result);
473     }
474     
475     private Object getCalendarValue(final int columnIndex) {
476         // TODO implement with calendar
477         Object result = currentRows[columnIndex - 1];
478         wasNull = null == result;
479         return result;
480     }
481     
482     private InputStream getInputStream(final String type) throws SQLException {
483         throw new SQLFeatureNotSupportedException(String.format("Get input stream from `%s`", type));
484     }
485 }