1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#include "rel_select.h"
11#include "rel_rel.h"
12#include "rel_sequence.h"
13#include "rel_exp.h"
14#include "sql_privileges.h"
15
16char*
17sql_next_seq_name(mvc *m)
18{
19 sqlid id = store_next_oid();
20 size_t len = 5 + 10; /* max nr of digits of (4 bytes) int is 10 */
21 char *msg = sa_alloc(m->sa, len);
22
23 snprintf(msg, len, "seq_%d", id);
24 return msg;
25}
26
27static sql_rel *
28rel_drop_seq(sql_allocator *sa, char *sname, char *seqname)
29{
30 sql_rel *rel = rel_create(sa);
31 list *exps = new_exp_list(sa);
32 if(!rel || !exps)
33 return NULL;
34
35 append(exps, exp_atom_clob(sa, sname));
36 append(exps, exp_atom_clob(sa, seqname));
37 append(exps, exp_atom_int(sa, 0));
38 rel->l = NULL;
39 rel->r = NULL;
40 rel->op = op_ddl;
41 rel->flag = ddl_drop_seq;
42 rel->exps = exps;
43 rel->card = 0;
44 rel->nrcols = 0;
45 return rel;
46}
47
48static sql_rel *
49rel_seq(sql_allocator *sa, int cat_type, char *sname, sql_sequence *s, sql_rel *r, sql_exp *val)
50{
51 sql_rel *rel = rel_create(sa);
52 list *exps = new_exp_list(sa);
53 if(!rel || !exps)
54 return NULL;
55
56 if (val)
57 append(exps, val);
58 else
59 append(exps, exp_atom_int(sa, 0));
60 append(exps, exp_atom_str(sa, sname, sql_bind_localtype("str") ));
61 append(exps, exp_atom_str(sa, s->base.name, sql_bind_localtype("str") ));
62 append(exps, exp_atom_ptr(sa, s));
63 rel->l = r;
64 rel->r = NULL;
65 rel->op = op_ddl;
66 rel->flag = cat_type;
67 rel->exps = exps;
68 rel->card = CARD_MULTI;
69 rel->nrcols = 0;
70 return rel;
71}
72
73static sql_rel *
74rel_create_seq(
75 mvc *sql,
76 sql_schema *ss,
77 dlist *qname,
78 sql_subtype *tpe,
79 lng start,
80 lng inc,
81 lng min,
82 lng max,
83 lng cache,
84 bit cycle,
85 bit bedropped)
86{
87 sql_rel *res = NULL;
88 sql_sequence *seq = NULL;
89 char *name = qname_table(qname);
90 char *sname = qname_schema(qname);
91 sql_schema *s = NULL;
92
93 if (sname && !(s = mvc_bind_schema(sql, sname)))
94 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: no such schema '%s'", sname);
95 if (s == NULL)
96 s = ss;
97 (void) tpe;
98 if (find_sql_sequence(s, name)) {
99 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: name '%s' already in use", name);
100 } else if (!mvc_schema_privs(sql, s)) {
101 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: insufficient privileges "
102 "for '%s' in schema '%s'", stack_get_string(sql, "current_user"), s->base.name);
103 }
104
105 /* generate defaults */
106 if (is_lng_nil(start)) start = 1;
107 if (is_lng_nil(inc)) inc = 1;
108 if (is_lng_nil(min)) min = 0;
109 if (cycle && (!is_lng_nil(max) && max < 0)) cycle = 0;
110 if (is_lng_nil(max)) max = 0;
111 if (is_lng_nil(cache)) cache = 1;
112
113 seq = create_sql_sequence(sql->sa, s, name, start, min, max, inc, cache, cycle);
114 seq->bedropped = bedropped;
115 res = rel_seq(sql->sa, ddl_create_seq, s->base.name, seq, NULL, NULL);
116 /* for multi statements we keep the sequence around */
117 if (res && stack_has_frame(sql, "MUL") != 0) {
118 if(!stack_push_rel_view(sql, name, rel_dup(res)))
119 return sql_error(sql, 02, SQLSTATE(HY001) MAL_MALLOC_FAIL);
120 }
121
122 return res;
123}
124
125#define SEQ_TYPE 0
126#define SEQ_START 1
127#define SEQ_INC 2
128#define SEQ_MIN 3
129#define SEQ_MAX 4
130#define SEQ_CYCLE 5
131#define SEQ_CACHE 6
132
133static sql_rel *
134list_create_seq(
135 mvc *sql,
136 sql_schema *ss,
137 dlist *qname,
138 dlist *options,
139 bit bedropped)
140{
141 dnode *n;
142 sql_subtype *t = NULL;
143 lng start = lng_nil, inc = lng_nil, min = lng_nil, max = lng_nil, cache = lng_nil;
144 unsigned int used = 0;
145 bit cycle = 0;
146
147 if (options) {
148 /* check if no option is given twice */
149 for (n = options->h; n; n = n->next) {
150 symbol *s = n->data.sym;
151
152 switch(s->token) {
153 case SQL_TYPE: {
154 bool found = false;
155 const char *valid_types[4] = {"tinyint", "smallint", "int", "bigint"};
156 size_t number_valid_types = sizeof(valid_types) / sizeof(valid_types[0]);
157
158 if ((used&(1<<SEQ_TYPE)))
159 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: AS type found should be used as most once");
160 used |= (1<<SEQ_TYPE);
161 t = &s->data.lval->h->data.typeval;
162 for (size_t i = 0; i < number_valid_types; i++) {
163 if (strcasecmp(valid_types[i], t->type->sqlname) == 0) {
164 found = true;
165 break;
166 }
167 }
168 if (!found)
169 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: The type of the sequence must be either tinyint, smallint, int or bigint");
170 } break;
171 case SQL_START:
172 if ((used&(1<<SEQ_START)))
173 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: START value should be passed as most once");
174 used |= (1<<SEQ_START);
175 if (is_lng_nil(s->data.l_val))
176 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START must not be null");
177 start = s->data.l_val;
178 break;
179 case SQL_INC:
180 if ((used&(1<<SEQ_INC)))
181 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: INCREMENT value should be passed as most once");
182 used |= (1<<SEQ_INC);
183 if (is_lng_nil(s->data.l_val))
184 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: INCREMENT must not be null");
185 inc = s->data.l_val;
186 break;
187 case SQL_MINVALUE:
188 if ((used&(1<<SEQ_MIN)))
189 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: MINVALUE or NO MINVALUE should be passed as most once");
190 used |= (1<<SEQ_MIN);
191 if (is_lng_nil(s->data.l_val))
192 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MINVALUE must not be null");
193 min = s->data.l_val;
194 break;
195 case SQL_MAXVALUE:
196 if ((used&(1<<SEQ_MAX)))
197 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: MAXVALUE or NO MAXVALUE should be passed as most once");
198 used |= (1<<SEQ_MAX);
199 if (is_lng_nil(s->data.l_val))
200 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MAXVALUE must be non-NULL");
201 max = s->data.l_val;
202 break;
203 case SQL_CYCLE:
204 if ((used&(1<<SEQ_CYCLE)))
205 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: CYCLE or NO CYCLE should be passed as most once");
206 used |= (1<<SEQ_CYCLE);
207 cycle = s->data.i_val != 0;
208 break;
209 case SQL_CACHE:
210 if ((used&(1<<SEQ_CACHE)))
211 return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SEQUENCE: CACHE value should be passed as most once");
212 used |= (1<<SEQ_CACHE);
213 if (is_lng_nil(s->data.l_val))
214 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: CACHE must be non-NULL");
215 cache = s->data.l_val;
216 break;
217 default:
218 assert(0);
219 }
220 }
221 if (!is_lng_nil(start)) {
222 if (!is_lng_nil(min) && start < min)
223 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START value is lesser than MINVALUE ("LLFMT" < "LLFMT")", start, min);
224 if (!is_lng_nil(max) && start > max)
225 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: START value is higher than MAXVALUE ("LLFMT" > "LLFMT")", start, max);
226 }
227 if (!is_lng_nil(min) && !is_lng_nil(max) && max < min)
228 return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: MAXVALUE value is lesser than MINVALUE ("LLFMT" < "LLFMT")", max, min);
229 }
230 if (is_lng_nil(start) && !is_lng_nil(min) && min) /* if start value not set, set it to the minimum if available */
231 start = min;
232 return rel_create_seq(sql, ss, qname, t, start, inc, min, max, cache, cycle, bedropped);
233}
234
235static sql_rel *
236rel_alter_seq(
237 sql_query *query,
238 sql_schema *ss,
239 dlist *qname,
240 sql_subtype *tpe,
241 dlist* start_list,
242 lng inc,
243 lng min,
244 lng max,
245 lng cache,
246 bit cycle)
247{
248 mvc *sql = query->sql;
249 char* name = qname_table(qname);
250 char *sname = qname_schema(qname);
251 sql_sequence *seq;
252 sql_schema *s = NULL;
253
254 int start_type = start_list->h->data.i_val;
255 sql_rel *r = NULL;
256 sql_exp *val = NULL;
257
258 assert(start_list->h->type == type_int);
259 if (sname && !(s = mvc_bind_schema(sql, sname)))
260 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: no such schema '%s'", sname);
261 if (!s)
262 s = ss;
263 (void) tpe;
264 if (!(seq = find_sql_sequence(s, name))) {
265 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: no such sequence '%s'", name);
266 }
267 if (!mvc_schema_privs(sql, s)) {
268 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: insufficient privileges "
269 "for '%s' in schema '%s'", stack_get_string(sql, "current_user"), s->base.name);
270 }
271
272 /* first alter the known values */
273 seq = create_sql_sequence(sql->sa, s, name, seq->start, min, max, inc, cache, (bit) cycle);
274
275 /* restart may be a query, i.e. we create a statement
276 restart(ssname,seqname,value) */
277
278 if (start_type == 0) {
279 val = exp_atom_lng(sql->sa, seq->start);
280 } else if (start_type == 1) { /* value (exp) */
281 exp_kind ek = {type_value, card_value, FALSE};
282 int is_last = 0;
283 sql_subtype *lng_t = sql_bind_localtype("lng");
284
285 val = rel_value_exp2(query, &r, start_list->h->next->data.sym, sql_sel, ek, &is_last);
286 if (!val || !(val = rel_check_type(sql, lng_t, r, val, type_equal)))
287 return NULL;
288 if (r && r->op == op_project) {
289 exp_label(sql->sa, val, ++sql->label);
290 val = rel_project_add_exp(sql, r, val);
291 }
292 } else if (start_type == 2) {
293 assert (start_list->h->next->type == type_lng);
294 val = exp_atom_lng(sql->sa, start_list->h->next->data.l_val);
295 }
296 if (val && val->card > CARD_ATOM) {
297 sql_subaggr *zero_or_one = sql_bind_aggr(sql->sa, sql->session->schema, "zero_or_one", exp_subtype(val));
298 val = exp_aggr1(sql->sa, val, zero_or_one, 0, 0, CARD_ATOM, 0);
299 }
300 return rel_seq(sql->sa, ddl_alter_seq, s->base.name, seq, r, val);
301}
302
303static sql_rel *
304list_alter_seq(
305 sql_query *query,
306 sql_schema *ss,
307 dlist *qname,
308 dlist *options)
309{
310 mvc *sql = query->sql;
311 dnode *n;
312 sql_subtype* t = NULL;
313 lng inc = lng_nil, min = lng_nil, max = lng_nil, cache = lng_nil;
314 dlist *start = NULL;
315 unsigned int used = 0;
316 bit cycle = 0;
317
318 /* check if no option is given twice */
319 for (n = options->h; n; n = n->next) {
320 symbol *s = n->data.sym;
321
322 switch(s->token) {
323 case SQL_TYPE:
324 if ((used&(1<<SEQ_TYPE)))
325 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: AS type found should be used as most once");
326 used |= (1<<SEQ_TYPE);
327 t = &s->data.lval->h->data.typeval;
328 break;
329 case SQL_START:
330 if ((used&(1<<SEQ_START)))
331 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: START value should be passed as most once");
332 used |= (1<<SEQ_START);
333 if (is_lng_nil(s->data.l_val))
334 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: START must be non-NULL");
335 start = s->data.lval;
336 break;
337 case SQL_INC:
338 if ((used&(1<<SEQ_INC)))
339 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: INCREMENT value should be passed as most once");
340 used |= (1<<SEQ_INC);
341 if (is_lng_nil(s->data.l_val))
342 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: INCREMENT must be non-NULL");
343 inc = s->data.l_val;
344 break;
345 case SQL_MINVALUE:
346 if ((used&(1<<SEQ_MIN)))
347 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: MINVALUE or NO MINVALUE should be passed as most once");
348 used |= (1<<SEQ_MIN);
349 if (is_lng_nil(s->data.l_val))
350 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MINVALUE must be non-NULL");
351 min = s->data.l_val;
352 break;
353 case SQL_MAXVALUE:
354 if ((used&(1<<SEQ_MAX)))
355 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: MAXVALUE or NO MAXVALUE should be passed as most once");
356 used |= (1<<SEQ_MAX);
357 if (is_lng_nil(s->data.l_val))
358 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MAXVALUE must be non-NULL");
359 max = s->data.l_val;
360 break;
361 case SQL_CYCLE:
362 if ((used&(1<<SEQ_CYCLE)))
363 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: CYCLE or NO CYCLE should be passed as most once");
364 used |= (1<<SEQ_CYCLE);
365 cycle = s->data.i_val != 0;
366 break;
367 case SQL_CACHE:
368 if ((used&(1<<SEQ_CACHE)))
369 return sql_error(sql, 02, SQLSTATE(3F000) "ALTER SEQUENCE: CACHE value should be passed as most once");
370 used |= (1<<SEQ_CACHE);
371 if (is_lng_nil(s->data.l_val))
372 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: CACHE must be non-NULL");
373 cache = s->data.l_val;
374 break;
375 default:
376 assert(0);
377 }
378 }
379 if (!is_lng_nil(min) && !is_lng_nil(max) && max < min)
380 return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: MAXVALUE value is lesser than MINVALUE ("LLFMT" < "LLFMT")", max, min);
381 return rel_alter_seq(query, ss, qname, t, start, inc, min, max, cache, cycle);
382}
383
384sql_rel *
385rel_sequences(sql_query *query, symbol *s)
386{
387 mvc *sql = query->sql;
388 sql_rel *res = NULL;
389
390 switch (s->token) {
391 case SQL_CREATE_SEQ:
392 {
393 dlist *l = s->data.lval;
394
395 res = list_create_seq(
396/* mvc* sql */ sql,
397/* sql_schema* s */ cur_schema(sql),
398/* dlist* qname */ l->h->data.lval,
399/* dlist* options */ l->h->next->data.lval,
400/* bit bedropped */ (bit) (l->h->next->next->data.i_val != 0));
401 }
402 break;
403 case SQL_ALTER_SEQ:
404 {
405 dlist* l = s->data.lval;
406
407 res = list_alter_seq(
408/* mvc* sql */ query,
409/* sql_schema* s */ cur_schema(sql),
410/* dlist* qname */ l->h->data.lval,
411/* dlist* options */ l->h->next->data.lval);
412 }
413 break;
414 case SQL_DROP_SEQ:
415 {
416 dlist *l = s->data.lval;
417 char *sname = qname_schema(l->h->data.lval);
418 char *seqname = qname_table(l->h->data.lval);
419
420 if (!sname) {
421 sql_schema *ss = cur_schema(sql);
422
423 sname = ss->base.name;
424 }
425 res = rel_drop_seq(sql->sa, sname, seqname);
426 }
427 break;
428 default:
429 return sql_error(sql, 01, SQLSTATE(42000) "sql_stmt Symbol(%p)->token = %s", s, token2string(s->token));
430 }
431 sql->type = Q_SCHEMA;
432 return res;
433}
434