1919
2020#include " iceberg/expression/residual_evaluator.h"
2121
22- #include " iceberg/expression/binder.h"
2322#include " iceberg/expression/expression.h"
2423#include " iceberg/expression/expression_visitor.h"
2524#include " iceberg/expression/predicate.h"
@@ -187,19 +186,19 @@ class ResidualVisitor : public BoundVisitor<std::shared_ptr<Expression>> {
187186
188187 Result<std::shared_ptr<Expression>> Predicate (
189188 const std::shared_ptr<UnboundPredicate>& pred) override {
190- ICEBERG_ASSIGN_OR_RAISE (auto bound_predicate , pred->Bind (schema_, case_sensitive_));
191- if (bound_predicate ->is_bound_predicate ()) {
189+ ICEBERG_ASSIGN_OR_RAISE (auto bound , pred->Bind (schema_, case_sensitive_));
190+ if (bound ->is_bound_predicate ()) {
192191 ICEBERG_ASSIGN_OR_RAISE (
193192 auto residual,
194- Predicate (std::dynamic_pointer_cast <BoundPredicate>(bound_predicate )));
193+ Predicate (internal::checked_pointer_cast <BoundPredicate>(bound )));
195194 if (residual->is_bound_predicate ()) {
196195 // replace inclusive original unbound predicate
197196 return pred;
198197 }
199198 return residual;
200199 }
201200 // if binding didn't result in a Predicate, return the expression
202- return bound_predicate ;
201+ return bound ;
203202 }
204203
205204 private:
@@ -218,7 +217,6 @@ class ResidualVisitor : public BoundVisitor<std::shared_ptr<Expression>> {
218217 const StructLike& partition_data_;
219218 bool case_sensitive_;
220219};
221- } // namespace
222220
223221Result<std::shared_ptr<Expression>> ResidualVisitor::Predicate (
224222 const std::shared_ptr<BoundPredicate>& pred) {
@@ -230,37 +228,30 @@ Result<std::shared_ptr<Expression>> ResidualVisitor::Predicate(
230228 // have returned false, so the predicate can also be eliminated if the inclusive
231229 // projection evaluates to false.
232230
233- // Get the field ID from the predicate's reference
234- const auto & ref = pred->reference ();
235- int32_t field_id = ref->field ().field_id ();
236-
237- // Find partition fields that match this source field ID
238- auto matching_fields = spec_.GetFieldsBySourceId (field_id);
239-
240- if (!matching_fields.has_value ()) {
231+ // If there is no strict projection or if it evaluates to false, then return the
232+ // predicate.
233+ ICEBERG_ASSIGN_OR_RAISE (
234+ auto parts, spec_.GetFieldsBySourceId (pred->reference ()->field ().field_id ()));
235+ if (parts.empty ()) {
241236 // Not associated with a partition field, can't be evaluated
242237 return pred;
243238 }
244239
245- for (const auto & part : matching_fields. value () ) {
240+ for (const auto & part : parts ) {
246241 // Check the strict projection
247242 ICEBERG_ASSIGN_OR_RAISE (auto strict_projection, part.get ().transform ()->ProjectStrict (
248243 part.get ().name (), pred));
249244 std::shared_ptr<Expression> strict_result = nullptr ;
250245
251246 if (strict_projection != nullptr ) {
252- // Bind the projected predicate to partition type
253247 ICEBERG_ASSIGN_OR_RAISE (
254248 auto bound_strict,
255- Binder::Bind (*partition_schema_,
256- std::shared_ptr<Expression>(std::move (strict_projection)),
257- case_sensitive_));
258-
249+ strict_projection->Bind (*partition_schema_, case_sensitive_));
259250 if (bound_strict->is_bound_predicate ()) {
260- // Evaluate the bound predicate against partition data
261251 ICEBERG_ASSIGN_OR_RAISE (
262- strict_result, BoundVisitor::Predicate (
263- std::dynamic_pointer_cast<BoundPredicate>(bound_strict)));
252+ strict_result,
253+ BoundVisitor::Predicate (
254+ internal::checked_pointer_cast<BoundPredicate>(bound_strict)));
264255 } else {
265256 // If the result is not a predicate, then it must be a constant like alwaysTrue
266257 // or alwaysFalse
@@ -279,19 +270,15 @@ Result<std::shared_ptr<Expression>> ResidualVisitor::Predicate(
279270 std::shared_ptr<Expression> inclusive_result = nullptr ;
280271
281272 if (inclusive_projection != nullptr ) {
282- // Bind the projected predicate to partition type
283273 ICEBERG_ASSIGN_OR_RAISE (
284274 auto bound_inclusive,
285- Binder::Bind (*partition_schema_,
286- std::shared_ptr<Expression>(std::move (inclusive_projection)),
287- case_sensitive_));
275+ inclusive_projection->Bind (*partition_schema_, case_sensitive_));
288276
289277 if (bound_inclusive->is_bound_predicate ()) {
290- // Evaluate the bound predicate against partition data
291278 ICEBERG_ASSIGN_OR_RAISE (
292279 inclusive_result,
293280 BoundVisitor::Predicate (
294- std::dynamic_pointer_cast <BoundPredicate>(bound_inclusive)));
281+ internal::checked_pointer_cast <BoundPredicate>(bound_inclusive)));
295282 } else {
296283 // If the result is not a predicate, then it must be a constant like alwaysTrue
297284 // or alwaysFalse
@@ -310,24 +297,12 @@ Result<std::shared_ptr<Expression>> ResidualVisitor::Predicate(
310297 return pred;
311298}
312299
313- ResidualEvaluator::ResidualEvaluator (std::shared_ptr<Expression> expr,
314- const PartitionSpec& spec, const Schema& schema,
315- bool case_sensitive)
316- : expr_(std::move(expr)),
317- spec_(spec),
318- schema_(schema),
319- case_sensitive_(case_sensitive) {}
320-
321- ResidualEvaluator::~ResidualEvaluator () = default ;
322-
323- namespace {
324-
325300// Unpartitioned residual evaluator that always returns the original expression
326301class UnpartitionedResidualEvaluator : public ResidualEvaluator {
327302 public:
328303 explicit UnpartitionedResidualEvaluator (std::shared_ptr<Expression> expr)
329304 : ResidualEvaluator(std::move(expr), *PartitionSpec::Unpartitioned(),
330- *empty_schema_ , true) {}
305+ *kEmptySchema_ , true) {}
331306
332307 Result<std::shared_ptr<Expression>> ResidualFor (
333308 const StructLike& /* partition_data*/ ) const override {
@@ -336,15 +311,22 @@ class UnpartitionedResidualEvaluator : public ResidualEvaluator {
336311
337312 private:
338313 // Store an empty schema to avoid dangling reference when passing to base class
339- static const std::shared_ptr<Schema> empty_schema_;
314+ inline static const std::shared_ptr<Schema> kEmptySchema_ =
315+ std::make_shared<Schema>(std::vector<SchemaField>{}, std::nullopt );
340316};
341317
342- // Static member definition
343- const std::shared_ptr<Schema> UnpartitionedResidualEvaluator::empty_schema_ =
344- std::make_shared<Schema>(std::vector<SchemaField>{}, std::nullopt );
345-
346318} // namespace
347319
320+ ResidualEvaluator::ResidualEvaluator (std::shared_ptr<Expression> expr,
321+ const PartitionSpec& spec, const Schema& schema,
322+ bool case_sensitive)
323+ : expr_(std::move(expr)),
324+ spec_(spec),
325+ schema_(schema),
326+ case_sensitive_(case_sensitive) {}
327+
328+ ResidualEvaluator::~ResidualEvaluator () = default ;
329+
348330Result<std::unique_ptr<ResidualEvaluator>> ResidualEvaluator::Unpartitioned (
349331 std::shared_ptr<Expression> expr) {
350332 return std::unique_ptr<ResidualEvaluator>(
0 commit comments