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 | |
16 | char* |
17 | sql_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 | |
27 | static sql_rel * |
28 | rel_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 | |
48 | static sql_rel * |
49 | rel_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 | |
73 | static sql_rel * |
74 | rel_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 | |
133 | static sql_rel * |
134 | list_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 | |
235 | static sql_rel * |
236 | rel_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 | |
303 | static sql_rel * |
304 | list_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 | |
384 | sql_rel * |
385 | rel_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 | |