| 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 | |