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