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