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
7using namespace duckdb;
8using namespace std;
9
10string Transformer::TransformCollation(PGCollateClause *collate) {
11 if (!collate) {
12 return string();
13 }
14 string collation;
15 for (auto c = collate->collname->head; c != NULL; c = lnext(c)) {
16 auto pgvalue = (PGValue *)c->data.ptr_value;
17 if (pgvalue->type != T_PGString) {
18 throw ParserException("Expected a string as collation type!");
19 }
20 auto collation_argument = string(pgvalue->val.str);
21 if (collation.empty()) {
22 collation = collation_argument;
23 } else {
24 collation += "." + collation_argument;
25 }
26 }
27 return collation;
28}
29
30unique_ptr<ParsedExpression> Transformer::TransformCollateExpr(PGCollateClause *collate) {
31 auto child = TransformExpression(collate->arg);
32 auto collation = TransformCollation(collate);
33 return make_unique<CollateExpression>(collation, move(child));
34}
35
36ColumnDefinition Transformer::TransformColumnDefinition(PGColumnDef *cdef) {
37 SQLType target_type = TransformTypeName(cdef->typeName);
38 target_type.collation = TransformCollation(cdef->collClause);
39
40 return ColumnDefinition(cdef->colname, target_type);
41}
42
43unique_ptr<CreateStatement> Transformer::TransformCreateTable(PGNode *node) {
44 auto stmt = reinterpret_cast<PGCreateStmt *>(node);
45 assert(stmt);
46 auto result = make_unique<CreateStatement>();
47 auto info = make_unique<CreateTableInfo>();
48
49 if (stmt->inhRelations) {
50 throw NotImplementedException("inherited relations not implemented");
51 }
52 assert(stmt->relation);
53
54 info->schema = INVALID_SCHEMA;
55 if (stmt->relation->schemaname) {
56 info->schema = stmt->relation->schemaname;
57 }
58 info->table = stmt->relation->relname;
59 info->on_conflict = stmt->if_not_exists ? OnCreateConflict::IGNORE : OnCreateConflict::ERROR;
60 info->temporary = stmt->relation->relpersistence == PGPostgresRelPersistence::PG_RELPERSISTENCE_TEMP;
61
62 if (info->temporary && stmt->oncommit != PGOnCommitAction::PG_ONCOMMIT_PRESERVE_ROWS &&
63 stmt->oncommit != PGOnCommitAction::PG_ONCOMMIT_NOOP) {
64 throw NotImplementedException("Only ON COMMIT PRESERVE ROWS is supported");
65 }
66 if (!stmt->tableElts) {
67 throw ParserException("Table must have at least one column!");
68 }
69
70 for (auto c = stmt->tableElts->head; c != NULL; c = lnext(c)) {
71 auto node = reinterpret_cast<PGNode *>(c->data.ptr_value);
72 switch (node->type) {
73 case T_PGColumnDef: {
74 auto cdef = (PGColumnDef *)c->data.ptr_value;
75 auto centry = TransformColumnDefinition(cdef);
76 if (cdef->constraints) {
77 for (auto constr = cdef->constraints->head; constr != nullptr; constr = constr->next) {
78 auto constraint = TransformConstraint(constr, centry, info->columns.size());
79 if (constraint) {
80 info->constraints.push_back(move(constraint));
81 }
82 }
83 }
84 info->columns.push_back(move(centry));
85 break;
86 }
87 case T_PGConstraint: {
88 info->constraints.push_back(TransformConstraint(c));
89 break;
90 }
91 default:
92 throw NotImplementedException("ColumnDef type not handled yet");
93 }
94 }
95 result->info = move(info);
96 return result;
97}
98