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
6namespace duckdb {
7
8unique_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