| 837 | } |
| 838 | |
| 839 | Result<Expression> FoldConstants(Expression expr) { |
| 840 | if (!expr.IsBound()) { |
| 841 | return Status::Invalid("Cannot fold constants in unbound expression."); |
| 842 | } |
| 843 | |
| 844 | return ModifyExpression( |
| 845 | std::move(expr), [](Expression expr) { return expr; }, |
| 846 | [](Expression expr, ...) -> Result<Expression> { |
| 847 | auto call = CallNotNull(expr); |
| 848 | if (!call->function->is_pure()) return expr; |
| 849 | |
| 850 | if (std::all_of(call->arguments.begin(), call->arguments.end(), |
| 851 | [](const Expression& argument) { return argument.literal(); })) { |
| 852 | // all arguments are literal; we can evaluate this subexpression *now* |
| 853 | static const ExecBatch ignored_input = ExecBatch({}, 1); |
| 854 | ARROW_ASSIGN_OR_RAISE(Datum constant, |
| 855 | ExecuteScalarExpression(expr, ignored_input)); |
| 856 | |
| 857 | return literal(std::move(constant)); |
| 858 | } |
| 859 | |
| 860 | // XXX the following should probably be in a registry of passes instead |
| 861 | // of inline |
| 862 | |
| 863 | if (GetNullHandling(*call) == compute::NullHandling::INTERSECTION) { |
| 864 | // kernels which always produce intersected validity can be resolved |
| 865 | // to null *now* if any of their inputs is a null literal |
| 866 | for (const Expression& argument : call->arguments) { |
| 867 | if (argument.IsNullLiteral()) { |
| 868 | if (argument.type()->Equals(*call->type.type)) { |
| 869 | return argument; |
| 870 | } else { |
| 871 | return literal(MakeNullScalar(call->type.GetSharedPtr())); |
| 872 | } |
| 873 | } |
| 874 | } |
| 875 | } |
| 876 | |
| 877 | if (call->function_name == "and_kleene") { |
| 878 | for (auto args : ArgumentsAndFlippedArguments(*call)) { |
| 879 | // true and x == x |
| 880 | if (args.first == literal(true)) return args.second; |
| 881 | |
| 882 | // false and x == false |
| 883 | if (args.first == literal(false)) return args.first; |
| 884 | |
| 885 | // x and x == x |
| 886 | if (args.first == args.second) return args.first; |
| 887 | } |
| 888 | return expr; |
| 889 | } |
| 890 | |
| 891 | if (call->function_name == "or_kleene") { |
| 892 | for (auto args : ArgumentsAndFlippedArguments(*call)) { |
| 893 | // false or x == x |
| 894 | if (args.first == literal(false)) return args.second; |
| 895 | |
| 896 | // true or x == true |
no test coverage detected