Skip to content

Commit 7730c88

Browse files
committed
IsBoundVisitor mixed bound/unbound predicate should error
1 parent f869003 commit 7730c88

File tree

2 files changed

+13
-11
lines changed

2 files changed

+13
-11
lines changed

src/iceberg/expression/binder.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ Result<bool> IsBoundVisitor::AlwaysFalse() { return true; }
9292
Result<bool> IsBoundVisitor::Not(bool child_result) { return child_result; }
9393

9494
Result<bool> IsBoundVisitor::And(bool left_result, bool right_result) {
95-
return left_result && right_result;
95+
ICEBERG_PRECHECK(left_result == right_result, "Found partially bound expression");
96+
return left_result;
9697
}
9798

9899
Result<bool> IsBoundVisitor::Or(bool left_result, bool right_result) {
99-
return left_result && right_result;
100+
ICEBERG_PRECHECK(left_result == right_result, "Found partially bound expression");
101+
return left_result;
100102
}
101103

102104
Result<bool> IsBoundVisitor::Predicate(const std::shared_ptr<BoundPredicate>& pred) {

src/iceberg/test/expression_visitor_test.cc

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,14 @@ TEST_F(IsBoundVisitorTest, AndWithBoundChildren) {
333333
}
334334

335335
TEST_F(IsBoundVisitorTest, AndWithUnboundChild) {
336-
// AND with any unbound child should return false
336+
// AND with mixed bound/unbound children should error
337337
auto bound_pred = Expressions::Equal("name", Literal::String("Alice"));
338338
ICEBERG_UNWRAP_OR_FAIL(auto pred1, Bind(bound_pred));
339339
auto pred2 = Expressions::Equal("age", Literal::Int(25)); // unbound
340340
auto mixed_and = Expressions::And(pred1, pred2);
341341

342-
ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(mixed_and));
343-
EXPECT_FALSE(is_bound);
342+
auto result = IsBoundVisitor::IsBound(mixed_and);
343+
EXPECT_THAT(result, HasErrorMessage("Found partially bound expression"));
344344
}
345345

346346
TEST_F(IsBoundVisitorTest, OrWithBoundChildren) {
@@ -355,14 +355,14 @@ TEST_F(IsBoundVisitorTest, OrWithBoundChildren) {
355355
}
356356

357357
TEST_F(IsBoundVisitorTest, OrWithUnboundChild) {
358-
// OR with any unbound child should return false
358+
// OR with mixed bound/unbound children should error
359359
auto pred1 = Expressions::IsNull("name"); // unbound
360360
auto bound_pred2 = Expressions::Equal("age", Literal::Int(25));
361361
ICEBERG_UNWRAP_OR_FAIL(auto pred2, Bind(bound_pred2));
362362
auto mixed_or = Expressions::Or(pred1, pred2);
363363

364-
ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(mixed_or));
365-
EXPECT_FALSE(is_bound);
364+
auto result = IsBoundVisitor::IsBound(mixed_or);
365+
EXPECT_THAT(result, HasErrorMessage("Found partially bound expression"));
366366
}
367367

368368
TEST_F(IsBoundVisitorTest, NotWithBoundChild) {
@@ -396,15 +396,15 @@ TEST_F(IsBoundVisitorTest, ComplexExpression) {
396396
ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(bound_complex));
397397
EXPECT_TRUE(is_bound);
398398

399-
// Complex expression: one unbound should return false
399+
// Complex expression: mixed bound/unbound children should error
400400
auto unbound_pred = Expressions::Equal("name", Literal::String("Alice"));
401401
ICEBERG_UNWRAP_OR_FAIL(auto bound_pred2, Bind(pred2));
402402
ICEBERG_UNWRAP_OR_FAIL(auto bound_pred3, Bind(pred3));
403403
auto mixed_and = Expressions::And(unbound_pred, bound_pred2);
404404
auto mixed_complex = Expressions::Or(mixed_and, bound_pred3);
405405

406-
ICEBERG_UNWRAP_OR_FAIL(auto is_bound_mixed, IsBoundVisitor::IsBound(mixed_complex));
407-
EXPECT_FALSE(is_bound_mixed);
406+
auto result_mixed = IsBoundVisitor::IsBound(mixed_complex);
407+
EXPECT_THAT(result_mixed, HasErrorMessage("Found partially bound expression"));
408408
}
409409

410410
class RewriteNotTest : public ExpressionVisitorTest {};

0 commit comments

Comments
 (0)