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, 2025 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_trans.h"
15 : #include "rel_rel.h"
16 : #include "rel_basetable.h"
17 : #include "rel_select.h"
18 : #include "rel_updates.h"
19 : #include "rel_exp.h"
20 : #include "rel_schema.h"
21 : #include "rel_remote.h"
22 : #include "rel_psm.h"
23 : #include "rel_dump.h"
24 : #include "rel_propagate.h"
25 : #include "rel_unnest.h"
26 : #include "sql_parser.h"
27 : #include "sql_privileges.h"
28 : #include "sql_partition.h"
29 : #include "sql_storage.h"
30 :
31 : #include "mal_authorize.h"
32 : #include "mal_exception.h"
33 :
34 : sql_rel *
35 34729 : rel_table(mvc *sql, int cat_type, const char *sname, sql_table *t, int nr)
36 : {
37 34729 : sql_rel *rel = rel_create(sql->sa);
38 34729 : list *exps = new_exp_list(sql->sa);
39 34729 : if (!rel || !exps)
40 : return NULL;
41 :
42 34729 : append(exps, exp_atom_int(sql->sa, nr));
43 34729 : append(exps, exp_atom_str(sql->sa, sname, sql_bind_localtype("str") ));
44 34729 : append(exps, exp_atom_str(sql->sa, t->base.name, sql_bind_localtype("str") ));
45 34729 : append(exps, exp_atom_ptr(sql->sa, t));
46 34729 : rel->l = rel_basetable(sql, t, a_create(sql->sa, t->base.name));
47 34729 : rel->r = NULL;
48 34729 : rel->op = op_ddl;
49 34729 : rel->flag = cat_type;
50 34729 : rel->exps = exps;
51 34729 : rel->card = CARD_MULTI;
52 34729 : rel->nrcols = 0;
53 34729 : return rel;
54 : }
55 :
56 : static sql_rel *
57 101 : rel_create_remote(mvc *sql, int cat_type, const char *sname, sql_table *t, int pw_encrypted, const char *username, const char *passwd)
58 : {
59 101 : sql_rel *rel = rel_create(sql->sa);
60 101 : list *exps = new_exp_list(sql->sa);
61 101 : if (!rel || !exps)
62 : return NULL;
63 :
64 101 : append(exps, exp_atom_int(sql->sa, pw_encrypted));
65 101 : append(exps, exp_atom_str(sql->sa, sname, sql_bind_localtype("str") ));
66 101 : append(exps, exp_atom_str(sql->sa, t->base.name, sql_bind_localtype("str") ));
67 101 : append(exps, exp_atom_ptr(sql->sa, t));
68 101 : append(exps, exp_atom_str(sql->sa, username, sql_bind_localtype("str") ));
69 101 : append(exps, exp_atom_str(sql->sa, passwd, sql_bind_localtype("str") ));
70 101 : rel->l = rel_basetable(sql, t, a_create(sql->sa, t->base.name));
71 101 : rel->r = NULL;
72 101 : rel->op = op_ddl;
73 101 : rel->flag = cat_type;
74 101 : rel->exps = exps;
75 101 : rel->card = CARD_MULTI;
76 101 : rel->nrcols = 0;
77 101 : return rel;
78 : }
79 :
80 : static sql_rel *
81 23007 : rel_create_view_ddl(mvc *sql, int cat_type, const char *sname, sql_table *t, int nr, int replace)
82 : {
83 23007 : sql_rel *rel = rel_table(sql, cat_type, sname, t, nr);
84 23007 : if (!rel)
85 : return NULL;
86 23007 : append(rel->exps, exp_atom_int(sql->sa, replace));
87 23007 : return rel;
88 : }
89 :
90 : static sql_rel *
91 2852 : rel_alter_table(allocator *sa, int cattype, char *sname, char *tname, char *sname2, char *tname2, int action)
92 : {
93 2852 : sql_rel *rel = rel_create(sa);
94 2852 : list *exps = new_exp_list(sa);
95 2852 : if (!rel || !exps)
96 : return NULL;
97 :
98 2852 : append(exps, exp_atom_clob(sa, sname));
99 2852 : append(exps, exp_atom_clob(sa, tname));
100 2852 : assert((sname2 && tname2) || (!sname2 && !tname2));
101 2852 : if (sname2) {
102 492 : append(exps, exp_atom_clob(sa, sname2));
103 492 : append(exps, exp_atom_clob(sa, tname2));
104 : }
105 2852 : append(exps, exp_atom_int(sa, action));
106 2852 : rel->l = NULL;
107 2852 : rel->r = NULL;
108 2852 : rel->op = op_ddl;
109 2852 : rel->flag = cattype;
110 2852 : rel->exps = exps;
111 2852 : rel->card = CARD_MULTI;
112 2852 : rel->nrcols = 0;
113 2852 : return rel;
114 : }
115 :
116 : static sql_rel *
117 9499 : view_rename_columns(mvc *sql, sql_alias *viewname, sql_rel *sq, dlist *column_spec)
118 : {
119 9499 : dnode *n = column_spec->h;
120 9499 : node *m = sq->exps->h, *p = m;
121 :
122 9499 : assert(is_project(sq->op));
123 39069 : for (; n && m; n = n->next, p = m, m = m->next) {
124 29570 : char *cname = n->data.sval;
125 29570 : sql_exp *e = m->data;
126 29570 : sql_exp *n = e;
127 :
128 29570 : exp_setname(sql, n, viewname, cname);
129 29570 : set_basecol(n);
130 : }
131 : /* skip any intern columns */
132 9499 : for (; m; m = m->next) {
133 0 : sql_exp *e = m->data;
134 0 : if (!is_intern(e))
135 : break;
136 : }
137 9499 : if (p)
138 9499 : p->next = 0;
139 9499 : if (n || m)
140 0 : return sql_error(sql, 02, SQLSTATE(M0M03) "Column lists do not match");
141 9499 : list_hash_clear(sq->exps);
142 9499 : set_processed(sq);
143 9499 : return sq;
144 : }
145 :
146 : static int
147 23124 : as_subquery(mvc *sql, sql_table *t, table_types tt, sql_rel *sq, dlist *column_spec, const char *msg)
148 : {
149 23124 : sql_rel *r = sq;
150 :
151 23124 : if (!r)
152 : return 0;
153 23124 : if (column_spec) {
154 715 : dnode *n = column_spec->h;
155 715 : node *m = r->exps->h;
156 :
157 3595 : for (; n && m; n = n->next, m = m->next) {
158 2880 : char *cname = n->data.sval;
159 2880 : sql_exp *e = m->data;
160 2880 : sql_subtype *tp = exp_subtype(e);
161 2880 : sql_column *col = NULL;
162 :
163 2880 : if (tt != tt_view && cname && cname[0] == '%') {
164 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: generated labels not allowed in column names, use an alias instead", msg);
165 0 : return -1;
166 2880 : } else if (!tp) {
167 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: columns must have a type defined", msg);
168 0 : return -1;
169 2880 : } else if (tp->type->eclass == EC_ANY) {
170 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: any type (plain null value) not allowed as a column type, use an explicit cast", msg);
171 0 : return -1;
172 2880 : } else if (mvc_bind_column(sql, t, cname)) {
173 0 : sql_error(sql, 01, SQLSTATE(42S21) "%s: duplicate column name %s", msg, cname);
174 0 : return -1;
175 : }
176 2880 : switch (mvc_create_column(&col, sql, t, cname, tp)) {
177 0 : case -1:
178 0 : sql_error(sql, 01, SQLSTATE(HY013) MAL_MALLOC_FAIL);
179 0 : return -1;
180 0 : case -2:
181 : case -3:
182 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: transaction conflict detected", msg);
183 0 : return -1;
184 : default:
185 2880 : break;
186 : }
187 : }
188 715 : if (n || m) {
189 0 : sql_error(sql, 01, SQLSTATE(21S02) "%s: number of columns does not match", msg);
190 0 : return -1;
191 : }
192 : } else {
193 228604 : for (node *m = r->exps->h; m; m = m->next) {
194 206199 : sql_exp *e = m->data;
195 206199 : const char *cname = exp_name(e);
196 206199 : sql_subtype *tp = exp_subtype(e);
197 206199 : sql_column *col = NULL;
198 :
199 206199 : if (!cname)
200 4 : cname = "v";
201 206199 : if (tt != tt_view && cname[0] == '%') {
202 1 : sql_error(sql, 01, SQLSTATE(42000) "%s: generated labels not allowed in column names, use an alias instead", msg);
203 4 : return -1;
204 206198 : } else if (!tp) {
205 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: columns must have a type defined", msg);
206 0 : return -1;
207 206198 : } else if (tp->type->eclass == EC_ANY) {
208 1 : sql_error(sql, 01, SQLSTATE(42000) "%s: any type (plain null value) not allowed as a column type, use an explicit cast", msg);
209 1 : return -1;
210 206197 : } else if (mvc_bind_column(sql, t, cname)) {
211 2 : sql_error(sql, 01, SQLSTATE(42S21) "%s: duplicate column name %s", msg, cname);
212 2 : return -1;
213 : }
214 206195 : switch (mvc_create_column(&col, sql, t, cname, tp)) {
215 0 : case -1:
216 0 : sql_error(sql, 01, SQLSTATE(HY013) MAL_MALLOC_FAIL);
217 0 : return -1;
218 0 : case -2:
219 : case -3:
220 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: transaction conflict detected", msg);
221 0 : return -1;
222 : default:
223 206195 : break;
224 : }
225 : }
226 : }
227 : return 0;
228 : }
229 :
230 : sql_table *
231 112 : mvc_create_table_as_subquery(mvc *sql, sql_rel *sq, sql_schema *s, const char *tname, dlist *column_spec, int temp, int commit_action, const char *action)
232 : {
233 112 : sql_table *t = NULL;
234 112 : table_types tt =(temp == SQL_REMOTE)?tt_remote:
235 : (temp == SQL_MERGE_TABLE)?tt_merge_table:
236 : (temp == SQL_REPLICA_TABLE)?tt_replica_table:
237 : (temp == SQL_UNLOGGED_TABLE)?tt_unlogged_table:tt_table;
238 :
239 112 : switch (mvc_create_table(&t, sql, s, tname, tt, 0, SQL_DECLARED_TABLE, commit_action, -1, 0)) {
240 0 : case -1:
241 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
242 0 : case -2:
243 : case -3:
244 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: transaction conflict detected", action);
245 0 : case -4:
246 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: the partition's expression is too long", action);
247 : case -5:
248 : return NULL;
249 : default:
250 112 : break;
251 : }
252 112 : if (as_subquery(sql, t, tt, sq, column_spec, action) != 0)
253 : return NULL;
254 109 : return t;
255 : }
256 :
257 : sql_table *
258 4 : mvc_create_remote_as_subquery(mvc *sql, sql_rel *sq, sql_schema *s, const char *tname, dlist *column_spec, const char *loc, const char *action)
259 : {
260 4 : sql_table *t = NULL;
261 4 : switch(mvc_create_remote(&t, sql, s, tname, SQL_DECLARED_TABLE, loc)) {
262 0 : case -1:
263 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
264 0 : case -2:
265 : case -3:
266 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: transaction conflict detected", action);
267 0 : case -4:
268 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: the partition's expression is too long", action);
269 : case -5:
270 : return NULL;
271 : default:
272 4 : break;
273 : }
274 4 : if (as_subquery(sql, t, tt_remote, sq, column_spec, action) != 0)
275 : return NULL;
276 4 : return t;
277 : }
278 :
279 : static char *
280 902 : table_constraint_name(mvc *sql, symbol *s, sql_schema *ss, sql_table *t)
281 : {
282 : /* create a descriptive name like table_col1_col2_pkey */
283 902 : char *suffix; /* stores the type of this constraint */
284 902 : dnode *nms = NULL;
285 902 : char *buf;
286 902 : size_t buflen, len, slen;
287 :
288 902 : switch (s->token) {
289 52 : case SQL_UNIQUE:
290 52 : suffix = "unique";
291 52 : nms = s->data.lval->h; /* list of columns */
292 899 : break;
293 6 : case SQL_UNIQUE_NULLS_NOT_DISTINCT:
294 6 : suffix = "nndunique";
295 6 : nms = s->data.lval->h; /* list of columns */
296 6 : break;
297 464 : case SQL_PRIMARY_KEY:
298 464 : suffix = "pkey";
299 464 : nms = s->data.lval->h; /* list of columns */
300 464 : break;
301 377 : case SQL_FOREIGN_KEY:
302 377 : suffix = "fkey";
303 377 : nms = s->data.lval->h->next->data.lval->h; /* list of columns */
304 377 : break;
305 : case SQL_CHECK:
306 3 : suffix = "check";
307 3 : char name[512], name2[512], *nme, *nme2;
308 3 : bool found;
309 3 : do {
310 3 : nme = number2name(name, sizeof(name), ++sql->label);
311 3 : buflen = snprintf(name2, sizeof(name2), "%s_%s_%s", t->base.name, nme, suffix);
312 3 : nme2 = name2;
313 3 : found = ol_find_name(t->keys, nme2) || mvc_bind_key(sql, ss, nme2);
314 3 : } while (found);
315 3 : buf = SA_NEW_ARRAY(sql->ta, char, buflen);
316 3 : strcpy(buf, nme2);
317 3 : return buf;
318 0 : default:
319 0 : suffix = "?";
320 0 : nms = NULL;
321 : }
322 :
323 : /* copy table name */
324 899 : len = strlen(t->base.name);
325 899 : buflen = BUFSIZ;
326 899 : slen = strlen(suffix);
327 899 : while (len + slen >= buflen)
328 0 : buflen += BUFSIZ;
329 899 : buf = SA_NEW_ARRAY(sql->ta, char, buflen);
330 899 : strcpy(buf, t->base.name);
331 :
332 : /* add column name(s) */
333 2180 : for (; nms; nms = nms->next) {
334 1281 : slen = strlen(nms->data.sval);
335 1281 : while (len + slen + 1 >= buflen) {
336 0 : size_t nbuflen = buflen + BUFSIZ;
337 0 : char *nbuf = SA_RENEW_ARRAY(sql->ta, char, buf, nbuflen, buflen);
338 : buf = nbuf;
339 : buflen = nbuflen;
340 : }
341 1281 : snprintf(buf + len, buflen - len, "_%s", nms->data.sval);
342 1281 : len += slen + 1;
343 : }
344 :
345 : /* add suffix */
346 899 : slen = strlen(suffix);
347 899 : while (len + 1 + slen >= buflen) {
348 0 : size_t nbuflen = buflen + BUFSIZ;
349 0 : char *nbuf = SA_RENEW_ARRAY(sql->ta, char, buf, nbuflen, buflen);
350 : buf = nbuf;
351 : buflen = nbuflen;
352 : }
353 899 : snprintf(buf + len, buflen - len, "_%s", suffix);
354 899 : return buf;
355 : }
356 :
357 : static char *
358 21967 : column_constraint_name(mvc *sql, symbol *s, sql_column *sc, sql_table *t)
359 : {
360 : /* create a descriptive name like table_col_pkey */
361 21967 : char *suffix /* stores the type of this constraint */, *buf;
362 21967 : size_t buflen;
363 :
364 21967 : switch (s->token) {
365 : case SQL_UNIQUE:
366 : suffix = "unique";
367 : break;
368 4 : case SQL_UNIQUE_NULLS_NOT_DISTINCT:
369 4 : suffix = "nndunique";
370 4 : break;
371 2910 : case SQL_PRIMARY_KEY:
372 2910 : suffix = "pkey";
373 2910 : break;
374 57 : case SQL_FOREIGN_KEY:
375 57 : suffix = "fkey";
376 57 : break;
377 17 : case SQL_CHECK:
378 17 : suffix = "check";
379 17 : break;
380 17209 : default:
381 17209 : suffix = "?";
382 : }
383 :
384 21967 : buflen = strlen(t->base.name) + strlen(sc->base.name) + strlen(suffix) + 3;
385 21967 : buf = SA_NEW_ARRAY(sql->ta, char, buflen);
386 21967 : snprintf(buf, buflen, "%s_%s_%s", t->base.name, sc->base.name, suffix);
387 21967 : return buf;
388 : }
389 :
390 : #define COL_NULL 0
391 : #define COL_DEFAULT 1
392 :
393 : static bool
394 971 : foreign_key_check_types(sql_subtype *lt, sql_subtype *rt)
395 : {
396 971 : if (lt->type->eclass == EC_EXTERNAL && rt->type->eclass == EC_EXTERNAL)
397 1 : return lt->type->localtype == rt->type->localtype;
398 1931 : return lt->type->eclass == rt->type->eclass || (EC_VARCHAR(lt->type->eclass) && EC_VARCHAR(rt->type->eclass));
399 : }
400 :
401 : static key_type
402 6079 : token2key_type(int token)
403 : {
404 6079 : switch (token) {
405 : case SQL_UNIQUE: return ukey;
406 17 : case SQL_UNIQUE_NULLS_NOT_DISTINCT: return unndkey;
407 3939 : case SQL_PRIMARY_KEY: return pkey;
408 38 : case SQL_CHECK: return ckey;
409 : }
410 0 : assert(0);
411 : return -1;
412 : }
413 :
414 : static sql_rel*
415 38 : create_check_plan(sql_query *query, symbol *s, sql_table *t)
416 : {
417 38 : mvc *sql = query->sql;
418 38 : exp_kind ek = {type_value, card_value, FALSE};
419 38 : sql_rel *rel = rel_basetable(sql, t, a_create(sql->sa, t->base.name));
420 38 : sql_exp *e = rel_logical_value_exp(query, &rel, s->data.lval->h->data.sym, sql_sel | sql_no_subquery, ek);
421 :
422 38 : if (!e || !rel || !is_basetable(rel->op))
423 : return NULL;
424 32 : e->comment = sa_strdup(sql->sa, s->data.lval->h->next->data.sval);
425 32 : rel->exps = rel_base_projection(sql, rel, 0);
426 32 : list *pexps = sa_list(sql->sa);
427 32 : pexps = append(pexps, e);
428 32 : rel = rel_project(sql->sa, rel, pexps);
429 32 : return rel;
430 : }
431 :
432 : static int
433 21972 : column_constraint_type(sql_query *query, const char *name, symbol *s, sql_schema *ss, sql_table *t, sql_column *cs, bool isDeclared, int *used)
434 : {
435 21972 : mvc *sql = query->sql;
436 21972 : int res = SQL_ERR;
437 :
438 21972 : if (cs && (cs->type.multiset || cs->type.type->composite)) {
439 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT: constraints on multisets or composite types are not supported");
440 1 : return res;
441 : }
442 21971 : if (isDeclared && (s->token != SQL_NULL && s->token != SQL_NOT_NULL)) {
443 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT: constraints on declared tables are not supported");
444 1 : return res;
445 : }
446 21970 : switch (s->token) {
447 4703 : case SQL_UNIQUE:
448 : case SQL_UNIQUE_NULLS_NOT_DISTINCT:
449 : case SQL_PRIMARY_KEY:
450 : case SQL_CHECK: {
451 4703 : key_type kt = token2key_type(s->token);
452 4703 : sql_key *k;
453 4703 : const char *ns = name;
454 :
455 4703 : if (kt == pkey && t->pkey) {
456 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT PRIMARY KEY: a table can have only one PRIMARY KEY");
457 3 : return res;
458 : }
459 4703 : if (!ns || !*ns) { /* add this to be safe */
460 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key name name cannot be empty", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
461 0 : return res;
462 : }
463 4703 : while (isdigit((unsigned char) *ns))
464 0 : ns++;
465 4703 : if (!*ns) { /* if a key name just contains digit characters, the generated index name can be mistaken with a label */
466 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key name cannot contain just digit characters (0 through 9)", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
467 0 : return res;
468 : }
469 4703 : if (ol_find_name(t->keys, name) || mvc_bind_key(sql, ss, name)) {
470 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key %s already exists", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE", name);
471 0 : return res;
472 : }
473 4703 : if (ol_find_name(t->idxs, name) || mvc_bind_idx(sql, ss, name)) {
474 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: an index named '%s' already exists, and it would conflict with the key", kt == pkey ? "PRIMARY KEY" : "UNIQUE", name);
475 0 : return res;
476 : }
477 4703 : char* check = NULL;
478 4703 : sql_rel* check_rel = NULL;
479 4703 : if (kt == ckey) {
480 17 : if ((check_rel = create_check_plan(query, s, t)) == NULL) {
481 : return -3;
482 : }
483 14 : check = exp2str(sql, check_rel->exps->h->data);
484 : }
485 4700 : switch (mvc_create_ukey(&k, sql, t, name, kt, check)) {
486 0 : case -1:
487 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
488 0 : return res;
489 0 : case -2:
490 : case -3:
491 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
492 0 : return res;
493 : default:
494 4700 : break;
495 : }
496 4700 : if (check) {
497 14 : sql_rel* btrel = check_rel->l;
498 14 : node* n = NULL;
499 28 : for (n = btrel->exps->h; n; n = n->next) {
500 14 : sql_exp* e = n->data;
501 14 : const char *nm = a_obj_name(&e->alias);
502 14 : sql_column *c = mvc_bind_column(sql, t, nm);
503 14 : if (!c) {
504 0 : (void) sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "CONSTRAINT CHECK: no such column '%s' for table '%s'",
505 : nm, t->base.name);
506 0 : return SQL_ERR;
507 : }
508 14 : switch (mvc_create_kc(sql, k, c)) {
509 0 : case -1:
510 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
511 0 : return SQL_ERR;
512 0 : case -2:
513 : case -3:
514 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT CHECK: transaction conflict detected");
515 0 : return SQL_ERR;
516 : default:
517 14 : break;
518 : }
519 : }
520 : }
521 : else
522 4686 : switch (mvc_create_kc(sql, k, cs)) {
523 0 : case -1:
524 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
525 0 : return res;
526 0 : case -2:
527 : case -3:
528 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
529 0 : return res;
530 : default:
531 : break;
532 : }
533 4700 : switch (mvc_create_key_done(sql, k)) {
534 0 : case -1:
535 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
536 0 : return res;
537 0 : case -2:
538 : case -3:
539 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
540 0 : return res;
541 : default:
542 4700 : break;
543 : }
544 4700 : res = SQL_OK;
545 4700 : } break;
546 58 : case SQL_FOREIGN_KEY: {
547 58 : dnode *n = s->data.lval->h;
548 58 : char *rsname = qname_schema(n->data.lval);
549 58 : char *rtname = qname_schema_object(n->data.lval);
550 58 : int ref_actions = n->next->next->next->data.i_val;
551 58 : sql_table *rt;
552 58 : sql_fkey *fk;
553 58 : list *cols;
554 58 : sql_key *rk = NULL;
555 58 : sql_kc *kc;
556 58 : const char *ns = name;
557 :
558 58 : assert(n->next->next->next->type == type_int);
559 58 : rt = find_table_or_view_on_scope(sql, ss, rsname, rtname, "CONSTRAINT FOREIGN KEY", false);
560 : /* self referenced table */
561 58 : if (!rt && t->s == ss && strcmp(t->base.name, rtname) == 0) {
562 1 : sql->errstr[0] = '\0'; /* reset table not found error */
563 1 : sql->session->status = 0;
564 1 : rt = t;
565 : }
566 1 : if (!rt)
567 1 : return SQL_ERR;
568 58 : if (!rt->s) { /* disable foreign key on declared table */
569 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key with declared tables");
570 0 : return res;
571 : }
572 58 : if (isTempSchema(t->s) != isTempSchema(rt->s)) { /* disable foreign key between temp and non temp */
573 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key between temporary and non temporary tables");
574 0 : return res;
575 : }
576 58 : if (isUnloggedTable(t) != isUnloggedTable(rt)) { /* disable foreign key between logged and unlogged */
577 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key between logged and unlogged tables");
578 0 : return res;
579 : }
580 58 : if (!ns || !*ns) { /* add this to be safe */
581 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key name name cannot be empty");
582 0 : return res;
583 : }
584 58 : while (isdigit((unsigned char) *ns))
585 0 : ns++;
586 58 : if (!*ns) { /* if a key name just contains digit characters, the generated index name can be mistaken with a label */
587 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key name cannot contain just digit characters (0 through 9)");
588 0 : return res;
589 : }
590 58 : if (ol_find_name(t->keys, name) || mvc_bind_key(sql, ss, name)) {
591 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key '%s' already exists", name);
592 0 : return res;
593 : }
594 58 : if (ol_find_name(t->idxs, name) || mvc_bind_idx(sql, ss, name)) {
595 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: an index named '%s' already exists, and it would conflict with the key", name);
596 0 : return res;
597 : }
598 :
599 : /* find unique referenced key */
600 58 : if (n->next->data.lval) {
601 53 : char *rcname = n->next->data.lval->h->data.sval;
602 :
603 53 : cols = list_append(sa_list(sql->sa), rcname);
604 53 : rk = mvc_bind_ukey(rt, cols);
605 5 : } else if (rt->pkey) {
606 : /* no columns specified use rt.pkey */
607 5 : rk = &rt->pkey->k;
608 : }
609 58 : if (!rk) {
610 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: could not find referenced PRIMARY KEY in table %s.%s", rsname, rtname);
611 0 : return res;
612 : }
613 58 : if (list_length(rk->columns) != 1) {
614 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: not all columns are handled");
615 1 : return res;
616 : }
617 57 : kc = rk->columns->h->data;
618 57 : if (!foreign_key_check_types(&cs->type, &kc->c->type)) {
619 0 : str tp1 = sql_subtype_string(sql->ta, &cs->type), tp2 = sql_subtype_string(sql->ta, &kc->c->type);
620 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: the type of the FOREIGN KEY column '%s' %s is not compatible with the referenced %s KEY column type %s",
621 0 : cs->base.name, tp1, rk->type == pkey ? "PRIMARY" : "UNIQUE", tp2);
622 0 : return res;
623 : }
624 57 : switch (mvc_create_fkey(&fk, sql, t, name, fkey, rk, ref_actions & 255, (ref_actions>>8) & 255)) {
625 0 : case -1:
626 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
627 0 : return res;
628 0 : case -2:
629 : case -3:
630 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
631 0 : return res;
632 : default:
633 57 : break;
634 : }
635 57 : switch (mvc_create_fkc(sql, fk, cs)) {
636 0 : case -1:
637 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
638 0 : return res;
639 0 : case -2:
640 : case -3:
641 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
642 0 : return res;
643 : default:
644 57 : break;
645 : }
646 57 : switch (mvc_create_key_done(sql, (sql_key*)fk)) {
647 0 : case -1:
648 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
649 0 : return res;
650 0 : case -2:
651 : case -3:
652 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
653 0 : return res;
654 : default:
655 57 : break;
656 : }
657 57 : res = SQL_OK;
658 57 : } break;
659 17209 : case SQL_NOT_NULL:
660 : case SQL_NULL: {
661 17209 : int null = (s->token != SQL_NOT_NULL);
662 :
663 17209 : if (((*used)&(1<<COL_NULL))) {
664 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "NULL constraint for a column may be specified at most once");
665 1 : return SQL_ERR;
666 : }
667 17208 : *used |= (1<<COL_NULL);
668 :
669 17208 : switch (mvc_null(sql, cs, null)) {
670 0 : case -1:
671 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
672 0 : return SQL_ERR;
673 0 : case -2:
674 : case -3:
675 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "NULL CONSTRAINT: transaction conflict detected");
676 0 : return SQL_ERR;
677 : default:
678 : break;
679 : }
680 : res = SQL_OK;
681 : } break;
682 : default:{
683 : res = SQL_ERR;
684 : }
685 : }
686 4757 : if (res == SQL_ERR) {
687 0 : (void) sql_error(sql, 02, SQLSTATE(M0M03) "Unknown constraint (%p)->token = %s", s, token2string(s->token));
688 : }
689 : return res;
690 : }
691 :
692 : static int
693 53590 : column_options(sql_query *query, dlist *opt_list, sql_schema *ss, sql_table *t, sql_column *cs, bool isDeclared)
694 : {
695 53590 : mvc *sql = query->sql;
696 53590 : int res = SQL_OK, used = 0;
697 53590 : assert(cs);
698 :
699 53590 : if (opt_list) {
700 41588 : for (dnode *n = opt_list->h; n && res == SQL_OK; n = n->next) {
701 23380 : symbol *s = n->data.sym;
702 :
703 23380 : switch (s->token) {
704 21972 : case SQL_CONSTRAINT: {
705 21972 : dlist *l = s->data.lval;
706 21972 : char *opt_name = l->h->data.sval, *default_name = NULL;
707 21972 : symbol *sym = l->h->next->data.sym;
708 :
709 21972 : if (!opt_name && !(default_name = column_constraint_name(sql, sym, cs, t)))
710 : return SQL_ERR;
711 :
712 21972 : res = column_constraint_type(query, opt_name ? opt_name : default_name, sym, ss, t, cs, isDeclared, &used);
713 21972 : } break;
714 1408 : case SQL_DEFAULT: {
715 1408 : symbol *sym = s->data.sym;
716 1408 : char *err = NULL, *r;
717 :
718 1408 : if ((used&(1<<COL_DEFAULT))) {
719 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "A default value for a column may be specified at most once");
720 4 : return SQL_ERR;
721 : }
722 1407 : used |= (1<<COL_DEFAULT);
723 :
724 1407 : if (sym->token == SQL_COLUMN || sym->token == SQL_IDENT || sym->token == SQL_NEXT) {
725 268 : exp_kind ek = {type_value, card_value, FALSE};
726 268 : sql_exp *e = rel_logical_value_exp(query, NULL, sym, sql_sel, ek);
727 :
728 268 : if (!e)
729 2 : return SQL_ERR;
730 266 : if (e && is_atom(e->type)) {
731 0 : atom *a = exp_value(sql, e);
732 :
733 0 : if (a && atom_null(a)) {
734 0 : switch (mvc_default(sql, cs, NULL)) {
735 0 : case -1:
736 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
737 0 : return SQL_ERR;
738 0 : case -2:
739 : case -3:
740 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "DEFAULT: transaction conflict detected while setting default value");
741 0 : return SQL_ERR;
742 : default:
743 0 : break;
744 : }
745 0 : break;
746 : }
747 : }
748 : /* reset error */
749 266 : sql->session->status = 0;
750 266 : sql->errstr[0] = '\0';
751 : }
752 1405 : r = symbol2string(sql, s->data.sym, 0, &err);
753 1405 : if (!r) {
754 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "Incorrect default value '%s'", err?err:"");
755 1 : return SQL_ERR;
756 : } else {
757 1404 : switch (mvc_default(sql, cs, r)) {
758 0 : case -1:
759 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
760 0 : return SQL_ERR;
761 0 : case -2:
762 : case -3:
763 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "DEFAULT: transaction conflict detected while setting default value");
764 0 : return SQL_ERR;
765 : default:
766 1404 : break;
767 : }
768 : }
769 1404 : } break;
770 0 : case SQL_NOT_NULL:
771 : case SQL_NULL: {
772 0 : int null = (s->token != SQL_NOT_NULL);
773 :
774 0 : if ((used&(1<<COL_NULL))) {
775 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "NULL constraint for a column may be specified at most once");
776 0 : return SQL_ERR;
777 : }
778 0 : used |= (1<<COL_NULL);
779 :
780 0 : switch (mvc_null(sql, cs, null)) {
781 0 : case -1:
782 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
783 0 : return SQL_ERR;
784 0 : case -2:
785 : case -3:
786 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "NULL CONSTRAINT: transaction conflict detected");
787 0 : return SQL_ERR;
788 : default:
789 : break;
790 : }
791 : } break;
792 0 : default: {
793 0 : (void) sql_error(sql, 02, SQLSTATE(M0M03) "Unknown column option (%p)->token = %s", s, token2string(s->token));
794 0 : return SQL_ERR;
795 : }
796 : }
797 : }
798 : }
799 : return res;
800 : }
801 :
802 : static int
803 897 : table_foreign_key(mvc *sql, const char *name, symbol *s, sql_schema *ss, sql_table *t)
804 : {
805 897 : dnode *n = s->data.lval->h;
806 897 : char *rsname = qname_schema(n->data.lval);
807 897 : char *rtname = qname_schema_object(n->data.lval);
808 897 : const char *ns = name;
809 897 : sql_table *ft = NULL;
810 :
811 897 : ft = find_table_or_view_on_scope(sql, ss, rsname, rtname, "CONSTRAINT FOREIGN KEY", false);
812 : /* self referenced table */
813 897 : if (!ft && t->s == ss && strcmp(t->base.name, rtname) == 0) {
814 10 : sql->errstr[0] = '\0'; /* reset table not found error */
815 10 : sql->session->status = 0;
816 10 : ft = t;
817 : }
818 10 : if (!ft) {
819 : return SQL_ERR;
820 : } else {
821 897 : sql_key *rk = NULL;
822 897 : sql_fkey *fk;
823 897 : dnode *nms = n->next->data.lval->h;
824 897 : node *fnms;
825 897 : int ref_actions = n->next->next->next->next->data.i_val;
826 :
827 897 : assert(n->next->next->next->next->type == type_int);
828 897 : if (!ft->s) { /* disable foreign key on declared table */
829 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key with declared tables");
830 26 : return SQL_ERR;
831 : }
832 897 : if (isTempSchema(t->s) != isTempSchema(ft->s)) { /* disable foreign key between temp and non temp */
833 2 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key between temporary and non temporary tables");
834 2 : return SQL_ERR;
835 : }
836 895 : if (isTempTable(ft) && !isGlobal(ft) && ft != t) { /* disable foreign key on local temporary table */
837 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key with local temporary tables");
838 1 : return SQL_ERR;
839 : }
840 894 : if (isUnloggedTable(t) != isUnloggedTable(ft)) { /* disable foreign key between logged and unlogged */
841 2 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: cannot create foreign key between logged and unlogged tables");
842 2 : return SQL_ERR;
843 : }
844 892 : if (!ns || !*ns) { /* add this to be safe */
845 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key name name cannot be empty");
846 0 : return SQL_ERR;
847 : }
848 892 : while (isdigit((unsigned char) *ns))
849 0 : ns++;
850 892 : if (!*ns) { /* if a key name just contains digit characters, the generated index name can be mistaken with a label */
851 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key name cannot contain just digit characters (0 through 9)");
852 0 : return SQL_ERR;
853 : }
854 892 : if (ol_find_name(t->keys, name) || mvc_bind_key(sql, ss, name)) {
855 2 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: key '%s' already exists", name);
856 2 : return SQL_ERR;
857 : }
858 890 : if (ol_find_name(t->idxs, name) || mvc_bind_idx(sql, ss, name)) {
859 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: an index named '%s' already exists, and it would conflict with the key", name);
860 1 : return SQL_ERR;
861 : }
862 889 : if (n->next->next->data.lval) { /* find unique referenced key */
863 852 : dnode *rnms = n->next->next->data.lval->h;
864 852 : list *cols = sa_list(sql->sa);
865 :
866 2587 : for (; rnms; rnms = rnms->next)
867 883 : list_append(cols, rnms->data.sval);
868 :
869 : /* find key in ft->keys */
870 852 : rk = mvc_bind_ukey(ft, cols);
871 37 : } else if (ft->pkey) {
872 : /* no columns specified use ft.pkey */
873 37 : rk = &ft->pkey->k;
874 : }
875 889 : if (!rk) {
876 5 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: could not find referenced PRIMARY KEY in table '%s'", ft->base.name);
877 5 : return SQL_ERR;
878 : }
879 884 : switch (mvc_create_fkey(&fk, sql, t, name, fkey, rk, ref_actions & 255, (ref_actions>>8) & 255)) {
880 0 : case -1:
881 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
882 0 : return SQL_ERR;
883 0 : case -2:
884 : case -3:
885 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
886 0 : return SQL_ERR;
887 : default:
888 884 : break;
889 : }
890 :
891 1789 : for (fnms = rk->columns->h; nms && fnms; nms = nms->next, fnms = fnms->next) {
892 917 : char *nm = nms->data.sval;
893 917 : sql_column *cs = mvc_bind_column(sql, t, nm);
894 917 : sql_kc *kc = fnms->data;
895 :
896 917 : if (!cs) {
897 3 : (void) sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "CONSTRAINT FOREIGN KEY: no such column '%s' in table '%s'", nm, t->base.name);
898 3 : return SQL_ERR;
899 : }
900 914 : if (!foreign_key_check_types(&cs->type, &kc->c->type)) {
901 9 : str tp1 = sql_subtype_string(sql->ta, &cs->type), tp2 = sql_subtype_string(sql->ta, &kc->c->type);
902 18 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: the type of the FOREIGN KEY column '%s' %s is not compatible with the referenced %s KEY column type %s",
903 9 : cs->base.name, tp1, rk->type == pkey ? "PRIMARY" : "UNIQUE", tp2);
904 9 : return SQL_ERR;
905 : }
906 905 : switch (mvc_create_fkc(sql, fk, cs)) {
907 0 : case -1:
908 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
909 0 : return SQL_ERR;
910 0 : case -2:
911 : case -3:
912 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
913 0 : return SQL_ERR;
914 : default:
915 905 : break;
916 : }
917 : }
918 872 : if (nms || fnms) {
919 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: not all columns are handled");
920 1 : return SQL_ERR;
921 : }
922 871 : switch (mvc_create_key_done(sql, (sql_key*)fk)) {
923 0 : case -1:
924 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
925 0 : return SQL_ERR;
926 0 : case -2:
927 : case -3:
928 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT FOREIGN KEY: transaction conflict detected");
929 0 : return SQL_ERR;
930 : default:
931 871 : break;
932 : }
933 : }
934 871 : return SQL_OK;
935 : }
936 :
937 : static int
938 2273 : table_constraint_type(sql_query *query, const char *name, symbol *s, sql_schema *ss, sql_table *t)
939 : {
940 2273 : mvc *sql = query->sql;
941 2273 : int res = SQL_OK;
942 :
943 2273 : switch (s->token) {
944 1376 : case SQL_UNIQUE:
945 : case SQL_UNIQUE_NULLS_NOT_DISTINCT:
946 : case SQL_PRIMARY_KEY:
947 : case SQL_CHECK: {
948 1376 : key_type kt = token2key_type(s->token);
949 1376 : dnode *nms = s->data.lval->h;
950 1376 : sql_key *k;
951 1376 : const char *ns = name;
952 :
953 1376 : if (kt == pkey && t->pkey) {
954 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT PRIMARY KEY: a table can have only one PRIMARY KEY");
955 12 : return SQL_ERR;
956 : }
957 1376 : if (!ns || !*ns) { /* add this to be safe */
958 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key name name cannot be empty", kt == pkey ? "PRIMARY KEY" : "UNIQUE");
959 0 : return SQL_ERR;
960 : }
961 1376 : while (isdigit((unsigned char) *ns))
962 0 : ns++;
963 1376 : if (!*ns) { /* if a key name just contains digit characters, the generated index name can be mistaken with a label */
964 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key name cannot contain just digit characters (0 through 9)", kt == pkey ? "PRIMARY KEY" : "UNIQUE");
965 0 : return SQL_ERR;
966 : }
967 1376 : if (ol_find_name(t->keys, name) || mvc_bind_key(sql, ss, name)) {
968 3 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: key '%s' already exists", kt == pkey ? "PRIMARY KEY" : "UNIQUE", name);
969 3 : return SQL_ERR;
970 : }
971 1373 : if (ol_find_name(t->idxs, name) || mvc_bind_idx(sql, ss, name)) {
972 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: an index named '%s' already exists, and it would conflict with the key", kt == pkey ? "PRIMARY KEY" : "UNIQUE", name);
973 0 : return SQL_ERR;
974 : }
975 1373 : char* check = NULL;
976 1373 : sql_rel* check_rel = NULL;
977 :
978 1373 : if (kt == ckey) {
979 21 : if ((check_rel = create_check_plan(query, s, t)) == NULL) {
980 : return -3;
981 : }
982 18 : check = exp2str(sql, check_rel->exps->h->data);
983 : }
984 :
985 1370 : switch (mvc_create_ukey(&k, sql, t, name, kt, check)) {
986 0 : case -1:
987 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
988 0 : return SQL_ERR;
989 0 : case -2:
990 : case -3:
991 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
992 0 : return SQL_ERR;
993 : default:
994 1370 : break;
995 : }
996 1370 : node* n = NULL;
997 1370 : if (check) {
998 18 : sql_rel* btrel = check_rel->l;
999 18 : n = btrel->exps->h;
1000 : }
1001 3351 : while (true) {
1002 3351 : const char *nm;
1003 3351 : if (check) {
1004 40 : if (!n)
1005 : break;
1006 22 : sql_exp* e = n->data;
1007 22 : nm = a_obj_name(&e->alias);
1008 22 : n = n->next;
1009 : } else {
1010 3311 : if (!nms)
1011 : break;
1012 1965 : nm = nms->data.sval;
1013 1965 : nms = nms->next;
1014 : }
1015 1987 : sql_column *c = mvc_bind_column(sql, t, nm);
1016 :
1017 1987 : if (!c) {
1018 6 : (void) sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "CONSTRAINT %s: no such column '%s' for table '%s'",
1019 : kt == pkey ? "PRIMARY KEY" : "UNIQUE",
1020 : nm, t->base.name);
1021 6 : return SQL_ERR;
1022 : }
1023 1981 : switch (mvc_create_kc(sql, k, c)) {
1024 0 : case -1:
1025 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1026 0 : return SQL_ERR;
1027 0 : case -2:
1028 : case -3:
1029 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
1030 0 : return SQL_ERR;
1031 : default:
1032 : break;
1033 : }
1034 : }
1035 1364 : switch (mvc_create_key_done(sql, k)) {
1036 0 : case -1:
1037 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1038 0 : return SQL_ERR;
1039 0 : case -2:
1040 : case -3:
1041 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "CONSTRAINT %s: transaction conflict detected", (kt == pkey) ? "PRIMARY KEY" : "UNIQUE");
1042 0 : return SQL_ERR;
1043 : default:
1044 1364 : break;
1045 : }
1046 1364 : } break;
1047 897 : case SQL_FOREIGN_KEY:
1048 897 : res = table_foreign_key(sql, name, s, ss, t);
1049 897 : break;
1050 : default:
1051 : res = SQL_ERR;
1052 : }
1053 2261 : if (res != SQL_OK) {
1054 26 : (void) sql_error(sql, 02, SQLSTATE(M0M03) "Table constraint type: wrong token (%p) = %s", s, token2string(s->token));
1055 26 : return SQL_ERR;
1056 : }
1057 : return res;
1058 : }
1059 :
1060 : static int
1061 2273 : table_constraint(sql_query *query, symbol *s, sql_schema *ss, sql_table *t)
1062 : {
1063 2273 : mvc *sql = query->sql;
1064 2273 : int res = SQL_OK;
1065 :
1066 2273 : if (s->token == SQL_CONSTRAINT) {
1067 2273 : dlist *l = s->data.lval;
1068 2273 : char *opt_name = l->h->data.sval;
1069 2273 : symbol *sym = l->h->next->data.sym;
1070 :
1071 2273 : if (!opt_name)
1072 902 : opt_name = table_constraint_name(sql, sym, ss, t);
1073 : else if (s->token)
1074 : if (opt_name == NULL)
1075 : return SQL_ERR;
1076 2273 : res = table_constraint_type(query, opt_name, sym, ss, t);
1077 : }
1078 :
1079 2273 : if (res != SQL_OK) {
1080 38 : (void) sql_error(sql, 02, SQLSTATE(M0M03) "Table constraint: wrong token (%p) = %s", s, token2string(s->token));
1081 38 : return SQL_ERR;
1082 : }
1083 : return res;
1084 : }
1085 :
1086 : static int
1087 53592 : create_column(sql_query *query, symbol *s, sql_schema *ss, sql_table *t, int alter, bool isDeclared)
1088 : {
1089 53592 : mvc *sql = query->sql;
1090 53592 : dlist *l = s->data.lval;
1091 53592 : char *cname = l->h->data.sval;
1092 53592 : sql_subtype *ctype = &l->h->next->data.typeval;
1093 53592 : dlist *opt_list = NULL;
1094 53592 : int res = SQL_OK;
1095 :
1096 53592 : (void) ss;
1097 53592 : if (alter && !(isTable(t) || ((isMergeTable(t) || isReplicaTable(t)) && list_length(t->members)==0))) {
1098 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot add column to %s '%s'%s",
1099 0 : TABLE_TYPE_DESCRIPTION(t->type, t->properties),
1100 0 : t->base.name, ((isMergeTable(t) || isReplicaTable(t)) && list_length(t->members)) ? " while it has partitions" : "");
1101 0 : return SQL_ERR;
1102 : }
1103 53592 : if (l->h->next->next)
1104 53592 : opt_list = l->h->next->next->data.lval;
1105 :
1106 53592 : if (ctype && ctype->type->eclass == EC_DEC && !ctype->digits && !ctype->scale) /* default 18,3 */
1107 47 : ctype = sql_bind_subtype(query->sql->sa, "decimal", 18, 3);
1108 :
1109 53592 : if (cname && ctype) {
1110 53592 : sql_column *cs = NULL;
1111 :
1112 53592 : if (!isView(t) && cname && cname[0] == '%') {
1113 0 : (void) sql_error(sql, 01, SQLSTATE(42000) "%s TABLE: generated labels not allowed in column names, use an alias instead", (alter)?"ALTER":"CREATE");
1114 10 : return SQL_ERR;
1115 53592 : } else if (ctype->type->eclass == EC_ANY) {
1116 0 : (void) sql_error(sql, 01, SQLSTATE(42000) "%s TABLE: any type (plain null value) not allowed as a column type, use an explicit cast", (alter)?"ALTER":"CREATE");
1117 0 : return SQL_ERR;
1118 53592 : } else if ((cs = find_sql_column(t, cname))) {
1119 2 : (void) sql_error(sql, 02, SQLSTATE(42S21) "%s TABLE: a column named '%s' already exists", (alter)?"ALTER":"CREATE", cname);
1120 2 : return SQL_ERR;
1121 : }
1122 53590 : switch (mvc_create_column(&cs, sql, t, cname, ctype)) {
1123 0 : case -1:
1124 0 : (void) sql_error(sql, 01, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1125 0 : return SQL_ERR;
1126 0 : case -2:
1127 : case -3:
1128 0 : (void) sql_error(sql, 01, SQLSTATE(42000) "%s TABLE: transaction conflict detected", (alter)?"ALTER":"CREATE");
1129 0 : return SQL_ERR;
1130 : default:
1131 53590 : break;
1132 : }
1133 53590 : if (column_options(query, opt_list, ss, t, cs, isDeclared) == SQL_ERR)
1134 : return SQL_ERR;
1135 : }
1136 : return res;
1137 : }
1138 :
1139 : static int
1140 56262 : table_element(sql_query *query, symbol *s, sql_schema *ss, sql_table *t, int alter, bool isDeclared, const char *action)
1141 : {
1142 56262 : mvc *sql = query->sql;
1143 56262 : int res = SQL_OK;
1144 :
1145 56262 : if (alter &&
1146 1262 : (isView(t) ||
1147 1254 : ((isMergeTable(t) || isReplicaTable(t)) && (s->token != SQL_TABLE && s->token != SQL_DROP_TABLE && list_length(t->members))) ||
1148 2498 : (isTable(t) && (s->token == SQL_TABLE || s->token == SQL_DROP_TABLE)) ||
1149 1249 : (partition_find_part(sql->session->tr, t, NULL) &&
1150 5 : (s->token == SQL_DROP_COLUMN || s->token == SQL_COLUMN || s->token == SQL_CONSTRAINT ||
1151 : s->token == SQL_DEFAULT || s->token == SQL_DROP_DEFAULT || s->token == SQL_NOT_NULL || s->token == SQL_NULL || s->token == SQL_DROP_CONSTRAINT)))){
1152 18 : const char *msg = "";
1153 :
1154 18 : switch (s->token) {
1155 : case SQL_TABLE:
1156 : msg = "add table to";
1157 : break;
1158 3 : case SQL_COLUMN:
1159 3 : msg = "add column to";
1160 3 : break;
1161 4 : case SQL_CONSTRAINT:
1162 4 : msg = "add constraint to";
1163 4 : break;
1164 4 : case SQL_COLUMN_OPTIONS:
1165 : case SQL_DEFAULT:
1166 : case SQL_NOT_NULL:
1167 : case SQL_NULL:
1168 4 : msg = "set column options for";
1169 4 : break;
1170 0 : case SQL_STORAGE:
1171 0 : msg = "set column storage for";
1172 0 : break;
1173 0 : case SQL_DROP_DEFAULT:
1174 0 : msg = "drop default column option from";
1175 0 : break;
1176 0 : case SQL_DROP_TABLE:
1177 0 : msg = "drop table from";
1178 0 : break;
1179 5 : case SQL_DROP_COLUMN:
1180 5 : msg = "drop column from";
1181 5 : break;
1182 2 : case SQL_DROP_CONSTRAINT:
1183 2 : msg = "drop constraint from";
1184 2 : break;
1185 0 : default:
1186 0 : sql_error(sql, 02, SQLSTATE(M0M03) "%s: Unknown table element (%p)->token = %s\n", action, s, token2string(s->token));
1187 0 : return SQL_ERR;
1188 : }
1189 18 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s %s '%s'%s\n",
1190 : action,
1191 : msg,
1192 18 : partition_find_part(sql->session->tr, t, NULL)?"a PARTITION of a MERGE or REPLICA TABLE":
1193 13 : TABLE_TYPE_DESCRIPTION(t->type, t->properties),
1194 18 : t->base.name, ((isMergeTable(t) || isReplicaTable(t)) && list_length(t->members)) ? " while it has partitions" : "");
1195 18 : return SQL_ERR;
1196 : }
1197 :
1198 56244 : switch (s->token) {
1199 53592 : case SQL_COLUMN:
1200 53592 : res = create_column(query, s, ss, t, alter, isDeclared);
1201 53592 : break;
1202 2273 : case SQL_CONSTRAINT:
1203 2273 : res = table_constraint(query, s, ss, t);
1204 2273 : break;
1205 0 : case SQL_COLUMN_OPTIONS:
1206 : {
1207 0 : dnode *n = s->data.lval->h;
1208 0 : char *cname = n->data.sval;
1209 0 : sql_column *c = mvc_bind_column(sql, t, cname);
1210 0 : dlist *olist = n->next->data.lval;
1211 :
1212 0 : if (!c) {
1213 0 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1214 0 : return SQL_ERR;
1215 : } else {
1216 0 : return column_options(query, olist, ss, t, c, isDeclared);
1217 : }
1218 21 : } break;
1219 21 : case SQL_DEFAULT:
1220 : {
1221 21 : char *r, *err = NULL;
1222 21 : dlist *l = s->data.lval;
1223 21 : char *cname = l->h->data.sval;
1224 21 : symbol *sym = l->h->next->data.sym;
1225 21 : sql_column *c = mvc_bind_column(sql, t, cname);
1226 :
1227 21 : if (!c) {
1228 3 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1229 4 : return SQL_ERR;
1230 : }
1231 18 : if (sym->token == SQL_COLUMN || sym->token == SQL_IDENT || sym->token == SQL_NEXT) {
1232 7 : exp_kind ek = {type_value, card_value, FALSE};
1233 7 : sql_exp *e = rel_logical_value_exp(query, NULL, sym, sql_sel, ek);
1234 :
1235 7 : if (!e)
1236 1 : return SQL_ERR;
1237 6 : if (e && is_atom(e->type)) {
1238 0 : atom *a = exp_value(sql, e);
1239 :
1240 0 : if (a && atom_null(a)) {
1241 0 : switch (mvc_default(sql, c, NULL)) {
1242 0 : case -1:
1243 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1244 0 : return SQL_ERR;
1245 0 : case -2:
1246 : case -3:
1247 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "DEFAULT: transaction conflict detected while setting default value");
1248 0 : return SQL_ERR;
1249 : default:
1250 0 : break;
1251 : }
1252 0 : break;
1253 : }
1254 : }
1255 : /* reset error */
1256 6 : sql->session->status = 0;
1257 6 : sql->errstr[0] = '\0';
1258 : }
1259 17 : r = symbol2string(sql, sym, 0, &err);
1260 17 : if (!r) {
1261 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "%s: incorrect default value '%s'\n", action, err?err:"");
1262 0 : return SQL_ERR;
1263 : }
1264 17 : switch (mvc_default(sql, c, r)) {
1265 0 : case -1:
1266 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1267 0 : return SQL_ERR;
1268 0 : case -2:
1269 : case -3:
1270 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "DEFAULT: transaction conflict detected while setting default value");
1271 0 : return SQL_ERR;
1272 : default:
1273 17 : break;
1274 : }
1275 : }
1276 17 : break;
1277 0 : case SQL_STORAGE:
1278 : {
1279 0 : dlist *l = s->data.lval;
1280 0 : char *cname = l->h->data.sval;
1281 0 : char *storage_type = l->h->next->data.sval;
1282 0 : sql_column *c = mvc_bind_column(sql, t, cname);
1283 :
1284 0 : if (!c) {
1285 0 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1286 0 : return SQL_ERR;
1287 : }
1288 0 : switch (mvc_storage(sql, c, storage_type)) {
1289 0 : case -1:
1290 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1291 0 : return SQL_ERR;
1292 0 : case -2:
1293 : case -3:
1294 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "STORAGE: transaction conflict detected");
1295 0 : return SQL_ERR;
1296 : default:
1297 : break;
1298 : }
1299 : }
1300 : break;
1301 45 : case SQL_NOT_NULL:
1302 : case SQL_NULL:
1303 : {
1304 45 : dnode *n = s->data.lval->h;
1305 45 : char *cname = n->data.sval;
1306 45 : sql_column *c = mvc_bind_column(sql, t, cname);
1307 45 : int null = (s->token != SQL_NOT_NULL);
1308 :
1309 45 : if (!c) {
1310 4 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1311 4 : return SQL_ERR;
1312 : }
1313 41 : switch (mvc_null(sql, c, null)) {
1314 0 : case -1:
1315 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1316 0 : return SQL_ERR;
1317 0 : case -2:
1318 : case -3:
1319 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "NULL CONSTRAINT: transaction conflict detected");
1320 0 : return SQL_ERR;
1321 : default:
1322 : break;
1323 : }
1324 : } break;
1325 8 : case SQL_DROP_DEFAULT:
1326 : {
1327 8 : char *cname = s->data.sval;
1328 8 : sql_column *c = mvc_bind_column(sql, t, cname);
1329 8 : if (!c) {
1330 2 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1331 2 : return SQL_ERR;
1332 : }
1333 6 : switch (mvc_drop_default(sql, c)) {
1334 0 : case -1:
1335 0 : (void) sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1336 0 : return SQL_ERR;
1337 0 : case -2:
1338 : case -3:
1339 0 : (void) sql_error(sql, 02, SQLSTATE(42000) "DEFAULT: transaction conflict detected while setting default value");
1340 0 : return SQL_ERR;
1341 : default:
1342 : break;
1343 : }
1344 : } break;
1345 69 : case SQL_LIKE:
1346 : {
1347 69 : char *sname = qname_schema(s->data.lval);
1348 69 : char *name = qname_schema_object(s->data.lval);
1349 69 : sql_table *ot = NULL;
1350 :
1351 69 : if (!(ot = find_table_or_view_on_scope(sql, ss, sname, name, action, false)))
1352 : return SQL_ERR;
1353 143 : for (node *n = ol_first_node(ot->columns); n; n = n->next) {
1354 76 : sql_column *oc = n->data, *nc = NULL;
1355 :
1356 76 : if (!isView(t) && oc->base.name && oc->base.name[0] == '%') {
1357 0 : sql_error(sql, 02, SQLSTATE(42000) "%s: generated labels not allowed in column names, use an alias instead", action);
1358 2 : return SQL_ERR;
1359 76 : } else if (mvc_bind_column(sql, t, oc->base.name)) {
1360 2 : sql_error(sql, 02, SQLSTATE(42S21) "%s: a column named '%s' already exists\n", action, oc->base.name);
1361 2 : return SQL_ERR;
1362 : }
1363 74 : assert(oc->type.type->eclass != EC_ANY);
1364 74 : switch (mvc_create_column(&nc, sql, t, oc->base.name, &oc->type)) {
1365 0 : case -1:
1366 0 : sql_error(sql, 01, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1367 0 : return SQL_ERR;
1368 0 : case -2:
1369 : case -3:
1370 0 : sql_error(sql, 01, SQLSTATE(42000) "%s: transaction conflict detected", action);
1371 0 : return SQL_ERR;
1372 : default:
1373 74 : break;
1374 : }
1375 : }
1376 : } break;
1377 86 : case SQL_DROP_COLUMN:
1378 : {
1379 86 : dlist *l = s->data.lval;
1380 86 : char *cname = l->h->data.sval;
1381 86 : int drop_action = l->h->next->data.i_val;
1382 86 : sql_column *col = mvc_bind_column(sql, t, cname);
1383 :
1384 86 : assert(l->h->next->type == type_int);
1385 86 : if (col == NULL) {
1386 9 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s'\n", action, cname);
1387 9 : return SQL_ERR;
1388 : }
1389 77 : if (ol_length(t->columns) <= 1) {
1390 2 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot drop column '%s': table needs at least one column\n", action, cname);
1391 2 : return SQL_ERR;
1392 : }
1393 75 : if (t->system) {
1394 0 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot drop column '%s': table is a system table\n", action, cname);
1395 0 : return SQL_ERR;
1396 : }
1397 75 : if (isView(t)) {
1398 0 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot drop column '%s': '%s' is a view\n", action, cname, t->base.name);
1399 0 : return SQL_ERR;
1400 : }
1401 75 : if (!drop_action && mvc_check_dependency(sql, col->base.id, COLUMN_DEPENDENCY, NULL)) {
1402 3 : sql_error(sql, 02, SQLSTATE(2BM37) "%s: cannot drop column '%s': there are database objects which depend on it\n", action, cname);
1403 3 : return SQL_ERR;
1404 : }
1405 64 : if (!drop_action && t->keys) {
1406 64 : node *n, *m;
1407 :
1408 64 : for (n = ol_first_node(t->keys); n; n = n->next) {
1409 0 : sql_key *k = n->data;
1410 0 : for (m = k->columns->h; m; m = m->next) {
1411 0 : sql_kc *kc = m->data;
1412 0 : if (strcmp(kc->c->base.name, cname) == 0) {
1413 0 : sql_error(sql, 02, SQLSTATE(2BM37) "%s: cannot drop column '%s': there are constraints which depend on it\n", action, cname);
1414 0 : return SQL_ERR;
1415 : }
1416 : }
1417 : }
1418 : }
1419 72 : if (isPartitionedByColumnTable(t) && t->part.pcol->base.id == col->base.id) {
1420 2 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot drop column '%s': is the partitioned column on the table '%s'\n", action, cname, t->base.name);
1421 2 : return SQL_ERR;
1422 : }
1423 70 : if (isPartitionedByExpressionTable(t)) {
1424 8 : for (node *n = t->part.pexp->cols->h; n; n = n->next) {
1425 6 : int next = *(int*) n->data;
1426 6 : if (next == col->colnr) {
1427 2 : sql_error(sql, 02, SQLSTATE(42000) "%s: cannot drop column '%s': the expression used in '%s' depends on it\n", action, cname, t->base.name);
1428 2 : return SQL_ERR;
1429 : }
1430 : }
1431 : }
1432 68 : switch (mvc_drop_column(sql, t, col, drop_action)) {
1433 0 : case -1:
1434 0 : sql_error(sql, 02, SQLSTATE(42000) "%s: %s\n", action, MAL_MALLOC_FAIL);
1435 0 : return SQL_ERR;
1436 0 : case -2:
1437 : case -3:
1438 0 : sql_error(sql, 02, SQLSTATE(42000) "%s: transaction conflict detected\n", action);
1439 0 : return SQL_ERR;
1440 : default:
1441 : break;
1442 : }
1443 : } break;
1444 : case SQL_DROP_CONSTRAINT:
1445 : res = SQL_OK;
1446 : break;
1447 : default:
1448 : res = SQL_ERR;
1449 : }
1450 55949 : if (res == SQL_ERR) {
1451 48 : sql_error(sql, 02, SQLSTATE(M0M03) "%s: Unknown table element (%p)->token = %s\n", action, s, token2string(s->token));
1452 48 : return SQL_ERR;
1453 : }
1454 : return res;
1455 : }
1456 :
1457 : static int
1458 10283 : create_partition_definition(mvc *sql, sql_table *t, symbol *partition_def)
1459 : {
1460 10283 : char *err = NULL;
1461 :
1462 10283 : if (partition_def) {
1463 112 : dlist *list = partition_def->data.lval;
1464 112 : symbol *type = list->h->next->data.sym;
1465 112 : dlist *list2 = type->data.lval;
1466 112 : if (isPartitionedByColumnTable(t)) {
1467 84 : str colname = list2->h->data.sval;
1468 84 : node *n;
1469 84 : sql_class sql_ec;
1470 100 : for (n = ol_first_node(t->columns); n ; n = n->next) {
1471 98 : sql_column *col = n->data;
1472 98 : if (!strcmp(col->base.name, colname)) {
1473 82 : t->part.pcol = col;
1474 82 : break;
1475 : }
1476 : }
1477 84 : if (!t->part.pcol) {
1478 2 : sql_error(sql, 02, SQLSTATE(42000) "CREATE MERGE TABLE: the partition column '%s' is not part of the table", colname);
1479 2 : return SQL_ERR;
1480 : }
1481 82 : sql_ec = t->part.pcol->type.type->eclass;
1482 82 : if (!(sql_ec == EC_BIT || EC_VARCHAR(sql_ec) || EC_TEMP(sql_ec) || sql_ec == EC_POS || sql_ec == EC_NUM ||
1483 2 : EC_INTERVAL(sql_ec)|| sql_ec == EC_DEC || sql_ec == EC_BLOB)) {
1484 2 : err = sql_subtype_string(sql->ta, &(t->part.pcol->type));
1485 2 : sql_error(sql, 02, SQLSTATE(42000) "CREATE MERGE TABLE: column type %s not yet supported for the partition column", err);
1486 2 : return SQL_ERR;
1487 : }
1488 28 : } else if (isPartitionedByExpressionTable(t)) {
1489 28 : char *query = symbol2string(sql, list2->h->data.sym, 1, &err);
1490 28 : if (!query) {
1491 1 : (void) sql_error(sql, 02, SQLSTATE(42000) "CREATE MERGE TABLE: error compiling expression '%s'", err?err:"");
1492 1 : return SQL_ERR;
1493 : }
1494 27 : t->part.pexp = SA_ZNEW(sql->sa, sql_expression);
1495 27 : t->part.pexp->exp = query;
1496 27 : t->part.pexp->type = *sql_bind_localtype("void");
1497 : }
1498 : }
1499 : return SQL_OK;
1500 : }
1501 :
1502 : sql_rel *
1503 10449 : rel_create_table(sql_query *query, int temp, const char *sname, const char *name, bool global, symbol *table_elements_or_subquery,
1504 : int commit_action, const char *loc, const char *username, const char *password, bool pw_encrypted,
1505 : symbol* partition_def, int if_not_exists)
1506 : {
1507 10449 : mvc *sql = query->sql;
1508 10449 : int tt = (temp == SQL_REMOTE)?tt_remote:
1509 : (temp == SQL_MERGE_TABLE)?tt_merge_table:
1510 : (temp == SQL_REPLICA_TABLE)?tt_replica_table:
1511 : (temp == SQL_UNLOGGED_TABLE)?tt_unlogged_table:tt_table;
1512 10449 : bit properties = partition_def ? (bit) partition_def->data.lval->h->next->next->data.i_val : 0;
1513 10449 : sql_table *t = NULL;
1514 10449 : const char *action = (temp == SQL_DECLARED_TABLE)?"DECLARE":"CREATE";
1515 10449 : sql_schema *s = cur_schema(sql);
1516 :
1517 10449 : if (sname && !(s = mvc_bind_schema(sql, sname)))
1518 1 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "%s TABLE: no such schema '%s'", action, sname);
1519 :
1520 10448 : if ((temp != SQL_PERSIST && tt == tt_table && commit_action == CA_COMMIT) || temp == SQL_DECLARE)
1521 197 : commit_action = CA_DELETE;
1522 :
1523 10448 : if (temp == SQL_LOCAL_TEMP || temp == SQL_GLOBAL_TEMP) {
1524 114 : if (sname && strcmp(sname, "tmp") != 0)
1525 7 : return sql_error(sql, 02, SQLSTATE(3F000) "%s TABLE: %s temporary tables should be stored in the 'tmp' schema",
1526 : action, (temp == SQL_LOCAL_TEMP) ? "local" : "global");
1527 109 : s = tmp_schema(sql);
1528 : }
1529 :
1530 10443 : if (global && mvc_bind_table(sql, s, name)) {
1531 8 : if (if_not_exists)
1532 2 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
1533 6 : return sql_error(sql, 02, SQLSTATE(42S01) "%s TABLE: name '%s' already in use", action, name);
1534 121 : } else if (!global && frame_find_table(sql, name)) {
1535 1 : assert(temp == SQL_DECLARED_TABLE);
1536 1 : if (if_not_exists)
1537 0 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
1538 1 : return sql_error(sql, 02, SQLSTATE(42S01) "%s TABLE: name '%s' already declared", action, name);
1539 10434 : } else if (temp != SQL_DECLARED_TABLE && (!mvc_schema_privs(sql, s) && !(isTempSchema(s) && temp == SQL_LOCAL_TEMP))){
1540 4 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE TABLE: insufficient privileges for user '%s' in schema '%s'", get_string_global_var(sql, "current_user"), s->base.name);
1541 10430 : } else if ((temp == SQL_PERSIST || temp == SQL_MERGE_TABLE || temp == SQL_REMOTE || temp == SQL_REPLICA_TABLE || temp == SQL_UNLOGGED_TABLE) && isTempSchema(s)) {
1542 7 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE %s: cannot create persistent table '%s' in the schema '%s'", TABLE_TYPE_DESCRIPTION(tt, properties), name, s->base.name);
1543 10424 : } else if (table_elements_or_subquery->token == SQL_CREATE_TABLE) {
1544 : /* table element list */
1545 10304 : dnode *n;
1546 10304 : dlist *columns = table_elements_or_subquery->data.lval;
1547 10304 : int res = LOG_OK;
1548 :
1549 10304 : if (tt == tt_remote) {
1550 97 : if (!mapiuri_valid(loc, sql->sa))
1551 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: incorrect uri '%s' for remote table '%s'", action, loc, name);
1552 97 : res = mvc_create_remote(&t, sql, s, name, SQL_DECLARED_TABLE, loc);
1553 : } else {
1554 10207 : res = mvc_create_table(&t, sql, s, name, tt, 0, SQL_DECLARED_TABLE, commit_action, -1, properties);
1555 : }
1556 10304 : switch (res) {
1557 0 : case -1:
1558 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1559 0 : case -2:
1560 : case -3:
1561 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: transaction conflict detected", action);
1562 0 : case -4:
1563 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: the partition's expression is too long", action);
1564 : case -5:
1565 : return NULL;
1566 : default:
1567 10304 : break;
1568 : }
1569 :
1570 65283 : for (n = columns->h; n; n = n->next) {
1571 55000 : symbol *sym = n->data.sym;
1572 109777 : int res = table_element(query, sym, s, t, 0, (temp == SQL_DECLARED_TABLE), (temp == SQL_DECLARED_TABLE)?"DECLARE TABLE":"CREATE TABLE");
1573 :
1574 55000 : if (res == SQL_ERR)
1575 : return NULL;
1576 : }
1577 :
1578 10283 : if (create_partition_definition(sql, t, partition_def) != SQL_OK)
1579 : return NULL;
1580 :
1581 10278 : temp = (tt == tt_table)?temp:SQL_PERSIST;
1582 :
1583 400 : if (tt == tt_remote)
1584 97 : return rel_create_remote(sql, ddl_create_table, s->base.name, t, pw_encrypted, username, password);
1585 10181 : return rel_table(sql, ddl_create_table, s->base.name, t, temp);
1586 : } else { /* [col name list] as subquery with or without data */
1587 120 : sql_rel *sq = NULL, *res = NULL;
1588 120 : dlist *as_sq = table_elements_or_subquery->data.lval;
1589 120 : dlist *column_spec = as_sq->h->data.lval;
1590 120 : symbol *subquery = as_sq->h->next->data.sym;
1591 120 : int with_data = as_sq->h->next->next->data.i_val;
1592 :
1593 120 : assert(as_sq->h->next->next->type == type_int);
1594 120 : sq = rel_selects(query, subquery);
1595 120 : if (!sq)
1596 : return NULL;
1597 119 : if (!is_project(sq->op)) /* make sure sq is a projection */
1598 6 : sq = rel_project(sql->sa, sq, rel_projections(sql, sq, NULL, 1, 1));
1599 :
1600 119 : if ((tt != tt_table && tt != tt_unlogged_table) && with_data)
1601 3 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: cannot create %s 'with data'", action,
1602 3 : TABLE_TYPE_DESCRIPTION(tt, properties));
1603 :
1604 : /* create table */
1605 6 : if (tt == tt_remote) {
1606 4 : if (!mapiuri_valid(loc, sql->sa))
1607 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s TABLE: incorrect uri '%s' for remote table '%s'", action, loc, name);
1608 8 : if ((t = mvc_create_remote_as_subquery(sql, sq, s, name, column_spec, loc, (temp == SQL_DECLARED_TABLE)?"DECLARE TABLE":"CREATE TABLE")) == NULL) {
1609 0 : rel_destroy(sq);
1610 0 : return NULL;
1611 : }
1612 : } else {
1613 221 : if ((t = mvc_create_table_as_subquery(sql, sq, s, name, column_spec, temp, commit_action, (temp == SQL_DECLARED_TABLE)?"DECLARE TABLE":"CREATE TABLE")) == NULL) {
1614 3 : rel_destroy(sq);
1615 3 : return NULL;
1616 : }
1617 : }
1618 :
1619 : /* insert query result into this table */
1620 113 : if (tt == tt_remote) {
1621 4 : res = rel_create_remote(sql, ddl_create_table, s->base.name, t, pw_encrypted, username, password);
1622 : /* we cannot insert in remote so just remove the subquery */
1623 4 : rel_destroy(sq);
1624 : } else {
1625 112 : res = rel_table(sql, ddl_create_table, s->base.name, t, (tt == tt_table)?temp:SQL_PERSIST);
1626 109 : if (with_data) {
1627 102 : res = rel_insert(query->sql, res, sq);
1628 : } else {
1629 7 : rel_destroy(sq);
1630 : }
1631 : }
1632 113 : return res;
1633 : }
1634 : /*return NULL;*/ /* never reached as all branches of the above if () end with return ... */
1635 : }
1636 :
1637 : static sql_rel *
1638 78809 : rel_create_view(sql_query *query, int temp, dlist *qname, dlist *column_spec, symbol *ast, int check, int persistent, int replace)
1639 : {
1640 78809 : mvc *sql = query->sql;
1641 78809 : const char *name = qname_schema_object(qname);
1642 78809 : const char *sname = qname_schema(qname);
1643 78809 : sql_alias *ta = qname2alias(sql->sa, qname);
1644 78809 : sql_schema *s = cur_schema(sql);
1645 78809 : sql_table *t = NULL;
1646 78809 : int instantiate = (sql->emode == m_instantiate || !persistent);
1647 78809 : int deps = (sql->emode == m_deps);
1648 78809 : int create = (!instantiate && !deps);
1649 78809 : sqlid pfoundid = 0, foundid = 0;
1650 78809 : const char *base = replace ? "CREATE OR REPLACE VIEW" : "CREATE VIEW";
1651 78809 : const char *action = (temp == SQL_DECLARED_TABLE)?"DECLARE":"CREATE";
1652 :
1653 78809 : (void) check; /* Stefan: unused!? */
1654 :
1655 78809 : if (temp == SQL_GLOBAL_TEMP)
1656 0 : temp = SQL_PERSIST; /* just normal view */
1657 :
1658 78809 : if (temp == SQL_LOCAL_TEMP || temp == SQL_GLOBAL_TEMP) {
1659 0 : if (sname && strcmp(sname, "tmp") != 0)
1660 0 : return sql_error(sql, 02, SQLSTATE(3F000) "%s VIEW: %s temporary views should be stored in the 'tmp' schema",
1661 : action, (temp == SQL_LOCAL_TEMP) ? "local" : "global");
1662 0 : s = tmp_schema(sql);
1663 78809 : } else if (sname && !(s = mvc_bind_schema(sql, sname)))
1664 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "%s: no such schema '%s'", base, sname);
1665 78809 : if (create && (!mvc_schema_privs(sql, s) && !(isTempSchema(s) && persistent == SQL_LOCAL_TEMP)))
1666 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s: access denied for %s to schema '%s'", base, get_string_global_var(sql, "current_user"), s->base.name);
1667 23021 : if (create && (t = mvc_bind_table(sql, s, name))) {
1668 21 : if (!replace)
1669 1 : return sql_error(sql, 02, SQLSTATE(42S01) "%s: name '%s' already in use", base, name);
1670 20 : if (!isView(t))
1671 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s: '%s' is not a view", base, name);
1672 20 : if (t->system)
1673 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot replace system view '%s'", base, name);
1674 20 : foundid = t->base.id; /* when recreating a view, the view itself can't be found */
1675 : }
1676 :
1677 78808 : if (ast) {
1678 78808 : sql_rel *sq = NULL;
1679 78808 : char *q = QUERY(sql->scanner);
1680 78808 : symbol *sym = ast;
1681 :
1682 78808 : if (sym->token == SQL_WITH)
1683 4537 : sym = sym->data.lval->h->next->data.sym;
1684 78808 : if (sym->token == SQL_SELECT) {
1685 74343 : SelectNode *sn = (SelectNode *) sym;
1686 :
1687 74343 : if (sn->limit || sn->sample)
1688 8 : return sql_error(sql, 01, SQLSTATE(42000) "%s: %s not supported", base, sn->limit ? "LIMIT" : "SAMPLE");
1689 : }
1690 :
1691 78801 : pfoundid = sql->objid;
1692 78801 : sql->objid = foundid; /* when recreating a view, the view itself can't be found */
1693 78801 : sq = schema_selects(query, s, ast);
1694 78801 : sql->objid = pfoundid;
1695 78801 : if (!sq)
1696 : return NULL;
1697 78780 : if (!is_project(sq->op)) /* make sure sq is a projection */
1698 0 : sq = rel_project(sql->sa, sq, rel_projections(sql, sq, NULL, 1, 1));
1699 :
1700 78780 : if (!create) {
1701 55772 : if (column_spec) {
1702 11232 : dnode *n = column_spec->h;
1703 11232 : node *m = sq->exps->h;
1704 :
1705 49433 : for (; n && m; n = n->next, m = m->next)
1706 : ;
1707 11232 : if (n || m) {
1708 2 : sql_error(sql, 01, SQLSTATE(21S02) "WITH CLAUSE: number of columns does not match");
1709 2 : rel_destroy(sq);
1710 2 : return NULL;
1711 : }
1712 : }
1713 : }
1714 :
1715 55770 : if (create) {
1716 23008 : q = query_cleaned(sql->ta, q);
1717 23008 : switch (mvc_create_view(&t, sql, s, name, SQL_DECLARED_TABLE, q, 0)) {
1718 0 : case -1:
1719 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
1720 0 : case -2:
1721 : case -3:
1722 0 : return sql_error(sql, 02, SQLSTATE(42000) "%s: transaction conflict detected", base);
1723 : default:
1724 23008 : break;
1725 : }
1726 23008 : if (as_subquery(sql, t, tt_view, sq, column_spec, base) != 0) {
1727 1 : rel_destroy(sq);
1728 1 : return NULL;
1729 : }
1730 23007 : return rel_create_view_ddl(sql, ddl_create_view, s->base.name, t, temp, replace);
1731 : }
1732 55770 : if (!persistent && column_spec)
1733 9499 : sq = view_rename_columns(sql, ta, sq, column_spec);
1734 55770 : if (sq && is_simple_project(sq->op) && sq->l && sq->exps && sq->card == CARD_AGGR) {
1735 6191 : exps_setcard(sq->exps, CARD_MULTI);
1736 6191 : sq->card = CARD_MULTI;
1737 : }
1738 55770 : return sq;
1739 : }
1740 : return NULL;
1741 : }
1742 :
1743 : static sql_rel *
1744 357 : rel_schema2(allocator *sa, int cat_type, char *sname, char *auth, int nr)
1745 : {
1746 357 : sql_rel *rel = rel_create(sa);
1747 357 : list *exps = new_exp_list(sa);
1748 357 : if (!rel || !exps)
1749 : return NULL;
1750 :
1751 357 : append(exps, exp_atom_clob(sa, sname));
1752 357 : append(exps, exp_atom_clob(sa, auth));
1753 357 : append(exps, exp_atom_int(sa, nr));
1754 357 : rel->l = NULL;
1755 357 : rel->r = NULL;
1756 357 : rel->op = op_ddl;
1757 357 : rel->flag = cat_type;
1758 357 : rel->exps = exps;
1759 357 : rel->card = 0;
1760 357 : rel->nrcols = 0;
1761 357 : return rel;
1762 : }
1763 :
1764 : static sql_rel *
1765 926 : rel_schema3(allocator *sa, int cat_type, char *sname, char *tname, char *name)
1766 : {
1767 926 : sql_rel *rel = rel_create(sa);
1768 926 : list *exps = new_exp_list(sa);
1769 926 : if (!rel || !exps)
1770 : return NULL;
1771 :
1772 926 : append(exps, exp_atom_clob(sa, sname));
1773 926 : append(exps, exp_atom_clob(sa, tname));
1774 926 : append(exps, exp_atom_clob(sa, name));
1775 926 : rel->l = NULL;
1776 926 : rel->r = NULL;
1777 926 : rel->op = op_ddl;
1778 926 : rel->flag = cat_type;
1779 926 : rel->exps = exps;
1780 926 : rel->card = 0;
1781 926 : rel->nrcols = 0;
1782 926 : return rel;
1783 : }
1784 :
1785 : static sql_rel *
1786 41 : rel_drop_type(mvc *sql, dlist *qname, int drop_action)
1787 : {
1788 41 : char *name = qname_schema_object(qname);
1789 41 : char *sname = qname_schema(qname);
1790 41 : sql_type *t = NULL;
1791 :
1792 41 : if (!(t = find_type_on_scope(sql, sname, name, "DROP TYPE")))
1793 : return NULL;
1794 40 : if (!mvc_schema_privs(sql, t->s))
1795 0 : return sql_error(sql, 02, SQLSTATE(42000) "DROP TYPE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), t->s->base.name);
1796 40 : return rel_schema2(sql->sa, ddl_drop_type, t->s->base.name, name, drop_action);
1797 : }
1798 :
1799 : static sql_rel *
1800 37 : rel_type(allocator *sa, int cat_type, const char *sname, const char *name, list *fields)
1801 : {
1802 37 : sql_rel *rel = rel_create(sa);
1803 37 : list *exps = new_exp_list(sa);
1804 37 : if (!rel || !exps)
1805 : return NULL;
1806 :
1807 37 : append(exps, exp_atom_str(sa, sname, sql_bind_localtype("str") ));
1808 37 : append(exps, exp_atom_str(sa, name, sql_bind_localtype("str") ));
1809 37 : append(exps, exp_atom_ptr(sa, fields));
1810 37 : rel->l = NULL;
1811 37 : rel->r = NULL;
1812 37 : rel->op = op_ddl;
1813 37 : rel->flag = cat_type;
1814 37 : rel->exps = exps;
1815 37 : rel->card = CARD_MULTI;
1816 37 : rel->nrcols = 0;
1817 37 : return rel;
1818 : }
1819 :
1820 : static sql_rel *
1821 963 : rel_create_type(mvc *sql, dlist *qname, dnode *impl_or_field_list)
1822 : {
1823 963 : char *name = qname_schema_object(qname);
1824 963 : char *sname = qname_schema(qname);
1825 963 : sql_schema *s = cur_schema(sql);
1826 :
1827 963 : if (sname && !(s = mvc_bind_schema(sql, sname)))
1828 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "CREATE TYPE: no such schema '%s'", sname);
1829 963 : if (schema_bind_type(sql, s, name) != NULL)
1830 0 : return sql_error(sql, 02, SQLSTATE(42S01) "CREATE TYPE: name '%s' already in use", name);
1831 963 : if (!mvc_schema_privs(sql, s))
1832 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE TYPE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), s->base.name);
1833 963 : if (impl_or_field_list->type == type_string) {
1834 926 : return rel_schema3(sql->sa, ddl_create_type, s->base.name, name, impl_or_field_list->data.sval);
1835 : } else {
1836 37 : dlist *dl = impl_or_field_list->data.lval;
1837 37 : assert(dl);
1838 37 : list *fields = sa_list(sql->sa);
1839 119 : for (dnode *dn = dl->h; dn; dn = dn->next->next) {
1840 82 : sql_subtype *st = &dn->next->data.typeval;
1841 82 : sql_arg *a = sql_create_arg(sql->sa, dn->data.sval, st, ARG_OUT);
1842 82 : list_append(fields, a);
1843 : }
1844 37 : return rel_type(sql->sa, ddl_create_type, s->base.name, name, fields);
1845 : }
1846 : return NULL;
1847 : }
1848 :
1849 : static char *
1850 1300 : dlist_get_schema_name(dlist *name_auth)
1851 : {
1852 1300 : assert(name_auth && name_auth->h);
1853 1300 : return name_auth->h->data.sval;
1854 : }
1855 :
1856 : static char *
1857 1107 : schema_auth(dlist *name_auth)
1858 : {
1859 1107 : assert(name_auth && name_auth->h && dlist_length(name_auth) == 2);
1860 1107 : return name_auth->h->next->data.sval;
1861 : }
1862 :
1863 : static sql_rel *
1864 4576 : rel_drop(allocator *sa, int cat_type, char *sname, char *first_val, char *second_val, int nr, int exists_check)
1865 : {
1866 4576 : sql_rel *rel = rel_create(sa);
1867 4576 : list *exps = new_exp_list(sa);
1868 :
1869 4576 : append(exps, exp_atom_int(sa, nr));
1870 4576 : append(exps, exp_atom_clob(sa, sname));
1871 4576 : if (first_val)
1872 4383 : append(exps, exp_atom_clob(sa, first_val));
1873 4576 : if (second_val)
1874 150 : append(exps, exp_atom_clob(sa, second_val));
1875 4576 : append(exps, exp_atom_int(sa, exists_check));
1876 4576 : rel->l = NULL;
1877 4576 : rel->r = NULL;
1878 4576 : rel->op = op_ddl;
1879 4576 : rel->flag = cat_type;
1880 4576 : rel->exps = exps;
1881 4576 : rel->card = 0;
1882 4576 : rel->nrcols = 0;
1883 4576 : return rel;
1884 : }
1885 :
1886 : static sql_rel *
1887 1104 : rel_create_schema_dll(allocator *sa, char *sname, char *auth, int nr)
1888 : {
1889 1104 : sql_rel *rel = rel_create(sa);
1890 1104 : list *exps = new_exp_list(sa);
1891 1104 : if (!rel || !exps)
1892 : return NULL;
1893 :
1894 1104 : append(exps, exp_atom_int(sa, nr));
1895 1104 : append(exps, exp_atom_clob(sa, sname));
1896 1104 : if (auth)
1897 38 : append(exps, exp_atom_clob(sa, auth));
1898 1104 : rel->l = NULL;
1899 1104 : rel->r = NULL;
1900 1104 : rel->op = op_ddl;
1901 1104 : rel->flag = ddl_create_schema;
1902 1104 : rel->exps = exps;
1903 1104 : rel->card = 0;
1904 1104 : rel->nrcols = 0;
1905 1104 : return rel;
1906 : }
1907 :
1908 : static sql_rel *
1909 1107 : rel_create_schema(sql_query *query, dlist *auth_name, dlist *schema_elements, int if_not_exists)
1910 : {
1911 1107 : mvc *sql = query->sql;
1912 1107 : char *name = dlist_get_schema_name(auth_name);
1913 1107 : char *auth = schema_auth(auth_name);
1914 1107 : sqlid auth_id = sql->role_id;
1915 :
1916 1107 : if (auth && (auth_id = sql_find_auth(sql, auth)) < 0)
1917 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(28000) "CREATE SCHEMA: no such authorization '%s'", auth);
1918 1107 : if (sql->user_id != USER_MONETDB && sql->role_id != ROLE_SYSADMIN)
1919 1 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE SCHEMA: insufficient privileges for user '%s'", get_string_global_var(sql, "current_user"));
1920 1106 : if (!name)
1921 0 : name = auth;
1922 0 : assert(name);
1923 1106 : if (mvc_bind_schema(sql, name)) {
1924 2 : if (!if_not_exists)
1925 1 : return sql_error(sql, 02, SQLSTATE(3F000) "CREATE SCHEMA: name '%s' already in use", name);
1926 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
1927 : } else {
1928 1104 : sql_schema *os = cur_schema(sql);
1929 1104 : dnode *n = schema_elements->h;
1930 1104 : sql_schema *ss = SA_ZNEW(sql->sa, sql_schema);
1931 1104 : sql_rel *ret = rel_create_schema_dll(sql->sa, name, auth, 0);
1932 :
1933 1104 : ss->base.name = name;
1934 1104 : ss->auth_id = auth_id;
1935 1104 : ss->owner = sql->user_id;
1936 :
1937 1104 : sql->session->schema = ss;
1938 1106 : while (n) {
1939 2 : sql_rel *res = rel_semantic(query, n->data.sym);
1940 2 : if (!res) {
1941 0 : rel_destroy(ret);
1942 0 : sql->session->schema = os;
1943 0 : return NULL;
1944 : }
1945 2 : ret = rel_list(sql->sa, ret, res);
1946 2 : n = n->next;
1947 : }
1948 1104 : sql->session->schema = os;
1949 1104 : return ret;
1950 : }
1951 : }
1952 :
1953 : static sql_rel *
1954 3876 : sql_drop_table(sql_query *query, dlist *qname, int nr, int if_exists)
1955 : {
1956 3876 : mvc *sql = query->sql;
1957 3876 : char *sname = qname_schema(qname);
1958 3876 : char *tname = qname_schema_object(qname);
1959 3876 : sql_table *t = NULL;
1960 :
1961 3876 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "DROP TABLE", false))) {
1962 118 : if (if_exists) {
1963 73 : sql->errstr[0] = '\0'; /* reset table not found error */
1964 73 : sql->session->status = 0;
1965 73 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
1966 : }
1967 : return NULL;
1968 : }
1969 3758 : if (isDeclaredTable(t))
1970 0 : return sql_error(sql, 02, SQLSTATE(42000) "DROP TABLE: cannot drop a declared table");
1971 :
1972 3758 : return rel_drop(sql->sa, ddl_drop_table, t->s->base.name, tname, NULL, nr, if_exists);
1973 : }
1974 :
1975 : static sql_rel *
1976 503 : sql_drop_view(sql_query *query, dlist *qname, int nr, int if_exists)
1977 : {
1978 503 : mvc *sql = query->sql;
1979 503 : char *sname = qname_schema(qname);
1980 503 : char *tname = qname_schema_object(qname);
1981 503 : sql_table *t = NULL;
1982 :
1983 503 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "DROP VIEW", true))) {
1984 27 : if (if_exists) {
1985 1 : sql->errstr[0] = '\0'; /* reset table not found error */
1986 1 : sql->session->status = 0;
1987 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
1988 : }
1989 : return NULL;
1990 : }
1991 476 : if (!isView(t))
1992 1 : return sql_error(sql, 02, SQLSTATE(42000) "DROP VIEW: unable to drop view '%s': is a table", tname);
1993 :
1994 475 : return rel_drop(sql->sa, ddl_drop_view, t->s->base.name, tname, NULL, nr, if_exists);
1995 : }
1996 :
1997 : static sql_rel *
1998 4445 : sql_alter_table(sql_query *query, dlist *dl, dlist *qname, symbol *te, int if_exists)
1999 : {
2000 4445 : mvc *sql = query->sql;
2001 4445 : char *sname = qname_schema(qname);
2002 4445 : char *tname = qname_schema_object(qname);
2003 4445 : sql_table *t = NULL, *nt = NULL;
2004 4445 : sql_rel *res = NULL, *r;
2005 4445 : sql_exp **updates, *e;
2006 :
2007 4445 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "ALTER TABLE", false))) {
2008 15 : if (if_exists) {
2009 1 : sql->errstr[0] = '\0'; /* reset table not found error */
2010 1 : sql->session->status = 0;
2011 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
2012 : }
2013 : return NULL;
2014 : }
2015 4430 : if (isDeclaredTable(t))
2016 0 : return sql_error(sql, 02, SQLSTATE(42S02) "ALTER TABLE: can't alter declared table '%s'", tname);
2017 4430 : if (isTempSchema(t->s))
2018 3 : return sql_error(sql, 02, SQLSTATE(42S02) "ALTER TABLE: can't alter temporary table '%s'", tname);
2019 4427 : if (!mvc_schema_privs(sql, t->s))
2020 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), t->s->base.name);
2021 :
2022 4427 : assert(te);
2023 4427 : if (t->persistence != SQL_DECLARED_TABLE)
2024 4427 : sname = t->s->base.name;
2025 :
2026 4427 : if ((te->token == SQL_TABLE || te->token == SQL_DROP_TABLE)) {
2027 805 : dlist *nqname = te->data.lval->h->data.lval;
2028 805 : sql_table *pt = NULL;
2029 805 : char *nsname = qname_schema(nqname);
2030 805 : char *ntname = qname_schema_object(nqname);
2031 :
2032 805 : if (!(pt = find_table_or_view_on_scope(sql, t->s, nsname, ntname, "ALTER TABLE", false)))
2033 : return NULL;
2034 795 : if (isView(pt))
2035 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: can't add/drop a view into a %s",
2036 1 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2037 794 : if (isDeclaredTable(pt))
2038 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: can't add/drop a declared table into a %s",
2039 0 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2040 794 : if (isTempSchema(pt->s))
2041 2 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: can't add/drop a temporary table into a %s",
2042 2 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2043 792 : if (isReplicaTable(t) && isMergeTable(pt))
2044 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: can't add/drop a %s table into a %s",
2045 0 : TABLE_TYPE_DESCRIPTION(pt->type, pt->properties), TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2046 792 : nsname = pt->s->base.name;
2047 792 : if (strcmp(sname, nsname) != 0)
2048 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: all children tables of '%s.%s' must be part of schema '%s'",
2049 : sname, tname, sname);
2050 :
2051 791 : if (te->token == SQL_TABLE) {
2052 611 : symbol *extra = dl->h->next->next->next->data.sym;
2053 :
2054 611 : if (!extra) {
2055 314 : if (isRangePartitionTable(t)) {
2056 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: a range partition is required while adding under a %s",
2057 1 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2058 313 : } else if (isListPartitionTable(t)) {
2059 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: a value partition is required while adding under a %s",
2060 1 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2061 : }
2062 312 : return rel_alter_table(sql->sa, ddl_alter_table_add_table, sname, tname, nsname, ntname, 0);
2063 : }
2064 297 : if ((isMergeTable(pt) || isReplicaTable(pt)) && list_length(pt->members)==0)
2065 2 : return sql_error(sql, 02, SQLSTATE(42000) "%s '%s'.'%s' should have at least one table associated",
2066 2 : TABLE_TYPE_DESCRIPTION(pt->type, pt->properties), pt->s->base.name, pt->base.name);
2067 :
2068 295 : if (extra->token == SQL_MERGE_PARTITION) { /* partition to hold null values only */
2069 17 : dlist* ll = extra->data.lval;
2070 17 : int update = ll->h->next->next->next->data.i_val;
2071 :
2072 17 : if (isRangePartitionTable(t)) {
2073 14 : return rel_alter_table_add_partition_range(query, t, pt, sname, tname, nsname, ntname, NULL, NULL, true, update);
2074 3 : } else if (isListPartitionTable(t)) {
2075 3 : return rel_alter_table_add_partition_list(query, t, pt, sname, tname, nsname, ntname, NULL, true, update);
2076 : } else {
2077 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot add a partition into a %s",
2078 0 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2079 : }
2080 278 : } else if (extra->token == SQL_PARTITION_RANGE) {
2081 218 : dlist* ll = extra->data.lval;
2082 218 : symbol* min = ll->h->data.sym, *max = ll->h->next->data.sym;
2083 218 : int nills = ll->h->next->next->data.i_val, update = ll->h->next->next->next->data.i_val;
2084 :
2085 218 : if (!isRangePartitionTable(t)) {
2086 2 : return sql_error(sql, 02,SQLSTATE(42000) "ALTER TABLE: cannot add a range partition into a %s",
2087 1 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2088 : }
2089 :
2090 217 : assert(nills == 0 || nills == 1);
2091 217 : return rel_alter_table_add_partition_range(query, t, pt, sname, tname, nsname, ntname, min, max, (bit) nills, update);
2092 60 : } else if (extra->token == SQL_PARTITION_LIST) {
2093 60 : dlist* ll = extra->data.lval, *values = ll->h->data.lval;
2094 60 : int nills = ll->h->next->data.i_val, update = ll->h->next->next->data.i_val;
2095 :
2096 60 : if (!isListPartitionTable(t)) {
2097 2 : return sql_error(sql, 02,SQLSTATE(42000) "ALTER TABLE: cannot add a value partition into a %s",
2098 1 : TABLE_TYPE_DESCRIPTION(t->type, t->properties));
2099 : }
2100 :
2101 59 : assert(nills == 0 || nills == 1);
2102 59 : return rel_alter_table_add_partition_list(query, t, pt, sname, tname, nsname, ntname, values, (bit) nills, update);
2103 : }
2104 0 : assert(0);
2105 : } else {
2106 180 : int drop_action = te->data.lval->h->next->data.i_val;
2107 :
2108 180 : return rel_alter_table(sql->sa, ddl_alter_table_del_table, sname, tname, nsname, ntname, drop_action);
2109 : }
2110 : }
2111 :
2112 : /* read only or read write */
2113 3622 : if (te->token == SQL_ALTER_TABLE) {
2114 2360 : int state = te->data.i_val;
2115 :
2116 2360 : if (state == tr_readonly) {
2117 : state = TABLE_READONLY;
2118 : } else if (state == tr_append) {
2119 : state = TABLE_APPENDONLY;
2120 : } else {
2121 0 : assert(state == tr_writable);
2122 : state = TABLE_WRITABLE;
2123 : }
2124 2360 : return rel_alter_table(sql->sa, ddl_alter_table_set_access, sname, tname, NULL, NULL, state);
2125 : }
2126 :
2127 1262 : nt = dup_sql_table(sql->sa, t);
2128 1262 : if (!nt || (table_element(query, te, t->s, nt, 1, t->persistence == SQL_DECLARED_TABLE, "ALTER TABLE") == SQL_ERR))
2129 75 : return NULL;
2130 :
2131 1187 : if (te->token == SQL_DROP_CONSTRAINT) {
2132 150 : dlist *l = te->data.lval;
2133 150 : char *kname = l->h->data.sval;
2134 150 : int drop_action = l->h->next->data.i_val;
2135 :
2136 150 : return rel_drop(sql->sa, ddl_drop_constraint, sname, tname, kname, drop_action, 0);
2137 : }
2138 :
2139 1037 : res = rel_table(sql, ddl_alter_table, sname, nt, 0);
2140 1037 : sql_rel *bt = rel_ddl_basetable_get(res);
2141 :
2142 1037 : if (!isTable(nt))
2143 : return res;
2144 :
2145 : /* New columns need update with default values. Add one more element for new column */
2146 1012 : updates = SA_ZNEW_ARRAY(sql->sa, sql_exp*, (ol_length(nt->columns) + 1));
2147 1012 : rel_base_use_tid(sql, bt);
2148 :
2149 1012 : e = basetable_get_tid_or_add_it(sql, bt);
2150 1012 : e = exp_ref(sql, e);
2151 :
2152 : /*
2153 : e = exp_column(sql->sa, nt->base.name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
2154 : e->alias.label = rel_base_nid(bt, NULL);
2155 : */
2156 1012 : r = rel_project(sql->sa, res, append(new_exp_list(sql->sa),e));
2157 :
2158 1012 : list *cols = new_exp_list(sql->sa);
2159 1012 : sql_exp *ne;
2160 :
2161 1012 : sql_alias *ta = table_alias(sql->sa, nt, schema_alias(sql->sa, t->s));
2162 14583 : for (node *n = ol_first_node(nt->columns); n; n = n->next) {
2163 13571 : sql_column *c = n->data;
2164 :
2165 13571 : rel_base_use(sql, bt, c->colnr);
2166 : /* handle new columns */
2167 13571 : if (!c->base.new || c->base.deleted)
2168 13463 : continue;
2169 108 : if (c->def) {
2170 7 : e = rel_parse_val(sql, nt->s, c->def, &c->type, sql->emode, NULL);
2171 : } else {
2172 101 : e = exp_atom(sql->sa, atom_general(sql->sa, &c->type, NULL, 0));
2173 : }
2174 108 : if (!e || (e = exp_check_type(sql, &c->type, r, e, type_equal)) == NULL) {
2175 0 : rel_destroy(r);
2176 0 : return NULL;
2177 : }
2178 108 : list_append(cols, ne=exp_column(sql->sa, ta, c->base.name, &c->type, CARD_MULTI, 0, 0, 0));
2179 108 : ne->alias.label = rel_base_nid(bt, c);
2180 108 : ne->nid = ne->alias.label;
2181 :
2182 108 : assert(!updates[c->colnr]);
2183 108 : exp_setname(sql, e, ta, c->base.name);
2184 108 : updates[c->colnr] = e;
2185 : }
2186 1012 : res = rel_update(sql, res, r, updates, list_length(cols)?cols:NULL);
2187 1012 : return res;
2188 : }
2189 :
2190 : static sql_rel *
2191 50 : rel_role(allocator *sa, char *grantee, char *auth, int grantor, int admin, int type)
2192 : {
2193 50 : sql_rel *rel = rel_create(sa);
2194 50 : list *exps = new_exp_list(sa);
2195 50 : if (!rel || !exps)
2196 : return NULL;
2197 :
2198 50 : assert(type == ddl_grant_roles || type == ddl_revoke_roles);
2199 50 : append(exps, exp_atom_clob(sa, grantee));
2200 50 : append(exps, exp_atom_clob(sa, auth));
2201 50 : append(exps, exp_atom_int(sa, grantor));
2202 50 : append(exps, exp_atom_int(sa, admin));
2203 50 : rel->l = NULL;
2204 50 : rel->r = NULL;
2205 50 : rel->op = op_ddl;
2206 50 : rel->flag = type;
2207 50 : rel->exps = exps;
2208 50 : rel->card = 0;
2209 50 : rel->nrcols = 0;
2210 50 : return rel;
2211 : }
2212 :
2213 : static sql_rel *
2214 50 : rel_grant_or_revoke_roles(mvc *sql, dlist *roles, dlist *grantees, int grant, int grantor, ddl_statement action)
2215 : {
2216 50 : sql_rel *res = NULL;
2217 : /* grant/revoke roles to the grantees */
2218 :
2219 100 : for (dnode *r = roles->h; r; r = r->next) {
2220 50 : char *role = r->data.sval;
2221 :
2222 100 : for (dnode *g = grantees->h; g; g = g->next) {
2223 50 : char *grantee = g->data.sval;
2224 :
2225 50 : if ((res = rel_list(sql->sa, res, rel_role(sql->sa, grantee, role, grantor, grant, action))) == NULL) {
2226 0 : rel_destroy(res);
2227 0 : return NULL;
2228 : }
2229 : }
2230 : }
2231 : return res;
2232 : }
2233 :
2234 : static sql_rel *
2235 19003 : rel_priv(allocator *sa, char *sname, char *name, char *grantee, int privs, char *cname, int grant, int grantor, int type)
2236 : {
2237 19003 : sql_rel *rel = rel_create(sa);
2238 19003 : list *exps = new_exp_list(sa);
2239 19003 : if (!rel || !exps)
2240 : return NULL;
2241 :
2242 19003 : assert(type == ddl_grant || type == ddl_revoke);
2243 19003 : append(exps, exp_atom_clob(sa, sname));
2244 19003 : append(exps, exp_atom_clob(sa, name));
2245 19003 : append(exps, exp_atom_clob(sa, grantee));
2246 19003 : append(exps, exp_atom_int(sa, privs));
2247 19003 : append(exps, cname?(void*)exp_atom_clob(sa, cname):(void*)cname);
2248 19003 : append(exps, exp_atom_int(sa, grant));
2249 19003 : append(exps, exp_atom_int(sa, grantor));
2250 19003 : rel->l = NULL;
2251 19003 : rel->r = NULL;
2252 19003 : rel->op = op_ddl;
2253 19003 : rel->flag = type;
2254 19003 : rel->exps = exps;
2255 19003 : rel->card = 0;
2256 19003 : rel->nrcols = 0;
2257 19003 : return rel;
2258 : }
2259 :
2260 : static sql_rel *
2261 101970 : rel_func_priv(allocator *sa, char *sname, int func, char *grantee, int privs, int grant, int grantor, int type)
2262 : {
2263 101970 : sql_rel *rel = rel_create(sa);
2264 101970 : list *exps = new_exp_list(sa);
2265 101970 : if (!rel || !exps)
2266 : return NULL;
2267 :
2268 101970 : assert(type == ddl_grant_func || type == ddl_revoke_func);
2269 101970 : append(exps, exp_atom_clob(sa, sname));
2270 101970 : append(exps, exp_atom_int(sa, func));
2271 101970 : append(exps, exp_atom_clob(sa, grantee));
2272 101970 : append(exps, exp_atom_int(sa, privs));
2273 101970 : append(exps, exp_atom_int(sa, grant));
2274 101970 : append(exps, exp_atom_int(sa, grantor));
2275 101970 : rel->l = NULL;
2276 101970 : rel->r = NULL;
2277 101970 : rel->op = op_ddl;
2278 101970 : rel->flag = type;
2279 101970 : rel->exps = exps;
2280 101970 : rel->card = 0;
2281 101970 : rel->nrcols = 0;
2282 101970 : return rel;
2283 : }
2284 :
2285 : static sql_rel *
2286 12 : rel_grant_or_revoke_global(mvc *sql, dlist *privs, dlist *grantees, int grant, int grantor, ddl_statement action)
2287 : {
2288 12 : sql_rel *res = NULL;
2289 12 : char *sname = cur_schema(sql)->base.name;
2290 :
2291 12 : if (!privs)
2292 : return NULL;
2293 24 : for (dnode *gn = grantees->h; gn; gn = gn->next) {
2294 12 : char *grantee = gn->data.sval;
2295 :
2296 12 : if (!grantee)
2297 0 : grantee = "public";
2298 :
2299 24 : for (dnode *opn = privs->h; opn; opn = opn->next) {
2300 12 : int priv = opn->data.i_val;
2301 :
2302 12 : if ((res = rel_list(sql->sa, res, rel_priv(sql->sa, sname, NULL, grantee, priv, NULL, grant, grantor, action))) == NULL) {
2303 0 : rel_destroy(res);
2304 0 : return NULL;
2305 : }
2306 : }
2307 : }
2308 : return res;
2309 : }
2310 :
2311 : static sql_rel *
2312 18953 : rel_grant_or_revoke_table(mvc *sql, dlist *privs, dlist *qname, dlist *grantees, int grant, int grantor, ddl_statement action, const char *err)
2313 : {
2314 18953 : sql_rel *res = NULL;
2315 18953 : int all = PRIV_SELECT | PRIV_UPDATE | PRIV_INSERT | PRIV_DELETE | PRIV_TRUNCATE;
2316 18953 : char *sname = qname_schema(qname);
2317 18953 : char *tname = qname_schema_object(qname);
2318 18953 : sql_table *t = NULL;
2319 :
2320 18953 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, err, false)))
2321 : return NULL;
2322 18952 : if (isDeclaredTable(t))
2323 0 : return sql_error(sql, 02, SQLSTATE(42000) "Cannot %s on a declared table", err);
2324 37904 : for (dnode *gn = grantees->h; gn; gn = gn->next) {
2325 18952 : char *grantee = gn->data.sval;
2326 :
2327 18952 : if (!grantee)
2328 18837 : grantee = "public";
2329 :
2330 18952 : if (!privs) {
2331 7 : if ((res = rel_list(sql->sa, res, rel_priv(sql->sa, t->s->base.name, tname, grantee, all, NULL, grant, grantor, action))) == NULL) {
2332 0 : rel_destroy(res);
2333 0 : return NULL;
2334 : }
2335 7 : continue;
2336 : }
2337 37916 : for (dnode *opn = privs->h; opn; opn = opn->next) {
2338 18971 : symbol *op = opn->data.sym;
2339 18971 : int priv = PRIV_SELECT;
2340 :
2341 18971 : switch (op->token) {
2342 : case SQL_SELECT:
2343 : priv = PRIV_SELECT;
2344 : break;
2345 28 : case SQL_UPDATE:
2346 28 : priv = PRIV_UPDATE;
2347 28 : break;
2348 28 : case SQL_INSERT:
2349 28 : priv = PRIV_INSERT;
2350 28 : break;
2351 21 : case SQL_DELETE:
2352 21 : priv = PRIV_DELETE;
2353 21 : break;
2354 1 : case SQL_TRUNCATE:
2355 1 : priv = PRIV_TRUNCATE;
2356 1 : break;
2357 0 : case SQL_EXECUTE:
2358 : default:
2359 0 : return sql_error(sql, 02, SQLSTATE(42000) "Cannot %s EXECUTE on table name %s", err, tname);
2360 : }
2361 :
2362 18971 : if ((op->token == SQL_SELECT || op->token == SQL_UPDATE) && op->data.lval) {
2363 103 : for (dnode *cn = op->data.lval->h; cn; cn = cn->next) {
2364 58 : char *cname = cn->data.sval;
2365 58 : if ((res = rel_list(sql->sa, res, rel_priv(sql->sa, t->s->base.name, tname, grantee, priv, cname, grant, grantor, action))) == NULL) {
2366 0 : rel_destroy(res);
2367 0 : return NULL;
2368 : }
2369 : }
2370 18926 : } else if ((res = rel_list(sql->sa, res, rel_priv(sql->sa, t->s->base.name, tname, grantee, priv, NULL, grant, grantor, action))) == NULL) {
2371 0 : rel_destroy(res);
2372 0 : return NULL;
2373 : }
2374 : }
2375 : }
2376 : return res;
2377 : }
2378 :
2379 : static sql_rel *
2380 101971 : rel_grant_or_revoke_func(mvc *sql, dlist *privs, dlist *qname, dlist *typelist, sql_ftype type, dlist *grantees, int grant, int grantor, ddl_statement action, const char *err)
2381 : {
2382 101971 : sql_rel *res = NULL;
2383 101971 : char *sname = qname_schema(qname);
2384 101971 : char *fname = qname_schema_object(qname);
2385 101971 : sql_func *func = resolve_func(sql, sname, fname, typelist, type, err, 0);
2386 :
2387 101971 : if (!func)
2388 : return NULL;
2389 101970 : if (!func->s)
2390 0 : return sql_error(sql, 02, SQLSTATE(42000) "Cannot %s EXECUTE on system function '%s'", err, fname);
2391 203940 : for (dnode *gn = grantees->h; gn; gn = gn->next) {
2392 101970 : char *grantee = gn->data.sval;
2393 :
2394 101970 : if (!grantee)
2395 101485 : grantee = "public";
2396 :
2397 101970 : if (!privs) {
2398 4 : if ((res = rel_list(sql->sa, res, rel_func_priv(sql->sa, func->s->base.name, func->base.id, grantee, PRIV_EXECUTE, grant, grantor, action))) == NULL) {
2399 0 : rel_destroy(res);
2400 0 : return NULL;
2401 : }
2402 4 : continue;
2403 : }
2404 203932 : for (dnode *opn = privs->h; opn; opn = opn->next) {
2405 101966 : symbol *op = opn->data.sym;
2406 :
2407 101966 : if (op->token != SQL_EXECUTE)
2408 0 : return sql_error(sql, 02, SQLSTATE(42000) "Can only %s 'EXECUTE' on function '%s'", err, fname);
2409 101966 : if ((res = rel_list(sql->sa, res, rel_func_priv(sql->sa, func->s->base.name, func->base.id, grantee, PRIV_EXECUTE, grant, grantor, action))) == NULL) {
2410 0 : rel_destroy(res);
2411 0 : return NULL;
2412 : }
2413 : }
2414 : }
2415 : return res;
2416 : }
2417 :
2418 : static sql_rel *
2419 120936 : rel_grant_or_revoke_privs(mvc *sql, dlist *privs, dlist *grantees, int grant, int grantor, ddl_statement action)
2420 : {
2421 120936 : dlist *obj_privs = privs->h->data.lval;
2422 120936 : symbol *obj = privs->h->next->data.sym;
2423 120936 : tokens token = obj->token;
2424 120936 : const char *err = (action == ddl_grant) ? "GRANT" : "REVOKE";
2425 :
2426 120936 : switch (token) {
2427 12 : case SQL_GRANT:
2428 12 : return rel_grant_or_revoke_global(sql, obj_privs, grantees, grant, grantor, action);
2429 18953 : case SQL_TABLE:
2430 : case SQL_NAME:
2431 18953 : return rel_grant_or_revoke_table(sql, obj_privs, obj->data.lval, grantees, grant, grantor, action, err);
2432 101971 : case SQL_FUNC: {
2433 101971 : dlist *r = obj->data.lval;
2434 101971 : dlist *qname = r->h->data.lval;
2435 101971 : dlist *typelist = r->h->next->data.lval;
2436 101971 : sql_ftype type = (sql_ftype) r->h->next->next->data.i_val;
2437 :
2438 101972 : return rel_grant_or_revoke_func(sql, obj_privs, qname, typelist, type, grantees, grant, grantor, (action == ddl_grant) ? ddl_grant_func : ddl_revoke_func, err);
2439 : }
2440 0 : default:
2441 0 : return sql_error(sql, 02, SQLSTATE(M0M03) "%s: unknown token %d", err, (int) token);
2442 : }
2443 : }
2444 :
2445 : /* iname, itype, sname.tname (col1 .. coln) */
2446 : static sql_rel *
2447 343 : rel_create_index(mvc *sql, char *iname, idx_type itype, dlist *qname, dlist *column_list)
2448 : {
2449 343 : sql_table *t = NULL, *nt;
2450 343 : sql_rel *r, *res;
2451 343 : sql_exp **updates, *e;
2452 343 : sql_idx *i;
2453 343 : dnode *n;
2454 343 : char *sname = qname_schema(qname), *tname = qname_schema_object(qname), *s = iname;
2455 :
2456 343 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "CREATE INDEX", false)))
2457 : return NULL;
2458 342 : if (isDeclaredTable(t))
2459 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: cannot create index on a declared table");
2460 342 : if (!mvc_schema_privs(sql, t->s))
2461 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), t->s->base.name);
2462 342 : if (!s || !*s) /* add this to be safe */
2463 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: index name cannot be empty");
2464 342 : while (isdigit((unsigned char) *s))
2465 0 : s++;
2466 342 : if (!*s) /* if an index name just contains digit characters, it can be mistaken with a label */
2467 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: index name cannot contain just digit characters (0 through 9)");
2468 342 : if ((i = mvc_bind_idx(sql, t->s, iname)))
2469 3 : return sql_error(sql, 02, SQLSTATE(42S11) "CREATE INDEX: name '%s' already in use", iname);
2470 339 : if (ol_find_name(t->keys, iname) || mvc_bind_key(sql, t->s, iname))
2471 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: a key named '%s' already exists, and it would conflict with the index", iname);
2472 339 : if (!isTable(t))
2473 2 : return sql_error(sql, 02, SQLSTATE(42S02) "CREATE INDEX: cannot create index on %s '%s'", TABLE_TYPE_DESCRIPTION(t->type, t->properties), tname);
2474 337 : nt = dup_sql_table(sql->sa, t);
2475 :
2476 337 : if (t->persistence != SQL_DECLARED_TABLE)
2477 337 : sname = t->s->base.name;
2478 :
2479 : /* add index here */
2480 337 : switch (mvc_create_idx(&i, sql, nt, iname, itype)) {
2481 0 : case -1:
2482 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
2483 0 : case -2:
2484 : case -3:
2485 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: transaction conflict detected");
2486 : default:
2487 337 : break;
2488 : }
2489 768 : for (n = column_list->h; n; n = n->next) {
2490 433 : sql_column *c = mvc_bind_column(sql, nt, n->data.sval);
2491 :
2492 433 : if (!c)
2493 2 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "CREATE INDEX: no such column '%s'", n->data.sval);
2494 431 : switch (mvc_create_ic(sql, i, c)) {
2495 0 : case -1:
2496 0 : return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
2497 0 : case -2:
2498 : case -3:
2499 0 : return sql_error(sql, 02, SQLSTATE(42000) "CREATE INDEX: transaction conflict detected");
2500 : default:
2501 431 : break;
2502 : }
2503 : }
2504 335 : mvc_create_idx_done(sql, i);
2505 :
2506 : /* new columns need update with default values */
2507 335 : updates = SA_ZNEW_ARRAY(sql->sa, sql_exp*, ol_length(nt->columns));
2508 :
2509 335 : sql_alias *ta = table_alias(sql->sa, nt, schema_alias(sql->sa, t->s));
2510 335 : res = rel_table(sql, ddl_alter_table, sname, nt, 0);
2511 335 : e = exp_column(sql->sa, ta, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
2512 335 : sql_rel *bt = rel_ddl_basetable_get(res);
2513 335 : e->alias.label = rel_base_nid(bt, NULL);
2514 335 : e->nid = e->alias.label;
2515 335 : r = rel_project(sql->sa, res, append(new_exp_list(sql->sa),e));
2516 335 : res = rel_update(sql, res, r, updates, NULL);
2517 335 : return res;
2518 : }
2519 :
2520 : static sql_rel *
2521 363 : rel_create_user(allocator *sa, char *user, char *passwd, int enc, char *fullname, char *schema, char *schema_path, lng max_memory, int max_workers, char *optimizer, char *default_role)
2522 : {
2523 363 : sql_rel *rel = rel_create(sa);
2524 363 : list *exps = new_exp_list(sa);
2525 363 : if (!rel || !exps)
2526 : return NULL;
2527 :
2528 363 : append(exps, exp_atom_clob(sa, user));
2529 363 : append(exps, exp_atom_clob(sa, passwd));
2530 363 : append(exps, exp_atom_int(sa, enc));
2531 363 : append(exps, exp_atom_clob(sa, schema));
2532 363 : append(exps, exp_atom_clob(sa, schema_path));
2533 363 : append(exps, exp_atom_clob(sa, fullname));
2534 363 : append(exps, exp_atom_lng(sa, max_memory >= 0 ? max_memory : 0));
2535 363 : append(exps, exp_atom_int(sa, max_workers >= 0 ? max_workers: 0));
2536 363 : append(exps, exp_atom_clob(sa, optimizer));
2537 363 : append(exps, exp_atom_clob(sa, default_role));
2538 363 : rel->l = NULL;
2539 363 : rel->r = NULL;
2540 363 : rel->op = op_ddl;
2541 363 : rel->flag = ddl_create_user;
2542 363 : rel->exps = exps;
2543 363 : rel->card = 0;
2544 363 : rel->nrcols = 0;
2545 363 : return rel;
2546 : }
2547 :
2548 : static sql_rel *
2549 83 : rel_alter_user(allocator *sa, char *user, char *passwd, int enc, char *schema, char *schema_path, char *oldpasswd, char *role, lng max_memory, int max_workers)
2550 : {
2551 83 : sql_rel *rel = rel_create(sa);
2552 83 : list *exps = new_exp_list(sa);
2553 83 : if (!rel || !exps)
2554 : return NULL;
2555 :
2556 83 : append(exps, exp_atom_clob(sa, user));
2557 83 : append(exps, exp_atom_clob(sa, passwd));
2558 83 : append(exps, exp_atom_int(sa, enc));
2559 83 : append(exps, exp_atom_clob(sa, schema));
2560 83 : append(exps, exp_atom_clob(sa, schema_path));
2561 83 : append(exps, exp_atom_clob(sa, oldpasswd));
2562 83 : append(exps, exp_atom_clob(sa, role));
2563 83 : append(exps, exp_atom_lng(sa, max_memory));
2564 83 : append(exps, exp_atom_int(sa, max_workers));
2565 :
2566 83 : rel->l = NULL;
2567 83 : rel->r = NULL;
2568 83 : rel->op = op_ddl;
2569 83 : rel->flag = ddl_alter_user;
2570 83 : rel->exps = exps;
2571 83 : rel->card = 0;
2572 83 : rel->nrcols = 0;
2573 83 : return rel;
2574 : }
2575 :
2576 : static sqlid
2577 250 : rel_find_designated_schema(mvc *sql, symbol *sym, sql_schema **schema_out) {
2578 250 : char *sname;
2579 250 : sql_schema *s;
2580 :
2581 250 : assert(sym->type == type_string);
2582 250 : sname = sym->data.sval;
2583 250 : if (!(s = mvc_bind_schema(sql, sname))) {
2584 0 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000) "COMMENT ON: no such schema: '%s'", sname);
2585 0 : return 0;
2586 : }
2587 :
2588 250 : *schema_out = s;
2589 250 : return s->base.id;
2590 : }
2591 :
2592 : static sqlid
2593 29 : rel_find_designated_table(mvc *sql, symbol *sym, sql_schema **schema_out) {
2594 29 : dlist *qname;
2595 29 : char *sname, *tname;
2596 29 : sql_table *t;
2597 29 : int want_table = sym->token == SQL_TABLE;
2598 :
2599 29 : assert(sym->type == type_list);
2600 29 : qname = sym->data.lval;
2601 29 : sname = qname_schema(qname);
2602 29 : tname = qname_schema_object(qname);
2603 29 : t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COMMENT ON", !want_table);
2604 29 : if (t && isDeclaredTable(t)) {
2605 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON declared table not allowed");
2606 0 : return 0;
2607 : }
2608 29 : if (t && t->s && isTempSchema(t->s)) {
2609 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON tmp object not allowed");
2610 0 : return 0;
2611 : }
2612 51 : if (t && !want_table == !isKindOfTable(t)) { /* comparing booleans can be tricky */
2613 29 : *schema_out = t->s;
2614 29 : return t->base.id;
2615 : }
2616 :
2617 0 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S02) "COMMENT ON: no such %s: %s%s%s'%s'",
2618 : want_table ? "table" : "view", sname ? "'":"", sname ? sname : "", sname ? "'.":"", tname);
2619 0 : return 0;
2620 : }
2621 :
2622 : static sqlid
2623 24 : rel_find_designated_column(mvc *sql, symbol *sym, sql_schema **schema_out) {
2624 24 : char *sname, *tname, *cname;
2625 24 : dlist *colname;
2626 24 : sql_table *t;
2627 24 : sql_column *c;
2628 :
2629 24 : assert(sym->type == type_list);
2630 24 : colname = sym->data.lval;
2631 24 : assert(colname->cnt == 2 || colname->cnt == 3);
2632 24 : assert(colname->h->type == type_string);
2633 24 : assert(colname->h->next->type == type_string);
2634 24 : if (colname->cnt == 2) {
2635 10 : sname = NULL;
2636 10 : tname = colname->h->data.sval;
2637 10 : cname = colname->h->next->data.sval;
2638 : } else {
2639 : // cnt == 3
2640 14 : sname = colname->h->data.sval;
2641 14 : tname = colname->h->next->data.sval;
2642 14 : assert(colname->h->next->next->type == type_string);
2643 14 : cname = colname->h->next->next->data.sval;
2644 : }
2645 24 : if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COMMENT ON", false)))
2646 : return 0;
2647 24 : if (t && isDeclaredTable(t)) {
2648 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON declared table not allowed");
2649 0 : return 0;
2650 : }
2651 24 : if (t && t->s && isTempSchema(t->s)) {
2652 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON tmp object not allowed");
2653 0 : return 0;
2654 : }
2655 24 : if (!(c = mvc_bind_column(sql, t, cname))) {
2656 0 : sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S12) "COMMENT ON: no such column: %s%s%s'%s'.'%s'",
2657 : sname ? "'":"", sname ? sname : "", sname ? "'.":"", tname, cname);
2658 0 : return 0;
2659 : }
2660 24 : *schema_out = t->s;
2661 24 : return c->base.id;
2662 : }
2663 :
2664 : static sqlid
2665 21 : rel_find_designated_index(mvc *sql, symbol *sym, sql_schema **schema_out) {
2666 21 : dlist *qname;
2667 21 : char *iname, *sname;
2668 21 : sql_idx *idx;
2669 :
2670 21 : assert(sym->type == type_list);
2671 21 : qname = sym->data.lval;
2672 21 : sname = qname_schema(qname);
2673 21 : iname = qname_schema_object(qname);
2674 21 : if (!(idx = find_idx_on_scope(sql, sname, iname, "COMMENT ON")))
2675 : return 0;
2676 21 : if (idx && idx->t->s && isTempSchema(idx->t->s)) {
2677 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON tmp object not allowed");
2678 0 : return 0;
2679 : }
2680 : if (idx) {
2681 21 : *schema_out = idx->t->s;
2682 21 : return idx->base.id;
2683 : }
2684 :
2685 : return 0;
2686 : }
2687 :
2688 : static sqlid
2689 12 : rel_find_designated_sequence(mvc *sql, symbol *sym, sql_schema **schema_out) {
2690 12 : (void)sql;
2691 12 : (void)sym;
2692 12 : dlist *qname;
2693 12 : char *seqname, *sname;
2694 12 : sql_sequence *seq;
2695 :
2696 12 : assert(sym->type == type_list);
2697 12 : qname = sym->data.lval;
2698 12 : sname = qname_schema(qname);
2699 12 : seqname = qname_schema_object(qname);
2700 :
2701 12 : seq = find_sequence_on_scope(sql, sname, seqname, "COMMENT ON");
2702 12 : if (seq && seq->s && isTempSchema(seq->s)) {
2703 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON tmp object not allowed");
2704 0 : return 0;
2705 : }
2706 : if (seq) {
2707 12 : *schema_out = seq->s;
2708 12 : return seq->base.id;
2709 : }
2710 :
2711 : return 0;
2712 : }
2713 :
2714 : static sqlid
2715 24 : rel_find_designated_routine(mvc *sql, symbol *sym, sql_schema **schema_out) {
2716 24 : (void)sql;
2717 24 : (void)sym;
2718 24 : dlist *designator;
2719 24 : dlist *qname;
2720 24 : dlist *typelist;
2721 24 : sql_ftype func_type;
2722 24 : char *fname, *sname;
2723 24 : sql_func *func;
2724 :
2725 24 : assert(sym->type == type_list);
2726 24 : designator = sym->data.lval;
2727 24 : assert(designator->cnt == 3);
2728 24 : qname = designator->h->data.lval;
2729 24 : sname = qname_schema(qname);
2730 24 : typelist = designator->h->next->data.lval;
2731 24 : func_type = (sql_ftype) designator->h->next->next->data.i_val;
2732 :
2733 24 : fname = qname_schema_object(qname);
2734 24 : func = resolve_func(sql, sname, fname, typelist, func_type, "COMMENT", 0);
2735 24 : if (func && func->s && isTempSchema(func->s)) {
2736 0 : sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON tmp object not allowed");
2737 0 : return 0;
2738 : }
2739 : if (func) {
2740 24 : *schema_out = func->s ? func->s : mvc_bind_schema(sql, "sys");
2741 24 : return func->base.id;
2742 : }
2743 :
2744 : return 0;
2745 : }
2746 :
2747 : static sqlid
2748 360 : rel_find_designated_object(mvc *sql, symbol *sym, sql_schema **schema_out)
2749 : {
2750 360 : sql_schema *dummy = NULL;
2751 :
2752 360 : if (schema_out == NULL)
2753 0 : schema_out = &dummy;
2754 360 : switch (sym->token) {
2755 250 : case SQL_SCHEMA:
2756 250 : return rel_find_designated_schema(sql, sym, schema_out);
2757 22 : case SQL_TABLE:
2758 22 : return rel_find_designated_table(sql, sym, schema_out);
2759 7 : case SQL_VIEW:
2760 7 : return rel_find_designated_table(sql, sym, schema_out);
2761 24 : case SQL_COLUMN:
2762 24 : return rel_find_designated_column(sql, sym, schema_out);
2763 21 : case SQL_INDEX:
2764 21 : return rel_find_designated_index(sql, sym, schema_out);
2765 12 : case SQL_SEQUENCE:
2766 12 : return rel_find_designated_sequence(sql, sym, schema_out);
2767 24 : case SQL_ROUTINE:
2768 24 : return rel_find_designated_routine(sql, sym, schema_out);
2769 0 : default:
2770 0 : sql_error(sql, 2, SQLSTATE(42000) "COMMENT ON %s is not supported", token2string(sym->token));
2771 0 : return 0;
2772 : }
2773 : }
2774 :
2775 : static sql_rel *
2776 359 : rel_comment_on(allocator *sa, sqlid obj_id, const char *remark)
2777 : {
2778 359 : sql_rel *rel = rel_create(sa);
2779 359 : list *exps = new_exp_list(sa);
2780 :
2781 359 : if (rel == NULL || exps == NULL)
2782 : return NULL;
2783 :
2784 359 : append(exps, exp_atom_int(sa, obj_id));
2785 359 : append(exps, exp_atom_clob(sa, remark));
2786 359 : rel->l = NULL;
2787 359 : rel->r = NULL;
2788 359 : rel->op = op_ddl;
2789 359 : rel->flag = ddl_comment_on;
2790 359 : rel->exps = exps;
2791 359 : rel->card = 0;
2792 359 : rel->nrcols = 0;
2793 359 : return rel;
2794 : }
2795 :
2796 : static char *
2797 10328 : credentials_username(dlist *credentials)
2798 : {
2799 10328 : if (credentials == NULL) {
2800 : return NULL;
2801 : }
2802 104 : assert(credentials->h);
2803 :
2804 104 : if (credentials->h->data.sval != NULL) {
2805 : return credentials->h->data.sval;
2806 : }
2807 :
2808 : // No username specified.
2809 : return NULL;
2810 : }
2811 :
2812 : static char *
2813 10328 : credentials_password(dlist *credentials)
2814 : {
2815 10328 : if (credentials == NULL) {
2816 : return NULL;
2817 : }
2818 104 : assert(credentials->h);
2819 :
2820 104 : char *password = credentials->h->next->next->data.sval;
2821 :
2822 104 : return password;
2823 : }
2824 :
2825 : static sql_rel *
2826 11 : rel_rename_schema(mvc *sql, char *old_name, char *new_name, int if_exists)
2827 : {
2828 11 : sql_schema *s;
2829 11 : sql_rel *rel;
2830 11 : list *exps;
2831 :
2832 11 : assert(old_name && new_name);
2833 11 : if (!(s = mvc_bind_schema(sql, old_name))) {
2834 1 : if (if_exists)
2835 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
2836 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(3F000)
2837 : "ALTER SCHEMA: no such schema '%s'", old_name);
2838 : }
2839 :
2840 10 : if (!mvc_schema_privs(sql, s))
2841 0 : return sql_error(sql, 02, SQLSTATE(3F000)
2842 : "ALTER SCHEMA: access denied for %s to schema '%s'",
2843 : get_string_global_var(sql, "current_user"), old_name);
2844 :
2845 10 : if (s->system)
2846 1 : return sql_error(sql, 02, SQLSTATE(3F000)
2847 : "ALTER SCHEMA: cannot rename a system schema");
2848 :
2849 9 : if (strNil(new_name) || *new_name == '\0')
2850 0 : return sql_error(sql, 02, SQLSTATE(3F000)
2851 : "ALTER SCHEMA: invalid new schema name");
2852 :
2853 9 : if (mvc_bind_schema(sql, new_name))
2854 0 : return sql_error(sql, 02, SQLSTATE(3F000)
2855 : "ALTER SCHEMA: there is a schema named '%s' in the database", new_name);
2856 :
2857 9 : if (mvc_check_dependency(sql, s->base.id, SCHEMA_DEPENDENCY, NULL) != NO_DEPENDENCY) {
2858 1 : return sql_error(sql, 02,
2859 : SQLSTATE(2BM37) "ALTER SCHEMA: unable to"
2860 : " rename schema '%s', there are database objects"
2861 : " which depend on it", old_name);
2862 : }
2863 :
2864 8 : rel = rel_create(sql->sa);
2865 8 : exps = new_exp_list(sql->sa);
2866 8 : append(exps, exp_atom_clob(sql->sa, old_name));
2867 8 : append(exps, exp_atom_clob(sql->sa, new_name));
2868 8 : rel->op = op_ddl;
2869 8 : rel->flag = ddl_rename_schema;
2870 8 : rel->exps = exps;
2871 :
2872 8 : return rel;
2873 : }
2874 :
2875 : static sql_rel *
2876 23 : rel_rename_table(mvc *sql, char *schema_name, char *old_name, char *new_name, int if_exists)
2877 : {
2878 23 : sql_table *t = NULL;
2879 23 : sql_rel *rel;
2880 23 : list *exps;
2881 :
2882 23 : assert(old_name && new_name);
2883 :
2884 23 : if (!(t = find_table_or_view_on_scope(sql, NULL, schema_name, old_name, "ALTER TABLE", false))) {
2885 1 : if (if_exists) {
2886 1 : sql->errstr[0] = '\0'; /* reset table not found error */
2887 1 : sql->session->status = 0;
2888 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
2889 : }
2890 : return NULL;
2891 : }
2892 22 : if (isDeclaredTable(t))
2893 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename a declared table");
2894 22 : if (!mvc_schema_privs(sql, t->s))
2895 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), t->s->base.name);
2896 22 : if (t->system)
2897 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename a system table");
2898 22 : if (isView(t))
2899 1 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename a view");
2900 21 : if (mvc_check_dependency(sql, t->base.id, TABLE_DEPENDENCY, NULL))
2901 2 : return sql_error(sql, 02, SQLSTATE(2BM37) "ALTER TABLE: unable to rename table '%s' (there are database objects which depend on it)", old_name);
2902 19 : if (strNil(new_name) || *new_name == '\0')
2903 0 : return sql_error(sql, 02, SQLSTATE(3F000) "ALTER TABLE: invalid new table name");
2904 19 : if (mvc_bind_table(sql, t->s, new_name))
2905 0 : return sql_error(sql, 02, SQLSTATE(3F000) "ALTER TABLE: there is a table named '%s' in schema '%s'", new_name, t->s->base.name);
2906 :
2907 19 : rel = rel_create(sql->sa);
2908 19 : exps = new_exp_list(sql->sa);
2909 19 : append(exps, exp_atom_clob(sql->sa, t->s->base.name));
2910 19 : append(exps, exp_atom_clob(sql->sa, t->s->base.name));
2911 19 : append(exps, exp_atom_clob(sql->sa, old_name));
2912 19 : append(exps, exp_atom_clob(sql->sa, new_name));
2913 19 : rel->op = op_ddl;
2914 19 : rel->flag = ddl_rename_table;
2915 19 : rel->exps = exps;
2916 19 : return rel;
2917 : }
2918 :
2919 : static sql_rel *
2920 20 : rel_rename_column(mvc *sql, char *schema_name, char *table_name, char *old_name, char *new_name, int if_exists)
2921 : {
2922 20 : sql_table *t = NULL;
2923 20 : sql_column *col;
2924 20 : sql_rel *rel;
2925 20 : list *exps;
2926 :
2927 20 : assert(table_name && old_name && new_name);
2928 :
2929 20 : if (!(t = find_table_or_view_on_scope(sql, NULL, schema_name, table_name, "ALTER TABLE", false))) {
2930 2 : if (if_exists) {
2931 1 : sql->errstr[0] = '\0'; /* reset table not found error */
2932 1 : sql->session->status = 0;
2933 1 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
2934 : }
2935 : return NULL;
2936 : }
2937 18 : if (isDeclaredTable(t))
2938 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename a column in a declared table");
2939 18 : if (!mvc_schema_privs(sql, t->s))
2940 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), t->s->base.name);
2941 18 : if (t->system)
2942 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename a column in a system table");
2943 18 : if (isView(t))
2944 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot rename column '%s': '%s' is a view", old_name, table_name);
2945 18 : if (!(col = mvc_bind_column(sql, t, old_name)))
2946 5 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "ALTER TABLE: no such column '%s' in table '%s'", old_name, table_name);
2947 13 : if (mvc_check_dependency(sql, col->base.id, COLUMN_DEPENDENCY, NULL))
2948 0 : return sql_error(sql, 02, SQLSTATE(2BM37) "ALTER TABLE: cannot rename column '%s' (there are database objects which depend on it)", old_name);
2949 13 : if (strNil(new_name) || *new_name == '\0')
2950 0 : return sql_error(sql, 02, SQLSTATE(3F000) "ALTER TABLE: invalid new column name");
2951 13 : if (mvc_bind_column(sql, t, new_name))
2952 0 : return sql_error(sql, 02, SQLSTATE(3F000) "ALTER TABLE: there is a column named '%s' in table '%s'", new_name, table_name);
2953 :
2954 13 : rel = rel_create(sql->sa);
2955 13 : exps = new_exp_list(sql->sa);
2956 13 : append(exps, exp_atom_clob(sql->sa, t->s->base.name));
2957 13 : append(exps, exp_atom_clob(sql->sa, table_name));
2958 13 : append(exps, exp_atom_clob(sql->sa, old_name));
2959 13 : append(exps, exp_atom_clob(sql->sa, new_name));
2960 13 : rel->op = op_ddl;
2961 13 : rel->flag = ddl_rename_column;
2962 13 : rel->exps = exps;
2963 13 : return rel;
2964 : }
2965 :
2966 : static sql_rel *
2967 29 : rel_set_table_schema(sql_query *query, char *old_schema, char *tname, char *new_schema, int if_exists)
2968 : {
2969 29 : mvc *sql = query->sql;
2970 29 : sql_schema *ns = NULL;
2971 29 : sql_table *ot = NULL;
2972 29 : sql_rel *rel;
2973 29 : list *exps;
2974 :
2975 29 : assert(tname && new_schema);
2976 :
2977 29 : if (!(ot = find_table_or_view_on_scope(sql, NULL, old_schema, tname, "ALTER TABLE", false))) {
2978 0 : if (if_exists) {
2979 0 : sql->errstr[0] = '\0'; /* reset table not found error */
2980 0 : sql->session->status = 0;
2981 0 : return rel_psm_block(sql->sa, new_exp_list(sql->sa));
2982 : }
2983 : return NULL;
2984 : }
2985 29 : if (isDeclaredTable(ot))
2986 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: not possible to change schema of a declared table");
2987 29 : if (!mvc_schema_privs(sql, ot->s))
2988 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: access denied for %s to schema '%s'", get_string_global_var(sql, "current_user"), ot->s->base.name);
2989 29 : if (ot->system)
2990 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: cannot set schema of a system table");
2991 29 : if (isTempSchema(ot->s))
2992 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: not possible to change a temporary table schema");
2993 29 : if (isView(ot))
2994 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: not possible to change schema of a view");
2995 29 : if (mvc_check_dependency(sql, ot->base.id, TABLE_DEPENDENCY, NULL) || list_length(ot->members) || ol_length(ot->triggers))
2996 3 : return sql_error(sql, 02, SQLSTATE(2BM37) "ALTER TABLE: unable to set schema of table '%s' (there are database objects which depend on it)", tname);
2997 26 : if (!(ns = mvc_bind_schema(sql, new_schema)))
2998 0 : return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S02) "ALTER TABLE: no such schema '%s'", new_schema);
2999 26 : if (!mvc_schema_privs(sql, ns))
3000 0 : return sql_error(sql, 02, SQLSTATE(42000) "ALTER TABLE: access denied for '%s' to schema '%s'", get_string_global_var(sql, "current_user"), new_schema);
3001 26 : if (isTempSchema(ns))
3002 0 : return sql_error(sql, 02, SQLSTATE(3F000) "ALTER TABLE: not possible to change table's schema to temporary");
3003 26 : if (mvc_bind_table(sql, ns, tname))
3004 0 : return sql_error(sql, 02, SQLSTATE(42S02) "ALTER TABLE: table '%s' on schema '%s' already exists", tname, new_schema);
3005 :
3006 26 : rel = rel_create(sql->sa);
3007 26 : exps = new_exp_list(sql->sa);
3008 26 : append(exps, exp_atom_clob(sql->sa, ot->s->base.name));
3009 26 : append(exps, exp_atom_clob(sql->sa, new_schema));
3010 26 : append(exps, exp_atom_clob(sql->sa, tname));
3011 26 : append(exps, exp_atom_clob(sql->sa, tname));
3012 26 : rel->op = op_ddl;
3013 26 : rel->flag = ddl_rename_table;
3014 26 : rel->exps = exps;
3015 26 : return rel;
3016 : }
3017 :
3018 : sql_rel *
3019 222840 : rel_schemas(sql_query *query, symbol *s)
3020 : {
3021 222840 : mvc *sql = query->sql;
3022 222840 : sql_rel *ret = NULL;
3023 :
3024 222840 : if (s->token != SQL_CREATE_TABLE && s->token != SQL_CREATE_VIEW && store_readonly(sql->session->tr->store))
3025 2 : return sql_error(sql, 06, SQLSTATE(25006) "Schema statements cannot be executed on a readonly database.");
3026 :
3027 222838 : switch (s->token) {
3028 1107 : case SQL_CREATE_SCHEMA:
3029 : {
3030 1107 : dlist *l = s->data.lval;
3031 :
3032 1107 : ret = rel_create_schema(query, l->h->data.lval,
3033 1107 : l->h->next->next->next->data.lval,
3034 1107 : l->h->next->next->next->next->data.i_val); /* if not exists */
3035 1107 : } break;
3036 193 : case SQL_DROP_SCHEMA:
3037 : {
3038 193 : dlist *l = s->data.lval;
3039 193 : dlist *auth_name = l->h->data.lval;
3040 :
3041 193 : assert(l->h->next->type == type_int);
3042 386 : ret = rel_drop(sql->sa, ddl_drop_schema,
3043 : dlist_get_schema_name(auth_name),
3044 : NULL,
3045 : NULL,
3046 : l->h->next->data.i_val, /* drop_action */
3047 193 : l->h->next->next->data.i_val); /* if exists */
3048 193 : } break;
3049 1 : case SQL_DECLARE_TABLE:
3050 1 : return sql_error(sql, 02, SQLSTATE(42000) "Tables cannot be declared on the global scope");
3051 10328 : case SQL_CREATE_TABLE:
3052 : {
3053 10328 : dlist *l = s->data.lval;
3054 10328 : dlist *qname = l->h->next->data.lval;
3055 10328 : char *sname = qname_schema(qname);
3056 10328 : char *name = qname_schema_object(qname);
3057 10328 : int temp = l->h->data.i_val;
3058 10328 : dlist *credentials = l->h->next->next->next->next->next->data.lval;
3059 10328 : char *username = credentials_username(credentials);
3060 10328 : char *password = credentials_password(credentials);
3061 10328 : bool pw_encrypted = credentials == NULL || credentials->h->next->data.i_val == SQL_PW_ENCRYPTED;
3062 10328 : if (username == NULL) {
3063 : // No username specified, get the current username
3064 10312 : username = get_string_global_var(sql, "current_user");
3065 : }
3066 :
3067 10328 : assert(l->h->type == type_int);
3068 10328 : assert(l->h->next->next->next->type == type_int);
3069 10328 : ret = rel_create_table(query, temp, sname, name, true,
3070 10328 : l->h->next->next->data.sym, /* elements or subquery */
3071 : l->h->next->next->next->data.i_val, /* commit action */
3072 10328 : l->h->next->next->next->next->data.sval, /* location */
3073 : username, password, pw_encrypted,
3074 10328 : l->h->next->next->next->next->next->next->next->data.sym,
3075 10328 : l->h->next->next->next->next->next->next->data.i_val); /* if not exists */
3076 10328 : } break;
3077 78809 : case SQL_CREATE_VIEW:
3078 : {
3079 78809 : dlist *l = s->data.lval;
3080 :
3081 78809 : assert(l->h->type == type_int);
3082 78809 : assert(l->h->next->next->next->next->type == type_int);
3083 78809 : assert(l->h->next->next->next->next->next->type == type_int);
3084 78809 : ret = rel_create_view(query, l->h->data.i_val,
3085 78809 : l->h->next->data.lval,
3086 78809 : l->h->next->next->data.lval,
3087 78809 : l->h->next->next->next->data.sym,
3088 : l->h->next->next->next->next->data.i_val,
3089 : l->h->next->next->next->next->next->data.i_val,
3090 78809 : l->h->next->next->next->next->next->next->data.i_val); /* or replace */
3091 78809 : } break;
3092 3876 : case SQL_DROP_TABLE:
3093 : {
3094 3876 : dlist *l = s->data.lval;
3095 :
3096 3876 : assert(l->h->next->type == type_int);
3097 3876 : ret = sql_drop_table(query, l->h->data.lval,
3098 : l->h->next->data.i_val,
3099 3876 : l->h->next->next->data.i_val); /* if exists */
3100 3876 : } break;
3101 503 : case SQL_DROP_VIEW:
3102 : {
3103 503 : dlist *l = s->data.lval;
3104 :
3105 503 : assert(l->h->next->type == type_int);
3106 503 : ret = sql_drop_view(query, l->h->data.lval,
3107 : l->h->next->data.i_val,
3108 503 : l->h->next->next->data.i_val); /* if exists */
3109 503 : } break;
3110 4445 : case SQL_ALTER_TABLE:
3111 : {
3112 4445 : dlist *l = s->data.lval;
3113 :
3114 4445 : ret = sql_alter_table(query, l,
3115 4445 : l->h->data.lval, /* table name */
3116 4445 : l->h->next->data.sym, /* table element */
3117 4445 : l->h->next->next->data.i_val); /* if exists */
3118 4445 : } break;
3119 40 : case SQL_GRANT_ROLES:
3120 : {
3121 40 : dlist *l = s->data.lval;
3122 :
3123 40 : assert(l->h->next->next->type == type_int);
3124 40 : assert(l->h->next->next->next->type == type_int);
3125 40 : ret = rel_grant_or_revoke_roles(sql, l->h->data.lval, /* authids */
3126 40 : l->h->next->data.lval, /* grantees */
3127 : l->h->next->next->data.i_val, /* admin? */
3128 40 : l->h->next->next->next->data.i_val == cur_user ? sql->user_id : sql->role_id, ddl_grant_roles);
3129 : /* grantor ? */
3130 40 : } break;
3131 10 : case SQL_REVOKE_ROLES:
3132 : {
3133 10 : dlist *l = s->data.lval;
3134 :
3135 10 : assert(l->h->next->next->type == type_int);
3136 10 : assert(l->h->next->next->next->type == type_int);
3137 10 : ret = rel_grant_or_revoke_roles(sql, l->h->data.lval, /* authids */
3138 10 : l->h->next->data.lval, /* grantees */
3139 : l->h->next->next->data.i_val, /* admin? */
3140 10 : l->h->next->next->next->data.i_val == cur_user? sql->user_id : sql->role_id, ddl_revoke_roles);
3141 : /* grantor ? */
3142 10 : } break;
3143 120920 : case SQL_GRANT:
3144 : {
3145 120920 : dlist *l = s->data.lval;
3146 :
3147 120920 : assert(l->h->next->next->type == type_int);
3148 120920 : assert(l->h->next->next->next->type == type_int);
3149 120920 : ret = rel_grant_or_revoke_privs(sql, l->h->data.lval, /* privileges */
3150 120920 : l->h->next->data.lval, /* grantees */
3151 : l->h->next->next->data.i_val, /* grant ? */
3152 120920 : l->h->next->next->next->data.i_val == cur_user? sql->user_id : sql->role_id, ddl_grant);
3153 : /* grantor ? */
3154 120920 : } break;
3155 16 : case SQL_REVOKE:
3156 : {
3157 16 : dlist *l = s->data.lval;
3158 :
3159 16 : assert(l->h->next->next->type == type_int);
3160 16 : assert(l->h->next->next->next->type == type_int);
3161 16 : ret = rel_grant_or_revoke_privs(sql, l->h->data.lval, /* privileges */
3162 16 : l->h->next->data.lval, /* grantees */
3163 : l->h->next->next->data.i_val, /* grant ? */
3164 16 : l->h->next->next->next->data.i_val == cur_user? sql->user_id : sql->role_id, ddl_revoke);
3165 : /* grantor ? */
3166 16 : } break;
3167 26 : case SQL_CREATE_ROLE:
3168 : {
3169 26 : dlist *l = s->data.lval;
3170 26 : char *rname = l->h->data.sval;
3171 26 : ret = rel_schema2(sql->sa, ddl_create_role, rname, NULL,
3172 26 : l->h->next->data.i_val == cur_user? sql->user_id : sql->role_id);
3173 26 : } break;
3174 19 : case SQL_DROP_ROLE:
3175 : {
3176 19 : char *rname = s->data.sval;
3177 19 : ret = rel_schema2(sql->sa, ddl_drop_role, rname, NULL, 0);
3178 19 : } break;
3179 343 : case SQL_CREATE_INDEX: {
3180 343 : dlist *l = s->data.lval;
3181 :
3182 343 : assert(l->h->next->type == type_int);
3183 343 : ret = rel_create_index(sql, l->h->data.sval, (idx_type) l->h->next->data.i_val, l->h->next->next->data.lval, l->h->next->next->next->data.lval);
3184 343 : } break;
3185 197 : case SQL_DROP_INDEX: {
3186 197 : dlist *l = s->data.lval;
3187 197 : char *sname = qname_schema(l);
3188 197 : char *iname = qname_schema_object(l);
3189 197 : sql_idx *idx = NULL;
3190 :
3191 197 : if (!(idx = find_idx_on_scope(sql, sname, iname, "DROP INDEX")))
3192 : return NULL;
3193 160 : ret = rel_schema2(sql->sa, ddl_drop_index, idx->t->s->base.name, iname, 0);
3194 160 : } break;
3195 363 : case SQL_CREATE_USER: {
3196 363 : dlist *l = s->data.lval;
3197 363 : dlist *schema_details = l->h->next->next->next->data.lval;
3198 :
3199 363 : ret = rel_create_user(sql->sa, l->h->data.sval, /* user name */
3200 : l->h->next->data.sval, /* password */
3201 363 : l->h->next->next->next->next->data.i_val == SQL_PW_ENCRYPTED, /* encrypted */
3202 : l->h->next->next->data.sval, /* fullname */
3203 : schema_details->h->data.sval, /* schema ident*/
3204 363 : schema_details->h->next->data.sval, /* schema path */
3205 : l->h->next->next->next->next->next->data.l_val, /* max memory */
3206 : l->h->next->next->next->next->next->next->data.i_val, /* max workers */
3207 : l->h->next->next->next->next->next->next->next->data.sval, /* optimizer */
3208 363 : l->h->next->next->next->next->next->next->next->next->data.sval); /* default role */
3209 363 : } break;
3210 107 : case SQL_DROP_USER:
3211 107 : ret = rel_schema2(sql->sa, ddl_drop_user, s->data.sval, NULL, 0);
3212 107 : break;
3213 83 : case SQL_ALTER_USER: {
3214 83 : dlist *l = s->data.lval;
3215 83 : dnode *a = l->h->next->data.lval->h;
3216 :
3217 83 : ret = rel_alter_user(sql->sa, l->h->data.sval, /* user */
3218 : a->data.sval, /* passwd */
3219 83 : a->next->next->next->data.i_val == SQL_PW_ENCRYPTED, /* encrypted */
3220 : a->next->data.sval, /* schema */
3221 : a->next->next->data.sval, /* schema path */
3222 83 : a->next->next->next->next->data.sval, /* old passwd */
3223 : l->h->next->next->data.sval, /* default role */
3224 : l->h->next->next->next->data.l_val, /* max_memory */
3225 83 : l->h->next->next->next->next->data.i_val /* max_workers */
3226 : );
3227 83 : } break;
3228 5 : case SQL_RENAME_USER: {
3229 5 : dlist *l = s->data.lval;
3230 :
3231 5 : ret = rel_schema2(sql->sa, ddl_rename_user, l->h->data.sval, l->h->next->data.sval, 0);
3232 5 : } break;
3233 11 : case SQL_RENAME_SCHEMA: {
3234 11 : dlist *l = s->data.lval;
3235 11 : ret = rel_rename_schema(sql, l->h->data.sval, l->h->next->data.sval, l->h->next->next->data.i_val);
3236 11 : } break;
3237 23 : case SQL_RENAME_TABLE: {
3238 23 : dlist *l = s->data.lval;
3239 23 : char *sname = qname_schema(l->h->data.lval);
3240 23 : char *tname = qname_schema_object(l->h->data.lval);
3241 23 : ret = rel_rename_table(sql, sname, tname, l->h->next->data.sval, l->h->next->next->data.i_val);
3242 23 : } break;
3243 20 : case SQL_RENAME_COLUMN: {
3244 20 : dlist *l = s->data.lval;
3245 20 : char *sname = qname_schema(l->h->data.lval);
3246 20 : char *tname = qname_schema_object(l->h->data.lval);
3247 20 : ret = rel_rename_column(sql, sname, tname, l->h->next->data.sval, l->h->next->next->data.sval, l->h->next->next->next->data.i_val);
3248 20 : } break;
3249 29 : case SQL_SET_TABLE_SCHEMA: {
3250 29 : dlist *l = s->data.lval;
3251 29 : char *sname = qname_schema(l->h->data.lval);
3252 29 : char *tname = qname_schema_object(l->h->data.lval);
3253 29 : ret = rel_set_table_schema(query, sname, tname, l->h->next->data.sval, l->h->next->next->data.i_val);
3254 29 : } break;
3255 963 : case SQL_CREATE_TYPE: {
3256 963 : dlist *l = s->data.lval;
3257 :
3258 963 : ret = rel_create_type(sql, l->h->data.lval, l->h->next);
3259 963 : } break;
3260 41 : case SQL_DROP_TYPE: {
3261 41 : dlist *l = s->data.lval;
3262 41 : ret = rel_drop_type(sql, l->h->data.lval, l->h->next->data.i_val);
3263 41 : } break;
3264 360 : case SQL_COMMENT:
3265 : {
3266 360 : dlist *l = s->data.lval;
3267 360 : symbol *catalog_object = l->h->data.sym;
3268 360 : char *remark;
3269 360 : sql_schema *s;
3270 360 : sqlid id;
3271 :
3272 360 : assert(l->cnt == 2);
3273 360 : remark = l->h->next->data.sval;
3274 :
3275 360 : id = rel_find_designated_object(sql, catalog_object, &s);
3276 360 : if (!id) {
3277 : /* rel_find_designated_object has already set the error message so we don't have to */
3278 : return NULL;
3279 : }
3280 :
3281 : // Check authorization
3282 360 : if (!mvc_schema_privs(sql, s)) {
3283 1 : return sql_error(sql, 02, SQLSTATE(42000) "COMMENT ON: insufficient privileges for user '%s' in schema '%s'", get_string_global_var(sql, "current_user"), s->base.name);
3284 : }
3285 :
3286 359 : return rel_comment_on(sql->sa, id, remark);
3287 : }
3288 0 : default:
3289 0 : return sql_error(sql, 01, SQLSTATE(M0M03) "Schema statement unknown symbol(%p)->token = %s", s, token2string(s->token));
3290 : }
3291 :
3292 222440 : sql->type = Q_SCHEMA;
3293 222440 : return ret;
3294 : }
|