/src/duckdb/src/parser/transform/statement/transform_create_table.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "duckdb/parser/statement/create_statement.hpp" |
2 | | #include "duckdb/parser/parsed_data/create_table_info.hpp" |
3 | | #include "duckdb/parser/transformer.hpp" |
4 | | #include "duckdb/parser/constraint.hpp" |
5 | | #include "duckdb/parser/expression/collate_expression.hpp" |
6 | | #include "duckdb/catalog/catalog_entry/table_column_type.hpp" |
7 | | #include "duckdb/common/case_insensitive_map.hpp" |
8 | | |
9 | | namespace duckdb { |
10 | | |
11 | 0 | string Transformer::TransformCollation(duckdb_libpgquery::PGCollateClause *collate) { |
12 | 0 | if (!collate) { |
13 | 0 | return string(); |
14 | 0 | } |
15 | 0 | string collation; |
16 | 0 | for (auto c = collate->collname->head; c != nullptr; c = lnext(c)) { |
17 | 0 | auto pgvalue = (duckdb_libpgquery::PGValue *)c->data.ptr_value; |
18 | 0 | if (pgvalue->type != duckdb_libpgquery::T_PGString) { |
19 | 0 | throw ParserException("Expected a string as collation type!"); |
20 | 0 | } |
21 | 0 | auto collation_argument = string(pgvalue->val.str); |
22 | 0 | if (collation.empty()) { |
23 | 0 | collation = collation_argument; |
24 | 0 | } else { |
25 | 0 | collation += "." + collation_argument; |
26 | 0 | } |
27 | 0 | } |
28 | 0 | return collation; |
29 | 0 | } |
30 | | |
31 | 2 | OnCreateConflict Transformer::TransformOnConflict(duckdb_libpgquery::PGOnCreateConflict conflict) { |
32 | 2 | switch (conflict) { |
33 | 2 | case duckdb_libpgquery::PG_ERROR_ON_CONFLICT: |
34 | 2 | return OnCreateConflict::ERROR_ON_CONFLICT; |
35 | 0 | case duckdb_libpgquery::PG_IGNORE_ON_CONFLICT: |
36 | 0 | return OnCreateConflict::IGNORE_ON_CONFLICT; |
37 | 0 | case duckdb_libpgquery::PG_REPLACE_ON_CONFLICT: |
38 | 0 | return OnCreateConflict::REPLACE_ON_CONFLICT; |
39 | 0 | default: |
40 | 0 | throw InternalException("Unrecognized OnConflict type"); |
41 | 2 | } |
42 | 2 | } |
43 | | |
44 | 0 | unique_ptr<ParsedExpression> Transformer::TransformCollateExpr(duckdb_libpgquery::PGCollateClause *collate) { |
45 | 0 | auto child = TransformExpression(collate->arg); |
46 | 0 | auto collation = TransformCollation(collate); |
47 | 0 | return make_unique<CollateExpression>(collation, move(child)); |
48 | 0 | } |
49 | | |
50 | 2 | ColumnDefinition Transformer::TransformColumnDefinition(duckdb_libpgquery::PGColumnDef *cdef) { |
51 | 2 | string colname; |
52 | 2 | if (cdef->colname) { |
53 | 2 | colname = cdef->colname; |
54 | 2 | } |
55 | 2 | bool optional_type = cdef->category == duckdb_libpgquery::COL_GENERATED; |
56 | 2 | LogicalType target_type = (optional_type && !cdef->typeName) ? LogicalType::ANY : TransformTypeName(cdef->typeName); |
57 | 2 | if (cdef->collClause) { |
58 | 0 | if (cdef->category == duckdb_libpgquery::COL_GENERATED) { |
59 | 0 | throw ParserException("Collations are not supported on generated columns"); |
60 | 0 | } |
61 | 0 | if (target_type.id() != LogicalTypeId::VARCHAR) { |
62 | 0 | throw ParserException("Only VARCHAR columns can have collations!"); |
63 | 0 | } |
64 | 0 | target_type = LogicalType::VARCHAR_COLLATION(TransformCollation(cdef->collClause)); |
65 | 0 | } |
66 | | |
67 | 2 | return ColumnDefinition(colname, target_type); |
68 | 2 | } |
69 | | |
70 | 2 | unique_ptr<CreateStatement> Transformer::TransformCreateTable(duckdb_libpgquery::PGNode *node) { |
71 | 2 | auto stmt = reinterpret_cast<duckdb_libpgquery::PGCreateStmt *>(node); |
72 | 2 | D_ASSERT(stmt); |
73 | 2 | auto result = make_unique<CreateStatement>(); |
74 | 2 | auto info = make_unique<CreateTableInfo>(); |
75 | | |
76 | 2 | if (stmt->inhRelations) { |
77 | 0 | throw NotImplementedException("inherited relations not implemented"); |
78 | 0 | } |
79 | 2 | D_ASSERT(stmt->relation); |
80 | | |
81 | 2 | info->schema = INVALID_SCHEMA; |
82 | 2 | if (stmt->relation->schemaname) { |
83 | 0 | info->schema = stmt->relation->schemaname; |
84 | 0 | } |
85 | 2 | info->table = stmt->relation->relname; |
86 | 2 | info->on_conflict = TransformOnConflict(stmt->onconflict); |
87 | 2 | info->temporary = |
88 | 2 | stmt->relation->relpersistence == duckdb_libpgquery::PGPostgresRelPersistence::PG_RELPERSISTENCE_TEMP; |
89 | | |
90 | 2 | if (info->temporary && stmt->oncommit != duckdb_libpgquery::PGOnCommitAction::PG_ONCOMMIT_PRESERVE_ROWS && |
91 | 2 | stmt->oncommit != duckdb_libpgquery::PGOnCommitAction::PG_ONCOMMIT_NOOP) { |
92 | 0 | throw NotImplementedException("Only ON COMMIT PRESERVE ROWS is supported"); |
93 | 0 | } |
94 | 2 | if (!stmt->tableElts) { |
95 | 0 | throw ParserException("Table must have at least one column!"); |
96 | 0 | } |
97 | | |
98 | 2 | idx_t column_count = 0; |
99 | 2 | for (auto c = stmt->tableElts->head; c != nullptr; c = lnext(c)) { |
100 | 2 | auto node = reinterpret_cast<duckdb_libpgquery::PGNode *>(c->data.ptr_value); |
101 | 2 | switch (node->type) { |
102 | 2 | case duckdb_libpgquery::T_PGColumnDef: { |
103 | 2 | auto cdef = (duckdb_libpgquery::PGColumnDef *)c->data.ptr_value; |
104 | 2 | auto centry = TransformColumnDefinition(cdef); |
105 | 2 | if (cdef->constraints) { |
106 | 0 | for (auto constr = cdef->constraints->head; constr != nullptr; constr = constr->next) { |
107 | 0 | auto constraint = TransformConstraint(constr, centry, info->columns.size()); |
108 | 0 | if (constraint) { |
109 | 0 | info->constraints.push_back(move(constraint)); |
110 | 0 | } |
111 | 0 | } |
112 | 0 | } |
113 | 2 | info->columns.push_back(move(centry)); |
114 | 2 | column_count++; |
115 | 2 | break; |
116 | 0 | } |
117 | 0 | case duckdb_libpgquery::T_PGConstraint: { |
118 | 0 | info->constraints.push_back(TransformConstraint(c)); |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | default: |
122 | 0 | throw NotImplementedException("ColumnDef type not handled yet"); |
123 | 2 | } |
124 | 2 | } |
125 | | |
126 | 0 | if (!column_count) { |
127 | 0 | throw ParserException("Table must have at least one column!"); |
128 | 0 | } |
129 | | |
130 | 0 | result->info = move(info); |
131 | 0 | return result; |
132 | 0 | } |
133 | | |
134 | | } // namespace duckdb |