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