LCOV - code coverage report
Current view: top level - sql/server - rel_schema.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1629 2067 78.8 %
Date: 2024-04-26 00:35:57 Functions: 58 58 100.0 %

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

Generated by: LCOV version 1.14