1 | #include "duckdb/parser/statement/insert_statement.hpp" |
---|---|
2 | #include "duckdb/parser/tableref/expressionlistref.hpp" |
3 | #include "duckdb/parser/transformer.hpp" |
4 | |
5 | namespace duckdb { |
6 | |
7 | unique_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 | |
25 | unique_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 |