]> git.proxmox.com Git - ceph.git/blob - ceph/src/arrow/cpp/src/gandiva/expr_validator.cc
import quincy 17.2.0
[ceph.git] / ceph / src / arrow / cpp / src / gandiva / expr_validator.cc
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
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
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
16 // under the License.
17
18 #include <sstream>
19 #include <string>
20 #include <vector>
21
22 #include "gandiva/expr_validator.h"
23
24 namespace gandiva {
25
26 Status ExprValidator::Validate(const ExpressionPtr& expr) {
27 ARROW_RETURN_IF(expr == nullptr,
28 Status::ExpressionValidationError("Expression cannot be null"));
29
30 Node& root = *expr->root();
31 ARROW_RETURN_NOT_OK(root.Accept(*this));
32
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()));
40
41 return Status::OK();
42 }
43
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()));
50
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(),
55 " not in schema."));
56
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()));
63
64 return Status::OK();
65 }
66
67 Status ExprValidator::Visit(const FunctionNode& node) {
68 auto desc = node.descriptor();
69 FunctionSignature signature(desc->name(), desc->params(), desc->return_type());
70
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. "));
75
76 for (auto& child : node.children()) {
77 ARROW_RETURN_NOT_OK(child->Accept(*this));
78 }
79
80 return Status::OK();
81 }
82
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));
87
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();
91
92 // condition must be of boolean type.
93 ARROW_RETURN_IF(
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()));
97
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."));
103
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."));
109
110 return Status::OK();
111 }
112
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()));
119
120 return Status::OK();
121 }
122
123 Status ExprValidator::Visit(const BooleanNode& node) {
124 ARROW_RETURN_IF(
125 node.children().size() < 2,
126 Status::ExpressionValidationError("Boolean expression has ", node.children().size(),
127 " children, expected at least two"));
128
129 for (auto& child : node.children()) {
130 const auto bool_type = arrow::boolean();
131 const auto ret_type = child->return_type();
132
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"));
137
138 ARROW_RETURN_NOT_OK(child->Accept(*this));
139 }
140
141 return Status::OK();
142 }
143
144 /*
145 * Validate the following
146 *
147 * 1. Non empty list of constants to search in.
148 * 2. Expression returns of the same type as the constants.
149 */
150 Status ExprValidator::Visit(const InExpressionNode<int32_t>& node) {
151 return ValidateInExpression(node.values().size(), node.eval_expr()->return_type(),
152 arrow::int32());
153 }
154
155 Status ExprValidator::Visit(const InExpressionNode<int64_t>& node) {
156 return ValidateInExpression(node.values().size(), node.eval_expr()->return_type(),
157 arrow::int64());
158 }
159 Status ExprValidator::Visit(const InExpressionNode<float>& node) {
160 return ValidateInExpression(node.values().size(), node.eval_expr()->return_type(),
161 arrow::float32());
162 }
163 Status ExprValidator::Visit(const InExpressionNode<double>& node) {
164 return ValidateInExpression(node.values().size(), node.eval_expr()->return_type(),
165 arrow::float64());
166 }
167
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()));
171 }
172
173 Status ExprValidator::Visit(const InExpressionNode<std::string>& node) {
174 return ValidateInExpression(node.values().size(), node.eval_expr()->return_type(),
175 arrow::utf8());
176 }
177
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."));
184 ARROW_RETURN_IF(
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()));
189
190 return Status::OK();
191 }
192
193 } // namespace gandiva