1#include "duckdb/parser/statement/insert_statement.hpp"
2#include "duckdb/parser/tableref/expressionlistref.hpp"
3#include "duckdb/parser/transformer.hpp"
4
5namespace duckdb {
6
7unique_ptr<TableRef> Transformer::TransformValuesList(duckdb_libpgquery::PGList *list) {
8 auto result = make_uniq<ExpressionListRef>();
9 for (auto value_list = list->head; value_list != nullptr; value_list = value_list->next) {
10 auto target = PGPointerCast<duckdb_libpgquery::PGList>(ptr: value_list->data.ptr_value);
11
12 vector<unique_ptr<ParsedExpression>> insert_values;
13 TransformExpressionList(list&: *target, result&: insert_values);
14 if (!result->values.empty()) {
15 if (result->values[0].size() != insert_values.size()) {
16 throw ParserException("VALUES lists must all be the same length");
17 }
18 }
19 result->values.push_back(x: std::move(insert_values));
20 }
21 result->alias = "valueslist";
22 return std::move(result);
23}
24
25unique_ptr<InsertStatement> Transformer::TransformInsert(duckdb_libpgquery::PGInsertStmt &stmt) {
26 auto result = make_uniq<InsertStatement>();
27 if (stmt.withClause) {
28 TransformCTE(de_with_clause&: *PGPointerCast<duckdb_libpgquery::PGWithClause>(ptr: stmt.withClause), cte_map&: result->cte_map);
29 }
30
31 // first check if there are any columns specified
32 if (stmt.cols) {
33 for (auto c = stmt.cols->head; c != nullptr; c = lnext(c)) {
34 auto target = PGPointerCast<duckdb_libpgquery::PGResTarget>(ptr: c->data.ptr_value);
35 result->columns.emplace_back(args&: target->name);
36 }
37 }
38
39 // Grab and transform the returning columns from the parser.
40 if (stmt.returningList) {
41 TransformExpressionList(list&: *stmt.returningList, result&: result->returning_list);
42 }
43 if (stmt.selectStmt) {
44 result->select_statement = TransformSelect(node: stmt.selectStmt, is_select: false);
45 } else {
46 result->default_values = true;
47 }
48
49 auto qname = TransformQualifiedName(root&: *stmt.relation);
50 result->table = qname.name;
51 result->schema = qname.schema;
52
53 if (stmt.onConflictClause) {
54 if (stmt.onConflictAlias != duckdb_libpgquery::PG_ONCONFLICT_ALIAS_NONE) {
55 // OR REPLACE | OR IGNORE are shorthands for the ON CONFLICT clause
56 throw ParserException("You can not provide both OR REPLACE|IGNORE and an ON CONFLICT clause, please remove "
57 "the first if you want to have more granual control");
58 }
59 result->on_conflict_info = TransformOnConflictClause(node: stmt.onConflictClause, relname: result->schema);
60 result->table_ref = TransformRangeVar(root&: *stmt.relation);
61 }
62 if (stmt.onConflictAlias != duckdb_libpgquery::PG_ONCONFLICT_ALIAS_NONE) {
63 D_ASSERT(!stmt.onConflictClause);
64 result->on_conflict_info = DummyOnConflictClause(type: stmt.onConflictAlias, relname: result->schema);
65 result->table_ref = TransformRangeVar(root&: *stmt.relation);
66 }
67 switch (stmt.insert_column_order) {
68 case duckdb_libpgquery::PG_INSERT_BY_POSITION:
69 result->column_order = InsertColumnOrder::INSERT_BY_POSITION;
70 break;
71 case duckdb_libpgquery::PG_INSERT_BY_NAME:
72 result->column_order = InsertColumnOrder::INSERT_BY_NAME;
73 break;
74 default:
75 throw InternalException("Unrecognized insert column order in TransformInsert");
76 }
77 result->catalog = qname.catalog;
78 return result;
79}
80
81} // namespace duckdb
82