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/12 19:45:15 UTC

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

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