1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
22 #include "gandiva/expr_validator.h"
26 Status
ExprValidator::Validate(const ExpressionPtr
& expr
) {
27 ARROW_RETURN_IF(expr
== nullptr,
28 Status::ExpressionValidationError("Expression cannot be null"));
30 Node
& root
= *expr
->root();
31 ARROW_RETURN_NOT_OK(root
.Accept(*this));
33 // Ensure root's return type match the expression return type. Type
34 // support validation is not required because root type is already supported.
35 ARROW_RETURN_IF(!root
.return_type()->Equals(*expr
->result()->type()),
36 Status::ExpressionValidationError("Return type of root node ",
37 root
.return_type()->ToString(),
38 " does not match that of expression ",
39 expr
->result()->type()->ToString()));
44 Status
ExprValidator::Visit(const FieldNode
& node
) {
45 auto llvm_type
= types_
->IRType(node
.return_type()->id());
46 ARROW_RETURN_IF(llvm_type
== nullptr,
47 Status::ExpressionValidationError("Field ", node
.field()->name(),
48 " has unsupported data type ",
49 node
.return_type()->name()));
51 // Ensure that field is found in schema
52 auto field_in_schema_entry
= field_map_
.find(node
.field()->name());
53 ARROW_RETURN_IF(field_in_schema_entry
== field_map_
.end(),
54 Status::ExpressionValidationError("Field ", node
.field()->name(),
57 // Ensure that that the found field match.
58 FieldPtr field_in_schema
= field_in_schema_entry
->second
;
59 ARROW_RETURN_IF(!field_in_schema
->Equals(node
.field()),
60 Status::ExpressionValidationError(
61 "Field definition in schema ", field_in_schema
->ToString(),
62 " different from field in expression ", node
.field()->ToString()));
67 Status
ExprValidator::Visit(const FunctionNode
& node
) {
68 auto desc
= node
.descriptor();
69 FunctionSignature
signature(desc
->name(), desc
->params(), desc
->return_type());
71 const NativeFunction
* native_function
= registry_
.LookupSignature(signature
);
72 ARROW_RETURN_IF(native_function
== nullptr,
73 Status::ExpressionValidationError("Function ", signature
.ToString(),
74 " not supported yet. "));
76 for (auto& child
: node
.children()) {
77 ARROW_RETURN_NOT_OK(child
->Accept(*this));
83 Status
ExprValidator::Visit(const IfNode
& node
) {
84 ARROW_RETURN_NOT_OK(node
.condition()->Accept(*this));
85 ARROW_RETURN_NOT_OK(node
.then_node()->Accept(*this));
86 ARROW_RETURN_NOT_OK(node
.else_node()->Accept(*this));
88 auto if_node_ret_type
= node
.return_type();
89 auto then_node_ret_type
= node
.then_node()->return_type();
90 auto else_node_ret_type
= node
.else_node()->return_type();
92 // condition must be of boolean type.
94 !node
.condition()->return_type()->Equals(arrow::boolean()),
95 Status::ExpressionValidationError("condition must be of boolean type, found type ",
96 node
.condition()->return_type()->ToString()));
98 // Then-branch return type must match.
99 ARROW_RETURN_IF(!if_node_ret_type
->Equals(*then_node_ret_type
),
100 Status::ExpressionValidationError(
101 "Return type of if ", if_node_ret_type
->ToString(), " and then ",
102 then_node_ret_type
->ToString(), " not matching."));
104 // Else-branch return type must match.
105 ARROW_RETURN_IF(!if_node_ret_type
->Equals(*else_node_ret_type
),
106 Status::ExpressionValidationError(
107 "Return type of if ", if_node_ret_type
->ToString(), " and else ",
108 else_node_ret_type
->ToString(), " not matching."));
113 Status
ExprValidator::Visit(const LiteralNode
& node
) {
114 auto llvm_type
= types_
->IRType(node
.return_type()->id());
115 ARROW_RETURN_IF(llvm_type
== nullptr,
116 Status::ExpressionValidationError("Value ", ToString(node
.holder()),
117 " has unsupported data type ",
118 node
.return_type()->name()));
123 Status
ExprValidator::Visit(const BooleanNode
& node
) {
125 node
.children().size() < 2,
126 Status::ExpressionValidationError("Boolean expression has ", node
.children().size(),
127 " children, expected at least two"));
129 for (auto& child
: node
.children()) {
130 const auto bool_type
= arrow::boolean();
131 const auto ret_type
= child
->return_type();
133 ARROW_RETURN_IF(!ret_type
->Equals(bool_type
),
134 Status::ExpressionValidationError(
135 "Boolean expression has a child with return type ",
136 ret_type
->ToString(), ", expected return type boolean"));
138 ARROW_RETURN_NOT_OK(child
->Accept(*this));
145 * Validate the following
147 * 1. Non empty list of constants to search in.
148 * 2. Expression returns of the same type as the constants.
150 Status
ExprValidator::Visit(const InExpressionNode
<int32_t>& node
) {
151 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
155 Status
ExprValidator::Visit(const InExpressionNode
<int64_t>& node
) {
156 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
159 Status
ExprValidator::Visit(const InExpressionNode
<float>& node
) {
160 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
163 Status
ExprValidator::Visit(const InExpressionNode
<double>& node
) {
164 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
168 Status
ExprValidator::Visit(const InExpressionNode
<gandiva::DecimalScalar128
>& node
) {
169 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
170 arrow::decimal(node
.get_precision(), node
.get_scale()));
173 Status
ExprValidator::Visit(const InExpressionNode
<std::string
>& node
) {
174 return ValidateInExpression(node
.values().size(), node
.eval_expr()->return_type(),
178 Status
ExprValidator::ValidateInExpression(size_t number_of_values
,
179 DataTypePtr in_expr_return_type
,
180 DataTypePtr type_of_values
) {
181 ARROW_RETURN_IF(number_of_values
== 0,
182 Status::ExpressionValidationError(
183 "IN Expression needs a non-empty constant list to match."));
185 !in_expr_return_type
->Equals(type_of_values
),
186 Status::ExpressionValidationError(
187 "Evaluation expression for IN clause returns ", in_expr_return_type
->ToString(),
188 " values are of type", type_of_values
->ToString()));
193 } // namespace gandiva