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