Coverage Report

Created: 2022-08-24 06:40

/src/duckdb/src/parser/transform/statement/transform_select_node.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "duckdb/common/exception.hpp"
2
#include "duckdb/parser/query_node/select_node.hpp"
3
#include "duckdb/parser/query_node/set_operation_node.hpp"
4
#include "duckdb/parser/statement/select_statement.hpp"
5
#include "duckdb/parser/transformer.hpp"
6
#include "duckdb/parser/expression/star_expression.hpp"
7
#include "duckdb/common/string_util.hpp"
8
9
namespace duckdb {
10
11
160
unique_ptr<QueryNode> Transformer::TransformSelectNode(duckdb_libpgquery::PGSelectStmt *stmt) {
12
160
  D_ASSERT(stmt->type == duckdb_libpgquery::T_PGSelectStmt);
13
160
  auto stack_checker = StackCheck();
14
15
160
  unique_ptr<QueryNode> node;
16
17
160
  switch (stmt->op) {
18
140
  case duckdb_libpgquery::PG_SETOP_NONE: {
19
140
    node = make_unique<SelectNode>();
20
140
    auto result = (SelectNode *)node.get();
21
140
    if (stmt->withClause) {
22
0
      TransformCTE(reinterpret_cast<duckdb_libpgquery::PGWithClause *>(stmt->withClause), node->cte_map);
23
0
    }
24
140
    if (stmt->windowClause) {
25
0
      for (auto window_ele = stmt->windowClause->head; window_ele != nullptr; window_ele = window_ele->next) {
26
0
        auto window_def = reinterpret_cast<duckdb_libpgquery::PGWindowDef *>(window_ele->data.ptr_value);
27
0
        D_ASSERT(window_def);
28
0
        D_ASSERT(window_def->name);
29
0
        auto window_name = StringUtil::Lower(string(window_def->name));
30
31
0
        auto it = window_clauses.find(window_name);
32
0
        if (it != window_clauses.end()) {
33
0
          throw ParserException("window \"%s\" is already defined", window_name);
34
0
        }
35
0
        window_clauses[window_name] = window_def;
36
0
      }
37
0
    }
38
39
    // checks distinct clause
40
140
    if (stmt->distinctClause != nullptr) {
41
0
      auto modifier = make_unique<DistinctModifier>();
42
      // checks distinct on clause
43
0
      auto target = reinterpret_cast<duckdb_libpgquery::PGNode *>(stmt->distinctClause->head->data.ptr_value);
44
0
      if (target) {
45
        //  add the columns defined in the ON clause to the select list
46
0
        TransformExpressionList(*stmt->distinctClause, modifier->distinct_on_targets);
47
0
      }
48
0
      result->modifiers.push_back(move(modifier));
49
0
    }
50
51
    // do this early so the value lists also have a `FROM`
52
140
    if (stmt->valuesLists) {
53
      // VALUES list, create an ExpressionList
54
0
      D_ASSERT(!stmt->fromClause);
55
0
      result->from_table = TransformValuesList(stmt->valuesLists);
56
0
      result->select_list.push_back(make_unique<StarExpression>());
57
140
    } else {
58
140
      if (!stmt->targetList) {
59
0
        throw ParserException("SELECT clause without selection list");
60
0
      }
61
      // select list
62
140
      TransformExpressionList(*stmt->targetList, result->select_list);
63
140
      result->from_table = TransformFrom(stmt->fromClause);
64
140
    }
65
66
    // where
67
140
    result->where_clause = TransformExpression(stmt->whereClause);
68
    // group by
69
140
    TransformGroupBy(stmt->groupClause, *result);
70
    // having
71
140
    result->having = TransformExpression(stmt->havingClause);
72
    // qualify
73
140
    result->qualify = TransformExpression(stmt->qualifyClause);
74
    // sample
75
140
    result->sample = TransformSampleOptions(stmt->sampleOptions);
76
140
    break;
77
140
  }
78
20
  case duckdb_libpgquery::PG_SETOP_UNION:
79
20
  case duckdb_libpgquery::PG_SETOP_EXCEPT:
80
20
  case duckdb_libpgquery::PG_SETOP_INTERSECT: {
81
20
    node = make_unique<SetOperationNode>();
82
20
    auto result = (SetOperationNode *)node.get();
83
20
    if (stmt->withClause) {
84
0
      TransformCTE(reinterpret_cast<duckdb_libpgquery::PGWithClause *>(stmt->withClause), node->cte_map);
85
0
    }
86
20
    result->left = TransformSelectNode(stmt->larg);
87
20
    result->right = TransformSelectNode(stmt->rarg);
88
20
    if (!result->left || !result->right) {
89
0
      throw Exception("Failed to transform setop children.");
90
0
    }
91
92
20
    bool select_distinct = true;
93
20
    switch (stmt->op) {
94
20
    case duckdb_libpgquery::PG_SETOP_UNION:
95
20
      select_distinct = !stmt->all;
96
20
      result->setop_type = SetOperationType::UNION;
97
20
      break;
98
0
    case duckdb_libpgquery::PG_SETOP_EXCEPT:
99
0
      result->setop_type = SetOperationType::EXCEPT;
100
0
      break;
101
0
    case duckdb_libpgquery::PG_SETOP_INTERSECT:
102
0
      result->setop_type = SetOperationType::INTERSECT;
103
0
      break;
104
0
    default:
105
0
      throw Exception("Unexpected setop type");
106
20
    }
107
20
    if (select_distinct) {
108
0
      result->modifiers.push_back(make_unique<DistinctModifier>());
109
0
    }
110
20
    if (stmt->sampleOptions) {
111
0
      throw ParserException("SAMPLE clause is only allowed in regular SELECT statements");
112
0
    }
113
20
    break;
114
20
  }
115
20
  default:
116
0
    throw NotImplementedException("Statement type %d not implemented!", stmt->op);
117
160
  }
118
  // transform the common properties
119
  // both the set operations and the regular select can have an ORDER BY/LIMIT attached to them
120
160
  vector<OrderByNode> orders;
121
160
  TransformOrderBy(stmt->sortClause, orders);
122
160
  if (!orders.empty()) {
123
0
    auto order_modifier = make_unique<OrderModifier>();
124
0
    order_modifier->orders = move(orders);
125
0
    node->modifiers.push_back(move(order_modifier));
126
0
  }
127
160
  if (stmt->limitCount || stmt->limitOffset) {
128
0
    if (stmt->limitCount && stmt->limitCount->type == duckdb_libpgquery::T_PGLimitPercent) {
129
0
      auto limit_percent_modifier = make_unique<LimitPercentModifier>();
130
0
      auto expr_node = reinterpret_cast<duckdb_libpgquery::PGLimitPercent *>(stmt->limitCount)->limit_percent;
131
0
      limit_percent_modifier->limit = TransformExpression(expr_node);
132
0
      if (stmt->limitOffset) {
133
0
        limit_percent_modifier->offset = TransformExpression(stmt->limitOffset);
134
0
      }
135
0
      node->modifiers.push_back(move(limit_percent_modifier));
136
0
    } else {
137
0
      auto limit_modifier = make_unique<LimitModifier>();
138
0
      if (stmt->limitCount) {
139
0
        limit_modifier->limit = TransformExpression(stmt->limitCount);
140
0
      }
141
0
      if (stmt->limitOffset) {
142
0
        limit_modifier->offset = TransformExpression(stmt->limitOffset);
143
0
      }
144
0
      node->modifiers.push_back(move(limit_modifier));
145
0
    }
146
0
  }
147
160
  return node;
148
160
}
149
150
} // namespace duckdb