Coverage Report

Created: 2024-09-08 07:45

/src/duckdb/src/main/relation.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "duckdb/main/relation.hpp"
2
#include "duckdb/common/printer.hpp"
3
#include "duckdb/parser/parser.hpp"
4
#include "duckdb/main/relation/aggregate_relation.hpp"
5
#include "duckdb/main/relation/cross_product_relation.hpp"
6
#include "duckdb/main/relation/distinct_relation.hpp"
7
#include "duckdb/main/relation/explain_relation.hpp"
8
#include "duckdb/main/relation/filter_relation.hpp"
9
#include "duckdb/main/relation/insert_relation.hpp"
10
#include "duckdb/main/relation/limit_relation.hpp"
11
#include "duckdb/main/relation/order_relation.hpp"
12
#include "duckdb/main/relation/projection_relation.hpp"
13
#include "duckdb/main/relation/setop_relation.hpp"
14
#include "duckdb/main/relation/subquery_relation.hpp"
15
#include "duckdb/main/relation/table_function_relation.hpp"
16
#include "duckdb/main/relation/create_table_relation.hpp"
17
#include "duckdb/main/relation/create_view_relation.hpp"
18
#include "duckdb/main/relation/write_csv_relation.hpp"
19
#include "duckdb/main/relation/write_parquet_relation.hpp"
20
#include "duckdb/main/client_context.hpp"
21
#include "duckdb/planner/binder.hpp"
22
#include "duckdb/parser/tableref/subqueryref.hpp"
23
#include "duckdb/parser/statement/select_statement.hpp"
24
#include "duckdb/parser/expression/conjunction_expression.hpp"
25
#include "duckdb/parser/expression/columnref_expression.hpp"
26
#include "duckdb/main/relation/join_relation.hpp"
27
#include "duckdb/main/relation/value_relation.hpp"
28
#include "duckdb/parser/statement/explain_statement.hpp"
29
30
namespace duckdb {
31
32
0
shared_ptr<Relation> Relation::Project(const string &select_list) {
33
0
  return Project(select_list, vector<string>());
34
0
}
35
36
0
shared_ptr<Relation> Relation::Project(const string &expression, const string &alias) {
37
0
  return Project(expression, vector<string>({alias}));
38
0
}
39
40
0
shared_ptr<Relation> Relation::Project(const string &select_list, const vector<string> &aliases) {
41
0
  auto expressions = Parser::ParseExpressionList(select_list, context.GetContext()->GetParserOptions());
42
0
  return make_shared_ptr<ProjectionRelation>(shared_from_this(), std::move(expressions), aliases);
43
0
}
44
45
0
shared_ptr<Relation> Relation::Project(const vector<string> &expressions) {
46
0
  vector<string> aliases;
47
0
  return Project(expressions, aliases);
48
0
}
49
50
shared_ptr<Relation> Relation::Project(vector<unique_ptr<ParsedExpression>> expressions,
51
0
                                       const vector<string> &aliases) {
52
0
  return make_shared_ptr<ProjectionRelation>(shared_from_this(), std::move(expressions), aliases);
53
0
}
54
55
static vector<unique_ptr<ParsedExpression>> StringListToExpressionList(ClientContext &context,
56
0
                                                                       const vector<string> &expressions) {
57
0
  if (expressions.empty()) {
58
0
    throw ParserException("Zero expressions provided");
59
0
  }
60
0
  vector<unique_ptr<ParsedExpression>> result_list;
61
0
  for (auto &expr : expressions) {
62
0
    auto expression_list = Parser::ParseExpressionList(expr, context.GetParserOptions());
63
0
    if (expression_list.size() != 1) {
64
0
      throw ParserException("Expected a single expression in the expression list");
65
0
    }
66
0
    result_list.push_back(std::move(expression_list[0]));
67
0
  }
68
0
  return result_list;
69
0
}
70
71
0
shared_ptr<Relation> Relation::Project(const vector<string> &expressions, const vector<string> &aliases) {
72
0
  auto result_list = StringListToExpressionList(*context.GetContext(), expressions);
73
0
  return make_shared_ptr<ProjectionRelation>(shared_from_this(), std::move(result_list), aliases);
74
0
}
75
76
0
shared_ptr<Relation> Relation::Filter(const string &expression) {
77
0
  auto expression_list = Parser::ParseExpressionList(expression, context.GetContext()->GetParserOptions());
78
0
  if (expression_list.size() != 1) {
79
0
    throw ParserException("Expected a single expression as filter condition");
80
0
  }
81
0
  return Filter(std::move(expression_list[0]));
82
0
}
83
84
0
shared_ptr<Relation> Relation::Filter(unique_ptr<ParsedExpression> expression) {
85
0
  return make_shared_ptr<FilterRelation>(shared_from_this(), std::move(expression));
86
0
}
87
88
0
shared_ptr<Relation> Relation::Filter(const vector<string> &expressions) {
89
  // if there are multiple expressions, we AND them together
90
0
  auto expression_list = StringListToExpressionList(*context.GetContext(), expressions);
91
0
  D_ASSERT(!expression_list.empty());
92
93
0
  auto expr = std::move(expression_list[0]);
94
0
  for (idx_t i = 1; i < expression_list.size(); i++) {
95
0
    expr = make_uniq<ConjunctionExpression>(ExpressionType::CONJUNCTION_AND, std::move(expr),
96
0
                                            std::move(expression_list[i]));
97
0
  }
98
0
  return make_shared_ptr<FilterRelation>(shared_from_this(), std::move(expr));
99
0
}
100
101
0
shared_ptr<Relation> Relation::Limit(int64_t limit, int64_t offset) {
102
0
  return make_shared_ptr<LimitRelation>(shared_from_this(), limit, offset);
103
0
}
104
105
0
shared_ptr<Relation> Relation::Order(const string &expression) {
106
0
  auto order_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions());
107
0
  return Order(std::move(order_list));
108
0
}
109
110
0
shared_ptr<Relation> Relation::Order(vector<OrderByNode> order_list) {
111
0
  return make_shared_ptr<OrderRelation>(shared_from_this(), std::move(order_list));
112
0
}
113
114
0
shared_ptr<Relation> Relation::Order(const vector<string> &expressions) {
115
0
  if (expressions.empty()) {
116
0
    throw ParserException("Zero ORDER BY expressions provided");
117
0
  }
118
0
  vector<OrderByNode> order_list;
119
0
  for (auto &expression : expressions) {
120
0
    auto inner_list = Parser::ParseOrderList(expression, context.GetContext()->GetParserOptions());
121
0
    if (inner_list.size() != 1) {
122
0
      throw ParserException("Expected a single ORDER BY expression in the expression list");
123
0
    }
124
0
    order_list.push_back(std::move(inner_list[0]));
125
0
  }
126
0
  return Order(std::move(order_list));
127
0
}
128
129
shared_ptr<Relation> Relation::Join(const shared_ptr<Relation> &other, const string &condition, JoinType type,
130
0
                                    JoinRefType ref_type) {
131
0
  auto expression_list = Parser::ParseExpressionList(condition, context.GetContext()->GetParserOptions());
132
0
  D_ASSERT(!expression_list.empty());
133
0
  return Join(other, std::move(expression_list), type, ref_type);
134
0
}
135
136
shared_ptr<Relation> Relation::Join(const shared_ptr<Relation> &other,
137
                                    vector<unique_ptr<ParsedExpression>> expression_list, JoinType type,
138
0
                                    JoinRefType ref_type) {
139
0
  if (expression_list.size() > 1 || expression_list[0]->type == ExpressionType::COLUMN_REF) {
140
    // multiple columns or single column ref: the condition is a USING list
141
0
    vector<string> using_columns;
142
0
    for (auto &expr : expression_list) {
143
0
      if (expr->type != ExpressionType::COLUMN_REF) {
144
0
        throw ParserException("Expected a single expression as join condition");
145
0
      }
146
0
      auto &colref = expr->Cast<ColumnRefExpression>();
147
0
      if (colref.IsQualified()) {
148
0
        throw ParserException("Expected unqualified column for column in USING clause");
149
0
      }
150
0
      using_columns.push_back(colref.column_names[0]);
151
0
    }
152
0
    return make_shared_ptr<JoinRelation>(shared_from_this(), other, std::move(using_columns), type, ref_type);
153
0
  } else {
154
    // single expression that is not a column reference: use the expression as a join condition
155
0
    return make_shared_ptr<JoinRelation>(shared_from_this(), other, std::move(expression_list[0]), type, ref_type);
156
0
  }
157
0
}
158
159
0
shared_ptr<Relation> Relation::CrossProduct(const shared_ptr<Relation> &other, JoinRefType join_ref_type) {
160
0
  return make_shared_ptr<CrossProductRelation>(shared_from_this(), other, join_ref_type);
161
0
}
162
163
0
shared_ptr<Relation> Relation::Union(const shared_ptr<Relation> &other) {
164
0
  return make_shared_ptr<SetOpRelation>(shared_from_this(), other, SetOperationType::UNION, true);
165
0
}
166
167
0
shared_ptr<Relation> Relation::Except(const shared_ptr<Relation> &other) {
168
0
  return make_shared_ptr<SetOpRelation>(shared_from_this(), other, SetOperationType::EXCEPT, true);
169
0
}
170
171
0
shared_ptr<Relation> Relation::Intersect(const shared_ptr<Relation> &other) {
172
0
  return make_shared_ptr<SetOpRelation>(shared_from_this(), other, SetOperationType::INTERSECT, true);
173
0
}
174
175
0
shared_ptr<Relation> Relation::Distinct() {
176
0
  return make_shared_ptr<DistinctRelation>(shared_from_this());
177
0
}
178
179
0
shared_ptr<Relation> Relation::Alias(const string &alias) {
180
0
  return make_shared_ptr<SubqueryRelation>(shared_from_this(), alias);
181
0
}
182
183
0
shared_ptr<Relation> Relation::Aggregate(const string &aggregate_list) {
184
0
  auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions());
