1 | #include "duckdb/parser/statement/create_statement.hpp" |
---|---|
2 | #include "duckdb/parser/parsed_data/create_sequence_info.hpp" |
3 | #include "duckdb/parser/tableref/basetableref.hpp" |
4 | #include "duckdb/parser/transformer.hpp" |
5 | |
6 | using namespace duckdb; |
7 | using namespace std; |
8 | |
9 | unique_ptr<CreateStatement> Transformer::TransformCreateSequence(PGNode *node) { |
10 | auto stmt = reinterpret_cast<PGCreateSeqStmt *>(node); |
11 | |
12 | auto result = make_unique<CreateStatement>(); |
13 | auto info = make_unique<CreateSequenceInfo>(); |
14 | |
15 | auto sequence_name = TransformRangeVar(stmt->sequence); |
16 | auto &sequence_ref = (BaseTableRef &)*sequence_name; |
17 | info->schema = sequence_ref.schema_name; |
18 | info->name = sequence_ref.table_name; |
19 | |
20 | if (stmt->options) { |
21 | PGListCell *cell = nullptr; |
22 | for_each_cell(cell, stmt->options->head) { |
23 | auto *def_elem = reinterpret_cast<PGDefElem *>(cell->data.ptr_value); |
24 | string opt_name = string(def_elem->defname); |
25 | |
26 | auto val = (PGValue *)def_elem->arg; |
27 | if (def_elem->defaction == PG_DEFELEM_UNSPEC && !val) { // e.g. NO MINVALUE |
28 | continue; |
29 | } |
30 | assert(val); |
31 | |
32 | if (opt_name == "increment") { |
33 | assert(val->type == T_PGInteger); |
34 | info->increment = val->val.ival; |
35 | if (info->increment == 0) { |
36 | throw ParserException("Increment must not be zero"); |
37 | } |
38 | if (info->increment < 0) { |
39 | info->start_value = info->max_value = -1; |
40 | info->min_value = numeric_limits<int64_t>::min(); |
41 | } else { |
42 | info->start_value = info->min_value = 1; |
43 | info->max_value = numeric_limits<int64_t>::max(); |
44 | } |
45 | } else if (opt_name == "minvalue") { |
46 | assert(val->type == T_PGInteger); |
47 | info->min_value = val->val.ival; |
48 | if (info->increment > 0) { |
49 | info->start_value = info->min_value; |
50 | } |
51 | } else if (opt_name == "maxvalue") { |
52 | assert(val->type == T_PGInteger); |
53 | info->max_value = val->val.ival; |
54 | if (info->increment < 0) { |
55 | info->start_value = info->max_value; |
56 | } |
57 | } else if (opt_name == "start") { |
58 | assert(val->type == T_PGInteger); |
59 | info->start_value = val->val.ival; |
60 | } else if (opt_name == "cycle") { |
61 | assert(val->type == T_PGInteger); |
62 | info->cycle = val->val.ival > 0; |
63 | } else { |
64 | throw ParserException("Unrecognized option \"%s\" for CREATE SEQUENCE", opt_name.c_str()); |
65 | } |
66 | } |
67 | } |
68 | info->temporary = !stmt->sequence->relpersistence; |
69 | info->on_conflict = stmt->if_not_exists ? OnCreateConflict::IGNORE : OnCreateConflict::ERROR; |
70 | if (info->max_value <= info->min_value) { |
71 | throw ParserException("MINVALUE (%lld) must be less than MAXVALUE (%lld)", info->min_value, info->max_value); |
72 | } |
73 | if (info->start_value < info->min_value) { |
74 | throw ParserException("START value (%lld) cannot be less than MINVALUE (%lld)", info->start_value, |
75 | info->min_value); |
76 | } |
77 | if (info->start_value > info->max_value) { |
78 | throw ParserException("START value (%lld) cannot be greater than MAXVALUE (%lld)", info->start_value, |
79 | info->max_value); |
80 | } |
81 | result->info = move(info); |
82 | return result; |
83 | } |
84 |