1 | #include "duckdb/parser/expression/list.hpp" |
2 | #include "duckdb/parser/transformer.hpp" |
3 | #include "duckdb/parser/query_node/select_node.hpp" |
4 | #include "duckdb/parser/tableref/subqueryref.hpp" |
5 | |
6 | namespace duckdb { |
7 | |
8 | unique_ptr<ParsedExpression> Transformer::TransformSubquery(duckdb_libpgquery::PGSubLink &root) { |
9 | auto subquery_expr = make_uniq<SubqueryExpression>(); |
10 | |
11 | subquery_expr->subquery = TransformSelect(node: root.subselect); |
12 | D_ASSERT(subquery_expr->subquery); |
13 | D_ASSERT(subquery_expr->subquery->node->GetSelectList().size() > 0); |
14 | |
15 | switch (root.subLinkType) { |
16 | case duckdb_libpgquery::PG_EXISTS_SUBLINK: { |
17 | subquery_expr->subquery_type = SubqueryType::EXISTS; |
18 | break; |
19 | } |
20 | case duckdb_libpgquery::PG_ANY_SUBLINK: |
21 | case duckdb_libpgquery::PG_ALL_SUBLINK: { |
22 | // comparison with ANY() or ALL() |
23 | subquery_expr->subquery_type = SubqueryType::ANY; |
24 | subquery_expr->child = TransformExpression(node: root.testexpr); |
25 | // get the operator name |
26 | if (!root.operName) { |
27 | // simple IN |
28 | subquery_expr->comparison_type = ExpressionType::COMPARE_EQUAL; |
29 | } else { |
30 | auto operator_name = |
31 | string((PGPointerCast<duckdb_libpgquery::PGValue>(ptr: root.operName->head->data.ptr_value))->val.str); |
32 | subquery_expr->comparison_type = OperatorToExpressionType(op: operator_name); |
33 | } |
34 | if (subquery_expr->comparison_type != ExpressionType::COMPARE_EQUAL && |
35 | subquery_expr->comparison_type != ExpressionType::COMPARE_NOTEQUAL && |
36 | subquery_expr->comparison_type != ExpressionType::COMPARE_GREATERTHAN && |
37 | subquery_expr->comparison_type != ExpressionType::COMPARE_GREATERTHANOREQUALTO && |
38 | subquery_expr->comparison_type != ExpressionType::COMPARE_LESSTHAN && |
39 | subquery_expr->comparison_type != ExpressionType::COMPARE_LESSTHANOREQUALTO) { |
40 | throw ParserException("ANY and ALL operators require one of =,<>,>,<,>=,<= comparisons!" ); |
41 | } |
42 | if (root.subLinkType == duckdb_libpgquery::PG_ALL_SUBLINK) { |
43 | // ALL sublink is equivalent to NOT(ANY) with inverted comparison |
44 | // e.g. [= ALL()] is equivalent to [NOT(<> ANY())] |
45 | // first invert the comparison type |
46 | subquery_expr->comparison_type = NegateComparisonExpression(type: subquery_expr->comparison_type); |
47 | return make_uniq<OperatorExpression>(args: ExpressionType::OPERATOR_NOT, args: std::move(subquery_expr)); |
48 | } |
49 | break; |
50 | } |
51 | case duckdb_libpgquery::PG_EXPR_SUBLINK: { |
52 | // return a single scalar value from the subquery |
53 | // no child expression to compare to |
54 | subquery_expr->subquery_type = SubqueryType::SCALAR; |
55 | break; |
56 | } |
57 | case duckdb_libpgquery::PG_ARRAY_SUBLINK: { |
58 | auto subquery_table_alias = "__subquery" ; |
59 | auto subquery_column_alias = "__arr_element" ; |
60 | |
61 | // ARRAY expression |
62 | // wrap subquery into "SELECT CASE WHEN ARRAY_AGG(i) IS NULL THEN [] ELSE ARRAY_AGG(i) END FROM (...) tbl(i)" |
63 | auto select_node = make_uniq<SelectNode>(); |
64 | |
65 | // ARRAY_AGG(i) |
66 | vector<unique_ptr<ParsedExpression>> children; |
67 | children.push_back( |
68 | x: make_uniq_base<ParsedExpression, ColumnRefExpression>(args&: subquery_column_alias, args&: subquery_table_alias)); |
69 | auto aggr = make_uniq<FunctionExpression>(args: "array_agg" , args: std::move(children)); |
70 | // ARRAY_AGG(i) IS NULL |
71 | auto agg_is_null = make_uniq<OperatorExpression>(args: ExpressionType::OPERATOR_IS_NULL, args: aggr->Copy()); |
72 | // empty list |
73 | vector<unique_ptr<ParsedExpression>> list_children; |
74 | auto empty_list = make_uniq<FunctionExpression>(args: "list_value" , args: std::move(list_children)); |
75 | // CASE |
76 | auto case_expr = make_uniq<CaseExpression>(); |
77 | CaseCheck check; |
78 | check.when_expr = std::move(agg_is_null); |
79 | check.then_expr = std::move(empty_list); |
80 | case_expr->case_checks.push_back(x: std::move(check)); |
81 | case_expr->else_expr = std::move(aggr); |
82 | |
83 | select_node->select_list.push_back(x: std::move(case_expr)); |
84 | |
85 | // FROM (...) tbl(i) |
86 | auto child_subquery = make_uniq<SubqueryRef>(args: std::move(subquery_expr->subquery), args&: subquery_table_alias); |
87 | child_subquery->column_name_alias.emplace_back(args&: subquery_column_alias); |
88 | select_node->from_table = std::move(child_subquery); |
89 | |
90 | auto new_subquery = make_uniq<SelectStatement>(); |
91 | new_subquery->node = std::move(select_node); |
92 | subquery_expr->subquery = std::move(new_subquery); |
93 | |
94 | subquery_expr->subquery_type = SubqueryType::SCALAR; |
95 | break; |
96 | } |
97 | default: |
98 | throw NotImplementedException("Subquery of type %d not implemented\n" , (int)root.subLinkType); |
99 | } |
100 | subquery_expr->query_location = root.location; |
101 | return std::move(subquery_expr); |
102 | } |
103 | |
104 | } // namespace duckdb |
105 | |