185
0
  return make_shared_ptr<AggregateRelation>(shared_from_this(), std::move(expression_list));
186
0
}
187
188
0
shared_ptr<Relation> Relation::Aggregate(vector<unique_ptr<ParsedExpression>> expressions) {
189
0
  return make_shared_ptr<AggregateRelation>(shared_from_this(), std::move(expressions));
190
0
}
191
192
0
shared_ptr<Relation> Relation::Aggregate(const string &aggregate_list, const string &group_list) {
193
0
  auto expression_list = Parser::ParseExpressionList(aggregate_list, context.GetContext()->GetParserOptions());
194
0
  auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions());
195
0
  return make_shared_ptr<AggregateRelation>(shared_from_this(), std::move(expression_list), std::move(groups));
196
0
}
197
198
0
shared_ptr<Relation> Relation::Aggregate(const vector<string> &aggregates) {
199
0
  auto aggregate_list = StringListToExpressionList(*context.GetContext(), aggregates);
200
0
  return make_shared_ptr<AggregateRelation>(shared_from_this(), std::move(aggregate_list));
201
0
}
202
203
0
shared_ptr<Relation> Relation::Aggregate(const vector<string> &aggregates, const vector<string> &groups) {
204
0
  auto aggregate_list = StringUtil::Join(aggregates, ", ");
205
0
  auto group_list = StringUtil::Join(groups, ", ");
206
0
  return this->Aggregate(aggregate_list, group_list);
207
0
}
208
209
0
shared_ptr<Relation> Relation::Aggregate(vector<unique_ptr<ParsedExpression>> expressions, const string &group_list) {
210
0
  auto groups = Parser::ParseGroupByList(group_list, context.GetContext()->GetParserOptions());
211
0
  return make_shared_ptr<AggregateRelation>(shared_from_this(), std::move(expressions), std::move(groups));
212
0
}
213
214
0
string Relation::GetAlias() {
215
0
  return "relation";
216
0
}
217
218
0
unique_ptr<TableRef> Relation::GetTableRef() {
219
0
  auto select = make_uniq<SelectStatement>();
220
0
  select->node = GetQueryNode();
221
0
  return make_uniq<SubqueryRef>(std::move(select), GetAlias());
222
0
}
223
224
0
unique_ptr<QueryResult> Relation::Execute() {
225
0
  return context.GetContext()->Execute(shared_from_this());
226
0
}
227
228
0
unique_ptr<QueryResult> Relation::ExecuteOrThrow() {
229
0
  auto res = Execute();
230
0
  D_ASSERT(res);
231
0
  if (res->HasError()) {
232
0
    res->ThrowError();
233
0
  }
234
0
  return res;
235
0
}
236
237
0
BoundStatement Relation::Bind(Binder &binder) {
238
0
  SelectStatement stmt;
239
0
  stmt.node = GetQueryNode();
240
0
  return binder.Bind(stmt.Cast<SQLStatement>());
241
0
}
242
243
0
shared_ptr<Relation> Relation::InsertRel(const string &schema_name, const string &table_name) {
244
0
  return make_shared_ptr<InsertRelation>(shared_from_this(), schema_name, table_name);
245
0
}
246
247
0
void Relation::Insert(const string &table_name) {
248
0
  Insert(INVALID_SCHEMA, table_name);
249
0
}
250
251
0
void Relation::Insert(const string &schema_name, const string &table_name) {
252
0
  auto insert = InsertRel(schema_name, table_name);
253
0
  auto res = insert->Execute();
254
0
  if (res->HasError()) {
255
0
    const string prepended_message = "Failed to insert into table '" + table_name + "': ";
256
0
    res->ThrowError(prepended_message);
257
0
  }
258
0
}
259
260
0
void Relation::Insert(const vector<vector<Value>> &values) {
261
0
  vector<string> column_names;
262
0
  auto rel = make_shared_ptr<ValueRelation>(context.GetContext(), values, std::move(column_names), "values");
263
0
  rel->Insert(GetAlias());
264
0
}
265
266
0
shared_ptr<Relation> Relation::CreateRel(const string &schema_name, const string &table_name, bool temporary) {
267
0
  return make_shared_ptr<CreateTableRelation>(shared_from_this(), schema_name, table_name, temporary);
268
0
}
269
270
0
void Relation::Create(const string &table_name, bool temporary) {
271
0
  Create(INVALID_SCHEMA, table_name, temporary);
272
0
}
273
274
0
void Relation::Create(const string &schema_name, const string &table_name, bool temporary) {
275
0
  auto create = CreateRel(schema_name, table_name, temporary);
276
0
  auto res = create->Execute();
277
0
  if (res->HasError()) {
278
0
    const string prepended_message = "Failed to create table '" + table_name + "': ";
279
0
    res->ThrowError(prepended_message);
280
0
  }
281
0
}
282
283
0
shared_ptr<Relation> Relation::WriteCSVRel(const string &csv_file, case_insensitive_map_t<vector<Value>> options) {
284
0
  return make_shared_ptr<duckdb::WriteCSVRelation>(shared_from_this(), csv_file, std::move(options));
285
0
}
286
287
0
void Relation::WriteCSV(const string &csv_file, case_insensitive_map_t<vector<Value>> options) {
288
0
  auto write_csv = WriteCSVRel(csv_file, std::move(options));
289
0
  auto res = write_csv->Execute();
290
0
  if (res->HasError()) {
291
0
    const string prepended_message = "Failed to write '" + csv_file + "': ";
292
0
    res->ThrowError(prepended_message);
293
0
  }
294
0
}
295
296
shared_ptr<Relation> Relation::WriteParquetRel(const string &parquet_file,
297
0
                                               case_insensitive_map_t<vector<Value>> options) {
298
0
  auto write_parquet =
299
0
      make_shared_ptr<duckdb::WriteParquetRelation>(shared_from_this(), parquet_file, std::move(options));
300
0
  return std::move(write_parquet);
301
0
}
302
303
0
void Relation::WriteParquet(const string &parquet_file, case_insensitive_map_t<vector<Value>> options) {
304
0
  auto write_parquet = WriteParquetRel(parquet_file, std::move(options));
305
0
  auto res = write_parquet->Execute();
306
0
  if (res->HasError()) {
307
0
    const string prepended_message = "Failed to write '" + parquet_file + "': ";
308
0
    res->ThrowError(prepended_message);
309
0
  }
310
0
}
311
312
0
shared_ptr<Relation> Relation::CreateView(const string &name, bool replace, bool temporary) {
313
0
  return CreateView(INVALID_SCHEMA, name, replace, temporary);
314
0
}
315
316
0
shared_ptr<Relation> Relation::CreateView(const string &schema_name, const string &name, bool replace, bool temporary) {
317
0
  auto view = make_shared_ptr<CreateViewRelation>(shared_from_this(), schema_name, name, replace, temporary);
318
0
  auto res = view->Execute();
319
0
  if (res->HasError()) {
320
0
    const string prepended_message = "Failed to create view '" + name + "': ";
321
0
    res->ThrowError(prepended_message);
322
0
  }
323
0
  return shared_from_this();
324
0
}
325
326
0
unique_ptr<QueryResult> Relation::Query(const string &sql) {
327
0
  return context.GetContext()->Query(sql, false);
328
0
}
329
330
0
unique_ptr<QueryResult> Relation::Query(const string &name, const string &sql) {
331
0
  CreateView(name);
332
0
  return Query(sql);
333
0
}
334
335
0
unique_ptr<QueryResult> Relation::Explain(ExplainType type, ExplainFormat format) {
336
0
  auto explain = make_shared_ptr<ExplainRelation>(shared_from_this(), type, format);
337
0
  return explain->Execute();
338
0
}
339
340
0
void Relation::Update(const string &update, const string &condition) {
341
0
  throw InvalidInputException("UPDATE can only be used on base tables!");
342
0
}
343
344
0
void Relation::Delete(const string &condition) {
345
0
  throw InvalidInputException("DELETE can only be used on base tables!");
346
0
}
347
348
shared_ptr<Relation> Relation::TableFunction(const std::string &fname, const vector<Value> &values,
349
0
                                             const named_parameter_map_t &named_parameters) {
350
0
  return make_shared_ptr<TableFunctionRelation>(context.GetContext(), fname, values, named_parameters,
351
0
                                                shared_from_this());
352
0
}
353
354
0
shared_ptr<Relation> Relation::TableFunction(const std::string &fname, const vector<Value> &values) {
355
0
  return make_shared_ptr<TableFunctionRelation>(context.GetContext(), fname, values, shared_from_this());
356
0
}
357
358
0
string Relation::ToString() {
359
0
  string str;
360
0
  str += "---------------------\n";
361
0
  str += "--- Relation Tree ---\n";
362
0
  str += "---------------------\n";
363
0
  str += ToString(0);
364
0
  str += "\n\n";
365
0
  str += "---------------------\n";
366
0
  str += "-- Result Columns  --\n";
367
0
  str += "---------------------\n";
368
0
  auto &cols = Columns();
369
0
  for (idx_t i = 0; i < cols.size(); i++) {
370
0
    str += "- " + cols[i].Name() + " (" + cols[i].Type().ToString() + ")\n";
371
0
  }
372
0
  return str;
373
0
}
374
375
// LCOV_EXCL_START
376
0
unique_ptr<QueryNode> Relation::GetQueryNode() {
377
0
  throw InternalException("Cannot create a query node from this node type");
378
0
}
379
380
0
void Relation::Head(idx_t limit) {
381
0
  auto limit_node = Limit(NumericCast<int64_t>(limit));
382
0
  limit_node->Execute()->Print();
383
0
}
384
// LCOV_EXCL_STOP
385
386
0
void Relation::Print() {
387
0
  Printer::Print(ToString());
388
0
}
389
390
0
string Relation::RenderWhitespace(idx_t depth) {
391
0
  return string(depth * 2, ' ');
392
0
}
393
394
0
void Relation::AddExternalDependency(shared_ptr<ExternalDependency> dependency) {
395
0
  external_dependencies.push_back(std::move(dependency));
396
0
}
397
398
0
vector<shared_ptr<ExternalDependency>> Relation::GetAllDependencies() {
399
0
  vector<shared_ptr<ExternalDependency>> all_dependencies;
400
0
  Relation *cur = this;
401
0
  while (cur) {
402
0
    for (auto &dep : cur->external_dependencies) {
403
0
      all_dependencies.push_back(dep);
404
0
    }
405
0
    cur = cur->ChildRelation();
406
0
  }
407
0
  return all_dependencies;
408
0
}
409
410
} // namespace duckdb