Skip to content

Commit 212d279

Browse files
Fix potential NPE due to exception not having an underlying message (#3302)
This introduces a new exception at the Record Layer level: `UnableToPlanException`. That exception is translated at the Relational Layer level into the SQL error code `UNSUPPORTED_OPERATION`.
1 parent 16b5f27 commit 212d279

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/CascadesPlanner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ private RecordQueryPlan resultOrFail() {
381381
}
382382
return (RecordQueryPlan)singleRoot;
383383
} else {
384-
throw new RecordCoreException("Cascades planner could not plan query")
384+
throw new UnableToPlanException("Cascades planner could not plan query")
385385
.addLogInfo("finalExpression", currentRoot.get());
386386
}
387387
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* UnableToPlanException.java
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2025 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package com.apple.foundationdb.record.query.plan.cascades;
22+
23+
import com.apple.foundationdb.annotation.API;
24+
import com.apple.foundationdb.record.RecordCoreException;
25+
26+
import javax.annotation.Nonnull;
27+
import javax.annotation.Nullable;
28+
29+
/**
30+
* Error being thrown when Cascades cannot plan a query.
31+
*/
32+
@API(API.Status.EXPERIMENTAL)
33+
public class UnableToPlanException extends RecordCoreException {
34+
private static final long serialVersionUID = -640771754012134420L;
35+
36+
public UnableToPlanException(@Nonnull String msg, @Nullable Object ... keyValues) {
37+
super(msg, keyValues);
38+
}
39+
}

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/FDBNestedRepeatedQueryTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import com.apple.foundationdb.record.query.plan.cascades.GraphExpansion;
6161
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
6262
import com.apple.foundationdb.record.query.plan.cascades.Reference;
63+
import com.apple.foundationdb.record.query.plan.cascades.UnableToPlanException;
6364
import com.apple.foundationdb.record.query.plan.cascades.expressions.ExplodeExpression;
6465
import com.apple.foundationdb.record.query.plan.cascades.expressions.GroupByExpression;
6566
import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalSortExpression;
@@ -2005,7 +2006,7 @@ private Quantifier explodeEntryQun(@Nonnull Quantifier outerQun, @Nonnull String
20052006
}
20062007

20072008
private void assertFailsToPlan(@Nonnull Supplier<Reference> querySupplier, String... allowedIndexes) {
2008-
final RecordCoreException rce = assertThrows(RecordCoreException.class, () -> planGraph(querySupplier, allowedIndexes));
2009+
final RecordCoreException rce = assertThrows(UnableToPlanException.class, () -> planGraph(querySupplier, allowedIndexes));
20092010
assertThat(rce.getMessage(), containsString("Cascades planner could not plan query"));
20102011
}
20112012

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/query/GroupByTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
import com.apple.foundationdb.record.Bindings;
2424
import com.apple.foundationdb.record.EvaluationContext;
25-
import com.apple.foundationdb.record.RecordCoreException;
2625
import com.apple.foundationdb.record.RecordCursor;
2726
import com.apple.foundationdb.record.TestRecords1Proto;
2827
import com.apple.foundationdb.record.metadata.Index;
@@ -41,6 +40,7 @@
4140
import com.apple.foundationdb.record.query.plan.cascades.GraphExpansion;
4241
import com.apple.foundationdb.record.query.plan.cascades.Quantifier;
4342
import com.apple.foundationdb.record.query.plan.cascades.Reference;
43+
import com.apple.foundationdb.record.query.plan.cascades.UnableToPlanException;
4444
import com.apple.foundationdb.record.query.plan.cascades.expressions.FullUnorderedScanExpression;
4545
import com.apple.foundationdb.record.query.plan.cascades.expressions.GroupByExpression;
4646
import com.apple.foundationdb.record.query.plan.cascades.expressions.LogicalSortExpression;
@@ -129,7 +129,7 @@ public void testSimpleGroupBy() {
129129
public void attemptToPlanGroupByWithoutCompatiblySortedIndexFails() {
130130
setupHookAndAddData(false, false);
131131
final var cascadesPlanner = (CascadesPlanner)planner;
132-
Assertions.assertThrows(RecordCoreException.class, () -> cascadesPlanner.planGraph(
132+
Assertions.assertThrows(UnableToPlanException.class, () -> cascadesPlanner.planGraph(
133133
() -> constructGroupByPlan(false, false, GroupingKind.REGULAR_GROUPING),
134134
Optional.empty(),
135135
IndexQueryabilityFilter.TRUE,

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/util/ExceptionUtil.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.apple.foundationdb.record.provider.foundationdb.FDBExceptions;
2929
import com.apple.foundationdb.record.provider.foundationdb.RecordAlreadyExistsException;
3030
import com.apple.foundationdb.record.query.plan.cascades.SemanticException;
31+
import com.apple.foundationdb.record.query.plan.cascades.UnableToPlanException;
3132
import com.apple.foundationdb.relational.api.exceptions.ErrorCode;
3233
import com.apple.foundationdb.relational.api.exceptions.UncheckedRelationalException;
3334
import com.apple.foundationdb.relational.api.exceptions.RelationalException;
@@ -80,7 +81,7 @@ private static RelationalException recordCoreToRelationalException(RecordCoreExc
8081
} else {
8182
code = ErrorCode.INTERNAL_ERROR;
8283
}
83-
} else if (re.getMessage().contains("Cascades planner could not plan query")) {
84+
} else if (re instanceof UnableToPlanException) {
8485
code = ErrorCode.UNSUPPORTED_QUERY;
8586
}
8687

0 commit comments

Comments
 (0)