Skip to content

Commit

Permalink
GH-39355: [Java] Improve JdbcConsumer exceptions (#39356)
Browse files Browse the repository at this point in the history
### Rationale for this change

This helps debug Arrow conversion errors from JDBC by exposing the JdbcFieldInfo for the related column and the ArrowType for the corresponding vector.

### What changes are included in this PR?

A new JdbcConsumerException which is thrown by the CompositeJdbcConsumer while consuming data for a specific vector.

### Are these changes tested?

N/A

### Are there any user-facing changes?

Users can now catch `JdbcConsumerException`s and extract the related ArrowType and JdbcFieldInfo from it for debugging.

* Closes: #39355

Authored-by: Diego Fernandez <[email protected]>
Signed-off-by: David Li <[email protected]>
  • Loading branch information
aiguofer authored Jan 8, 2024
1 parent 6ce3c3f commit a71c941
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import org.apache.arrow.adapter.jdbc.consumer.CompositeJdbcConsumer;
import org.apache.arrow.adapter.jdbc.consumer.JdbcConsumer;
import org.apache.arrow.adapter.jdbc.consumer.exceptions.JdbcConsumerException;
import org.apache.arrow.util.AutoCloseables;
import org.apache.arrow.util.Preconditions;
import org.apache.arrow.vector.FieldVector;
Expand Down Expand Up @@ -114,7 +115,11 @@ private void consumeData(VectorSchemaRoot root) {
root.setRowCount(readRowCount);
} catch (Throwable e) {
compositeConsumer.close();
throw new RuntimeException("Error occurred while consuming data.", e);
if (e instanceof JdbcConsumerException) {
throw (JdbcConsumerException) e;
} else {
throw new RuntimeException("Error occurred while consuming data.", e);
}
}
}

Expand Down Expand Up @@ -168,6 +173,7 @@ public boolean hasNext() {
* Gets the next vector.
* If {@link JdbcToArrowConfig#isReuseVectorSchemaRoot()} is false,
* the client is responsible for freeing its resources.
* @throws JdbcConsumerException on error from VectorConsumer
*/
@Override
public VectorSchemaRoot next() {
Expand All @@ -178,7 +184,11 @@ public VectorSchemaRoot next() {
return ret;
} catch (Exception e) {
close();
throw new RuntimeException("Error occurred while getting next schema root.", e);
if (e instanceof JdbcConsumerException) {
throw (JdbcConsumerException) e;
} else {
throw new RuntimeException("Error occurred while getting next schema root.", e);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.apache.arrow.adapter.jdbc.consumer.TimestampTZConsumer;
import org.apache.arrow.adapter.jdbc.consumer.TinyIntConsumer;
import org.apache.arrow.adapter.jdbc.consumer.VarCharConsumer;
import org.apache.arrow.adapter.jdbc.consumer.exceptions.JdbcConsumerException;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.util.Preconditions;
import org.apache.arrow.vector.BigIntVector;
Expand Down Expand Up @@ -386,6 +387,7 @@ static boolean isColumnNullable(ResultSetMetaData resultSetMetadata, int index,
* @param root Arrow {@link VectorSchemaRoot} object to populate
* @param config The configuration to use when reading the data.
* @throws SQLException on error
* @throws JdbcConsumerException on error from VectorConsumer
*/
public static void jdbcToArrowVectors(ResultSet rs, VectorSchemaRoot root, JdbcToArrowConfig config)
throws SQLException, IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.arrow.adapter.jdbc.JdbcFieldInfo;
import org.apache.arrow.adapter.jdbc.consumer.exceptions.JdbcConsumerException;
import org.apache.arrow.util.AutoCloseables;
import org.apache.arrow.vector.ValueVector;
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.types.pojo.ArrowType;

/**
* Composite consumer which hold all consumers.
Expand All @@ -43,7 +46,18 @@ public CompositeJdbcConsumer(JdbcConsumer[] consumers) {
@Override
public void consume(ResultSet rs) throws SQLException, IOException {
for (int i = 0; i < consumers.length; i++) {
consumers[i].consume(rs);
try {
consumers[i].consume(rs);
} catch (Exception e) {
if (consumers[i] instanceof BaseConsumer) {
BaseConsumer consumer = (BaseConsumer) consumers[i];
JdbcFieldInfo fieldInfo = new JdbcFieldInfo(rs.getMetaData(), consumer.columnIndexInResultSet);
ArrowType arrowType = consumer.vector.getMinorType().getType();
throw new JdbcConsumerException("Exception while consuming JDBC value", e, fieldInfo, arrowType);
} else {
throw e;
}
}
}
}

Expand Down Expand Up @@ -74,3 +88,4 @@ public void resetVectorSchemaRoot(VectorSchemaRoot root) {
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.consumer.exceptions;

import org.apache.arrow.adapter.jdbc.JdbcFieldInfo;
import org.apache.arrow.vector.types.pojo.ArrowType;

/**
* Exception while consuming JDBC data. This exception stores the JdbcFieldInfo for the column and the
* ArrowType for the corresponding vector for easier debugging.
*/
public class JdbcConsumerException extends RuntimeException {
final JdbcFieldInfo fieldInfo;
final ArrowType arrowType;

/**
* Construct JdbcConsumerException with all fields.
*
* @param message error message
* @param cause original exception
* @param fieldInfo JdbcFieldInfo for the column
* @param arrowType ArrowType for the corresponding vector
*/
public JdbcConsumerException(String message, Throwable cause, JdbcFieldInfo fieldInfo, ArrowType arrowType) {
super(message, cause);
this.fieldInfo = fieldInfo;
this.arrowType = arrowType;
}

public ArrowType getArrowType() {
return this.arrowType;
}

public JdbcFieldInfo getFieldInfo() {
return this.fieldInfo;
}
}

0 comments on commit a71c941

Please sign in to comment.