1 | #include "duckdb/parser/statement/insert_statement.hpp" |
---|---|
2 | #include "duckdb/parser/statement/update_statement.hpp" |
3 | #include "duckdb/parser/tableref/expressionlistref.hpp" |
4 | #include "duckdb/parser/transformer.hpp" |
5 | |
6 | namespace duckdb { |
7 | |
8 | OnConflictAction TransformOnConflictAction(duckdb_libpgquery::PGOnConflictClause *on_conflict) { |
9 | if (!on_conflict) { |
10 | return OnConflictAction::THROW; |
11 | } |
12 | switch (on_conflict->action) { |
13 | case duckdb_libpgquery::PG_ONCONFLICT_NONE: |
14 | return OnConflictAction::THROW; |
15 | case duckdb_libpgquery::PG_ONCONFLICT_NOTHING: |
16 | return OnConflictAction::NOTHING; |
17 | case duckdb_libpgquery::PG_ONCONFLICT_UPDATE: |
18 | return OnConflictAction::UPDATE; |
19 | default: |
20 | throw InternalException("Type not implemented for OnConflictAction"); |
21 | } |
22 | } |
23 | |
24 | vector<string> Transformer::TransformConflictTarget(duckdb_libpgquery::PGList &list) { |
25 | vector<string> columns; |
26 | for (auto cell = list.head; cell != nullptr; cell = cell->next) { |
27 | auto index_element = PGPointerCast<duckdb_libpgquery::PGIndexElem>(ptr: cell->data.ptr_value); |
28 | if (index_element->collation) { |
29 | throw NotImplementedException("Index with collation not supported yet!"); |
30 | } |
31 | if (index_element->opclass) { |
32 | throw NotImplementedException("Index with opclass not supported yet!"); |
33 | } |
34 | if (!index_element->name) { |
35 | throw NotImplementedException("Non-column index element not supported yet!"); |
36 | } |
37 | if (index_element->nulls_ordering) { |
38 | throw NotImplementedException("Index with null_ordering not supported yet!"); |
39 | } |
40 | if (index_element->ordering) { |
41 | throw NotImplementedException("Index with ordering not supported yet!"); |
42 | } |
43 | columns.emplace_back(args&: index_element->name); |
44 | } |
45 | return columns; |
46 | } |
47 | |
48 | unique_ptr<OnConflictInfo> Transformer::DummyOnConflictClause(duckdb_libpgquery::PGOnConflictActionAlias type, |
49 | const string &relname) { |
50 | switch (type) { |
51 | case duckdb_libpgquery::PGOnConflictActionAlias::PG_ONCONFLICT_ALIAS_REPLACE: { |
52 | // This can not be fully resolved yet until the bind stage |
53 | auto result = make_uniq<OnConflictInfo>(); |
54 | result->action_type = OnConflictAction::REPLACE; |
55 | return result; |
56 | } |
57 | case duckdb_libpgquery::PGOnConflictActionAlias::PG_ONCONFLICT_ALIAS_IGNORE: { |
58 | // We can just fully replace this with DO NOTHING, and be done with it |
59 | auto result = make_uniq<OnConflictInfo>(); |
60 | result->action_type = OnConflictAction::NOTHING; |
61 | return result; |
62 | } |
63 | default: { |
64 | throw InternalException("Type not implemented for PGOnConflictActionAlias"); |
65 | } |
66 | } |
67 | } |
68 | |
69 | unique_ptr<OnConflictInfo> Transformer::TransformOnConflictClause(duckdb_libpgquery::PGOnConflictClause *node, |
70 | const string &relname) { |
71 | auto stmt = reinterpret_cast<duckdb_libpgquery::PGOnConflictClause *>(node); |
72 | D_ASSERT(stmt); |
73 | |
74 | auto result = make_uniq<OnConflictInfo>(); |
75 | result->action_type = TransformOnConflictAction(on_conflict: stmt); |
76 | if (stmt->infer) { |
77 | // A filter for the ON CONFLICT ... is specified |
78 | if (stmt->infer->indexElems) { |
79 | // Columns are specified |
80 | result->indexed_columns = TransformConflictTarget(list&: *stmt->infer->indexElems); |
81 | if (stmt->infer->whereClause) { |
82 | result->condition = TransformExpression(node: stmt->infer->whereClause); |
83 | } |
84 | } else { |
85 | throw NotImplementedException("ON CONSTRAINT conflict target is not supported yet"); |
86 | } |
87 | } |
88 | |
89 | if (result->action_type == OnConflictAction::UPDATE) { |
90 | result->set_info = TransformUpdateSetInfo(target_list: stmt->targetList, where_clause: stmt->whereClause); |
91 | } |
92 | return result; |
93 | } |
94 | |
95 | } // namespace duckdb |
96 |