Coverage Report

Created: 2022-08-24 06:40

/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