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 196 : sql_next_seq_name(mvc *m)
22 : {
23 196 : sqlid id = store_next_oid(m->session->tr->store);
24 196 : size_t len = 5 + 10; /* max nr of digits of (4 bytes) int is 10 */
25 196 : char *msg = sa_alloc(m->sa, len);
26 :
27 196 : snprintf(msg, len, "seq_%d", id);
28 196 : return msg;
29 : }
30 :
31 : static sql_rel *
32 31 : rel_drop_seq(allocator *sa, char *sname, char *seqname)
33 : {
34 31 : sql_rel *rel = rel_create(sa);
35 31 : list *exps = new_exp_list(sa);
36 31 : if(!rel || !exps)
37 : return NULL;
38 :
39 31 : append(exps, exp_atom_clob(sa, sname));
40 31 : append(exps, exp_atom_clob(sa, seqname));
41 31 : append(exps, exp_atom_int(sa, 0));
42 31 : rel->l = NULL;
43 31 : rel->r = NULL;
44 31 : rel->op = op_ddl;
45 31 : rel->flag = ddl_drop_seq;
46 31 : rel->exps = exps;
47 31 : rel->card = 0;
48 31 : rel->nrcols = 0;
49 31 : return rel;
50 : }
51 :
52 : static sql_rel *
53 359 : rel_seq(allocator *sa, int cat_type, char *sname, sql_sequence *s, sql_rel *r, sql_exp *val)
54 : {
55 359 : sql_rel *rel = rel_create(sa);
56 359 : list *exps = new_exp_list(sa);
57 359 : if(!rel || !exps)
58 : return NULL;
59 :
60 359 : if (val)
61 45 : append(exps, val);
62 : else
63 314 : append(exps, exp_atom_int(sa, 0));
64 359 : append(exps, exp_atom_str(sa, sname, sql_bind_localtype("str") ));
65 359 : append(exps, exp_atom_str(sa, s->base.name, sql_bind_localtype("str") ));
66 359 : append(exps, exp_atom_ptr(sa, s));
67 359 : rel->l = r;
68 359 : rel->r = NULL;
69 359 : rel->op = op_ddl;
70 359 : rel->flag = cat_type;
71 359 : rel->exps = exps;
72 359 : rel->card = CARD_MULTI;
73 359 : rel->nrcols = 0;
74 359 : return rel;
75 : }
76 :
77 : static sql_rel *
78 317 : 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 317 : bit nomin = s_min && s_min ->type == type_int ? 1: 0;
91 317 : bit nomax = s_max && s_max ->type == type_int ? 1: 0;
92 317 : lng min = s_min ? s_min->data.l_val : lng_nil;
93 317 : lng max = s_max ? s_max->data.l_val : lng_nil;
94 317 : sql_rel *res = NULL;
95 317 : sql_sequence *seq = NULL;
96 317 : char *sname = qname_schema(qname);
97 317 : char *name = qname_schema_object(qname);
98 317 : sql_schema *s = cur_schema(sql);
99 :
100 317 : 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 317 : 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 317 : (void) tpe;
105 317 : 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 317 : 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 317 : if (is_lng_nil(inc)) inc = 1;
113 317 : if (nomin) min = GDK_lng_min;
114 317 : if (nomax) max = GDK_lng_max;
115 317 : if (is_lng_nil(min)) min = inc > 0 ? 0 : GDK_lng_min;
116 317 : if (is_lng_nil(max)) max = inc > 0 ? GDK_lng_max : 0;
117 317 : 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 317 : if (is_lng_nil(cache)) cache = 1;
119 317 : if (is_bit_nil(cycle)) cycle = 0;
120 :
121 317 : if (inc == 0)
122 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: INCREMENT cannot be 0");
123 317 : if (cache <= 0)
124 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: CACHE must be positive");
125 317 : lng calc = llabs(inc) * cache;
126 317 : 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 317 : 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 316 : 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 315 : 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 314 : seq = create_sql_sequence(sql->store, sql->sa, s, name, start, min, max, inc, cache, cycle);
136 314 : seq->bedropped = bedropped;
137 314 : res = rel_seq(sql->sa, ddl_create_seq, s->base.name, seq, NULL, NULL);
138 : /* for multi statements we keep the sequence around */
139 314 : if (res && stack_has_frame(sql, "%MUL") != 0) {
140 196 : 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 325 : list_create_seq(
157 : mvc *sql,
158 : dlist *qname,
159 : dlist *options,
160 : bit bedropped)
161 : {
162 325 : dnode *n;
163 325 : sql_subtype *t = NULL;
164 325 : lng start = lng_nil, inc = lng_nil, cache = lng_nil;
165 325 : symbol* min = NULL,* max = NULL;
166 325 : unsigned int used = 0;
167 325 : bit cycle = 0;
168 :
169 325 : if (options) {
170 : /* check if no option is given twice */
171 761 : for (n = options->h; n; n = n->next) {
172 449 : symbol *s = n->data.sym;
173 :
174 449 : switch(s->token) {
175 301 : case SQL_TYPE: {
176 301 : bool found = false;
177 301 : const char *valid_types[4] = {"tinyint", "smallint", "int", "bigint"};
178 301 : size_t number_valid_types = sizeof(valid_types) / sizeof(valid_types[0]);
179 :
180 301 : 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 301 : used |= (1<<SEQ_TYPE);
183 301 : t = &s->data.lval->h->data.typeval;
184 932 : for (size_t i = 0; i < number_valid_types; i++) {
185 924 : if (strcasecmp(valid_types[i], t->type->base.name) == 0) {
186 : found = true;
187 : break;
188 : }
189 : }
190 301 : 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 293 : } break;
193 51 : case SQL_START:
194 51 : 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 51 : used |= (1<<SEQ_START);
197 51 : 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 317 : return rel_create_seq(sql, qname, t, start, inc, min, max, cache, cycle, bedropped);
253 : }
254 :
255 : static sql_rel *
256 46 : 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 46 : bit nomin = s_min && s_min ->type == type_int ? 1: 0;
268 46 : bit nomax = s_max && s_max ->type == type_int ? 1: 0;
269 46 : lng min = s_min ? s_min->data.l_val : lng_nil;
270 46 : lng max = s_max ? s_max->data.l_val : lng_nil;
271 46 : mvc *sql = query->sql;
272 46 : char *sname = qname_schema(qname);
273 46 : char *name = qname_schema_object(qname);
274 46 : sql_sequence *seq;
275 46 : int start_type = start_list?start_list->h->data.i_val:0;
276 46 : sql_rel *r = NULL;
277 46 : sql_exp *val = NULL;
278 :
279 46 : assert(!start_list || start_list->h->type == type_int);
280 46 : (void) tpe;
281 46 : if (!(seq = find_sequence_on_scope(sql, sname, name, "ALTER SEQUENCE")))
282 : return NULL;
283 45 : 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 45 : if (is_lng_nil(inc)) inc = seq->increment;
289 45 : if (nomin) min = GDK_lng_min;
290 45 : if (nomax) max = GDK_lng_max;
291 45 : if (is_lng_nil(min)) min = seq->minvalue;
292 45 : if (is_lng_nil(max)) max = seq->maxvalue;
293 45 : if (is_lng_nil(cache)) cache = seq->cacheinc;
294 45 : if (is_bit_nil(cycle)) cycle = seq->cycle;
295 :
296 45 : if (inc == 0)
297 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: INCREMENT cannot be 0");
298 45 : if (cache <= 0)
299 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: CACHE must be positive");
300 45 : lng calc = llabs(inc) * cache;
301 45 : 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 45 : 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 45 : 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 45 : if (start_type == 0) {
312 0 : val = exp_atom_lng(sql->sa, seq->start);
313 45 : } else if (start_type == 1) { /* value (exp) */
314 5 : exp_kind ek = {type_value, card_value, FALSE};
315 5 : sql_subtype *lng_t = sql_bind_localtype("lng");
316 :
317 5 : val = rel_value_exp2(query, &r, start_list->h->next->data.sym, sql_sel, ek);
318 5 : if (!val || !(val = exp_check_type(sql, lng_t, r, val, type_equal)))
319 0 : return NULL;
320 5 : 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 45 : 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 45 : return rel_seq(sql->sa, ddl_alter_seq, seq->s->base.name, seq, r, val);
333 : }
334 :
335 : static sql_rel *
336 46 : list_alter_seq(
337 : sql_query *query,
338 : dlist *qname,
339 : dlist *options)
340 : {
341 46 : mvc *sql = query->sql;
342 46 : dnode *n;
343 46 : sql_subtype* t = NULL;
344 46 : lng inc = lng_nil, cache = lng_nil;
345 46 : symbol* min = NULL,* max = NULL;
346 46 : dlist *start = NULL;
347 46 : unsigned int used = 0;
348 46 : bit cycle = 0;
349 :
350 : /* check if no option is given twice */
351 175 : for (n = options->h; n; n = n->next) {
352 129 : symbol *s = n->data.sym;
353 :
354 129 : 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 45 : case SQL_START:
362 45 : 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 45 : used |= (1<<SEQ_START);
365 45 : 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 45 : start = s->data.lval;
368 45 : 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 46 : return rel_alter_seq(query, qname, t, start, inc, min, max, cache, cycle);
420 : }
421 :
422 : sql_rel *
423 402 : rel_sequences(sql_query *query, symbol *s)
424 : {
425 402 : mvc *sql = query->sql;
426 402 : sql_rel *res = NULL;
427 :
428 402 : switch (s->token) {
429 325 : case SQL_CREATE_SEQ:
430 : {
431 325 : dlist *l = s->data.lval;
432 :
433 325 : res = list_create_seq(
434 : /* mvc* sql */ sql,
435 325 : /* dlist* qname */ l->h->data.lval,
436 325 : /* dlist* options */ l->h->next->data.lval,
437 325 : /* bit bedropped */ (bit) (l->h->next->next->data.i_val != 0));
438 : }
439 325 : break;
440 46 : case SQL_ALTER_SEQ:
441 : {
442 46 : dlist* l = s->data.lval;
443 :
444 46 : res = list_alter_seq(
445 : /* mvc* sql */ query,
446 46 : /* dlist* qname */ l->h->data.lval,
447 46 : /* dlist* options */ l->h->next->data.lval);
448 : }
449 46 : break;
450 31 : case SQL_DROP_SEQ:
451 : {
452 31 : dlist *l = s->data.lval;
453 31 : char *sname = qname_schema(l->h->data.lval);
454 31 : char *seqname = qname_schema_object(l->h->data.lval);
455 31 : sql_sequence *seq = NULL;
456 :
457 31 : if (!(seq = find_sequence_on_scope(sql, sname, seqname, "DROP SEQUENCE")))
458 : return NULL;
459 31 : res = rel_drop_seq(sql->sa, seq->s->base.name, seqname);
460 : }
461 31 : 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 402 : sql->type = Q_SCHEMA;
466 402 : return res;
467 : }
|