Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/iceberg/expression/binder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "iceberg/expression/binder.h"

#include "iceberg/util/macros.h"

namespace iceberg {

Binder::Binder(const Schema& schema, bool case_sensitive)
Expand Down Expand Up @@ -89,11 +91,13 @@ Result<bool> IsBoundVisitor::AlwaysFalse() { return true; }
Result<bool> IsBoundVisitor::Not(bool child_result) { return child_result; }

Result<bool> IsBoundVisitor::And(bool left_result, bool right_result) {
return left_result && right_result;
ICEBERG_PRECHECK(left_result == right_result, "Found partially bound expression");
return left_result;
}

Result<bool> IsBoundVisitor::Or(bool left_result, bool right_result) {
return left_result && right_result;
ICEBERG_PRECHECK(left_result == right_result, "Found partially bound expression");
return left_result;
}

Result<bool> IsBoundVisitor::Predicate(const std::shared_ptr<BoundPredicate>& pred) {
Expand Down
18 changes: 9 additions & 9 deletions src/iceberg/test/expression_visitor_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -332,14 +332,14 @@ TEST_F(IsBoundVisitorTest, AndWithBoundChildren) {
}

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

ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(mixed_and));
EXPECT_FALSE(is_bound);
auto result = IsBoundVisitor::IsBound(mixed_and);
EXPECT_THAT(result, HasErrorMessage("Found partially bound expression"));
}

TEST_F(IsBoundVisitorTest, OrWithBoundChildren) {
Expand All @@ -354,14 +354,14 @@ TEST_F(IsBoundVisitorTest, OrWithBoundChildren) {
}

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

ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(mixed_or));
EXPECT_FALSE(is_bound);
auto result = IsBoundVisitor::IsBound(mixed_or);
EXPECT_THAT(result, HasErrorMessage("Found partially bound expression"));
}

TEST_F(IsBoundVisitorTest, NotWithBoundChild) {
Expand Down Expand Up @@ -395,15 +395,15 @@ TEST_F(IsBoundVisitorTest, ComplexExpression) {
ICEBERG_UNWRAP_OR_FAIL(auto is_bound, IsBoundVisitor::IsBound(bound_complex));
EXPECT_TRUE(is_bound);

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

ICEBERG_UNWRAP_OR_FAIL(auto is_bound_mixed, IsBoundVisitor::IsBound(mixed_complex));
EXPECT_FALSE(is_bound_mixed);
auto result_mixed = IsBoundVisitor::IsBound(mixed_complex);
EXPECT_THAT(result_mixed, HasErrorMessage("Found partially bound expression"));
}

class RewriteNotTest : public ExpressionVisitorTest {};
Expand Down
Loading