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