1#include "duckdb/parser/expression/case_expression.hpp"
2#include "duckdb/parser/expression/cast_expression.hpp"
3#include "duckdb/parser/expression/comparison_expression.hpp"
4#include "duckdb/parser/expression/conjunction_expression.hpp"
5#include "duckdb/parser/expression/constant_expression.hpp"
6#include "duckdb/parser/expression/function_expression.hpp"
7#include "duckdb/parser/expression/operator_expression.hpp"
8#include "duckdb/parser/transformer.hpp"
9
10using namespace duckdb;
11using namespace std;
12
13ExpressionType Transformer::OperatorToExpressionType(string &op) {
14 if (op == "=" || op == "==") {
15 return ExpressionType::COMPARE_EQUAL;
16 } else if (op == "!=" || op == "<>") {
17 return ExpressionType::COMPARE_NOTEQUAL;
18 } else if (op == "<") {
19 return ExpressionType::COMPARE_LESSTHAN;
20 } else if (op == ">") {
21 return ExpressionType::COMPARE_GREATERTHAN;
22 } else if (op == "<=") {
23 return ExpressionType::COMPARE_LESSTHANOREQUALTO;
24 } else if (op == ">=") {
25 return ExpressionType::COMPARE_GREATERTHANOREQUALTO;
26 }
27 return ExpressionType::INVALID;
28}
29
30unique_ptr<ParsedExpression> Transformer::TransformUnaryOperator(string op, unique_ptr<ParsedExpression> child) {
31 const auto schema = DEFAULT_SCHEMA;
32
33 vector<unique_ptr<ParsedExpression>> children;
34 children.push_back(move(child));
35
36 // built-in operator function
37 auto result = make_unique<FunctionExpression>(schema, op, children);
38 result->is_operator = true;
39 return move(result);
40}
41
42unique_ptr<ParsedExpression> Transformer::TransformBinaryOperator(string op, unique_ptr<ParsedExpression> left,
43 unique_ptr<ParsedExpression> right) {
44 const auto schema = DEFAULT_SCHEMA;
45
46 vector<unique_ptr<ParsedExpression>> children;
47 children.push_back(move(left));
48 children.push_back(move(right));
49
50 if (op == "~" || op == "!~") {
51 // rewrite 'asdf' SIMILAR TO '.*sd.*' into regexp_full_match('asdf', '.*sd.*')
52 bool invert_similar = op == "!~";
53
54 auto result = make_unique<FunctionExpression>(schema, "regexp_full_match", children);
55 if (invert_similar) {
56 return make_unique<OperatorExpression>(ExpressionType::OPERATOR_NOT, move(result));
57 } else {
58 return move(result);
59 }
60 } else {
61 auto target_type = OperatorToExpressionType(op);
62 if (target_type != ExpressionType::INVALID) {
63 // built-in comparison operator
64 return make_unique<ComparisonExpression>(target_type, move(children[0]), move(children[1]));
65 } else {
66 // built-in operator function
67 auto result = make_unique<FunctionExpression>(schema, op, children);
68 result->is_operator = true;
69 return move(result);
70 }
71 }
72}
73
74unique_ptr<ParsedExpression> Transformer::TransformAExpr(PGAExpr *root) {
75 if (!root) {
76 return nullptr;
77 }
78 auto name = string((reinterpret_cast<PGValue *>(root->name->head->data.ptr_value))->val.str);
79
80 switch (root->kind) {
81 case PG_AEXPR_DISTINCT:
82 break;
83 case PG_AEXPR_IN: {
84 auto left_expr = TransformExpression(root->lexpr);
85 ExpressionType operator_type;
86 // this looks very odd, but seems to be the way to find out its NOT IN
87 if (name == "<>") {
88 // NOT IN
89 operator_type = ExpressionType::COMPARE_NOT_IN;
90 } else {
91 // IN
92 operator_type = ExpressionType::COMPARE_IN;
93 }
94 auto result = make_unique<OperatorExpression>(operator_type, move(left_expr));
95 TransformExpressionList((PGList *)root->rexpr, result->children);
96 return move(result);
97 } break;
98 // rewrite NULLIF(a, b) into CASE WHEN a=b THEN NULL ELSE a END
99 case PG_AEXPR_NULLIF: {
100 auto case_expr = make_unique<CaseExpression>();
101 auto value = TransformExpression(root->lexpr);
102 // the check (A = B)
103 case_expr->check = make_unique<ComparisonExpression>(ExpressionType::COMPARE_EQUAL, value->Copy(),
104 TransformExpression(root->rexpr));
105 // if A = B, then constant NULL
106 case_expr->result_if_true = make_unique<ConstantExpression>(SQLType::SQLNULL, Value());
107 // else A
108 case_expr->result_if_false = move(value);
109 return move(case_expr);
110 } break;
111 // rewrite (NOT) X BETWEEN A AND B into (NOT) AND(GREATERTHANOREQUALTO(X,
112 // A), LESSTHANOREQUALTO(X, B))
113 case PG_AEXPR_BETWEEN:
114 case PG_AEXPR_NOT_BETWEEN: {
115 auto between_args = reinterpret_cast<PGList *>(root->rexpr);
116
117 if (between_args->length != 2 || !between_args->head->data.ptr_value || !between_args->tail->data.ptr_value) {
118 throw Exception("(NOT) BETWEEN needs two args");
119 }
120
121 auto between_left = TransformExpression(reinterpret_cast<PGNode *>(between_args->head->data.ptr_value));
122 auto between_right = TransformExpression(reinterpret_cast<PGNode *>(between_args->tail->data.ptr_value));
123
124 auto compare_left = make_unique<ComparisonExpression>(ExpressionType::COMPARE_GREATERTHANOREQUALTO,
125 TransformExpression(root->lexpr), move(between_left));
126 auto compare_right = make_unique<ComparisonExpression>(ExpressionType::COMPARE_LESSTHANOREQUALTO,
127 TransformExpression(root->lexpr), move(between_right));
128 auto compare_between = make_unique<ConjunctionExpression>(ExpressionType::CONJUNCTION_AND, move(compare_left),
129 move(compare_right));
130 if (root->kind == PG_AEXPR_BETWEEN) {
131 return move(compare_between);
132 } else {
133 return make_unique<OperatorExpression>(ExpressionType::OPERATOR_NOT, move(compare_between));
134 }
135 } break;
136 // rewrite SIMILAR TO into regexp_full_match('asdf', '.*sd.*')
137 case PG_AEXPR_SIMILAR: {
138 auto left_expr = TransformExpression(root->lexpr);
139 auto right_expr = TransformExpression(root->rexpr);
140
141 vector<unique_ptr<ParsedExpression>> children;
142 children.push_back(move(left_expr));
143
144 auto &similar_func = reinterpret_cast<FunctionExpression &>(*right_expr);
145 assert(similar_func.function_name == "similar_escape");
146 assert(similar_func.children.size() == 2);
147 if (similar_func.children[1]->type != ExpressionType::VALUE_CONSTANT) {
148 throw NotImplementedException("Custom escape in SIMILAR TO");
149 }
150 auto &constant = (ConstantExpression &)*similar_func.children[1];
151 if (!constant.value.is_null) {
152 throw NotImplementedException("Custom escape in SIMILAR TO");
153 }
154 // take the child of the similar_func
155 children.push_back(move(similar_func.children[0]));
156
157 // this looks very odd, but seems to be the way to find out its NOT IN
158 bool invert_similar = false;
159 if (name == "!~") {
160 // NOT SIMILAR TO
161 invert_similar = true;
162 }
163 const auto schema = DEFAULT_SCHEMA;
164 const auto regex_function = "regexp_full_match";
165 auto result = make_unique<FunctionExpression>(schema, regex_function, children);
166
167 if (invert_similar) {
168 return make_unique<OperatorExpression>(ExpressionType::OPERATOR_NOT, move(result));
169 } else {
170 return move(result);
171 }
172 } break;
173 default:
174 break;
175 }
176 auto left_expr = TransformExpression(root->lexpr);
177 auto right_expr = TransformExpression(root->rexpr);
178
179 if (!left_expr) {
180 // prefix operator
181 return TransformUnaryOperator(name, move(right_expr));
182 } else if (!right_expr) {
183 throw NotImplementedException("Postfix operators not implemented!");
184 } else {
185 return TransformBinaryOperator(name, move(left_expr), move(right_expr));
186 }
187}
188