45 static Result<Literal> AdjustLiteral(
const Literal& literal,
int adjustment) {
46 switch (literal.type()->type_id()) {
48 return Literal::Int(std::get<int32_t>(literal.value()) + adjustment);
50 return Literal::Long(std::get<int64_t>(literal.value()) + adjustment);
52 return Literal::Date(std::get<int32_t>(literal.value()) + adjustment);
53 case TypeId::kTimestamp:
54 return Literal::Timestamp(std::get<int64_t>(literal.value()) + adjustment);
55 case TypeId::kTimestampTz:
56 return Literal::TimestampTz(std::get<int64_t>(literal.value()) + adjustment);
57 case TypeId::kTimestampNs:
58 return Literal::TimestampNs(std::get<int64_t>(literal.value()) + adjustment);
59 case TypeId::kTimestampTzNs:
60 return Literal::TimestampTzNs(std::get<int64_t>(literal.value()) + adjustment);
61 case TypeId::kDecimal: {
62 const auto& decimal_type =
63 internal::checked_cast<const DecimalType&>(*literal.type());
64 Decimal adjusted = std::get<Decimal>(literal.value()) +
Decimal(adjustment);
66 decimal_type.scale());
69 return NotSupported(
"{} is not a valid literal type for value adjustment",
70 literal.type()->ToString());
74 static Result<Literal> PlusOne(
const Literal& literal) {
75 return AdjustLiteral(literal, +1);
78 static Result<Literal> MinusOne(
const Literal& literal) {
79 return AdjustLiteral(literal, -1);
82 static Result<std::unique_ptr<UnboundPredicate>> MakePredicate(
84 const std::shared_ptr<TransformFunction>& func,
const Literal& literal) {
86 ICEBERG_ASSIGN_OR_RAISE(
auto lit, func->Transform(literal));
90 static Result<std::unique_ptr<UnboundPredicate>> TransformSet(
91 std::string_view name,
const std::shared_ptr<BoundSetPredicate>& pred,
92 const std::shared_ptr<TransformFunction>& func) {
93 std::vector<Literal> transformed;
94 transformed.reserve(pred->literal_set().size());
95 for (
const auto& lit : pred->literal_set()) {
96 ICEBERG_ASSIGN_OR_RAISE(
auto transformed_lit, func->Transform(lit));
97 transformed.push_back(std::move(transformed_lit));
101 std::move(transformed));
104 static Result<std::unique_ptr<UnboundPredicate>> TruncateByteArray(
105 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
106 const std::shared_ptr<TransformFunction>& func) {
107 switch (pred->op()) {
108 case Expression::Operation::kLt:
109 case Expression::Operation::kLtEq:
110 return MakePredicate(Expression::Operation::kLtEq, name, func, pred->literal());
111 case Expression::Operation::kGt:
112 case Expression::Operation::kGtEq:
113 return MakePredicate(Expression::Operation::kGtEq, name, func, pred->literal());
114 case Expression::Operation::kEq:
115 case Expression::Operation::kStartsWith:
116 return MakePredicate(pred->op(), name, func, pred->literal());
122 static Result<std::unique_ptr<UnboundPredicate>> TruncateByteArrayStrict(
123 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
124 const std::shared_ptr<TransformFunction>& func) {
125 switch (pred->op()) {
126 case Expression::Operation::kLt:
127 case Expression::Operation::kLtEq:
128 return MakePredicate(Expression::Operation::kLt, name, func, pred->literal());
129 case Expression::Operation::kGt:
130 case Expression::Operation::kGtEq:
131 return MakePredicate(Expression::Operation::kGt, name, func, pred->literal());
132 case Expression::Operation::kNotEq:
133 return MakePredicate(Expression::Operation::kNotEq, name, func, pred->literal());
140 static Result<std::unique_ptr<UnboundPredicate>> TransformNumeric(
141 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
142 const std::shared_ptr<TransformFunction>& func) {
143 switch (func->source_type()->type_id()) {
146 case TypeId::kDecimal:
148 case TypeId::kTimestamp:
149 case TypeId::kTimestampTz:
150 case TypeId::kTimestampNs:
151 case TypeId::kTimestampTzNs:
154 return NotSupported(
"{} is not a valid input type for numeric transform",
155 func->source_type()->ToString());
158 switch (pred->op()) {
159 case Expression::Operation::kLt: {
161 ICEBERG_ASSIGN_OR_RAISE(
auto adjusted, MinusOne(pred->literal()));
162 return MakePredicate(Expression::Operation::kLtEq, name, func, adjusted);
164 case Expression::Operation::kGt: {
166 ICEBERG_ASSIGN_OR_RAISE(
auto adjusted, PlusOne(pred->literal()));
167 return MakePredicate(Expression::Operation::kGtEq, name, func, adjusted);
169 case Expression::Operation::kLtEq:
170 case Expression::Operation::kGtEq:
171 case Expression::Operation::kEq:
172 return MakePredicate(pred->op(), name, func, pred->literal());
178 static Result<std::unique_ptr<UnboundPredicate>> TransformNumericStrict(
179 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
180 const std::shared_ptr<TransformFunction>& func) {
181 switch (func->source_type()->type_id()) {
184 case TypeId::kDecimal:
186 case TypeId::kTimestamp:
187 case TypeId::kTimestampTz:
188 case TypeId::kTimestampNs:
189 case TypeId::kTimestampTzNs:
192 return NotSupported(
"{} is not a valid input type for numeric transform",
193 func->source_type()->ToString());
196 switch (pred->op()) {
197 case Expression::Operation::kLtEq: {
198 ICEBERG_ASSIGN_OR_RAISE(
auto adjusted, PlusOne(pred->literal()));
199 return MakePredicate(Expression::Operation::kLt, name, func, adjusted);
201 case Expression::Operation::kGtEq: {
202 ICEBERG_ASSIGN_OR_RAISE(
auto adjusted, MinusOne(pred->literal()));
203 return MakePredicate(Expression::Operation::kGt, name, func, adjusted);
205 case Expression::Operation::kLt:
206 case Expression::Operation::kGt:
207 case Expression::Operation::kNotEq:
208 return MakePredicate(pred->op(), name, func, pred->literal());
214 static Result<std::unique_ptr<UnboundPredicate>> TruncateStringLiteral(
215 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
216 const std::shared_ptr<TransformFunction>& func) {
217 const auto op = pred->op();
218 if (op != Expression::Operation::kStartsWith &&
219 op != Expression::Operation::kNotStartsWith) {
220 return TruncateByteArray(name, pred, func);
223 const auto& literal = pred->literal();
226 const auto width =
static_cast<size_t>(
227 internal::checked_pointer_cast<TruncateTransform>(func)->width());
229 if (length < width) {
230 return MakePredicate(op, name, func, literal);
233 if (length == width) {
234 if (op == Expression::Operation::kStartsWith) {
235 return MakePredicate(Expression::Operation::kEq, name, func, literal);
237 return MakePredicate(Expression::Operation::kNotEq, name, func, literal);
241 if (op == Expression::Operation::kStartsWith) {
242 return TruncateByteArray(name, pred, func);
248 static Result<std::unique_ptr<UnboundPredicate>> TruncateStringLiteralStrict(
249 std::string_view name,
const std::shared_ptr<BoundLiteralPredicate>& pred,
250 const std::shared_ptr<TransformFunction>& func) {
251 const auto op = pred->op();
252 if (op != Expression::Operation::kStartsWith &&
253 op != Expression::Operation::kNotStartsWith) {
254 return TruncateByteArrayStrict(name, pred, func);
257 const auto& literal = pred->literal();
260 const auto width =
static_cast<size_t>(
261 internal::checked_pointer_cast<TruncateTransform>(func)->width());
263 if (length < width) {
264 return MakePredicate(op, name, func, literal);
267 if (length == width) {
268 if (op == Expression::Operation::kStartsWith) {
269 return MakePredicate(Expression::Operation::kEq, name, func, literal);
271 return MakePredicate(Expression::Operation::kNotEq, name, func, literal);
275 if (op == Expression::Operation::kNotStartsWith) {
276 return MakePredicate(Expression::Operation::kNotStartsWith, name, func, literal);
285 static Result<std::unique_ptr<UnboundPredicate>> FixInclusiveTimeProjection(
286 std::unique_ptr<UnboundPredicateImpl<BoundReference>> projected) {
287 if (projected ==
nullptr) {
293 switch (projected->op()) {
294 case Expression::Operation::kLt: {
295 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
296 const auto& literal = projected->literals().front();
297 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
299 if (
auto value = std::get<int32_t>(literal.value()); value < 0) {
301 std::move(projected->term()),
302 Literal::Int(value + 1));
308 case Expression::Operation::kLtEq: {
309 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
310 const auto& literal = projected->literals().front();
311 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
314 if (
auto value = std::get<int32_t>(literal.value()); value < 0) {
316 std::move(projected->term()),
317 Literal::Int(value + 1));
322 case Expression::Operation::kGt:
323 case Expression::Operation::kGtEq:
327 case Expression::Operation::kEq: {
328 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
329 const auto& literal = projected->literals().front();
330 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
332 if (
auto value = std::get<int32_t>(literal.value()); value < 0) {
336 Expression::Operation::kIn, std::move(projected->term()),
337 {literal, Literal::Int(value + 1)});
342 case Expression::Operation::kIn: {
343 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
344 const auto& literals = projected->literals();
346 std::ranges::all_of(literals,
347 [](
const auto& lit) {
348 return std::holds_alternative<int32_t>(lit.value());
351 std::unordered_set<int32_t> value_set;
352 bool has_negative_value =
false;
353 for (
const auto& lit : literals) {
354 auto value = std::get<int32_t>(lit.value());
355 value_set.insert(value);
357 value_set.insert(value + 1);
358 has_negative_value =
true;
361 if (has_negative_value) {
363 std::views::transform(value_set,
364 [](int32_t value) {
return Literal::Int(value); }) |
365 std::ranges::to<std::vector>();
367 std::move(projected->term()),
373 case Expression::Operation::kNotIn:
374 case Expression::Operation::kNotEq:
386 static Result<std::unique_ptr<UnboundPredicate>> FixStrictTimeProjection(
387 std::unique_ptr<UnboundPredicateImpl<BoundReference>> projected) {
388 if (projected ==
nullptr) {
392 switch (projected->op()) {
393 case Expression::Operation::kLt:
394 case Expression::Operation::kLtEq:
399 case Expression::Operation::kGt: {
403 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
404 const auto& literal = projected->literals().front();
405 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
407 if (
auto value = std::get<int32_t>(literal.value()); value <= 0) {
409 std::move(projected->term()),
410 Literal::Int(value + 1));
415 case Expression::Operation::kGtEq: {
416 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
417 const auto& literal = projected->literals().front();
418 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
420 if (
auto value = std::get<int32_t>(literal.value()); value <= 0) {
422 std::move(projected->term()),
423 Literal::Int(value + 1));
428 case Expression::Operation::kEq:
429 case Expression::Operation::kIn:
433 case Expression::Operation::kNotEq: {
434 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
435 const auto& literal = projected->literals().front();
436 ICEBERG_DCHECK(std::holds_alternative<int32_t>(literal.value()),
438 if (
auto value = std::get<int32_t>(literal.value()); value < 0) {
440 Expression::Operation::kNotIn, std::move(projected->term()),
441 {literal, Literal::Int(value + 1)});
446 case Expression::Operation::kNotIn: {
447 ICEBERG_DCHECK(!projected->literals().empty(),
"Expected at least one literal");
448 const auto& literals = projected->literals();
450 std::ranges::all_of(literals,
451 [](
const auto& lit) {
452 return std::holds_alternative<int32_t>(lit.value());
455 std::unordered_set<int32_t> value_set;
456 bool has_negative_value =
false;
457 for (
const auto& lit : literals) {
458 auto value = std::get<int32_t>(lit.value());
459 value_set.insert(value);
461 value_set.insert(value + 1);
462 has_negative_value =
true;
465 if (has_negative_value) {
467 std::views::transform(value_set,
468 [](int32_t value) {
return Literal::Int(value); }) |
469 std::ranges::to<std::vector>();
471 std::move(projected->term()),
483 static Result<std::unique_ptr<UnboundPredicate>> IdentityProject(
484 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred) {
486 switch (pred->kind()) {
487 case BoundPredicate::Kind::kUnary: {
490 case BoundPredicate::Kind::kLiteral: {
491 const auto& literalPredicate =
492 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
494 literalPredicate->literal());
496 case BoundPredicate::Kind::kSet: {
497 const auto& setPredicate =
498 internal::checked_pointer_cast<BoundSetPredicate>(pred);
500 pred->op(), std::move(ref),
501 std::vector<Literal>(setPredicate->literal_set().begin(),
502 setPredicate->literal_set().end()));
508 static Result<std::unique_ptr<UnboundPredicate>> BucketProject(
509 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
510 const std::shared_ptr<TransformFunction>& func) {
512 switch (pred->kind()) {
513 case BoundPredicate::Kind::kUnary: {
516 case BoundPredicate::Kind::kLiteral: {
517 if (pred->op() == Expression::Operation::kEq) {
518 const auto& literalPredicate =
519 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
520 ICEBERG_ASSIGN_OR_RAISE(
auto transformed,
521 func->Transform(literalPredicate->literal()));
523 std::move(transformed));
527 case BoundPredicate::Kind::kSet: {
529 if (pred->op() == Expression::Operation::kIn) {
530 const auto& setPredicate =
531 internal::checked_pointer_cast<BoundSetPredicate>(pred);
532 return TransformSet(name, setPredicate, func);
544 static Result<std::unique_ptr<UnboundPredicate>> TruncateProject(
545 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
546 const std::shared_ptr<TransformFunction>& func) {
549 if (pred->kind() == BoundPredicate::Kind::kUnary) {
554 if (pred->kind() == BoundPredicate::Kind::kSet) {
555 if (pred->op() == Expression::Operation::kIn) {
556 const auto& setPredicate =
557 internal::checked_pointer_cast<BoundSetPredicate>(pred);
558 return TransformSet(name, setPredicate, func);
564 const auto& literalPredicate =
565 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
567 switch (func->source_type()->type_id()) {
570 case TypeId::kDecimal:
571 return TransformNumeric(name, literalPredicate, func);
572 case TypeId::kString:
573 return TruncateStringLiteral(name, literalPredicate, func);
574 case TypeId::kBinary:
575 return TruncateByteArray(name, literalPredicate, func);
577 return NotSupported(
"{} is not a valid input type for truncate transform",
578 func->source_type()->ToString());
582 static Result<std::unique_ptr<UnboundPredicate>> TemporalProject(
583 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
584 const std::shared_ptr<TransformFunction>& func) {
586 if (pred->kind() == BoundPredicate::Kind::kUnary) {
588 }
else if (pred->kind() == BoundPredicate::Kind::kLiteral) {
589 const auto& literalPredicate =
590 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
591 ICEBERG_ASSIGN_OR_RAISE(
auto projected,
592 TransformNumeric(name, literalPredicate, func));
593 if (func->transform_type() != TransformType::kDay ||
594 func->source_type()->type_id() != TypeId::kDate) {
595 return FixInclusiveTimeProjection(
596 internal::checked_pointer_cast<UnboundPredicateImpl<BoundReference>>(
597 std::move(projected)));
600 }
else if (pred->kind() == BoundPredicate::Kind::kSet &&
601 pred->op() == Expression::Operation::kIn) {
602 const auto& setPredicate = internal::checked_pointer_cast<BoundSetPredicate>(pred);
603 ICEBERG_ASSIGN_OR_RAISE(
auto projected, TransformSet(name, setPredicate, func));
604 if (func->transform_type() != TransformType::kDay ||
605 func->source_type()->type_id() != TypeId::kDate) {
606 return FixInclusiveTimeProjection(
607 internal::checked_pointer_cast<UnboundPredicateImpl<BoundReference>>(
608 std::move(projected)));
616 static Result<std::unique_ptr<UnboundPredicate>> RemoveTransform(
617 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred) {
619 switch (pred->kind()) {
620 case BoundPredicate::Kind::kUnary: {
623 case BoundPredicate::Kind::kLiteral: {
624 const auto& literalPredicate =
625 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
627 literalPredicate->literal());
629 case BoundPredicate::Kind::kSet: {
630 const auto& setPredicate =
631 internal::checked_pointer_cast<BoundSetPredicate>(pred);
633 pred->op(), std::move(ref),
634 std::vector<Literal>(setPredicate->literal_set().begin(),
635 setPredicate->literal_set().end()));
641 static Result<std::unique_ptr<UnboundPredicate>> BucketProjectStrict(
642 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
643 const std::shared_ptr<TransformFunction>& func) {
645 switch (pred->kind()) {
646 case BoundPredicate::Kind::kUnary: {
649 case BoundPredicate::Kind::kLiteral: {
650 if (pred->op() == Expression::Operation::kNotEq) {
651 const auto& literalPredicate =
652 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
653 ICEBERG_ASSIGN_OR_RAISE(
auto transformed,
654 func->Transform(literalPredicate->literal()));
657 std::move(transformed));
661 case BoundPredicate::Kind::kSet: {
662 if (pred->op() == Expression::Operation::kNotIn) {
663 const auto& setPredicate =
664 internal::checked_pointer_cast<BoundSetPredicate>(pred);
665 return TransformSet(name, setPredicate, func);
675 static Result<std::unique_ptr<UnboundPredicate>> TruncateProjectStrict(
676 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
677 const std::shared_ptr<TransformFunction>& func) {
680 if (pred->kind() == BoundPredicate::Kind::kUnary) {
685 if (pred->kind() == BoundPredicate::Kind::kSet) {
686 if (pred->op() == Expression::Operation::kNotIn) {
687 const auto& setPredicate =
688 internal::checked_pointer_cast<BoundSetPredicate>(pred);
689 return TransformSet(name, setPredicate, func);
695 const auto& literalPredicate =
696 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
698 switch (func->source_type()->type_id()) {
701 case TypeId::kDecimal:
702 return TransformNumericStrict(name, literalPredicate, func);
703 case TypeId::kString:
704 return TruncateStringLiteralStrict(name, literalPredicate, func);
705 case TypeId::kBinary:
706 return TruncateByteArrayStrict(name, literalPredicate, func);
708 return NotSupported(
"{} is not a valid input type for truncate transform",
709 func->source_type()->ToString());
713 static Result<std::unique_ptr<UnboundPredicate>> TemporalProjectStrict(
714 std::string_view name,
const std::shared_ptr<BoundPredicate>& pred,
715 const std::shared_ptr<TransformFunction>& func) {
717 if (pred->kind() == BoundPredicate::Kind::kUnary) {
719 }
else if (pred->kind() == BoundPredicate::Kind::kLiteral) {
720 const auto& literalPredicate =
721 internal::checked_pointer_cast<BoundLiteralPredicate>(pred);
722 ICEBERG_ASSIGN_OR_RAISE(
auto projected,
723 TransformNumericStrict(name, literalPredicate, func));
724 if (func->transform_type() != TransformType::kDay ||
725 func->source_type()->type_id() != TypeId::kDate) {
726 return FixStrictTimeProjection(
727 internal::checked_pointer_cast<UnboundPredicateImpl<BoundReference>>(
728 std::move(projected)));
731 }
else if (pred->kind() == BoundPredicate::Kind::kSet &&
732 pred->op() == Expression::Operation::kNotIn) {
733 const auto& setPredicate = internal::checked_pointer_cast<BoundSetPredicate>(pred);
734 ICEBERG_ASSIGN_OR_RAISE(
auto projected, TransformSet(name, setPredicate, func));
735 if (func->transform_type() != TransformType::kDay ||
736 func->source_type()->type_id() != TypeId::kDate) {
737 return FixStrictTimeProjection(
738 internal::checked_pointer_cast<UnboundPredicateImpl<BoundReference>>(
739 std::move(projected)));