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 32 : rel_drop_seq(sql_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 355 : rel_seq(sql_allocator *sa, int cat_type, char *sname, sql_sequence *s, sql_rel *r, sql_exp *val)
54 : {
55 355 : sql_rel *rel = rel_create(sa);
56 355 : list *exps = new_exp_list(sa);
57 355 : if(!rel || !exps)
58 : return NULL;
59 :
60 355 : if (val)
61 44 : append(exps, val);
62 : else
63 311 : append(exps, exp_atom_int(sa, 0));
64 355 : append(exps, exp_atom_str(sa, sname, sql_bind_localtype("str") ));
65 355 : append(exps, exp_atom_str(sa, s->base.name, sql_bind_localtype("str") ));
66 355 : append(exps, exp_atom_ptr(sa, s));
67 355 : rel->l = r;
68 355 : rel->r = NULL;
69 355 : rel->op = op_ddl;
70 355 : rel->flag = cat_type;
71 355 : rel->exps = exps;
72 355 : rel->card = CARD_MULTI;
73 355 : rel->nrcols = 0;
74 355 : return rel;
75 : }
76 :
77 : static sql_rel *
78 314 : 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 314 : bit nomin = s_min && s_min ->type == type_int ? 1: 0;
91 314 : bit nomax = s_max && s_max ->type == type_int ? 1: 0;
92 314 : lng min = s_min ? s_min->data.l_val : lng_nil;
93 314 : lng max = s_max ? s_max->data.l_val : lng_nil;
94 314 : sql_rel *res = NULL;
95 314 : sql_sequence *seq = NULL;
96 314 : char *sname = qname_schema(qname);
97 314 : char *name = qname_schema_object(qname);
98 314 : sql_schema *s = cur_schema(sql);
99 :
100 314 : 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 314 : 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 314 : (void) tpe;
105 314 : 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 314 : 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 314 : if (is_lng_nil(inc)) inc = 1;
113 314 : if (nomin) min = GDK_lng_min;
114 314 : if (nomax) max = GDK_lng_max;
115 314 : if (is_lng_nil(min)) min = inc > 0 ? 0 : GDK_lng_min;
116 314 : if (is_lng_nil(max)) max = inc > 0 ? GDK_lng_max : 0;
117 314 : 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 314 : if (is_lng_nil(cache)) cache = 1;
119 314 : if (is_bit_nil(cycle)) cycle = 0;
120 :
121 314 : if (inc == 0)
122 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: INCREMENT cannot be 0");
123 314 : if (cache <= 0)
124 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE SEQUENCE: CACHE must be positive");
125 314 : lng calc = llabs(inc) * cache;
126 314 : 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 314 : 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 313 : 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 312 : 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 311 : seq = create_sql_sequence(sql->store, sql->sa, s, name, start, min, max, inc, cache, cycle);
136 311 : seq->bedropped = bedropped;
137 311 : res = rel_seq(sql->sa, ddl_create_seq, s->base.name, seq, NULL, NULL);
138 : /* for multi statements we keep the sequence around */
139 311 : 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 322 : list_create_seq(
157 : mvc *sql,
158 : dlist *qname,
159 : dlist *options,
160 : bit bedropped)
161 : {
162 322 : dnode *n;
163 322 : sql_subtype *t = NULL;
164 322 : lng start = lng_nil, inc = lng_nil, cache = lng_nil;
165 322 : symbol* min = NULL,* max = NULL;
166 322 : unsigned int used = 0;
167 322 : bit cycle = 0;
168 :
169 322 : if (options) {
170 : /* check if no option is given twice */
171 756 : for (n = options->h; n; n = n->next) {
172 447 : symbol *s = n->data.sym;
173 :
174 447 : switch(s->token) {
175 298 : case SQL_TYPE: {
176 298 : bool found = false;
177 298 : const char *valid_types[4] = {"tinyint", "smallint", "int", "bigint"};
178 298 : size_t number_valid_types = sizeof(valid_types) / sizeof(valid_types[0]);
179 :
180 298 : 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 298 : used |= (1<<SEQ_TYPE);
183 298 : t = &s->data.lval->h->data.typeval;
184 923 : for (size_t i = 0; i < number_valid_types; i++) {
185 915 : if (strcasecmp(valid_types[i], t->type->base.name) == 0) {
186 : found = true;
187 : break;
188 : }
189 : }
190 298 : 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 290 : } 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 314 : return rel_create_seq(sql, qname, t, start, inc, min, max, cache, cycle, bedropped);
253 : }
254 :
255 : static sql_rel *
256 45 : 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 45 : bit nomin = s_min && s_min ->type == type_int ? 1: 0;
268 45 : bit nomax = s_max && s_max ->type == type_int ? 1: 0;
269 45 : lng min = s_min ? s_min->data.l_val : lng_nil;
270 45 : lng max = s_max ? s_max->data.l_val : lng_nil;
271 45 : mvc *sql = query->sql;
272 45 : char *sname = qname_schema(qname);
273 45 : char *name = qname_schema_object(qname);
274 45 : sql_sequence *seq;
275 45 : int start_type = start_list?start_list->h->data.i_val:0;
276 45 : sql_rel *r = NULL;
277 45 : sql_exp *val = NULL;
278 :
279 45 : assert(!start_list || start_list->h->type == type_int);
280 45 : (void) tpe;
281 45 : if (!(seq = find_sequence_on_scope(sql, sname, name, "ALTER SEQUENCE")))
282 : return NULL;
283 44 : 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 44 : if (is_lng_nil(inc)) inc = seq->increment;
289 44 : if (nomin) min = GDK_lng_min;
290 44 : if (nomax) max = GDK_lng_max;
291 44 : if (is_lng_nil(min)) min = seq->minvalue;
292 44 : if (is_lng_nil(max)) max = seq->maxvalue;
293 44 : if (is_lng_nil(cache)) cache = seq->cacheinc;
294 44 : if (is_bit_nil(cycle)) cycle = seq->cycle;
295 :
296 44 : if (inc == 0)
297 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: INCREMENT cannot be 0");
298 44 : if (cache <= 0)
299 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER SEQUENCE: CACHE must be positive");
300 44 : lng calc = llabs(inc) * cache;
301 44 : 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 44 : 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 44 : 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 44 : if (start_type == 0) {
312 0 : val = exp_atom_lng(sql->sa, seq->start);
313 44 : } 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 37 : } else if (start_type == 2) {
325 37 : assert (start_list->h->next->type == type_lng);
326 37 : val = exp_atom_lng(sql->sa, start_list->h->next->data.l_val);
327 : }
328 44 : 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);
330 0 : val = exp_aggr1(sql->sa, val, zero_or_one, 0, 0, CARD_ATOM, has_nil(val));
331 : }
332 44 : return rel_seq(sql->sa, ddl_alter_seq, seq->s->base.name, seq, r, val);
333 : }
334 :
335 : static sql_rel *
336 45 : list_alter_seq(
337 : sql_query *query,
338 : dlist *qname,
339 : dlist *options)
340 : {
341 45 : mvc *sql = query->sql;
342 45 : dnode *n;
343 45 : sql_subtype* t = NULL;
344 45 : lng inc = lng_nil, cache = lng_nil;
345 45 : symbol* min = NULL,* max = NULL;
346 45 : dlist *start = NULL;
347 45 : unsigned int used = 0;
348 45 : bit cycle = 0;
349 :
350 : /* check if no option is given twice */
351 164 : for (n = options->h; n; n = n->next) {
352 119 : symbol *s = n->data.sym;
353 :
354 119 : 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 44 : case SQL_START:
362 44 : 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 44 : used |= (1<<SEQ_START);
365 44 : 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 44 : start = s->data.lval;
368 44 : break;
369 6 : case SQL_INC:
370 6 : 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 6 : used |= (1<<SEQ_INC);
373 6 : 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 31 : case SQL_MINVALUE:
378 31 : 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 31 : used |= (1<<SEQ_MIN);
381 31 : if (s->type == type_lng) {
382 31 : 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 31 : 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 5 : case SQL_MAXVALUE:
390 5 : 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 5 : used |= (1<<SEQ_MAX);
393 5 : if (s->type == type_lng) {
394 5 : 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 5 : 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 33 : case SQL_CYCLE:
402 33 : 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 33 : used |= (1<<SEQ_CYCLE);
405 33 : cycle = s->data.i_val != 0;
406 33 : 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 45 : return rel_alter_seq(query, qname, t, start, inc, min, max, cache, cycle);
420 : }
421 :
422 : sql_rel *
423 399 : rel_sequences(sql_query *query, symbol *s)
424 : {
425 399 : mvc *sql = query->sql;
426 399 : sql_rel *res = NULL;
427 :
428 399 : switch (s->token) {
429 322 : case SQL_CREATE_SEQ:
430 : {
431 322 : dlist *l = s->data.lval;
432 :
433 322 : res = list_create_seq(
434 : /* mvc* sql */ sql,
435 322 : /* dlist* qname */ l->h->data.lval,
436 322 : /* dlist* options */ l->h->next->data.lval,
437 322 : /* bit bedropped */ (bit) (l->h->next->next->data.i_val != 0));
438 : }
439 322 : break;
440 45 : case SQL_ALTER_SEQ:
441 : {
442 45 : dlist* l = s->data.lval;
443 :
444 45 : res = list_alter_seq(
445 : /* mvc* sql */ query,
446 45 : /* dlist* qname */ l->h->data.lval,
447 45 : /* dlist* options */ l->h->next->data.lval);
448 : }
449 45 : 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 399 : sql->type = Q_SCHEMA;
466 399 : return res;
467 : }
|