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

Generated by: LCOV version 1.14