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

Generated by: LCOV version 1.14