You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@arrow.apache.org by GitBox <gi...@apache.org> on 2022/05/11 20:23:29 UTC

[GitHub] [arrow] toddfarmer opened a new pull request, #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

toddfarmer opened a new pull request, #13123:
URL: https://github.com/apache/arrow/pull/13123

   The minimum required to support existing use cases of FakeResultSet has been implemented here - every other method throws a SQLException, and support can be added in the future as specific methods of MockResultSet are referenced.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] lidavidm closed pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
lidavidm closed pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets
URL: https://github.com/apache/arrow/pull/13123


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] toddfarmer commented on a diff in pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
toddfarmer commented on code in PR #13123:
URL: https://github.com/apache/arrow/pull/13123#discussion_r871875410


##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");
+      }
+      ArrayList<MockColumnMetaData> columns = new ArrayList<>();
+      for (int i = 0; i < firstRow.dataElements.size(); i++) {
+        MockDataElement element = firstRow.getDataElementAtIndex(i);
+        columns.add(MockColumnMetaData.fromDataElement(element, i));
+      }
+      return new MockResultSetMetaData(columns);
+    }
+
+    public static class MockColumnMetaData {
+      private int index;
+      private int sqlType;
+      private int precision;
+      private int scale;
+      private int nullable;
+
+      private MockColumnMetaData(int i, MockDataElement element) throws SQLException {
+        this.index = i;
+        this.sqlType = element.sqlType;
+        this.precision = element.getPrecision();
+        this.scale = element.getScale();
+        this.nullable = element.isNullable();
+      }
+
+      private String getLabel() {
+        return "col_" + index;
+      }
+
+      private String getName() {
+        return getLabel();
+      }
+
+      private int getType() {
+        return sqlType;
+      }
+
+      private int getPrecision() {
+        return precision;
+      }
+
+      private int getScale() {
+        return scale;
+      }
+
+      private int isNullable() {
+        return nullable;
+      }
+
+      static MockColumnMetaData fromDataElement(MockDataElement element, int i) throws SQLException {
+        return new MockColumnMetaData(i, element);
+      }
+
+    }
+
+  }
+
+  public static class MockRow {
+    private final ArrayList<MockDataElement> dataElements;
+
+    public MockRow(ArrayList<MockDataElement> elements) {
+      this.dataElements = elements;
+    }
+
+    public MockDataElement getDataElementAtIndex(int idx) throws SQLException {
+      if (idx > dataElements.size()) {
+        throw new SQLException("Unable to find data element at position: " + idx);
+      }
+      return dataElements.get(idx);
+    }
+  }
+
+  public static class MockDataElement {
+    private final Object value;
+    private final int sqlType;
+
+    public MockDataElement(String val) {
+      this(val, Types.VARCHAR);
+    }
+
+    public MockDataElement(Object val, int sqlType) {
+      this.value = val;
+      this.sqlType = sqlType;
+    }
+
+    private boolean isNull() {
+      return value == null;
+    }
+
+    private String getValueAsString() {
+      return value.toString();
+    }
+
+    private int getPrecision() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return getValueAsString().length();
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int getScale() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return 0;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int isNullable() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return ResultSetMetaData.columnNullable;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    public BigDecimal getBigDecimal() throws SQLException {
+      try {
+        return new BigDecimal(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public String getString() throws SQLException {
+      return getValueAsString();
+    }
+
+    public boolean getBoolean() throws SQLException {
+      try {
+        return Boolean.parseBoolean(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public int getInt() throws SQLException {
+      try {
+        return Integer.parseInt(getValueAsString());

Review Comment:
   That's an option, but the thinking behind my approach here was to enable easy type conversion.  By way of example, the following test succeeds with the current code, but will fail with object casting:
   
   ```java
     @Test
     public void testMockDataTypes() throws SQLException {
       ResultSetUtility.MockDataElement element = new ResultSetUtility.MockDataElement(1L, Types.NUMERIC);
       assertEquals(1L, element.getLong());
       assertEquals(1, element.getInt());
       assertEquals("1", element.getString());
     }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] lidavidm commented on a diff in pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
lidavidm commented on code in PR #13123:
URL: https://github.com/apache/arrow/pull/13123#discussion_r871746085


##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();

Review Comment:
   Given this is the definition of `isLast`, should this be `index > rows.size()`?



##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");
+      }
+      ArrayList<MockColumnMetaData> columns = new ArrayList<>();
+      for (int i = 0; i < firstRow.dataElements.size(); i++) {
+        MockDataElement element = firstRow.getDataElementAtIndex(i);
+        columns.add(MockColumnMetaData.fromDataElement(element, i));
+      }
+      return new MockResultSetMetaData(columns);
+    }
+
+    public static class MockColumnMetaData {
+      private int index;
+      private int sqlType;
+      private int precision;
+      private int scale;
+      private int nullable;
+
+      private MockColumnMetaData(int i, MockDataElement element) throws SQLException {
+        this.index = i;
+        this.sqlType = element.sqlType;
+        this.precision = element.getPrecision();
+        this.scale = element.getScale();
+        this.nullable = element.isNullable();
+      }
+
+      private String getLabel() {
+        return "col_" + index;
+      }
+
+      private String getName() {
+        return getLabel();
+      }
+
+      private int getType() {
+        return sqlType;
+      }
+
+      private int getPrecision() {
+        return precision;
+      }
+
+      private int getScale() {
+        return scale;
+      }
+
+      private int isNullable() {
+        return nullable;
+      }
+
+      static MockColumnMetaData fromDataElement(MockDataElement element, int i) throws SQLException {
+        return new MockColumnMetaData(i, element);
+      }
+
+    }
+
+  }
+
+  public static class MockRow {
+    private final ArrayList<MockDataElement> dataElements;
+
+    public MockRow(ArrayList<MockDataElement> elements) {
+      this.dataElements = elements;
+    }
+
+    public MockDataElement getDataElementAtIndex(int idx) throws SQLException {
+      if (idx > dataElements.size()) {
+        throw new SQLException("Unable to find data element at position: " + idx);
+      }
+      return dataElements.get(idx);
+    }
+  }
+
+  public static class MockDataElement {
+    private final Object value;
+    private final int sqlType;
+
+    public MockDataElement(String val) {
+      this(val, Types.VARCHAR);
+    }
+
+    public MockDataElement(Object val, int sqlType) {
+      this.value = val;
+      this.sqlType = sqlType;
+    }
+
+    private boolean isNull() {
+      return value == null;
+    }
+
+    private String getValueAsString() {
+      return value.toString();
+    }
+
+    private int getPrecision() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return getValueAsString().length();
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int getScale() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return 0;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");

Review Comment:
   ```suggestion
         throw getExceptionToThrow("Unable to determine scale for data type!");
   ```



##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");

Review Comment:
   Is it not valid to have a zero-column dataset?



##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");
+      }
+      ArrayList<MockColumnMetaData> columns = new ArrayList<>();
+      for (int i = 0; i < firstRow.dataElements.size(); i++) {
+        MockDataElement element = firstRow.getDataElementAtIndex(i);
+        columns.add(MockColumnMetaData.fromDataElement(element, i));
+      }
+      return new MockResultSetMetaData(columns);
+    }
+
+    public static class MockColumnMetaData {
+      private int index;
+      private int sqlType;
+      private int precision;
+      private int scale;
+      private int nullable;
+
+      private MockColumnMetaData(int i, MockDataElement element) throws SQLException {
+        this.index = i;
+        this.sqlType = element.sqlType;
+        this.precision = element.getPrecision();
+        this.scale = element.getScale();
+        this.nullable = element.isNullable();
+      }
+
+      private String getLabel() {
+        return "col_" + index;
+      }
+
+      private String getName() {
+        return getLabel();
+      }
+
+      private int getType() {
+        return sqlType;
+      }
+
+      private int getPrecision() {
+        return precision;
+      }
+
+      private int getScale() {
+        return scale;
+      }
+
+      private int isNullable() {
+        return nullable;
+      }
+
+      static MockColumnMetaData fromDataElement(MockDataElement element, int i) throws SQLException {
+        return new MockColumnMetaData(i, element);
+      }
+
+    }
+
+  }
+
+  public static class MockRow {
+    private final ArrayList<MockDataElement> dataElements;
+
+    public MockRow(ArrayList<MockDataElement> elements) {
+      this.dataElements = elements;
+    }
+
+    public MockDataElement getDataElementAtIndex(int idx) throws SQLException {
+      if (idx > dataElements.size()) {
+        throw new SQLException("Unable to find data element at position: " + idx);
+      }
+      return dataElements.get(idx);
+    }
+  }
+
+  public static class MockDataElement {
+    private final Object value;
+    private final int sqlType;
+
+    public MockDataElement(String val) {
+      this(val, Types.VARCHAR);
+    }
+
+    public MockDataElement(Object val, int sqlType) {
+      this.value = val;
+      this.sqlType = sqlType;
+    }
+
+    private boolean isNull() {
+      return value == null;
+    }
+
+    private String getValueAsString() {
+      return value.toString();
+    }
+
+    private int getPrecision() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return getValueAsString().length();
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int getScale() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return 0;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int isNullable() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return ResultSetMetaData.columnNullable;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");

Review Comment:
   Should this be `columnNullableUnknown`?



##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");
+      }
+      ArrayList<MockColumnMetaData> columns = new ArrayList<>();
+      for (int i = 0; i < firstRow.dataElements.size(); i++) {
+        MockDataElement element = firstRow.getDataElementAtIndex(i);
+        columns.add(MockColumnMetaData.fromDataElement(element, i));
+      }
+      return new MockResultSetMetaData(columns);
+    }
+
+    public static class MockColumnMetaData {
+      private int index;
+      private int sqlType;
+      private int precision;
+      private int scale;
+      private int nullable;
+
+      private MockColumnMetaData(int i, MockDataElement element) throws SQLException {
+        this.index = i;
+        this.sqlType = element.sqlType;
+        this.precision = element.getPrecision();
+        this.scale = element.getScale();
+        this.nullable = element.isNullable();
+      }
+
+      private String getLabel() {
+        return "col_" + index;
+      }
+
+      private String getName() {
+        return getLabel();
+      }
+
+      private int getType() {
+        return sqlType;
+      }
+
+      private int getPrecision() {
+        return precision;
+      }
+
+      private int getScale() {
+        return scale;
+      }
+
+      private int isNullable() {
+        return nullable;
+      }
+
+      static MockColumnMetaData fromDataElement(MockDataElement element, int i) throws SQLException {
+        return new MockColumnMetaData(i, element);
+      }
+
+    }
+
+  }
+
+  public static class MockRow {
+    private final ArrayList<MockDataElement> dataElements;
+
+    public MockRow(ArrayList<MockDataElement> elements) {
+      this.dataElements = elements;
+    }
+
+    public MockDataElement getDataElementAtIndex(int idx) throws SQLException {
+      if (idx > dataElements.size()) {
+        throw new SQLException("Unable to find data element at position: " + idx);
+      }
+      return dataElements.get(idx);
+    }
+  }
+
+  public static class MockDataElement {
+    private final Object value;
+    private final int sqlType;
+
+    public MockDataElement(String val) {
+      this(val, Types.VARCHAR);
+    }
+
+    public MockDataElement(Object val, int sqlType) {
+      this.value = val;
+      this.sqlType = sqlType;
+    }
+
+    private boolean isNull() {
+      return value == null;
+    }
+
+    private String getValueAsString() {
+      return value.toString();
+    }
+
+    private int getPrecision() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return getValueAsString().length();
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int getScale() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return 0;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int isNullable() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return ResultSetMetaData.columnNullable;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    public BigDecimal getBigDecimal() throws SQLException {
+      try {
+        return new BigDecimal(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public String getString() throws SQLException {
+      return getValueAsString();
+    }
+
+    public boolean getBoolean() throws SQLException {
+      try {
+        return Boolean.parseBoolean(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public int getInt() throws SQLException {
+      try {
+        return Integer.parseInt(getValueAsString());

Review Comment:
   Hmm, why don't we just cast the object we're holding?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] github-actions[bot] commented on pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
github-actions[bot] commented on PR #13123:
URL: https://github.com/apache/arrow/pull/13123#issuecomment-1124253413

   :warning: Ticket **has not been started in JIRA**, please click 'Start Progress'.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] toddfarmer commented on a diff in pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
toddfarmer commented on code in PR #13123:
URL: https://github.com/apache/arrow/pull/13123#discussion_r871869381


##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");

Review Comment:
   If it is, it's not possible to dynamically construct a MockResultSetMetaData from a zero-column data set.  I've added a comment to clarify.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] ursabot commented on pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
ursabot commented on PR #13123:
URL: https://github.com/apache/arrow/pull/13123#issuecomment-1126840807

   Benchmark runs are scheduled for baseline = d9346927a0cb79c53464c43c9f991907fca63f10 and contender = 745a5879ff4beaa897cf02afae37af52bf73f184. 745a5879ff4beaa897cf02afae37af52bf73f184 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
   Conbench compare runs links:
   [Finished :arrow_down:0.0% :arrow_up:0.0%] [ec2-t3-xlarge-us-east-2](https://conbench.ursa.dev/compare/runs/a1bbafdfd3ec4d149f9f4d1cfebaea06...0394330e35214fd68f9ecee60f8d7c28/)
   [Finished :arrow_down:0.27% :arrow_up:0.0%] [test-mac-arm](https://conbench.ursa.dev/compare/runs/d90d26403e1f424f94409593cf2fb235...a1fafe2b89d54cc8b837fa8b2d5a54c2/)
   [Failed :arrow_down:0.36% :arrow_up:0.0%] [ursa-i9-9960x](https://conbench.ursa.dev/compare/runs/f8db3985ea5d48a68b33ec4e5163a1d8...29bc19654a9c4448ac7e0ea2faa4a1e3/)
   [Finished :arrow_down:0.04% :arrow_up:0.04%] [ursa-thinkcentre-m75q](https://conbench.ursa.dev/compare/runs/8b8014c8858e47b4940e533e50d65a40...b9b9de1dee334ebe810aa840972db90c/)
   Buildkite builds:
   [Finished] [`745a5879` ec2-t3-xlarge-us-east-2](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ec2-t3-xlarge-us-east-2/builds/755)
   [Finished] [`745a5879` test-mac-arm](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-test-mac-arm/builds/752)
   [Failed] [`745a5879` ursa-i9-9960x](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ursa-i9-9960x/builds/742)
   [Finished] [`745a5879` ursa-thinkcentre-m75q](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ursa-thinkcentre-m75q/builds/757)
   [Finished] [`d9346927` ec2-t3-xlarge-us-east-2](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ec2-t3-xlarge-us-east-2/builds/754)
   [Finished] [`d9346927` test-mac-arm](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-test-mac-arm/builds/751)
   [Finished] [`d9346927` ursa-i9-9960x](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ursa-i9-9960x/builds/741)
   [Finished] [`d9346927` ursa-thinkcentre-m75q](https://buildkite.com/apache-arrow/arrow-bci-benchmark-on-ursa-thinkcentre-m75q/builds/756)
   Supported benchmarks:
   ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python, R. Runs only benchmarks with cloud = True
   test-mac-arm: Supported benchmark langs: C++, Python, R
   ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
   ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] github-actions[bot] commented on pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
github-actions[bot] commented on PR #13123:
URL: https://github.com/apache/arrow/pull/13123#issuecomment-1124253393

   https://issues.apache.org/jira/browse/ARROW-16538


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [arrow] lidavidm commented on a diff in pull request #13123: ARROW-16538: [Java] Adding flexibility to mock ResultSets

Posted by GitBox <gi...@apache.org>.
lidavidm commented on code in PR #13123:
URL: https://github.com/apache/arrow/pull/13123#discussion_r872333579


##########
java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/ResultSetUtility.java:
##########
@@ -0,0 +1,1617 @@
+/*
+ * 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.arrow.adapter.jdbc;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLType;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Map;
+
+public class ResultSetUtility {
+
+  public static ResultSet generateEmptyResultSet() throws SQLException {
+    MockDataElement element = new MockDataElement("string_example");
+    MockResultSetMetaData.MockColumnMetaData columnMetaData =
+            MockResultSetMetaData.MockColumnMetaData.fromDataElement(element, 1);
+    ArrayList<MockResultSetMetaData.MockColumnMetaData> cols = new ArrayList<>();
+    cols.add(columnMetaData);
+    ResultSetMetaData metadata = new MockResultSetMetaData(cols);
+    return MockResultSet.builder()
+            .setMetaData(metadata)
+            .build();
+  }
+
+  public static ResultSet generateBasicResultSet(int rows) throws SQLException {
+    MockResultSet.Builder builder = MockResultSet.builder();
+    for (int i = 0; i < rows; i++) {
+      builder.addDataElement("row number: " + (i + 1)).addDataElement("data").finishRow();
+    }
+    return builder.build();
+  }
+
+  public static class MockResultSet extends ThrowingResultSet {
+    private final ArrayList<MockRow> rows;
+    private int index = 0;
+    private boolean isClosed = false;
+    private ResultSetMetaData metadata;
+    private boolean wasNull;
+
+    public MockResultSet(ArrayList<MockRow> rows) throws SQLException {
+      this(rows, MockResultSetMetaData.fromRows(rows));
+    }
+
+    public MockResultSet(ArrayList<MockRow> rows, ResultSetMetaData metadata) {
+      this.rows = rows;
+      this.metadata = metadata;
+      this.wasNull = false;
+    }
+
+    public static Builder builder() {
+      return new Builder();
+    }
+
+    private void throwIfClosed() throws SQLException {
+      if (isClosed) {
+        throw new SQLException("ResultSet is already closed!");
+      }
+    }
+
+    private void setWasNull(MockDataElement element) {
+      wasNull = element.isNull();
+    }
+
+    @Override
+    public boolean next() throws SQLException {
+      index++;
+      return index <= rows.size();
+    }
+
+    @Override
+    public void close() throws SQLException {
+      throwIfClosed();
+      isClosed = true;
+    }
+
+    @Override
+    public boolean isBeforeFirst() throws SQLException {
+      throwIfClosed();
+      return index == 0;
+    }
+
+    @Override
+    public boolean isAfterLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public boolean isFirst() throws SQLException {
+      return index == 1;
+    }
+
+    @Override
+    public boolean isLast() throws SQLException {
+      return index == rows.size();
+    }
+
+    @Override
+    public void beforeFirst() throws SQLException {
+      index = 0;
+    }
+
+    @Override
+    public void afterLast() throws SQLException {
+      index = rows.size();
+    }
+
+    private MockRow getCurrentRow() throws SQLException {
+      throwIfClosed();
+      if (index <= rows.size()) {
+        return rows.get(index - 1);
+      }
+      throw new SQLException("Unable to fetch row at index: " + index);
+    }
+
+    private MockDataElement getDataElementAtCol(int idx) throws SQLException {
+      MockRow row = getCurrentRow();
+      MockDataElement element = row.getDataElementAtIndex(idx - 1);
+      setWasNull(element);
+      return element;
+    }
+
+    @Override
+    public String getString(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getString();
+    }
+
+    @Override
+    public boolean getBoolean(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBoolean();
+    }
+
+    @Override
+    public short getShort(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getShort();
+    }
+
+    @Override
+    public int getInt(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getInt();
+    }
+
+    @Override
+    public long getLong(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getLong();
+    }
+
+    @Override
+    public float getFloat(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getFloat();
+    }
+
+    @Override
+    public double getDouble(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDouble();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getBigDecimal();
+    }
+
+    @Override
+    public Date getDate(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getDate();
+    }
+
+    @Override
+    public Time getTime(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTime();
+    }
+
+    @Override
+    public Timestamp getTimestamp(int idx) throws SQLException {
+      return getDataElementAtCol(idx).getTimestamp();
+    }
+
+    @Override
+    public ResultSetMetaData getMetaData() throws SQLException {
+      return metadata;
+    }
+
+    @Override
+    public boolean wasNull() throws SQLException {
+      return wasNull;
+    }
+
+    public static class Builder {
+      private final ArrayList<MockRow> rows;
+      private ArrayList<MockDataElement> bufferedElements;
+      private ResultSetMetaData metadata;
+
+      Builder() {
+        this.rows = new ArrayList<>();
+        this.bufferedElements = new ArrayList<>();
+      }
+
+      public Builder finishRow() {
+        rows.add(new MockRow(this.bufferedElements));
+        this.bufferedElements = new ArrayList<>();
+        return this;
+      }
+
+      public Builder addDataElement(MockDataElement element) {
+        this.bufferedElements.add(element);
+        return this;
+      }
+
+      public Builder addDataElement(String str) {
+        return this.addDataElement(new MockDataElement(str));
+      }
+
+      public Builder addDataElement(Object val, int sqlType) {
+        return this.addDataElement(new MockDataElement(val, sqlType));
+      }
+
+      public Builder setMetaData(ResultSetMetaData metaData) {
+        this.metadata = metaData;
+        return this;
+      }
+
+      public MockResultSet build() throws SQLException {
+        if (this.metadata == null) {
+          return new MockResultSet(this.rows);
+        }
+        return new MockResultSet(this.rows, this.metadata);
+      }
+    }
+  }
+
+  public static class MockResultSetMetaData extends ThrowingResultSetMetaData {
+    private ArrayList<MockColumnMetaData> columns;
+
+    public MockResultSetMetaData(ArrayList<MockColumnMetaData> columns) {
+      this.columns = columns;
+    }
+
+    @Override
+    public int getColumnCount() throws SQLException {
+      return columns.size();
+    }
+
+    @Override
+    public String getColumnLabel(int column) throws SQLException {
+      return columns.get(column - 1).getLabel();
+    }
+
+    @Override
+    public String getColumnName(int column) throws SQLException {
+      return columns.get(column - 1).getName();
+    }
+
+    @Override
+    public int getColumnType(int column) throws SQLException {
+      return columns.get(column - 1).getType();
+    }
+
+    @Override
+    public int getPrecision(int column) throws SQLException {
+      return columns.get(column - 1).getPrecision();
+    }
+
+    @Override
+    public int getScale(int column) throws SQLException {
+      return columns.get(column - 1).getScale();
+    }
+
+    @Override
+    public int isNullable(int column) throws SQLException {
+      return columns.get(column - 1).isNullable();
+    }
+
+    public static MockResultSetMetaData fromRows(ArrayList<MockRow> rows) throws SQLException {
+
+      if (rows.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because row count is zero!");
+      }
+      MockRow firstRow = rows.get(0);
+      if (firstRow.dataElements.size() == 0) {
+        throw new SQLException("Unable to dynamically generate ResultSetMetaData because column count is zero!");
+      }
+      ArrayList<MockColumnMetaData> columns = new ArrayList<>();
+      for (int i = 0; i < firstRow.dataElements.size(); i++) {
+        MockDataElement element = firstRow.getDataElementAtIndex(i);
+        columns.add(MockColumnMetaData.fromDataElement(element, i));
+      }
+      return new MockResultSetMetaData(columns);
+    }
+
+    public static class MockColumnMetaData {
+      private int index;
+      private int sqlType;
+      private int precision;
+      private int scale;
+      private int nullable;
+
+      private MockColumnMetaData(int i, MockDataElement element) throws SQLException {
+        this.index = i;
+        this.sqlType = element.sqlType;
+        this.precision = element.getPrecision();
+        this.scale = element.getScale();
+        this.nullable = element.isNullable();
+      }
+
+      private String getLabel() {
+        return "col_" + index;
+      }
+
+      private String getName() {
+        return getLabel();
+      }
+
+      private int getType() {
+        return sqlType;
+      }
+
+      private int getPrecision() {
+        return precision;
+      }
+
+      private int getScale() {
+        return scale;
+      }
+
+      private int isNullable() {
+        return nullable;
+      }
+
+      static MockColumnMetaData fromDataElement(MockDataElement element, int i) throws SQLException {
+        return new MockColumnMetaData(i, element);
+      }
+
+    }
+
+  }
+
+  public static class MockRow {
+    private final ArrayList<MockDataElement> dataElements;
+
+    public MockRow(ArrayList<MockDataElement> elements) {
+      this.dataElements = elements;
+    }
+
+    public MockDataElement getDataElementAtIndex(int idx) throws SQLException {
+      if (idx > dataElements.size()) {
+        throw new SQLException("Unable to find data element at position: " + idx);
+      }
+      return dataElements.get(idx);
+    }
+  }
+
+  public static class MockDataElement {
+    private final Object value;
+    private final int sqlType;
+
+    public MockDataElement(String val) {
+      this(val, Types.VARCHAR);
+    }
+
+    public MockDataElement(Object val, int sqlType) {
+      this.value = val;
+      this.sqlType = sqlType;
+    }
+
+    private boolean isNull() {
+      return value == null;
+    }
+
+    private String getValueAsString() {
+      return value.toString();
+    }
+
+    private int getPrecision() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return getValueAsString().length();
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int getScale() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return 0;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    private int isNullable() throws SQLException {
+      if (this.sqlType == Types.VARCHAR) {
+        return ResultSetMetaData.columnNullable;
+      }
+      throw getExceptionToThrow("Unable to determine precision for data type!");
+    }
+
+    public BigDecimal getBigDecimal() throws SQLException {
+      try {
+        return new BigDecimal(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public String getString() throws SQLException {
+      return getValueAsString();
+    }
+
+    public boolean getBoolean() throws SQLException {
+      try {
+        return Boolean.parseBoolean(getValueAsString());
+      } catch (Exception ex) {
+        throw new SQLException(ex);
+      }
+    }
+
+    public int getInt() throws SQLException {
+      try {
+        return Integer.parseInt(getValueAsString());

Review Comment:
   Ah, ok, sounds good.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org