blob: 55782a637470dcf70b3b6c14d85f0d26677785f8 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef GANDIVA_EXPR_NODE_H
#define GANDIVA_EXPR_NODE_H
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>
#include "arrow/status.h"
#include "gandiva/arrow.h"
#include "gandiva/func_descriptor.h"
#include "gandiva/gandiva_aliases.h"
#include "gandiva/literal_holder.h"
#include "gandiva/node_visitor.h"
#include "gandiva/visibility.h"
namespace gandiva {
/// \brief Represents a node in the expression tree. Validity and value are
/// in a joined state.
class GANDIVA_EXPORT Node {
public:
explicit Node(DataTypePtr return_type) : return_type_(return_type) {}
virtual ~Node() = default;
const DataTypePtr& return_type() const { return return_type_; }
/// Derived classes should simply invoke the Visit api of the visitor.
virtual Status Accept(NodeVisitor& visitor) const = 0;
virtual std::string ToString() const = 0;
protected:
DataTypePtr return_type_;
};
/// \brief Node in the expression tree, representing a literal.
class GANDIVA_EXPORT LiteralNode : public Node {
public:
LiteralNode(DataTypePtr type, const LiteralHolder& holder, bool is_null)
: Node(type), holder_(holder), is_null_(is_null) {}
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
const LiteralHolder& holder() const { return holder_; }
bool is_null() const { return is_null_; }
std::string ToString() const override {
std::stringstream ss;
ss << "(const " << return_type()->ToString() << ") ";
if (is_null()) {
ss << std::string("null");
return ss.str();
}
ss << gandiva::ToString(holder_);
// The default formatter prints in decimal can cause a loss in precision. so,
// print in hex. Can't use hexfloat since gcc 4.9 doesn't support it.
if (return_type()->id() == arrow::Type::DOUBLE) {
double dvalue = arrow::util::get<double>(holder_);
uint64_t bits;
memcpy(&bits, &dvalue, sizeof(bits));
ss << " raw(" << std::hex << bits << ")";
} else if (return_type()->id() == arrow::Type::FLOAT) {
float fvalue = arrow::util::get<float>(holder_);
uint32_t bits;
memcpy(&bits, &fvalue, sizeof(bits));
ss << " raw(" << std::hex << bits << ")";
}
return ss.str();
}
private:
LiteralHolder holder_;
bool is_null_;
};
/// \brief Node in the expression tree, representing an arrow field.
class GANDIVA_EXPORT FieldNode : public Node {
public:
explicit FieldNode(FieldPtr field) : Node(field->type()), field_(field) {}
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
const FieldPtr& field() const { return field_; }
std::string ToString() const override {
return "(" + field()->type()->ToString() + ") " + field()->name();
}
private:
FieldPtr field_;
};
/// \brief Node in the expression tree, representing a function.
class GANDIVA_EXPORT FunctionNode : public Node {
public:
FunctionNode(const std::string& name, const NodeVector& children, DataTypePtr retType);
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
const FuncDescriptorPtr& descriptor() const { return descriptor_; }
const NodeVector& children() const { return children_; }
std::string ToString() const override {
std::stringstream ss;
ss << descriptor()->return_type()->ToString() << " " << descriptor()->name() << "(";
bool skip_comma = true;
for (auto& child : children()) {
if (skip_comma) {
ss << child->ToString();
skip_comma = false;
} else {
ss << ", " << child->ToString();
}
}
ss << ")";
return ss.str();
}
private:
FuncDescriptorPtr descriptor_;
NodeVector children_;
};
inline FunctionNode::FunctionNode(const std::string& name, const NodeVector& children,
DataTypePtr return_type)
: Node(return_type), children_(children) {
DataTypeVector param_types;
for (auto& child : children) {
param_types.push_back(child->return_type());
}
descriptor_ = FuncDescriptorPtr(new FuncDescriptor(name, param_types, return_type));
}
/// \brief Node in the expression tree, representing an if-else expression.
class GANDIVA_EXPORT IfNode : public Node {
public:
IfNode(NodePtr condition, NodePtr then_node, NodePtr else_node, DataTypePtr result_type)
: Node(result_type),
condition_(condition),
then_node_(then_node),
else_node_(else_node) {}
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
const NodePtr& condition() const { return condition_; }
const NodePtr& then_node() const { return then_node_; }
const NodePtr& else_node() const { return else_node_; }
std::string ToString() const override {
std::stringstream ss;
ss << "if (" << condition()->ToString() << ") { ";
ss << then_node()->ToString() << " } else { ";
ss << else_node()->ToString() << " }";
return ss.str();
}
private:
NodePtr condition_;
NodePtr then_node_;
NodePtr else_node_;
};
/// \brief Node in the expression tree, representing an and/or boolean expression.
class GANDIVA_EXPORT BooleanNode : public Node {
public:
enum ExprType : char { AND, OR };
BooleanNode(ExprType expr_type, const NodeVector& children)
: Node(arrow::boolean()), expr_type_(expr_type), children_(children) {}
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
ExprType expr_type() const { return expr_type_; }
const NodeVector& children() const { return children_; }
std::string ToString() const override {
std::stringstream ss;
bool first = true;
for (auto& child : children_) {
if (!first) {
if (expr_type() == BooleanNode::AND) {
ss << " && ";
} else {
ss << " || ";
}
}
ss << child->ToString();
first = false;
}
return ss.str();
}
private:
ExprType expr_type_;
NodeVector children_;
};
/// \brief Node in expression tree, representing an in expression.
template <typename Type>
class InExpressionNode : public Node {
public:
InExpressionNode(NodePtr eval_expr, const std::unordered_set<Type>& values)
: Node(arrow::boolean()), eval_expr_(eval_expr), values_(values) {}
const NodePtr& eval_expr() const { return eval_expr_; }
const std::unordered_set<Type>& values() const { return values_; }
Status Accept(NodeVisitor& visitor) const override { return visitor.Visit(*this); }
std::string ToString() const override {
std::stringstream ss;
ss << eval_expr_->ToString() << " IN (";
bool add_comma = false;
for (auto& value : values_) {
if (add_comma) {
ss << ", ";
}
// add type in the front to differentiate
ss << value;
add_comma = true;
}
ss << ")";
return ss.str();
}
private:
NodePtr eval_expr_;
std::unordered_set<Type> values_;
};
} // namespace gandiva
#endif // GANDIVA_EXPR_NODE_H