| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.calcite.avatica.util; |
| |
| import org.apache.calcite.avatica.AvaticaParameter; |
| import org.apache.calcite.avatica.AvaticaResultSet; |
| import org.apache.calcite.avatica.AvaticaResultSetMetaData; |
| import org.apache.calcite.avatica.ColumnMetaData; |
| import org.apache.calcite.avatica.ColumnMetaData.ArrayType; |
| import org.apache.calcite.avatica.ColumnMetaData.AvaticaType; |
| import org.apache.calcite.avatica.ColumnMetaData.Rep; |
| import org.apache.calcite.avatica.ColumnMetaData.ScalarType; |
| import org.apache.calcite.avatica.Meta; |
| import org.apache.calcite.avatica.QueryState; |
| import org.apache.calcite.avatica.util.AbstractCursor.ArrayAccessor; |
| import org.apache.calcite.avatica.util.Cursor.Accessor; |
| |
| import java.sql.Array; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Types; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.TimeZone; |
| |
| /** |
| * Implementation of {@link ArrayImpl.Factory}. |
| */ |
| public class ArrayFactoryImpl implements ArrayImpl.Factory { |
| private TimeZone timeZone; |
| |
| public ArrayFactoryImpl(TimeZone timeZone) { |
| this.timeZone = Objects.requireNonNull(timeZone); |
| } |
| |
| @Override public ResultSet create(AvaticaType elementType, Iterable<Object> elements) |
| throws SQLException { |
| // The ColumnMetaData for offset "1" in the ResultSet for an Array. |
| ScalarType arrayOffsetType = ColumnMetaData.scalar(Types.INTEGER, "INTEGER", Rep.PRIMITIVE_INT); |
| // Two columns (types) in the ResultSet we will create |
| List<ColumnMetaData> types = Arrays.asList(ColumnMetaData.dummy(arrayOffsetType, false), |
| ColumnMetaData.dummy(elementType, true)); |
| List<List<Object>> rows = createResultSetRowsForArrayData(elements); |
| // `(List<Object>) rows` is a compile error. |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| List<Object> untypedRows = (List<Object>) ((List) rows); |
| try (ListIteratorCursor cursor = new ListIteratorCursor(rows.iterator())) { |
| final String sql = "MOCKED"; |
| QueryState state = new QueryState(sql); |
| Meta.Signature signature = new Meta.Signature(types, sql, |
| Collections.<AvaticaParameter>emptyList(), Collections.<String, Object>emptyMap(), |
| Meta.CursorFactory.LIST, Meta.StatementType.SELECT); |
| AvaticaResultSetMetaData resultSetMetaData = new AvaticaResultSetMetaData(null, sql, |
| signature); |
| Meta.Frame frame = new Meta.Frame(0, true, untypedRows); |
| AvaticaResultSet resultSet = new AvaticaResultSet(null, state, signature, resultSetMetaData, |
| timeZone, frame); |
| resultSet.execute2(cursor, types); |
| return resultSet; |
| } |
| } |
| |
| @Override public Array createArray(AvaticaType elementType, Iterable<Object> elements) { |
| final ArrayType array = ColumnMetaData.array(elementType, elementType.name, Rep.ARRAY); |
| final List<ColumnMetaData> types = Collections.singletonList(ColumnMetaData.dummy(array, true)); |
| // Avoid creating a new List if we already have a List |
| List<Object> elementList; |
| if (elements instanceof List) { |
| elementList = (List<Object>) elements; |
| } else { |
| elementList = new ArrayList<>(); |
| for (Object element : elements) { |
| elementList.add(element); |
| } |
| } |
| try (ListIteratorCursor cursor = new ListIteratorCursor(createRowForArrayData(elementList))) { |
| List<Accessor> accessor = cursor.createAccessors(types, Unsafe.localCalendar(), this); |
| assert 1 == accessor.size(); |
| return new ArrayImpl(elementList, (ArrayAccessor) accessor.get(0)); |
| } |
| } |
| |
| /** |
| * Creates the row-level view over the values that will make up an Array. The Iterator has a row |
| * per Array element, each row containing two columns. The second column is the array element and |
| * the first column is the offset into the array of that array element (one-based, not |
| * zero-based). |
| * |
| * <p>The ordering of the rows is not guaranteed to be in the same order as the array elements. |
| * |
| * <p>A list of {@code elements}: |
| * <pre>[1, 2, 3]</pre> |
| * <p>might be converted into |
| * <pre>Iterator{ [1, 1], [2, 2], [3, 3] }</pre> |
| * |
| * @param elements The elements of an array. |
| */ |
| private List<List<Object>> createResultSetRowsForArrayData(Iterable<Object> elements) { |
| List<List<Object>> rows = new ArrayList<>(); |
| int i = 0; |
| for (Object element : elements) { |
| rows.add(Arrays.asList(i + 1, element)); |
| i++; |
| } |
| return rows; |
| } |
| |
| /** |
| * Creates an row-level view over the values that will make up an Array. The Iterator has one |
| * entry which has a list that also has one entry. |
| * |
| * <p>A provided list of {@code elements} |
| * <pre>[1, 2, 3]</pre> |
| * <p>would be converted into |
| * <pre>Iterator{ [ [1,2,3] ] }</pre> |
| * |
| * @param elements The elements of an array |
| */ |
| private Iterator<List<Object>> createRowForArrayData(List<Object> elements) { |
| // Make a "row" with one "column" (which is really a list) |
| final List<Object> row = Collections.singletonList((Object) elements); |
| // Make an iterator over this one "row" |
| return Collections.singletonList(row).iterator(); |
| } |
| } |
| |
| // End ArrayFactoryImpl.java |