Skip to content

Commit 23fbf10

Browse files
authored
feat: typed DataFusionException hierarchy across the JNI boundary (#81)
1 parent d4f53df commit 23fbf10

11 files changed

Lines changed: 744 additions & 6 deletions
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* Invalid or unrecognised DataFusion configuration option. Surfaces upstream {@code
24+
* DataFusionError::Configuration}.
25+
*/
26+
public class ConfigurationException extends DataFusionException {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
public ConfigurationException(String message) {
31+
super(message);
32+
}
33+
34+
public ConfigurationException(String message, Throwable cause) {
35+
super(message, cause);
36+
}
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* Base unchecked exception for every error surfaced from the native DataFusion side.
24+
*
25+
* <p>Concrete subclasses correspond to caller-relevant error categories (planning, execution, IO,
26+
* resources, configuration, not-implemented). Variants of {@code DataFusionError} on the Rust side
27+
* that don't fit a clean caller-facing category surface as the parent class itself.
28+
*
29+
* <p>All subclasses extend {@link RuntimeException} so existing callers that {@code catch
30+
* (RuntimeException)} keep working unchanged. Callers that want to discriminate can {@code catch
31+
* (PlanException)} / {@code catch (ResourcesExhaustedException)} etc., or {@code catch
32+
* (DataFusionException)} for "anything from DataFusion".
33+
*/
34+
public class DataFusionException extends RuntimeException {
35+
36+
private static final long serialVersionUID = 1L;
37+
38+
public DataFusionException(String message) {
39+
super(message);
40+
}
41+
42+
public DataFusionException(String message, Throwable cause) {
43+
super(message, cause);
44+
}
45+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* Runtime execution failure: a UDF threw, a join task panicked, an external (non-DataFusion) error
24+
* propagated up, or an FFI-level failure surfaced. Surfaces upstream {@code
25+
* DataFusionError::Execution}, {@code ExecutionJoin}, {@code External}, and {@code Ffi}.
26+
*
27+
* <p>Note: this is {@code org.apache.datafusion.ExecutionException}, distinct from {@code
28+
* java.util.concurrent.ExecutionException}. A file that needs both should fully-qualify one or
29+
* import them with care.
30+
*/
31+
public class ExecutionException extends DataFusionException {
32+
33+
private static final long serialVersionUID = 1L;
34+
35+
public ExecutionException(String message) {
36+
super(message);
37+
}
38+
39+
public ExecutionException(String message, Throwable cause) {
40+
super(message, cause);
41+
}
42+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* IO-shaped failure: a local filesystem read failed, an object store request failed, or a parquet /
24+
* arrow / avro decoder reported a malformed file. Surfaces upstream {@code
25+
* DataFusionError::IoError}, {@code ObjectStore}, {@code ArrowError}, {@code ParquetError}, and
26+
* {@code AvroError}.
27+
*
28+
* <p>Note: this is {@code org.apache.datafusion.IoException} (lowercase {@code o}), distinct from
29+
* {@code java.io.IOException}. The {@code IoException} spelling matches the orthography of the
30+
* underlying {@code DataFusionError::IoError} variant; a file that needs both should fully-qualify
31+
* one.
32+
*/
33+
public class IoException extends DataFusionException {
34+
35+
private static final long serialVersionUID = 1L;
36+
37+
public IoException(String message) {
38+
super(message);
39+
}
40+
41+
public IoException(String message, Throwable cause) {
42+
super(message, cause);
43+
}
44+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* The requested feature is recognised by DataFusion but not implemented yet. Surfaces upstream
24+
* {@code DataFusionError::NotImplemented}.
25+
*/
26+
public class NotImplementedException extends DataFusionException {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
public NotImplementedException(String message) {
31+
super(message);
32+
}
33+
34+
public NotImplementedException(String message, Throwable cause) {
35+
super(message, cause);
36+
}
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* SQL parsing, logical planning, or schema-resolution failure. Surfaces upstream {@code
24+
* DataFusionError::Plan}, {@code DataFusionError::SQL}, and {@code DataFusionError::SchemaError}.
25+
*/
26+
public class PlanException extends DataFusionException {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
public PlanException(String message) {
31+
super(message);
32+
}
33+
34+
public PlanException(String message, Throwable cause) {
35+
super(message, cause);
36+
}
37+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
/**
23+
* The DataFusion runtime exhausted a configured resource budget — typically the memory pool, but
24+
* applies to any guard upstream surfaces as {@code DataFusionError::ResourcesExhausted}.
25+
*
26+
* <p>Distinguishing this from {@link ExecutionException} lets callers retry transient
27+
* resource-pressure failures without retrying genuine query bugs.
28+
*/
29+
public class ResourcesExhaustedException extends DataFusionException {
30+
31+
private static final long serialVersionUID = 1L;
32+
33+
public ResourcesExhaustedException(String message) {
34+
super(message);
35+
}
36+
37+
public ResourcesExhaustedException(String message, Throwable cause) {
38+
super(message, cause);
39+
}
40+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.datafusion;
21+
22+
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
24+
import static org.junit.jupiter.api.Assertions.assertSame;
25+
26+
import org.junit.jupiter.api.Test;
27+
28+
class DataFusionExceptionTest {
29+
30+
@Test
31+
void parentExtendsRuntimeException() {
32+
DataFusionException e = new DataFusionException("x");
33+
assertInstanceOf(RuntimeException.class, e);
34+
assertEquals("x", e.getMessage());
35+
}
36+
37+
@Test
38+
void parentCauseConstructorPropagatesCause() {
39+
Throwable cause = new IllegalStateException("inner");
40+
DataFusionException e = new DataFusionException("outer", cause);
41+
assertEquals("outer", e.getMessage());
42+
assertSame(cause, e.getCause());
43+
}
44+
45+
@Test
46+
void allSubclassesExtendDataFusionException() {
47+
// Each subclass must extend the parent so callers can `catch
48+
// (DataFusionException)` for "anything from DataFusion" and `catch
49+
// (RuntimeException)` keeps working unchanged.
50+
assertInstanceOf(DataFusionException.class, new PlanException("x"));
51+
assertInstanceOf(DataFusionException.class, new ExecutionException("x"));
52+
assertInstanceOf(DataFusionException.class, new ResourcesExhaustedException("x"));
53+
assertInstanceOf(DataFusionException.class, new IoException("x"));
54+
assertInstanceOf(DataFusionException.class, new NotImplementedException("x"));
55+
assertInstanceOf(DataFusionException.class, new ConfigurationException("x"));
56+
}
57+
58+
@Test
59+
void allSubclassesExtendRuntimeException() {
60+
// Existing callers use `catch (RuntimeException)`. A typed-exception PR
61+
// that breaks them is a regression even if the new types are correct.
62+
assertInstanceOf(RuntimeException.class, new PlanException("x"));
63+
assertInstanceOf(RuntimeException.class, new ExecutionException("x"));
64+
assertInstanceOf(RuntimeException.class, new ResourcesExhaustedException("x"));
65+
assertInstanceOf(RuntimeException.class, new IoException("x"));
66+
assertInstanceOf(RuntimeException.class, new NotImplementedException("x"));
67+
assertInstanceOf(RuntimeException.class, new ConfigurationException("x"));
68+
}
69+
70+
@Test
71+
void allSubclassesAcceptCauseConstructor() {
72+
// The (String, Throwable) constructor is the seam upstream issue #55
73+
// plugs into for Java-throwable propagation from JVM upcalls. v1 has no
74+
// production caller for it, but it must exist on every subclass so #55
75+
// doesn't have to add it later.
76+
Throwable cause = new IllegalStateException("c");
77+
assertSame(cause, new PlanException("m", cause).getCause());
78+
assertSame(cause, new ExecutionException("m", cause).getCause());
79+
assertSame(cause, new ResourcesExhaustedException("m", cause).getCause());
80+
assertSame(cause, new IoException("m", cause).getCause());
81+
assertSame(cause, new NotImplementedException("m", cause).getCause());
82+
assertSame(cause, new ConfigurationException("m", cause).getCause());
83+
}
84+
}

0 commit comments

Comments
 (0)