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 | shared_ptr<Relation> Relation::Project(const string &select_list) { |
33 | return Project(select_list, aliases: vector<string>()); |
34 | } |
35 | |
36 | shared_ptr<Relation> Relation::Project(const string &expression, const string &alias) { |
37 | return Project(select_list: expression, aliases: vector<string>({alias})); |
38 | } |
39 | |
40 | shared_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 | |
45 | shared_ptr<Relation> Relation::Project(const vector<string> &expressions) { |
46 | vector<string> aliases; |
47 | return Project(expressions, aliases); |
48 | } |
49 | |
50 | static 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 | |
66 | shared_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 | |
71 | shared_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 | |
79 | shared_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 | |
92 | shared_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 | |
96 | shared_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 | |
101 | shared_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 | |
116 | shared_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 | |
140 | shared_ptr<Relation> Relation::CrossProduct(const shared_ptr<Relation> &other) { |
141 | return make_shared<CrossProductRelation>(args: shared_from_this(), args: other); |
142 | } |
143 | |
144 | shared_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 | |
148 | shared_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 | |
152 | shared_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 | |
156 | shared_ptr<Relation> Relation::Distinct() { |
157 | return make_shared<DistinctRelation>(args: shared_from_this()); |
158 | } |
159 | |
160 | shared_ptr<Relation> Relation::Alias(const string &alias) { |
161 | return make_shared<SubqueryRelation>(args: shared_from_this(), args: alias); |
162 | } |
163 | |
164 | shared_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 | |
169 | shared_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 | |
175 | shared_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 | |
180 | shared_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 | |
186 | string Relation::GetAlias() { |
187 | return "relation" ; |
188 | } |
189 | |
190 | unique_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 | |
196 | unique_ptr<QueryResult> Relation::Execute() { |
197 | return context.GetContext()->Execute(relation: shared_from_this()); |
198 | } |
199 | |
200 | unique_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 | |
209 | BoundStatement Relation::Bind(Binder &binder) { |
210 | SelectStatement stmt; |
211 | stmt.node = GetQueryNode(); |
212 | return binder.Bind(statement&: stmt.Cast<SQLStatement>()); |
213 | } |
214 | |
215 | shared_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 | |
219 | void Relation::Insert(const string &table_name) { |
220 | Insert(INVALID_SCHEMA, table_name); |
221 | } |
222 | |
223 | void 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 | |
232 | void 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 | |
238 | shared_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 | |
242 | void Relation::Create(const string &table_name) { |
243 | Create(INVALID_SCHEMA, table_name); |
244 | } |
245 | |
246 | void 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 | |
255 | shared_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 | |
259 | void 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 | |
268 | shared_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 | |
275 | void 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 | |
284 | shared_ptr<Relation> Relation::CreateView(const string &name, bool replace, bool temporary) { |
285 | return CreateView(INVALID_SCHEMA, name, replace, temporary); |
286 | } |
287 | |
288 | shared_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 | |
298 | unique_ptr<QueryResult> Relation::Query(const string &sql) { |
299 | return context.GetContext()->Query(query: sql, allow_stream_result: false); |
300 | } |
301 | |
302 | unique_ptr<QueryResult> Relation::Query(const string &name, const string &sql) { |
303 | CreateView(name); |
304 | return Query(sql); |
305 | } |
306 | |
307 | unique_ptr<QueryResult> Relation::Explain(ExplainType type) { |
308 | auto explain = make_shared<ExplainRelation>(args: shared_from_this(), args&: type); |
309 | return explain->Execute(); |
310 | } |
311 | |
312 | void Relation::Update(const string &update, const string &condition) { |
313 | throw Exception("UPDATE can only be used on base tables!" ); |
314 | } |
315 | |
316 | void Relation::Delete(const string &condition) { |
317 | throw Exception("DELETE can only be used on base tables!" ); |
318 | } |
319 | |
320 | shared_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 | |
326 | shared_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 | |
330 | string 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 |
348 | unique_ptr<QueryNode> Relation::GetQueryNode() { |
349 | throw InternalException("Cannot create a query node from this node type" ); |
350 | } |
351 | |
352 | void Relation::Head(idx_t limit) { |
353 | auto limit_node = Limit(limit); |
354 | limit_node->Execute()->Print(); |
355 | } |
356 | // LCOV_EXCL_STOP |
357 | |
358 | void Relation::Print() { |
359 | Printer::Print(str: ToString()); |
360 | } |
361 | |
362 | string Relation::RenderWhitespace(idx_t depth) { |
363 | return string(depth * 2, ' '); |
364 | } |
365 | |
366 | vector<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 | |