LCOV - code coverage report
Current view: top level - sql/server - rel_updates.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1359 1475 92.1 %
Date: 2025-03-25 21:27:32 Functions: 43 43 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, 2025 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "rel_updates.h"
      15             : #include "rel_semantic.h"
      16             : #include "rel_select.h"
      17             : #include "rel_rel.h"
      18             : #include "rel_basetable.h"
      19             : #include "rel_exp.h"
      20             : #include "rel_schema.h"
      21             : #include "sql_privileges.h"
      22             : #include "sql_partition.h"
      23             : #include "rel_dump.h"
      24             : #include "rel_psm.h"
      25             : #include "sql_symbol.h"
      26             : #include "rel_prop.h"
      27             : #include "sql_storage.h"
      28             : 
      29             : static sql_exp *
      30     1310221 : insert_value(sql_query *query, sql_column *c, sql_rel **r, symbol *s, const char* action)
      31             : {
      32     1310221 :         mvc *sql = query->sql;
      33     1310221 :         if (s->token == SQL_NULL) {
      34       45662 :                 return exp_atom(sql->sa, atom_general(sql->sa, &c->type, NULL, 0));
      35     1264559 :         } else if (s->token == SQL_DEFAULT) {
      36          22 :                 if (c->def) {
      37          20 :                         sql_exp *e = rel_parse_val(sql, c->t->s, c->def, &c->type, sql->emode, NULL);
      38          20 :                         if (!e || (e = exp_check_type(sql, &c->type, r ? *r : NULL, e, type_equal)) == NULL)
      39           0 :                                 return NULL;
      40             :                         return e;
      41             :                 } else {
      42           2 :                         return sql_error(sql, 02, SQLSTATE(42000) "%s: column '%s' has no valid default value", action, c->base.name);
      43             :                 }
      44             :         } else {
      45     1264537 :                 exp_kind ek = {type_value, card_value, FALSE};
      46             : #if 0
      47             :                 if (c->type.type->composite) {
      48             :                         ek.card = card_row;
      49             :                         ek.type = list_length(c->type.type->d.fields); /* TODO how to handle recursive onces */
      50             :                 }
      51             : #endif
      52     1264537 :                 sql_exp *e = rel_value_exp2(query, r, s, sql_sel | sql_values, ek);
      53             : 
      54     1264804 :                 if (!e)
      55             :                         return(NULL);
      56     1264787 :                 return exp_check_type(sql, &c->type, r ? *r : NULL, e, type_equal);
      57             :         }
      58             : }
      59             : 
      60             : static sql_exp **
      61      122281 : insert_exp_array(mvc *sql, sql_table *t, int *Len)
      62             : {
      63      122281 :         *Len = ol_length(t->columns);
      64      122350 :         return SA_ZNEW_ARRAY(sql->sa, sql_exp*, *Len);
      65             : }
      66             : 
      67             : sql_table *
      68      127669 : get_table(sql_rel *t)
      69             : {
      70      127669 :         sql_table *tab = NULL;
      71             : 
      72      127669 :         assert(is_updateble(t));
      73      127669 :         if (t->op == op_basetable) { /* existing base table */
      74      126220 :                 tab = t->l;
      75        1449 :         } else if (t->op == op_ddl &&
      76        1449 :                            (t->flag == ddl_alter_table || t->flag == ddl_create_table || t->flag == ddl_create_view)) {
      77        1449 :                 return rel_ddl_table_get(t);
      78             :         }
      79             :         return tab;
      80             : }
      81             : 
      82             : static sql_rel *
      83        5905 : get_basetable(sql_rel *t)
      84             : {
      85       14186 :         if (is_simple_project(t->op) || is_select(t->op) || is_join(t->op) || is_semi(t->op)) {
      86        8281 :                 return get_basetable(t->l);
      87        5905 :         } else if (t->op == op_basetable) { /* existing base table */
      88             :                 return t;
      89        1808 :         } else if (t->op == op_ddl &&
      90        1808 :                            (t->flag == ddl_alter_table || t->flag == ddl_create_table || t->flag == ddl_create_view)) {
      91        1808 :                 return rel_ddl_basetable_get(t);
      92             :         }
      93             :         return t;
      94             : }
      95             : 
      96             : static sql_rel *
      97       14623 : rel_insert_hash_idx(mvc *sql, sql_alias* alias, sql_idx *i, sql_rel *inserts)
      98             : {
      99       14623 :         char *iname = sa_strconcat( sql->sa, "%", i->base.name);
     100       14622 :         node *m;
     101       14622 :         sql_subtype *it, *lng;
     102       14622 :         int bits = 1 + ((sizeof(lng)*8)-1)/(list_length(i->columns)+1);
     103       14627 :         sql_exp *h = NULL;
     104       14627 :         sql_rel *ins = inserts->r;
     105             : 
     106       14627 :         assert(is_project(ins->op) || ins->op == op_table);
     107       14627 :         if (list_length(i->columns) <= 1 || non_updatable_index(i->type)) {
     108             :                 /* dummy append */
     109       13150 :                 list *exps = rel_projections(sql, ins, NULL, 1, 1);
     110       13157 :                 if (!exps)
     111             :                         return NULL;
     112       13156 :                 inserts->r = ins = rel_project(sql->sa, ins, exps);
     113       13153 :                 if (!ins)
     114             :                         return NULL;
     115       13153 :                 list_append(ins->exps, exp_label(sql->sa, exp_atom_lng(sql->sa, 0), ++sql->label));
     116       13154 :                 return inserts;
     117             :         }
     118             : 
     119        1472 :         it = sql_bind_localtype("int");
     120        1472 :         lng = sql_bind_localtype("lng");
     121        4979 :         for (m = i->columns->h; m; m = m->next) {
     122        3507 :                 sql_kc *c = m->data;
     123        3507 :                 sql_exp *e = list_fetch(ins->exps, c->c->colnr);
     124        3507 :                 e = exp_ref(sql, e);
     125             : 
     126        5542 :                 if (h && i->type == hash_idx)  {
     127        2035 :                         list *exps = new_exp_list(sql->sa);
     128        2035 :                         sql_subfunc *xor = sql_bind_func_result(sql, "sys", "rotate_xor_hash", F_FUNC, true, lng, 3, lng, it, &c->c->type);
     129             : 
     130        2035 :                         append(exps, h);
     131        2035 :                         append(exps, exp_atom_int(sql->sa, bits));
     132        2035 :                         append(exps, e);
     133        2035 :                         h = exp_op(sql->sa, exps, xor);
     134           0 :                 } else if (h)  { /* order preserving hash */
     135           0 :                         sql_exp *h2;
     136           0 :                         sql_subfunc *lsh = sql_bind_func_result(sql, "sys", "left_shift", F_FUNC, true, lng, 2, lng, it);
     137           0 :                         sql_subfunc *lor = sql_bind_func_result(sql, "sys", "bit_or", F_FUNC, true, lng, 2, lng, lng);
     138           0 :                         sql_subfunc *hf = sql_bind_func_result(sql, "sys", "hash", F_FUNC, true, lng, 1, &c->c->type);
     139             : 
     140           0 :                         h = exp_binop(sql->sa, h, exp_atom_int(sql->sa, bits), lsh);
     141           0 :                         h2 = exp_unop(sql->sa, e, hf);
     142           0 :                         h = exp_binop(sql->sa, h, h2, lor);
     143             :                 } else {
     144        1472 :                         sql_subfunc *hf = sql_bind_func_result(sql, "sys", "hash", F_FUNC, true, lng, 1, &c->c->type);
     145        1472 :                         h = exp_unop(sql->sa, e, hf);
     146        1472 :                         if (i->type == oph_idx)
     147             :                                 break;
     148             :                 }
     149             :         }
     150             :         /* append inserts to hash */
     151        1472 :         inserts->r = ins = rel_project(sql->sa, ins, rel_projections(sql, ins, NULL, 1, 1));
     152        1472 :         exp_setname(sql, h, alias, iname);
     153        1472 :         list_append(ins->exps, h);
     154        1472 :         return inserts;
     155             : }
     156             : 
     157             : static sql_rel *
     158         782 : rel_insert_join_idx(mvc *sql, sql_alias* alias, sql_idx *i, sql_rel *inserts)
     159             : {
     160         782 :         char *iname = sa_strconcat( sql->sa, "%", i->base.name);
     161         782 :         node *m, *o;
     162         782 :         sql_trans *tr = sql->session->tr;
     163         782 :         sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)i->key)->rkey);
     164         782 :         sql_rel *rt = rel_basetable(sql, rk->t, a_create(sql->sa, rk->t->base.name)), *brt = rt;
     165         782 :         int selfref = (rk->t->base.id == i->t->base.id);
     166         782 :         int need_nulls = 0;
     167         782 :         if (selfref)
     168          22 :                 TRC_DEBUG(SQL_TRANS, "Self-reference index\n");
     169             : 
     170         782 :         sql_subtype *bt = sql_bind_localtype("bit");
     171         782 :         sql_subfunc *or = sql_bind_func_result(sql, "sys", "or", F_FUNC, true, bt, 2, bt, bt);
     172             : 
     173         782 :         sql_rel *_nlls = NULL, *nnlls, *ins = inserts->r;
     174         782 :         sql_exp *lnll_exps = NULL, *rnll_exps = NULL, *e;
     175         782 :         list *join_exps = new_exp_list(sql->sa), *pexps;
     176             : 
     177         782 :         assert(is_project(ins->op) || ins->op == op_table);
     178        1599 :         for (m = i->columns->h; m; m = m->next) {
     179         817 :                 sql_kc *c = m->data;
     180             : 
     181         817 :                 if (c->c->null)
     182         817 :                         need_nulls = 1;
     183             :         }
     184         782 :         need_nulls = 0;
     185             :         /* NULL and NOT NULL, for 'SIMPLE MATCH' semantics */
     186             :         /* AND joins expressions */
     187        1599 :         for (m = i->columns->h, o = rk->columns->h; m && o; m = m->next, o = o->next) {
     188         817 :                 sql_kc *c = m->data;
     189         817 :                 sql_kc *rc = o->data;
     190         817 :                 sql_subfunc *isnil = sql_bind_func(sql, "sys", "isnull", &c->c->type, NULL, F_FUNC, true, true);
     191         817 :                 sql_exp *_is = list_fetch(ins->exps, c->c->colnr), *lnl, *rnl, *je;
     192             : 
     193         817 :                 if (rel_base_use(sql, brt, rc->c->colnr)) {
     194             :                         /* TODO add access error */
     195           0 :                         return NULL;
     196             :                 }
     197         817 :                 int unique = list_length(i->columns) == 1 && list_length(rk->columns) == 1 && is_column_unique(rc->c);
     198         817 :                 sql_exp *rtc = exp_column(sql->sa, rel_name(rt), rc->c->base.name, &rc->c->type, CARD_MULTI, rc->c->null, unique, 0);
     199         817 :                 rtc->nid = rel_base_nid(brt, rc->c);
     200         817 :                 rtc->alias.label = rtc->nid;
     201             : 
     202         817 :                 _is = exp_ref(sql, _is);
     203         817 :                 lnl = exp_unop(sql->sa, _is, isnil);
     204         817 :                 set_has_no_nil(lnl);
     205         817 :                 rnl = exp_unop(sql->sa, _is, isnil);
     206         817 :                 set_has_no_nil(rnl);
     207         817 :                 if (need_nulls) {
     208             :                         if (lnll_exps) {
     209             :                                 lnll_exps = exp_binop(sql->sa, lnll_exps, lnl, or);
     210             :                                 rnll_exps = exp_binop(sql->sa, rnll_exps, rnl, or);
     211             :                         } else {
     212             :                                 lnll_exps = lnl;
     213             :                                 rnll_exps = rnl;
     214             :                         }
     215             :                 }
     216             : 
     217         817 :                 if (rel_convert_types(sql, rt, ins, &rtc, &_is, 1, type_equal) < 0)
     218             :                         return NULL;
     219         817 :                 je = exp_compare(sql->sa, rtc, _is, cmp_equal);
     220         817 :                 append(join_exps, je);
     221             :         }
     222         782 :         if (need_nulls) {
     223             :                 _nlls = rel_select( sql->sa, rel_dup(ins),
     224             :                                 exp_compare(sql->sa, lnll_exps, exp_atom_bool(sql->sa, 1), cmp_equal ));
     225             :                 set_processed(_nlls);
     226             :                 nnlls = rel_select( sql->sa, rel_dup(ins),
     227             :                                 exp_compare(sql->sa, rnll_exps, exp_atom_bool(sql->sa, 0), cmp_equal ));
     228             :                 set_processed(nnlls);
     229             :                 _nlls = rel_project(sql->sa, _nlls, rel_projections(sql, _nlls, NULL, 1, 1));
     230             :                 /* add constant value for NULLS */
     231             :                 e = exp_atom(sql->sa, atom_general(sql->sa, sql_bind_localtype("oid"), NULL, 0));
     232             :                 exp_setname(sql, e, alias, iname);
     233             :                 append(_nlls->exps, e);
     234             :         } else {
     235         782 :                 nnlls = ins;
     236             :         }
     237             : 
     238         782 :         pexps = rel_projections(sql, nnlls, NULL, 1, 1);
     239         782 :         nnlls = rel_crossproduct(sql->sa, nnlls, rt, op_left/*op_join*/);
     240         782 :         nnlls->exps = join_exps;
     241         782 :         nnlls = rel_project(sql->sa, nnlls, pexps);
     242             :         /* add row numbers */
     243         782 :         e = exp_column(sql->sa, rel_name(rt), TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     244         782 :         rel_base_use_tid(sql, brt);
     245         782 :         exp_setname(sql, e, alias, iname);
     246         782 :         e->nid = rel_base_nid(brt, NULL);
     247         782 :         append(nnlls->exps, e);
     248         782 :         set_processed(nnlls);
     249             : 
     250         782 :         if (need_nulls) {
     251             :                 rel_destroy(ins);
     252             :                 rt = inserts->r = rel_setop(sql->sa, _nlls, nnlls, op_union );
     253             :                 rel_setop_set_exps(sql, rt, rel_projections(sql, nnlls, NULL, 1, 1), false);
     254             :                 set_processed(rt);
     255             :         } else {
     256         782 :                 inserts->r = nnlls;
     257             :         }
     258         782 :         return inserts;
     259             : }
     260             : 
     261             : static sql_rel *
     262      122367 : rel_insert_idxs(mvc *sql, sql_table *t, sql_alias* alias, sql_rel *inserts)
     263             : {
     264      122367 :         if (!ol_length(t->idxs))
     265             :                 return inserts;
     266             : 
     267       11213 :         inserts->r = rel_label(sql, inserts->r, 1);
     268       26619 :         for (node *n = ol_first_node(t->idxs); n; n = n->next) {
     269       15405 :                 sql_idx *i = n->data;
     270             : 
     271       15405 :                 if (hash_index(i->type) || non_updatable_index(i->type)) {
     272       14623 :                         if (rel_insert_hash_idx(sql, alias, i, inserts) == NULL)
     273             :                                 return NULL;
     274         782 :                 } else if (i->type == join_idx) {
     275         782 :                         if (rel_insert_join_idx(sql, alias, i, inserts) == NULL)
     276             :                                 return NULL;
     277             :                 }
     278             :         }
     279             :         return inserts;
     280             : }
     281             : 
     282             : sql_rel *
     283      122297 : rel_insert(mvc *sql, sql_rel *t, sql_rel *inserts)
     284             : {
     285      122297 :         sql_rel * r = rel_create(sql->sa);
     286      122368 :         sql_table *tab = get_table(t);
     287      122370 :         if(!r)
     288             :                 return NULL;
     289             : 
     290      122370 :         r->op = op_insert;
     291      122370 :         r->l = t;
     292      122370 :         r->r = inserts;
     293      122370 :         r->card = inserts->card;
     294             :         /* insert indices */
     295      122370 :         if (tab)
     296      122389 :                 return rel_insert_idxs(sql, tab, rel_name(t), r);
     297             :         return r;
     298             : }
     299             : 
     300             : static sql_rel *
     301      122159 : rel_insert_table(sql_query *query, sql_table *t, char *name, sql_rel *inserts)
     302             : {
     303      122159 :         sql_rel *rel = rel_basetable(query->sql, t, a_create(query->sql->sa, name));
     304      122195 :         rel_base_use_all(query->sql, rel);
     305      122367 :         rel = rewrite_basetable(query->sql, rel);
     306      122218 :         return rel_insert(query->sql, rel, inserts);
     307             : }
     308             : 
     309             : static node *
     310          64 : skip_nested_columns(mvc *sql, sql_column *ct, node *n)
     311             : {
     312          64 :         if (ct->type.multiset)
     313             :                 return n;
     314          36 :         if (ct->type.multiset) { /* skip  id and optional number columns */
     315             :                 n = n->next;
     316             :                 if (ct->type.multiset == MS_ARRAY)
     317             :                         n = n->next;
     318             :         }
     319             :         /* skip fields */
     320         114 :         for(node *fn = ct->type.type->d.fields->h; fn; fn = fn->next) {
     321          78 :                 sql_arg *f = fn->data;
     322          78 :                 sql_column *fc = n->data;
     323          78 :                 if (fc->type.type->composite) {
     324          24 :                         n = skip_nested_columns(sql, fc, n->next);
     325             :                 } else {
     326          54 :                         n = n->next;
     327             :                 }
     328          78 :                 (void)f;
     329             :         }
     330             :         return n;
     331             : }
     332             : 
     333             : static list *
     334      122194 : check_table_columns(mvc *sql, sql_table *t, dlist *columns, const char *op, char *tname)
     335             : {
     336      122194 :         list *collist;
     337             : 
     338      122194 :         if (columns) {
     339        4291 :                 dnode *n;
     340             : 
     341        4291 :                 collist = sa_list(sql->sa);
     342       16357 :                 for (n = columns->h; n; n = n->next) {
     343       12076 :                         sql_column *c = mvc_bind_column(sql, t, n->data.sval);
     344             : 
     345       12076 :                         if (c) {
     346       12066 :                                 list_append(collist, c);
     347             :                         } else {
     348          10 :                                 return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s.%s'", op, tname, n->data.sval);
     349             :                         }
     350             :                 }
     351             :         } else {
     352      117903 :                 collist = t->columns->l;
     353             :                 /* skip inner columns */
     354      117903 :                 list *reslist = NULL;
     355      848244 :                 for (node *n = collist->h; n; ) {
     356      729991 :                         sql_column *c = n->data;
     357      729991 :                         if (c->type.type->composite) {
     358          40 :                                 if (!reslist) {
     359          38 :                                         reslist = sa_list(sql->sa);
     360          52 :                                         for(node *m = collist->h; m != n; m = m->next)
     361          14 :                                                 list_append(reslist, m->data);
     362             :                                 }
     363          40 :                                 n = skip_nested_columns(sql, c, n->next);
     364             :                         } else {
     365      729951 :                                 n = n->next;
     366             :                         }
     367      730100 :                         if (reslist)
     368          45 :                                 list_append(reslist, c);
     369             :                 }
     370      118253 :                 if (reslist)
     371          38 :                         return reslist;
     372             :         }
     373             :         return collist;
     374             : }
     375             : 
     376             : static list *
     377      122268 : rel_inserts(mvc *sql, sql_table *t, sql_rel *r, list *collist, size_t rowcount, int copy, const char* action)
     378             : {
     379      122268 :         int len, i;
     380      122268 :         sql_exp **inserts = insert_exp_array(sql, t, &len);
     381      122287 :         list *exps = NULL;
     382      122287 :         node *n, *m;
     383      122287 :         bool has_rel = false, all_values = true;
     384             : 
     385      122287 :         if (r->exps) {
     386      122187 :                 if (!copy) {
     387      862026 :                         for (n = r->exps->h, m = collist->h; n && m; n = n->next, m = m->next) {
     388      739870 :                                 sql_column *c = m->data;
     389      739870 :                                 sql_exp *e = n->data;
     390             : 
     391      739870 :                                 if (inserts[c->colnr])
     392           1 :                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: column '%s' specified more than once", action, c->base.name);
     393      739869 :                                 if (!(inserts[c->colnr] = exp_check_type(sql, &c->type, r, e, type_equal)))
     394             :                                         return NULL;
     395      739848 :                                 has_rel = (has_rel || exp_has_rel(e));
     396     1343897 :                                 all_values &= is_values(e);
     397             :                         }
     398             :                 } else {
     399         135 :                         sql_alias *ta = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
     400         499 :                         for (m = collist->h; m; m = m->next) {
     401         365 :                                 sql_column *c = m->data;
     402         365 :                                 sql_exp *e;
     403             : 
     404         365 :                                 e = exps_bind_column2(r->exps, ta, c->base.name, NULL);
     405         365 :                                 if (e) {
     406         364 :                                         if (inserts[c->colnr])
     407           1 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: column '%s' specified more than once", action, c->base.name);
     408         363 :                                         inserts[c->colnr] = exp_ref(sql, e);
     409         363 :                                         has_rel = has_rel || exp_has_rel(e);
     410         726 :                                         all_values &= is_values(e);
     411             :                                 }
     412             :                         }
     413             :                 }
     414             :         }
     415      866011 :         for (m = ol_first_node(t->columns); m; m = m->next) {
     416      743554 :                 sql_column *c = m->data;
     417      743554 :                 sql_exp *exps = NULL;
     418             : 
     419      743554 :                 if (c->column_type == column_plain && !inserts[c->colnr]) {
     420        7828 :                         for (size_t j = 0; j < rowcount; j++) {
     421        4105 :                                 sql_exp *e = NULL;
     422             : 
     423        4105 :                                 if (c->def) {
     424        1188 :                                         e = rel_parse_val(sql, t->s, c->def, &c->type, sql->emode, NULL);
     425        1188 :                                         if (!e || (e = exp_check_type(sql, &c->type, r, e, type_equal)) == NULL)
     426           0 :                                                 return NULL;
     427             :                                 } else {
     428        2917 :                                         atom *a = atom_general(sql->sa, &c->type, NULL, 0);
     429        2917 :                                         e = exp_atom(sql->sa, a);
     430             :                                 }
     431        2917 :                                 if (!e)
     432           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: column '%s' has no valid default value", action, c->base.name);
     433        4105 :                                 if (!exps && (j+1) < rowcount) {
     434          92 :                                         exps = exp_values(sql->sa, sa_list(sql->sa));
     435          92 :                                         exps->tpe = c->type;
     436          92 :                                         exp_label(sql->sa, exps, ++sql->label);
     437             :                                 }
     438          92 :                                 if (exps) {
     439         474 :                                         list *vals_list = exps->f;
     440             : 
     441         474 :                                         list_append(vals_list, e);
     442             :                                 }
     443         474 :                                 if (!exps)
     444             :                                         exps = e;
     445             :                         }
     446        3723 :                         inserts[c->colnr] = exps;
     447        3723 :                         assert(inserts[c->colnr]);
     448             :                 }
     449             :         }
     450             :         /* rewrite into unions */
     451      122472 :         if (has_rel && rowcount && all_values) {
     452             :                 sql_rel *c = NULL;
     453          57 :                 for (size_t j = 0; j < rowcount; j++) {
     454          42 :                         sql_rel *p = rel_project(sql->sa, NULL, sa_list(sql->sa));
     455         123 :                         for (m = ol_first_node(t->columns); m; m = m->next) {
     456          81 :                                 sql_column *c = m->data;
     457          81 :                                 sql_exp *e = inserts[c->colnr];
     458          81 :                                 assert(is_values(e));
     459          81 :                                 list *vals = e->f;
     460          81 :                                 append(p->exps, list_fetch(vals, (int) j));
     461             :                         }
     462          42 :                         if (c) {
     463          27 :                                 c = rel_setop(sql->sa, c, p, op_union);
     464          27 :                                 rel_setop_set_exps(sql, c, rel_projections(sql, c->l, NULL, 1, 1), false);
     465          27 :                                 set_processed(c);
     466             :                         } else
     467             :                                 c = p;
     468             :                 }
     469          15 :                 r->l = c;
     470          15 :                 exps = rel_projections(sql, r->l, NULL, 1, 1);
     471             :         } else {
     472             :                 /* now rewrite project exps in proper table order */
     473      122442 :                 exps = new_exp_list(sql->sa);
     474      988312 :                 for (i = 0; i<len; i++)
     475      743513 :                         if (inserts[i])
     476      743437 :                                 list_append(exps, inserts[i]);
     477             :         }
     478             :         return exps;
     479             : }
     480             : 
     481             : static bool
     482      170105 : has_complex_indexes(sql_table *t)
     483             : {
     484      170203 :         for (node *n = ol_first_node(t->idxs); n; n = n->next) {
     485       11569 :                 sql_idx *i = n->data;
     486             : 
     487       11569 :                 if (hash_index(i->type) || oid_index(i->type) || i->type == no_idx)
     488             :                         return true;
     489             :         }
     490             :         return false;
     491             : }
     492             : 
     493             : sql_table *
     494      122572 : insert_allowed(mvc *sql, sql_table *t, char *tname, char *op, char *opname)
     495             : {
     496      122572 :         list *mts = NULL;
     497             : 
     498      122572 :         if (!t) {
     499          17 :                 if (sql->session->status) /* if find_table_or_view_on_scope was already called, don't overwrite error message */
     500             :                         return NULL;
     501           0 :                 return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S02) "%s: no such table '%s'", op, tname);
     502      122555 :         } else if (isView(t)) {
     503           6 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s view '%s'", op, opname, tname);
     504      122549 :         } else if (isNonPartitionedTable(t)) {
     505           4 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s merge table '%s'", op, opname, tname);
     506      122545 :         } else if ((isRangePartitionTable(t) || isListPartitionTable(t)) && list_length(t->members)==0) {
     507           2 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: %s partitioned table '%s' has no partitions set", op, isListPartitionTable(t)?"list":"range", tname);
     508      122543 :         } else if ((isRangePartitionTable(t) || isListPartitionTable(t)) && has_complex_indexes(t)) {
     509           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: not possible to insert into a partitioned table with complex indexes at the moment", op);
     510      122542 :         } else if (isRemote(t)) {
     511           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s remote table '%s' from this server at the moment", op, opname, tname);
     512      122541 :         } else if (isReplicaTable(t)) {
     513           2 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s replica table '%s'", op, opname, tname);
     514      122539 :         } else if (t->access == TABLE_READONLY) {
     515           3 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s read only table '%s'", op, opname, tname);
     516             :         }
     517      122536 :         if (t && !isTempTable(t) && store_readonly(sql->session->tr->store))
     518           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: %s table '%s' not allowed in readonly mode", op, opname, tname);
     519      122432 :         if (has_complex_indexes(t) && (mts = partition_find_mergetables(sql, t))) {
     520          65 :                 for (node *n = mts->h ; n ; n = n->next) {
     521          33 :                         sql_part *pt = n->data;
     522             : 
     523          33 :                         if ((isRangePartitionTable(pt->t) || isListPartitionTable(pt->t)))
     524           1 :                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: not possible to insert into a partitioned table with complex indexes at the moment", op);
     525             :                 }
     526             :         }
     527      122648 :         if (!table_privs(sql, t, PRIV_INSERT))
     528          12 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: insufficient privileges for user '%s' to %s table '%s'", op, get_string_global_var(sql, "current_user"), opname, tname);
     529             :         return t;
     530             : }
     531             : 
     532             : static int
     533         294 : copy_allowed(mvc *sql, int from)
     534             : {
     535         294 :         if (!global_privs(sql, (from)?PRIV_COPYFROMFILE:PRIV_COPYINTOFILE))
     536           4 :                 return 0;
     537             :         return 1;
     538             : }
     539             : 
     540             : sql_table *
     541       47281 : update_allowed(mvc *sql, sql_table *t, char *tname, char *op, char *opname, int is_delete)
     542             : {
     543       47281 :         list *mts = NULL;
     544             : 
     545       47281 :         if (!t) {
     546           3 :                 return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S02) "%s: no such table '%s'", op, tname);
     547       47278 :         } else if (isView(t)) {
     548           5 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s view '%s'", op, opname, tname);
     549       47273 :         } else if (isNonPartitionedTable(t) && is_delete == 0) {
     550           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s merge table '%s'", op, opname, tname);
     551       47273 :         } else if (isNonPartitionedTable(t) && is_delete != 0 && list_length(t->members)==0) {
     552           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s merge table '%s' has no partitions set", op, opname, tname);
     553       47273 :         } else if ((isRangePartitionTable(t) || isListPartitionTable(t)) && list_length(t->members)==0) {
     554           8 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: %s partitioned table '%s' has no partitions set", op, isListPartitionTable(t)?"list":"range", tname);
     555       47267 :         } else if ((isRangePartitionTable(t) || isListPartitionTable(t)) && has_complex_indexes(t)) {
     556           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: not possible to update a partitioned table with complex indexes at the moment", op);
     557       47267 :         } else if (isRemote(t)) {
     558           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s remote table '%s' from this server at the moment", op, opname, tname);
     559       47267 :         } else if (isReplicaTable(t)) {
     560           3 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s replica table '%s'", op, opname, tname);
     561       47264 :         } else if (t->access == TABLE_READONLY || t->access == TABLE_APPENDONLY) {
     562           8 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: cannot %s read or append only table '%s'", op, opname, tname);
     563             :         }
     564       47256 :         if (t && !isTempTable(t) && store_readonly(sql->session->tr->store))
     565           2 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: %s table '%s' not allowed in readonly mode", op, opname, tname);
     566       47220 :         if (has_complex_indexes(t) && (mts = partition_find_mergetables(sql, t))) {
     567           0 :                 for (node *n = mts->h ; n ; n = n->next) {
     568           0 :                         sql_part *pt = n->data;
     569             : 
     570           0 :                         if ((isRangePartitionTable(pt->t) || isListPartitionTable(pt->t)))
     571           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: not possible to update a partitioned table with complex indexes at the moment", op);
     572             :                 }
     573             :         }
     574       47334 :         if ((is_delete == 1 && !table_privs(sql, t, PRIV_DELETE)) || (is_delete == 2 && !table_privs(sql, t, PRIV_TRUNCATE)))
     575          39 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: insufficient privileges for user '%s' to %s table '%s'", op, get_string_global_var(sql, "current_user"), opname, tname);
     576             :         return t;
     577             : }
     578             : 
     579             : static sql_rel *
     580      121017 : insert_generate_inserts(sql_query *query, sql_table *t, dlist *columns, symbol *val_or_q, const char* action)
     581             : {
     582      121017 :         mvc *sql = query->sql;
     583      121017 :         sql_rel *r = NULL;
     584      121017 :         size_t rowcount = 0;
     585      121017 :         bool is_subquery = false;
     586      121017 :         list *collist = check_table_columns(sql, t, columns, action, t->base.name);
     587      121254 :         if (!collist)
     588             :                 return NULL;
     589             : 
     590      121246 :         if (val_or_q->token == SQL_VALUES) {
     591      110607 :                 dlist *rowlist = val_or_q->data.lval;
     592      110607 :                 list *exps = new_exp_list(sql->sa);
     593             : 
     594      110376 :                 if (!rowlist->h) {
     595         165 :                         r = rel_project(sql->sa, NULL, NULL);
     596         165 :                         if (!columns)
     597      110376 :                                 collist = NULL;
     598             :                 }
     599             : 
     600      110376 :                 if (!rowlist->h) /* no values insert 1 row */
     601         165 :                         rowcount++;
     602      416112 :                 for (dnode *o = rowlist->h; o; o = o->next, rowcount++) {
     603      305518 :                         dlist *values = o->data.lval;
     604             : 
     605      305518 :                         if (dlist_length(values) != list_length(collist)) {
     606          10 :                                 return sql_error(sql, 02, SQLSTATE(21S01) "%s: number of values doesn't match number of columns of table '%s'", action, t->base.name);
     607             :                         } else {
     608      305463 :                                 dnode *n;
     609      305463 :                                 node *v, *m;
     610             : 
     611      305463 :                                 if (o->next && list_empty(exps)) { /* allways create an atom list, also for single atoms */
     612      164871 :                                         for (n = values->h, m = collist->h; n && m; n = n->next, m = m->next) {
     613      135581 :                                                 sql_exp *vals = exp_values(sql->sa, sa_list(sql->sa));
     614      135821 :                                                 sql_column *c = m->data;
     615             : 
     616      135821 :                                                 vals->tpe = c->type;
     617      135821 :                                                 exp_label(sql->sa, vals, ++sql->label);
     618      135872 :                                                 list_append(exps, vals);
     619             :                                         }
     620             :                                 }
     621      305693 :                                 if (!list_empty(exps)) {
     622      967557 :                                         for (n = values->h, m = collist->h, v = exps->h; n && m && v; n = n->next, m = m->next, v = v->next) {
     623      742961 :                                                 sql_exp *vals = v->data;
     624      742961 :                                                 list *vals_list = vals->f;
     625      742961 :                                                 sql_column *c = m->data;
     626      742961 :                                                 sql_exp *ins = insert_value(query, c, &r, n->data.sym, action);
     627             : 
     628      742464 :                                                 if (!ins)
     629             :                                                         return NULL;
     630      742463 :                                                 if (!exp_name(ins))
     631      742690 :                                                         exp_label(sql->sa, ins, ++sql->label);
     632      743500 :                                                 list_append(vals_list, ins);
     633             :                                         }
     634             :                                 } else {
     635             :                                         /* only allow correlation in a single row of values */
     636      648641 :                                         for (n = values->h, m = collist->h; n && m; n = n->next, m = m->next) {
     637      567501 :                                                 sql_column *c = m->data;
     638      567501 :                                                 sql_exp *ins = insert_value(query, c, &r, n->data.sym, action);
     639             : 
     640      567532 :                                                 if (!ins)
     641             :                                                         return NULL;
     642      567511 :                                                 if (!exp_name(ins))
     643      567413 :                                                         exp_label(sql->sa, ins, ++sql->label);
     644      567495 :                                                 list_append(exps, ins);
     645             :                                         }
     646             :                                 }
     647             :                         }
     648             :                 }
     649      110594 :                 if (collist)
     650      110429 :                         r = rel_project(sql->sa, r, exps);
     651             :         } else {
     652       10639 :                 exp_kind ek = {type_value, card_relation, TRUE};
     653             : 
     654       10639 :                 r = rel_subquery(query, val_or_q, ek);
     655       10752 :                 rowcount++;
     656       10752 :                 is_subquery = true;
     657             :         }
     658      121134 :         if (!r)
     659             :                 return NULL;
     660             : 
     661             :         /* For the subquery case a projection is always needed */
     662      121128 :         if (is_subquery)
     663       10633 :                 r = rel_project(sql->sa, r, rel_projections(sql, r, NULL, 1, 0));
     664      121128 :         if ((r->exps && list_length(r->exps) != list_length(collist)) || (!r->exps && collist))
     665           2 :                 return sql_error(sql, 02, SQLSTATE(21S01) "%s: query result doesn't match number of columns in table '%s'", action, t->base.name);
     666      121165 :         if (is_subquery && !(r->exps = check_distinct_exp_names(sql, r->exps)))
     667           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: duplicate column names in subquery column list", action);
     668             : 
     669      121164 :         r->exps = rel_inserts(sql, t, r, collist, rowcount, 0, action);
     670      121017 :         if(!r->exps)
     671             :                 return NULL;
     672             :         return r;
     673             : }
     674             : 
     675             : static sql_rel *
     676          30 : merge_generate_inserts(sql_query *query, sql_table *t, sql_rel *r, dlist *columns, symbol *val_or_q)
     677             : {
     678          30 :         mvc *sql = query->sql;
     679          30 :         sql_rel *res = NULL;
     680          30 :         list *collist = check_table_columns(sql, t, columns, "MERGE", t->base.name);
     681             : 
     682          30 :         if (!collist)
     683             :                 return NULL;
     684             : 
     685          30 :         if (val_or_q->token == SQL_VALUES) {
     686          28 :                 list *exps = new_exp_list(sql->sa);
     687          28 :                 dlist *rowlist = val_or_q->data.lval;
     688             : 
     689          28 :                 if (!rowlist->h) {
     690           4 :                         res = rel_project(sql->sa, NULL, NULL);
     691           4 :                         if (!columns)
     692             :                                 collist = NULL;
     693             :                 } else {
     694          24 :                         node *m;
     695          24 :                         dnode *n;
     696          24 :                         dlist *inserts = rowlist->h->data.lval;
     697             : 
     698          24 :                         if (dlist_length(rowlist) != 1)
     699           1 :                                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: number of insert rows must be exactly one in a merge statement");
     700          23 :                         if (dlist_length(inserts) != list_length(collist))
     701           0 :                                 return sql_error(sql, 02, SQLSTATE(21S01) "MERGE: number of values doesn't match number of columns of table '%s'", t->base.name);
     702             : 
     703          77 :                         for (n = inserts->h, m = collist->h; n && m; n = n->next, m = m->next) {
     704          55 :                                 sql_column *c = m->data;
     705          55 :                                 sql_exp *ins = insert_value(query, c, &r, n->data.sym, "MERGE");
     706          55 :                                 if (!ins)
     707             :                                         return NULL;
     708          54 :                                 if (!exp_name(ins))
     709          23 :                                         exp_label(sql->sa, ins, ++sql->label);
     710          54 :                                 list_append(exps, ins);
     711             :                         }
     712             :                 }
     713          22 :                 if (collist)
     714          22 :                         res = rel_project(sql->sa, r, exps);
     715             :         } else {
     716           2 :                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: subqueries not supported in INSERT clauses inside MERGE statements");
     717             :         }
     718          26 :         if (!res)
     719             :                 return NULL;
     720          26 :         if ((res->exps && list_length(res->exps) != list_length(collist)) || (!res->exps && collist))
     721           0 :                 return sql_error(sql, 02, SQLSTATE(21S01) "MERGE: query result doesn't match number of columns in table '%s'", t->base.name);
     722             : 
     723          26 :         res->l = r;
     724          26 :         res->exps = rel_inserts(sql, t, res, collist, 1, 0, "MERGE");
     725          26 :         if(!res->exps)
     726             :                 return NULL;
     727             :         return res;
     728             : }
     729             : 
     730             : static sql_rel *
     731      121034 : insert_into(sql_query *query, dlist *qname, dlist *columns, symbol *val_or_q, dlist *opt_returning)
     732             : {
     733      121034 :         mvc *sql = query->sql;
     734      121034 :         char *sname = qname_schema(qname);
     735      121136 :         char *tname = qname_schema_object(qname);
     736      121227 :         sql_table *t = NULL;
     737      121227 :         sql_rel *r = NULL;
     738             : 
     739      121227 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "INSERT INTO", false);
     740      121332 :         if (insert_allowed(sql, t, tname, "INSERT INTO", "insert into") == NULL)
     741             :                 return NULL;
     742      121061 :         r = insert_generate_inserts(query, t, columns, val_or_q, "INSERT INTO");
     743      121099 :         if(!r)
     744             :                 return NULL;
     745      121049 :         sql_rel* ins = rel_insert_table(query, t, t->base.name, r);
     746             : 
     747      120736 :         if (opt_returning) {
     748           8 :                 mvc *sql = query->sql;
     749           8 :                 list *pexps = sa_list(sql->sa);
     750           8 :                 sql_rel* inner = ins->l;
     751          15 :                 for (dnode *n = opt_returning->h; n; n = n->next) {
     752          10 :                         sql_exp *ce = rel_column_exp(query, &inner, n->data.sym, sql_sel | sql_no_subquery);
     753          10 :                         if (ce == NULL)
     754           3 :                                 return NULL;
     755           7 :                         pexps = append(pexps, ce);
     756             :                 }
     757           5 :                 ins->returning = 1;
     758             : 
     759           5 :                 if (is_groupby(inner->op)) {
     760           2 :                         inner->l = ins;
     761           2 :                         ins = rel_project(sql->sa, inner, pexps);
     762             :                 }
     763             :                 else
     764           3 :                         ins = rel_project(sql->sa, ins, pexps);
     765             :         }
     766             : 
     767             :         return ins;
     768             : }
     769             : 
     770             : static int
     771         185 : is_idx_updated(sql_idx * i, list *exps)
     772             : {
     773         185 :         int update = 0;
     774         185 :         node *m, *n;
     775             : 
     776         395 :         for (m = i->columns->h; m; m = m->next) {
     777         210 :                 sql_kc *ic = m->data;
     778             : 
     779         610 :                 for (n = exps->h; n; n = n->next) {
     780         485 :                         sql_exp *ce = n->data;
     781         485 :                         sql_column *c = find_sql_column(i->t, exp_name(ce));
     782             : 
     783         485 :                         if (c && ic->c->colnr == c->colnr) {
     784             :                                 update = 1;
     785             :                                 break;
     786             :                         }
     787             :                 }
     788             :         }
     789         185 :         return update;
     790             : }
     791             : 
     792             : static sql_rel *
     793         525 : rel_update_hash_idx(mvc *sql, sql_alias* alias, sql_idx *i, sql_rel *updates)
     794             : {
     795         525 :         char *iname = sa_strconcat( sql->sa, "%", i->base.name);
     796         525 :         node *m;
     797         525 :         sql_subtype *it, *lng = 0; /* is not set in first if below */
     798         525 :         int bits = 1 + ((sizeof(lng)*8)-1)/(list_length(i->columns)+1);
     799         525 :         sql_exp *h = NULL;
     800         525 :         sql_rel *ups = updates->r, *bt = get_basetable(updates->l);
     801             : 
     802         525 :         assert(is_project(ups->op) || ups->op == op_table);
     803         525 :         if (list_length(i->columns) <= 1 || non_updatable_index(i->type)) {
     804         400 :                 h = exp_label(sql->sa, exp_atom_lng(sql->sa, 0), ++sql->label);
     805             :         } else {
     806         125 :                 it = sql_bind_localtype("int");
     807         125 :                 lng = sql_bind_localtype("lng");
     808         402 :                 for (m = i->columns->h; m; m = m->next) {
     809         277 :                         sql_kc *c = m->data;
     810         277 :                         sql_exp *e = list_fetch(ups->exps, c->c->colnr+1);
     811         277 :                         e = exp_ref(sql, e);
     812             : 
     813         429 :                         if (h && i->type == hash_idx)  {
     814         152 :                                 list *exps = new_exp_list(sql->sa);
     815         152 :                                 sql_subfunc *xor = sql_bind_func_result(sql, "sys", "rotate_xor_hash", F_FUNC, true, lng, 3, lng, it, &c->c->type);
     816             : 
     817         152 :                                 append(exps, h);
     818         152 :                                 append(exps, exp_atom_int(sql->sa, bits));
     819         152 :                                 append(exps, e);
     820         152 :                                 h = exp_op(sql->sa, exps, xor);
     821           0 :                         } else if (h)  { /* order preserving hash */
     822           0 :                                 sql_exp *h2;
     823           0 :                                 sql_subfunc *lsh = sql_bind_func_result(sql, "sys", "left_shift", F_FUNC, true, lng, 2, lng, it);
     824           0 :                                 sql_subfunc *lor = sql_bind_func_result(sql, "sys", "bit_or", F_FUNC, true, lng, 2, lng, lng);
     825           0 :                                 sql_subfunc *hf = sql_bind_func_result(sql, "sys", "hash", F_FUNC, true, lng, 1, &c->c->type);
     826             : 
     827           0 :                                 h = exp_binop(sql->sa, h, exp_atom_int(sql->sa, bits), lsh);
     828           0 :                                 h2 = exp_unop(sql->sa, e, hf);
     829           0 :                                 h = exp_binop(sql->sa, h, h2, lor);
     830             :                         } else {
     831         125 :                                 sql_subfunc *hf = sql_bind_func_result(sql, "sys", "hash", F_FUNC, true, lng, 1, &c->c->type);
     832         125 :                                 h = exp_unop(sql->sa, e, hf);
     833         125 :                                 if (i->type == oph_idx)
     834             :                                         break;
     835             :                         }
     836             :                 }
     837             :         }
     838             :         /* append hash to updates */
     839         525 :         updates->r = ups = rel_project(sql->sa, ups, rel_projections(sql, ups, NULL, 1, 1));
     840         525 :         exp_setalias(h, rel_base_idx_nid(bt, i), alias, iname);
     841         525 :         list_append(ups->exps, h);
     842             : 
     843         525 :         if (!updates->exps)
     844         459 :                 updates->exps = new_exp_list(sql->sa);
     845         525 :         append(updates->exps, h=exp_column(sql->sa, alias, iname, lng, CARD_MULTI, 0, 0, 0));
     846         525 :         h->alias.label = rel_base_idx_nid(bt, i);
     847         525 :         h->nid = h->alias.label;
     848         525 :         return updates;
     849             : }
     850             : 
     851             : /*
     852             :          A referential constraint is satisfied if one of the following con-
     853             :          ditions is true, depending on the <match option> specified in the
     854             :          <referential constraint definition>:
     855             : 
     856             :          -  If no <match type> was specified then, for each row R1 of the
     857             :             referencing table, either at least one of the values of the
     858             :             referencing columns in R1 shall be a null value, or the value of
     859             :             each referencing column in R1 shall be equal to the value of the
     860             :             corresponding referenced column in some row of the referenced
     861             :             table.
     862             : 
     863             :          -  If MATCH FULL was specified then, for each row R1 of the refer-
     864             :             encing table, either the value of every referencing column in R1
     865             :             shall be a null value, or the value of every referencing column
     866             :             in R1 shall not be null and there shall be some row R2 of the
     867             :             referenced table such that the value of each referencing col-
     868             :             umn in R1 is equal to the value of the corresponding referenced
     869             :             column in R2.
     870             : 
     871             :          -  If MATCH PARTIAL was specified then, for each row R1 of the
     872             :             referencing table, there shall be some row R2 of the refer-
     873             :             enced table such that the value of each referencing column in
     874             :             R1 is either null or is equal to the value of the corresponding
     875             :             referenced column in R2.
     876             : */
     877             : static sql_rel *
     878         655 : rel_update_join_idx(mvc *sql, sql_alias* alias, sql_idx *i, sql_rel *updates)
     879             : {
     880         655 :         int nr = ++sql->label;
     881         655 :         char name[16], *nme = number2name(name, sizeof(name), nr);
     882         655 :         char *iname = sa_strconcat( sql->sa, "%", i->base.name);
     883             : 
     884         655 :         int need_nulls = 0;
     885         655 :         node *m, *o;
     886         655 :         sql_trans *tr = sql->session->tr;
     887         655 :         sql_key *rk = (sql_key*)os_find_id(tr->cat->objects, tr, ((sql_fkey*)i->key)->rkey);
     888         655 :         sql_rel *rt = rel_basetable(sql, rk->t, a_create(sql->sa, sa_strdup(sql->sa, nme))), *brt = rt;
     889             : 
     890         655 :         sql_subtype *bt = sql_bind_localtype("bit");
     891         655 :         sql_subfunc *or = sql_bind_func_result(sql, "sys", "or", F_FUNC, true, bt, 2, bt, bt);
     892             : 
     893         655 :         sql_rel *_nlls = NULL, *nnlls, *ups = updates->r;
     894         655 :         sql_exp *lnll_exps = NULL, *rnll_exps = NULL, *e;
     895         655 :         list *join_exps = new_exp_list(sql->sa), *pexps;
     896             : 
     897         655 :         assert(is_project(ups->op) || ups->op == op_table);
     898        1331 :         for (m = i->columns->h; m; m = m->next) {
     899         676 :                 sql_kc *c = m->data;
     900             : 
     901         676 :                 if (c->c->null)
     902         286 :                         need_nulls = 1;
     903             :         }
     904        1331 :         for (m = i->columns->h, o = rk->columns->h; m && o; m = m->next, o = o->next) {
     905         676 :                 sql_kc *c = m->data;
     906         676 :                 sql_kc *rc = o->data;
     907         676 :                 sql_subfunc *isnil = sql_bind_func(sql, "sys", "isnull", &c->c->type, NULL, F_FUNC, true, true);
     908         676 :                 sql_exp *upd = list_fetch(ups->exps, c->c->colnr + 1), *lnl, *rnl, *je;
     909         676 :                 if (rel_base_use(sql, rt, rc->c->colnr)) {
     910             :                         /* TODO add access error */
     911           0 :                         return NULL;
     912             :                 }
     913         676 :                 int unique = list_length(i->columns) == 1 && list_length(rk->columns) == 1 && is_column_unique(rc->c);
     914         676 :                 sql_exp *rtc = exp_column(sql->sa, rel_name(rt), rc->c->base.name, &rc->c->type, CARD_MULTI, rc->c->null, unique, 0);
     915         676 :                 rtc->alias.label = rel_base_nid(brt, rc->c);
     916         676 :                 rtc->nid = rtc->alias.label;
     917             : 
     918             :                 /* FOR MATCH FULL/SIMPLE/PARTIAL see above */
     919             :                 /* Currently only the default MATCH SIMPLE is supported */
     920         676 :                 upd = exp_ref(sql, upd);
     921         676 :                 lnl = exp_unop(sql->sa, upd, isnil);
     922         676 :                 set_has_no_nil(lnl);
     923         676 :                 rnl = exp_unop(sql->sa, upd, isnil);
     924         676 :                 set_has_no_nil(rnl);
     925         676 :                 if (need_nulls) {
     926         288 :                         if (lnll_exps) {
     927          11 :                                 lnll_exps = exp_binop(sql->sa, lnll_exps, lnl, or);
     928          11 :                                 rnll_exps = exp_binop(sql->sa, rnll_exps, rnl, or);
     929             :                         } else {
     930             :                                 lnll_exps = lnl;
     931             :                                 rnll_exps = rnl;
     932             :                         }
     933             :                 }
     934         676 :                 if (rel_convert_types(sql, rt, updates, &rtc, &upd, 1, type_equal) < 0) {
     935           0 :                         list_destroy(join_exps);
     936           0 :                         return NULL;
     937             :                 }
     938         676 :                 je = exp_compare(sql->sa, rtc, upd, cmp_equal);
     939         676 :                 append(join_exps, je);
     940             :         }
     941         655 :         if (need_nulls) {
     942         277 :                 _nlls = rel_select( sql->sa, rel_dup(ups),
     943             :                                 exp_compare(sql->sa, lnll_exps, exp_atom_bool(sql->sa, 1), cmp_equal ));
     944         277 :                 set_processed(_nlls);
     945         277 :                 nnlls = rel_select( sql->sa, rel_dup(ups),
     946             :                                 exp_compare(sql->sa, rnll_exps, exp_atom_bool(sql->sa, 0), cmp_equal ));
     947         277 :                 set_processed(nnlls);
     948         277 :                 _nlls = rel_project(sql->sa, _nlls, rel_projections(sql, _nlls, NULL, 1, 1));
     949             :                 /* add constant value for NULLS */
     950         277 :                 e = exp_atom(sql->sa, atom_general(sql->sa, sql_bind_localtype("oid"), NULL, 0));
     951         277 :                 exp_setname(sql, e, alias, iname);
     952         277 :                 append(_nlls->exps, e);
     953             :         } else {
     954             :                 nnlls = ups;
     955             :         }
     956             : 
     957         655 :         pexps = rel_projections(sql, nnlls, NULL, 1, 1);
     958         655 :         nnlls = rel_crossproduct(sql->sa, nnlls, rt, op_join);
     959         655 :         nnlls->exps = join_exps;
     960         655 :         nnlls->flag |= LEFT_JOIN;
     961         655 :         nnlls = rel_project(sql->sa, nnlls, pexps);
     962             :         /* add row numbers */
     963         655 :         e = exp_column(sql->sa, rel_name(rt), TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
     964         655 :         rel_base_use_tid(sql, brt);
     965         655 :         exp_setname(sql, e, alias, iname);
     966         655 :         e->nid = rel_base_nid(brt, NULL);
     967         655 :         append(nnlls->exps, e);
     968         655 :         set_processed(nnlls);
     969             : 
     970         655 :         if (need_nulls) {
     971         277 :                 rel_destroy(ups);
     972         277 :                 rt = updates->r = rel_setop(sql->sa, _nlls, nnlls, op_union );
     973         277 :                 rel_setop_set_exps(sql, rt, rel_projections(sql, nnlls, NULL, 1, 1), false);
     974         277 :                 set_processed(rt);
     975             :         } else {
     976         378 :                 updates->r = nnlls;
     977             :         }
     978         655 :         if (!updates->exps)
     979         639 :                 updates->exps = new_exp_list(sql->sa);
     980         655 :         append(updates->exps, e = exp_column(sql->sa, alias, iname, sql_bind_localtype("oid"), CARD_MULTI, 0, 0, 0));
     981         655 :         e->alias.label = rel_base_nid(brt, NULL);
     982         655 :         e->nid = e->alias.label;
     983         655 :         return updates;
     984             : }
     985             : 
     986             : /* for cascade of updates we change the 'relup' relations into
     987             :  * a ddl_list of update relations.
     988             :  */
     989             : static sql_rel *
     990        5380 : rel_update_idxs(mvc *sql, sql_alias *alias, sql_table *t, sql_rel *relup)
     991             : {
     992        5380 :         sql_rel *p = relup->r;
     993             : 
     994        5380 :         if (!ol_length(t->idxs))
     995             :                 return relup;
     996             : 
     997        2493 :         for (node *n = ol_first_node(t->idxs); n; n = n->next) {
     998        1283 :                 sql_idx *i = n->data;
     999             : 
    1000             :                 /* check if update is needed,
    1001             :                  * ie at least on of the idx columns is updated
    1002             :                  */
    1003        1283 :                 if (relup->exps && is_idx_updated(i, relup->exps) == 0)
    1004         103 :                         continue;
    1005             : 
    1006             :                 /*
    1007             :                  * relup->exps isn't set in case of alter statements!
    1008             :                  * Ie todo check for new indices.
    1009             :                  */
    1010             : 
    1011        1180 :                 if (hash_index(i->type) || non_updatable_index(i->type)) {
    1012         525 :                         rel_update_hash_idx(sql, alias, i, relup);
    1013         655 :                 } else if (i->type == join_idx) {
    1014         655 :                         rel_update_join_idx(sql, alias, i, relup);
    1015             :                 }
    1016             :         }
    1017        1210 :         if (relup->r != p) {
    1018        1166 :                 sql_rel *r = rel_create(sql->sa);
    1019        1166 :                 if(!r)
    1020             :                         return NULL;
    1021        1166 :                 r->op = op_update;
    1022        1166 :                 r->l = rel_dup(p);
    1023        1166 :                 r->r = relup;
    1024        1166 :                 r->card = relup->card;
    1025        1166 :                 r->flag |= UPD_COMP; /* mark as special update */
    1026        1166 :                 return r;
    1027             :         }
    1028             :         return relup;
    1029             : }
    1030             : 
    1031             : sql_rel *
    1032        5380 : rel_update(mvc *sql, sql_rel *t, sql_rel *uprel, sql_exp **updates, list *exps)
    1033             : {
    1034        5380 :         sql_rel *r = rel_create(sql->sa);
    1035        5380 :         sql_table *tab = get_table(t);
    1036        5380 :         sql_rel *bt = get_basetable(uprel);
    1037        5380 :         sql_alias*alias = rel_name(t);
    1038        5380 :         node *m;
    1039             : 
    1040        5380 :         if (!r)
    1041             :                 return NULL;
    1042             : 
    1043             :         /* todo only add column used by indices */
    1044        5380 :         if (tab && updates)
    1045       64120 :                 for (m = ol_first_node(tab->columns); m; m = m->next) {
    1046       58758 :                         sql_column *c = m->data;
    1047       58758 :                         sql_exp *v = updates[c->colnr];
    1048             : 
    1049       58758 :                         if (!v && rel_base_use(sql, bt, c->colnr) < 0) /* not allowed */
    1050           0 :                                 continue;
    1051       58758 :                         if (ol_length(tab->idxs) && !v) {
    1052       18285 :                                 v = exp_column(sql->sa, alias, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
    1053       18285 :                                 v->alias.label = rel_base_nid(bt, c);
    1054       18285 :                                 v->nid = v->alias.label;
    1055             :                         }
    1056       58622 :                         if (v)
    1057       22484 :                                 v = rel_project_add_exp(sql, uprel, v);
    1058             :                 }
    1059             : 
    1060        5380 :         r->op = op_update;
    1061        5380 :         r->l = t;
    1062        5380 :         r->r = uprel;
    1063        5380 :         r->card = uprel->card;
    1064        5380 :         r->exps = exps;
    1065             :         /* update indices */
    1066        5380 :         if (tab)
    1067        5380 :                 return rel_update_idxs(sql, alias, tab, r);
    1068             :         return r;
    1069             : }
    1070             : 
    1071             : sql_exp *
    1072        4120 : update_check_column(mvc *sql, sql_table *t, sql_column *c, sql_exp *v, sql_rel *r, char *cname, const char *action)
    1073             : {
    1074        4120 :         if (!table_privs(sql, t, PRIV_UPDATE) && sql_privilege(sql, sql->user_id, c->base.id, PRIV_UPDATE) < 0)
    1075           6 :                 return sql_error(sql, 02, SQLSTATE(42000) "%s: insufficient privileges for user '%s' to update table '%s' on column '%s'", action, get_string_global_var(sql, "current_user"), t->base.name, cname);
    1076        4114 :         if (!v || (v = exp_check_type(sql, &c->type, r, v, type_equal)) == NULL)
    1077           0 :                 return NULL;
    1078             :         return v;
    1079             : }
    1080             : 
    1081             : static sql_rel *
    1082        4059 : update_generate_assignments(sql_query *query, sql_table *t, sql_rel *r, sql_rel *bt, dlist *assignmentlist, const char *action)
    1083             : {
    1084        4059 :         mvc *sql = query->sql;
    1085        4059 :         sql_exp **updates = SA_ZNEW_ARRAY(sql->sa, sql_exp*, ol_length(t->columns)), *ne;
    1086        4059 :         list *exps, *mts = partition_find_mergetables(sql, t);
    1087        4059 :         dnode *n;
    1088        4059 :         sql_alias *rname = NULL;
    1089             : 
    1090        4059 :         if (!list_empty(mts)) {
    1091          22 :                 for (node *nn = mts->h; nn; ) { /* extract mergetable from the parts */
    1092          11 :                         node *next = nn->next;
    1093          11 :                         sql_part *pt = nn->data;
    1094             : 
    1095          11 :                         if (isPartitionedByColumnTable(pt->t) || isPartitionedByExpressionTable(pt->t))
    1096          11 :                                 nn->data = pt->t;
    1097             :                         else
    1098           0 :                                 list_remove_node(mts, NULL, nn);
    1099             :                         nn = next;
    1100             :                 }
    1101             :         }
    1102        4059 :         if (isPartitionedByColumnTable(t) || isPartitionedByExpressionTable(t)) { /* validate update on mergetable */
    1103          19 :                 if (!mts)
    1104          19 :                         mts = sa_list(sql->sa);
    1105          19 :                 list_append(mts, t);
    1106             :         }
    1107             : 
    1108             :         /* first create the project */
    1109        4059 :         exps = list_append(new_exp_list(sql->sa), ne=exp_column(sql->sa, rname = rel_name(r), TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1));
    1110        4059 :         ne->alias.label = rel_base_nid(bt, NULL);
    1111        4059 :         ne->nid = ne->alias.label;
    1112             : 
    1113        8125 :         for (n = assignmentlist->h; n; n = n->next) {
    1114        4110 :                 symbol *a = NULL;
    1115        4110 :                 sql_exp *v = NULL;
    1116        4110 :                 sql_rel *rel_val = NULL;
    1117        4110 :                 dlist *assignment = n->data.sym->data.lval;
    1118        4110 :                 int single = (assignment->h->next->type == type_string), outer = 0;
    1119             :                 /* Single assignments have a name, multicolumn a list */
    1120             : 
    1121        4110 :                 a = assignment->h->data.sym;
    1122        4110 :                 if (a) {
    1123        4110 :                         exp_kind ek = { (single)?type_value:type_relation, card_column, FALSE};
    1124             : 
    1125        4115 :                         if (single && a->token == SQL_DEFAULT) {
    1126           7 :                                 char *colname = assignment->h->next->data.sval;
    1127           7 :                                 sql_column *c = mvc_bind_column(sql, t, colname);
    1128             : 
    1129           7 :                                 if (!c)
    1130          17 :                                         return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s.%s'", action, t->base.name, colname);
    1131           7 :                                 if (c->def) {
    1132           5 :                                         v = rel_parse_val(sql, t->s, c->def, &c->type, sql->emode, NULL);
    1133             :                                 } else {
    1134           2 :                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: column '%s' has no valid default value", action, c->base.name);
    1135             :                                 }
    1136        4084 :                         } else if (single) {
    1137        4084 :                                 v = rel_value_exp(query, &r, a, sql_sel | sql_update_set, ek);
    1138        4084 :                                 outer = 1;
    1139             :                         } else {
    1140          19 :                                 if (r)
    1141          19 :                                         query_push_outer(query, r, sql_sel | sql_update_set);
    1142          19 :                                 rel_val = rel_subquery(query, a, ek);
    1143          19 :                                 if (r) {
    1144          19 :                                         r = query_pop_outer(query);
    1145          19 :                                         if (r && is_groupby(r->op))
    1146           0 :                                                 return sql_error(sql, 02, SQLSTATE(42000) "SELECT: aggregate functions not allowed in SET, WHILE, IF, ELSE, CASE, WHEN, RETURN, ANALYZE clauses");
    1147             :                                 }
    1148             :                                 outer = 1;
    1149             :                         }
    1150        4108 :                         if ((single && !v) || (!single && !rel_val))
    1151             :                                 return NULL;
    1152        4093 :                         if (rel_val && outer) {
    1153          18 :                                 if (single) {
    1154           0 :                                         if (!exp_name(v))
    1155           0 :                                                 exp_label(sql->sa, v, ++sql->label);
    1156           0 :                                         if (rel_val->op != op_project || is_processed(rel_val))
    1157           0 :                                                 rel_val = rel_project(sql->sa, rel_val, NULL);
    1158           0 :                                         v = rel_project_add_exp(sql, rel_val, v);
    1159           0 :                                         reset_processed(rel_val);
    1160             :                                 }
    1161          18 :                                 r = rel_crossproduct(sql->sa, r, rel_val, op_left);
    1162          18 :                                 r->flag |= MERGE_LEFT;
    1163          18 :                                 set_dependent(r);
    1164          18 :                                 set_processed(r);
    1165          18 :                                 if (single) {
    1166           0 :                                         v = exp_column(sql->sa, NULL, exp_name(v), exp_subtype(v), v->card, has_nil(v), is_unique(v), is_intern(v));
    1167           0 :                                         rel_val = NULL;
    1168             :                                 }
    1169             :                         }
    1170             :                 }
    1171        4093 :                 if (!single) {
    1172          18 :                         dlist *cols = assignment->h->next->data.lval;
    1173          18 :                         dnode *m;
    1174          18 :                         node *n;
    1175             : 
    1176          18 :                         if (!rel_val)
    1177           0 :                                 rel_val = r;
    1178          18 :                         if (!rel_val || !is_project(rel_val->op))
    1179           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: Invalid right side of the SET clause", action);
    1180          18 :                         if (dlist_length(cols) != list_length(rel_val->exps))
    1181           2 :                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: The number of specified columns between the SET clause and the right side don't match (%d != %d)", action, dlist_length(cols), list_length(rel_val->exps));
    1182          16 :                         sql_alias *ta = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
    1183          62 :                         for (n = rel_val->exps->h, m = cols->h; n && m; n = n->next, m = m->next) {
    1184          46 :                                 char *cname = m->data.sval;
    1185          46 :                                 sql_column *c = mvc_bind_column(sql, t, cname);
    1186          46 :                                 sql_exp *v = n->data;
    1187             : 
    1188          46 :                                 if (!c)
    1189           0 :                                         return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s.%s'", action, t->base.name, cname);
    1190          46 :                                 if (updates[c->colnr])
    1191           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: Multiple assignments to same column '%s'", action, c->base.name);
    1192          46 :                                 if (!list_empty(mts)) {
    1193           0 :                                         for (node *nn = mts->h; nn; nn = nn->next) {
    1194           0 :                                                 sql_table *mt = nn->data;
    1195             : 
    1196           0 :                                                 if (isPartitionedByColumnTable(mt)) {
    1197           0 :                                                         if (mt->part.pcol->colnr == c->colnr)
    1198           0 :                                                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: Update on the partitioned column is not possible at the moment", action);
    1199           0 :                                                 } else if (isPartitionedByExpressionTable(mt)) {
    1200           0 :                                                         for (node *nnn = mt->part.pexp->cols->h ; nnn ; nnn = nnn->next) {
    1201           0 :                                                                 int next = *(int*) nnn->data;
    1202           0 :                                                                 if (next == c->colnr)
    1203           0 :                                                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: Update a column used by the partition's expression is not possible at the moment", action);
    1204             :                                                         }
    1205             :                                                 }
    1206             :                                         }
    1207             :                                 }
    1208          46 :                                 if (!exp_name(v))
    1209           8 :                                         exp_label(sql->sa, v, ++sql->label);
    1210          46 :                                 if (!exp_is_atom(v) || outer)
    1211          46 :                                         v = exp_ref(sql, v);
    1212          46 :                                 if (!v) /* check for NULL */
    1213           0 :                                         v = exp_atom(sql->sa, atom_general(sql->sa, &c->type, NULL, 0));
    1214          46 :                                 if (!(v = update_check_column(sql, t, c, v, r, cname, action)))
    1215             :                                         return NULL;
    1216          46 :                                 list_append(exps, ne=exp_column(sql->sa, ta, cname, &c->type, CARD_MULTI, 0, 0, 0));
    1217          46 :                                 ne->alias.label = rel_base_nid(bt, c);
    1218          46 :                                 ne->nid = ne->alias.label;
    1219          46 :                                 exp_setname(sql, v, ta, c->base.name);
    1220          46 :                                 updates[c->colnr] = v;
    1221          46 :                                 rel_base_use(sql, bt, c->colnr);
    1222             :                         }
    1223             :                 } else {
    1224        4075 :                         char *cname = assignment->h->next->data.sval;
    1225        4075 :                         sql_column *c = mvc_bind_column(sql, t, cname);
    1226             : 
    1227        4075 :                         if (!c)
    1228           3 :                                 return sql_error(sql, ERR_NOTFOUND, SQLSTATE(42S22) "%s: no such column '%s.%s'", action, t->base.name, cname);
    1229        4072 :                         if (updates[c->colnr])
    1230           2 :                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: Multiple assignments to same column '%s'", action, c->base.name);
    1231        4070 :                         if (!list_empty(mts)) {
    1232          48 :                                 for (node *nn = mts->h; nn; nn = nn->next) {
    1233          31 :                                         sql_table *mt = nn->data;
    1234             : 
    1235          31 :                                         if (isPartitionedByColumnTable(mt)) {
    1236          19 :                                                 if (mt->part.pcol->colnr == c->colnr)
    1237           8 :                                                         return sql_error(sql, 02, SQLSTATE(42000) "%s: Update on the partitioned column is not possible at the moment", action);
    1238          12 :                                         } else if (isPartitionedByExpressionTable(mt)) {
    1239          18 :                                                 for (node *nnn = mt->part.pexp->cols->h ; nnn ; nnn = nnn->next) {
    1240          12 :                                                         int next = *(int*) nnn->data;
    1241          12 :                                                         if (next == c->colnr)
    1242           6 :                                                                 return sql_error(sql, 02, SQLSTATE(42000) "%s: Update a column used by the partition's expression is not possible at the moment", action);
    1243             :                                                 }
    1244             :                                         }
    1245             :                                 }
    1246             :                         }
    1247        4056 :                         if (!v)
    1248           0 :                                 v = exp_atom(sql->sa, atom_general(sql->sa, &c->type, NULL, 0));
    1249        4056 :                         if (!(v = update_check_column(sql, t, c, v, r, cname, action)))
    1250             :                                 return NULL;
    1251        4050 :                         sql_alias *ta = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
    1252        4050 :                         list_append(exps, ne=exp_column(sql->sa, ta, cname, &c->type, CARD_MULTI, 0, 0, 0));
    1253        4050 :                         ne->alias.label = rel_base_nid(bt, c);
    1254        4050 :                         ne->nid = ne->alias.label;
    1255        4050 :                         exp_setname(sql, v, ta, c->base.name);
    1256        4050 :                         updates[c->colnr] = v;
    1257        4050 :                         rel_base_use(sql, bt, c->colnr);
    1258             :                 }
    1259             :         }
    1260        4015 :         sql_exp *v = exp_column(sql->sa, rname, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
    1261        4015 :         if (!v)
    1262             :                 return NULL;
    1263        4015 :         v->alias.label = rel_base_nid(bt, NULL);
    1264        4015 :         v->nid = v->alias.label;
    1265        4015 :         r = rel_project(sql->sa, r, list_append(new_exp_list(sql->sa), v));
    1266        4015 :         reset_single(r); /* don't let single joins get propagated */
    1267        4015 :         r = rel_update(sql, bt, r, updates, exps);
    1268        4015 :         return r;
    1269             : }
    1270             : 
    1271             : static sql_rel *
    1272        4065 : update_table(sql_query *query, dlist *qname, str alias, dlist *assignmentlist, symbol *opt_from, symbol *opt_where, dlist *opt_returning)
    1273             : {
    1274        4065 :         mvc *sql = query->sql;
    1275        4065 :         char *sname = qname_schema(qname);
    1276        4065 :         char *tname = qname_schema_object(qname);
    1277        4065 :         sql_alias *ta = qname2alias(sql->sa, qname);
    1278        4065 :         sql_table *t = NULL;
    1279             : 
    1280        4065 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "UPDATE", false);
    1281        4065 :         if (update_allowed(sql, t, tname, "UPDATE", "update", 0) != NULL) {
    1282        4057 :                 sql_rel *r = NULL, *res = rel_basetable(sql, t, alias ? a_create(sql->sa, alias) : ta), *bt = rel_dup(res);
    1283             : 
    1284             :                 /* We have always to reduce the column visibility because of the SET clause */
    1285        4057 :                 if (!table_privs(sql, t, PRIV_SELECT)) {
    1286          16 :                         rel_base_disallow(res);
    1287          16 :                         if (rel_base_has_column_privileges(sql, res) == 0 && opt_where)
    1288           5 :                                 return sql_error(sql, 02, SQLSTATE(42000) "UPDATE: insufficient privileges for user '%s' to update table '%s'",
    1289             :                                                                  get_string_global_var(sql, "current_user"), tname);
    1290             :                 }
    1291        4052 :                 rel_base_use_tid(sql, res);
    1292        4052 :                 if (opt_from) {
    1293          18 :                         dlist *fl = opt_from->data.lval;
    1294          18 :                         list *refs = list_append(new_exp_list(sql->sa), (char*) rel_name(res));
    1295          18 :                         sql_rel *tables = NULL;
    1296             : 
    1297          36 :                         for (dnode *n = fl->h; n && res; n = n->next) {
    1298          19 :                                 sql_rel *fnd = table_ref(query, n->data.sym, 0, refs);
    1299             : 
    1300          19 :                                 if (!fnd)
    1301             :                                         return NULL;
    1302          18 :                                 if (fnd && tables) {
    1303           1 :                                         tables = rel_crossproduct(sql->sa, tables, fnd, op_join);
    1304             :                                 } else {
    1305             :                                         tables = fnd;
    1306             :                                 }
    1307             :                         }
    1308          17 :                         if (!tables)
    1309             :                                 return NULL;
    1310          17 :                         res = rel_crossproduct(sql->sa, res, tables, op_join);
    1311          17 :                         set_single(res);
    1312             :                 }
    1313        4051 :                 if (opt_where) {
    1314        2844 :                         if (!(r = rel_logical_exp(query, res, opt_where, sql_where)))
    1315             :                                 return NULL;
    1316             :                         /* handle join */
    1317        2833 :                         if (!opt_from && is_join(r->op))
    1318           0 :                                 r->op = op_semi;
    1319        2833 :                         else if (r->nrcols != res->nrcols)
    1320           0 :                                 r = rel_project(sql->sa, r, rel_projections(sql, res, NULL, 1, 1));
    1321             :                 } else {        /* update all */
    1322             :                         r = res;
    1323             :                 }
    1324        4040 :                 r = update_generate_assignments(query, t, r, bt, assignmentlist, "UPDATE");
    1325        4040 :                 if (opt_returning) {
    1326          10 :                         query_processed(query);
    1327          10 :                         r->returning = 1;
    1328          10 :                         list *pexps = sa_list(sql->sa);
    1329          10 :                         sql_rel* inner = r->l;
    1330          20 :                         for (dnode *n = opt_returning->h; n; n = n->next) {
    1331          14 :                                 sql_exp *ce = rel_column_exp(query, &inner, n->data.sym, sql_sel | sql_no_subquery);
    1332          14 :                                 if (ce == NULL)
    1333           4 :                                         return NULL;
    1334          10 :                                 pexps = append(pexps, ce);
    1335             :                         }
    1336           6 :                         if (is_groupby(inner->op)) {
    1337           2 :                                 inner->l = r;
    1338           2 :                                 r = rel_project(sql->sa, inner, pexps);
    1339             :                         }
    1340             :                         else
    1341           4 :                                 r = rel_project(sql->sa, r, pexps);
    1342             :                 }
    1343             : 
    1344        4036 :                 return r;
    1345             :         }
    1346             :         return NULL;
    1347             : }
    1348             : 
    1349             : sql_rel *
    1350         997 : rel_delete(allocator *sa, sql_rel *t, sql_rel *deletes)
    1351             : {
    1352         997 :         sql_rel *r = rel_create(sa);
    1353         997 :         if(!r)
    1354             :                 return NULL;
    1355             : 
    1356         997 :         r->op = op_delete;
    1357         997 :         r->l = t;
    1358         997 :         r->r = deletes;
    1359         997 :         r->card = deletes ? deletes->card : CARD_ATOM;
    1360         997 :         return r;
    1361             : }
    1362             : 
    1363             : sql_rel *
    1364       42152 : rel_truncate(allocator *sa, sql_rel *t, int restart_sequences, int drop_action)
    1365             : {
    1366       42152 :         sql_rel *r = rel_create(sa);
    1367       42202 :         list *exps = new_exp_list(sa);
    1368             : 
    1369       42161 :         append(exps, exp_atom_int(sa, restart_sequences));
    1370       42132 :         append(exps, exp_atom_int(sa, drop_action));
    1371       42209 :         r->exps = exps;
    1372       42209 :         r->op = op_truncate;
    1373       42209 :         r->l = t;
    1374       42209 :         r->r = NULL;
    1375       42209 :         r->card = CARD_ATOM;
    1376       42209 :         return r;
    1377             : }
    1378             : 
    1379             : static sql_rel *
    1380         999 : delete_table(sql_query *query, dlist *qname, str alias, symbol *opt_where, dlist *opt_returning)
    1381             : {
    1382         999 :         mvc *sql = query->sql;
    1383         999 :         char *sname = qname_schema(qname);
    1384         999 :         char *tname = qname_schema_object(qname);
    1385         999 :         sql_alias *ta = qname2alias(sql->sa, qname);
    1386         999 :         sql_table *t = NULL;
    1387             : 
    1388         999 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "DELETE FROM", false);
    1389         999 :         if (update_allowed(sql, t, tname, "DELETE FROM", "delete from", 1) != NULL) {
    1390         982 :                 sql_rel *r = rel_basetable(sql, t, alias ? a_create(sql->sa, alias) : ta), *bt = r;
    1391             : 
    1392         982 :                 if (opt_where) {
    1393         393 :                         sql_exp *e;
    1394             : 
    1395         393 :                         if (!table_privs(sql, t, PRIV_SELECT)) {
    1396           3 :                                 rel_base_disallow(r);
    1397           3 :                                 if (rel_base_has_column_privileges(sql, r) == 0)
    1398           1 :                                         return sql_error(sql, 02, SQLSTATE(42000) "DELETE FROM: insufficient privileges for user '%s' to delete from table '%s'",
    1399             :                                                                          get_string_global_var(sql, "current_user"), tname);
    1400             :                         }
    1401         392 :                         rel_base_use_tid(sql, r);
    1402             : 
    1403         392 :                         if (!(r = rel_logical_exp(query, r, opt_where, sql_where)))
    1404             :                                 return NULL;
    1405         378 :                         e = exp_column(sql->sa, rel_name(r), TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
    1406         378 :                         e->nid = rel_base_nid(bt, NULL);
    1407         378 :                         e->alias.label = e->nid;
    1408         378 :                         r = rel_project(sql->sa, r, list_append(new_exp_list(sql->sa), e));
    1409         378 :                         r = rel_delete(sql->sa, rel_dup(bt), r);
    1410             :                 } else {        /* delete all */
    1411         589 :                         r = rel_delete(sql->sa, r, NULL);
    1412             :                 }
    1413         967 :                 if (opt_returning) {
    1414           8 :                         query_processed(query);
    1415           8 :                         r->returning = 1;
    1416           8 :                         list *pexps = sa_list(sql->sa);
    1417           8 :                         sql_rel* inner = r->l;
    1418          15 :                         for (dnode *n = opt_returning->h; n; n = n->next) {
    1419          11 :                                 sql_exp *ce = rel_column_exp(query, &inner, n->data.sym, sql_sel | sql_no_subquery);
    1420          11 :                                 if (ce == NULL)
    1421           4 :                                         return NULL;
    1422           7 :                                 pexps = append(pexps, ce);
    1423             :                         }
    1424           4 :                         if (is_groupby(inner->op)) {
    1425           2 :                                 inner->l = r;
    1426           2 :                                 r = rel_project(sql->sa, inner, pexps);
    1427             :                         }
    1428             :                         else
    1429           2 :                                 r = rel_project(sql->sa, r, pexps);
    1430             :                 }
    1431         963 :                 return r;
    1432             :         }
    1433             :         return NULL;
    1434             : }
    1435             : 
    1436             : static sql_rel *
    1437       42159 : truncate_table(mvc *sql, dlist *qname, int restart_sequences, int drop_action)
    1438             : {
    1439       42159 :         char *sname = qname_schema(qname);
    1440       42186 :         char *tname = qname_schema_object(qname);
    1441       42223 :         sql_alias *ta = qname2alias(sql->sa, qname);
    1442       42171 :         sql_table *t = NULL;
    1443             : 
    1444       42171 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "TRUNCATE", false);
    1445       42209 :         if (update_allowed(sql, t, tname, "TRUNCATE", "truncate", 2) != NULL)
    1446       42156 :                 return rel_truncate(sql->sa, rel_basetable(sql, t, ta), restart_sequences, drop_action);
    1447             :         return NULL;
    1448             : }
    1449             : 
    1450             : static sql_rel *
    1451          44 : rel_merge(allocator *sa, sql_rel *join, sql_rel *upd1, sql_rel *upd2)
    1452             : {
    1453          44 :         sql_rel *r = rel_create(sa);
    1454             : 
    1455          44 :         r->exps = new_exp_list(sa);
    1456          44 :         r->op = op_merge;
    1457          44 :         r->l = join;
    1458          44 :         r->r = rel_list(sa, upd1, upd2);
    1459          44 :         r->card = MAX(upd1 ? upd1->card : 0, upd2 ? upd2->card : 0);
    1460          44 :         return r;
    1461             : }
    1462             : 
    1463             : #define MERGE_UPDATE_DELETE 1
    1464             : #define MERGE_INSERT        2
    1465             : 
    1466             : static sql_rel *
    1467          56 : merge_into_table(sql_query *query, dlist *qname, str alias, symbol *tref, symbol *search_cond, dlist *merge_list)
    1468             : {
    1469          56 :         mvc *sql = query->sql;
    1470          56 :         char *sname = qname_schema(qname), *tname = qname_schema_object(qname);
    1471          56 :         sql_alias *ta = qname2alias(sql->sa, qname);
    1472          56 :         sql_table *t = NULL;
    1473          56 :         sql_rel *bt, *joined, *join_rel = NULL, *extra_project, *insert = NULL, *upd_del = NULL, *res = NULL;
    1474          56 :         int processed = 0;
    1475             : 
    1476          56 :         assert(tref && search_cond && merge_list);
    1477             : 
    1478          56 :         if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "MERGE", false)))
    1479             :                 return NULL;
    1480          56 :         if (isMergeTable(t))
    1481           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: merge statements not supported for merge tables");
    1482             : 
    1483          55 :         bt = rel_basetable(sql, t, alias ? a_create(sql->sa, alias) : ta);
    1484          55 :         if (!table_privs(sql, t, PRIV_SELECT)) {
    1485           0 :                 rel_base_disallow(bt);
    1486           0 :                 if (rel_base_has_column_privileges(sql, bt) == 0)
    1487           0 :                         return sql_error(sql, 02, SQLSTATE(42000) "MERGE: access denied for %s to table %s%s%s'%s'",
    1488           0 :                                                          get_string_global_var(sql, "current_user"), t->s ? "'":"", t->s ? t->s->base.name : "", t->s ? "'.":"", tname);
    1489             :         }
    1490          55 :         joined = table_ref(query, tref, 0, NULL);
    1491          55 :         if (!bt || !joined)
    1492             :                 return NULL;
    1493             : 
    1494          55 :         sql_alias *bt_name = rel_name(bt);
    1495          55 :         if (rel_name(joined) && a_cmp_obj_names(bt_name, rel_name(joined)))
    1496           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: '%s' on both sides of the joining condition", a_obj_name(bt_name));
    1497             : 
    1498         109 :         for (dnode *m = merge_list->h; m; m = m->next) {
    1499          65 :                 symbol *sym = m->data.sym, *opt_search, *action;
    1500          65 :                 tokens token = sym->token;
    1501          65 :                 dlist* dl = sym->data.lval, *sts;
    1502          65 :                 opt_search = dl->h->data.sym;
    1503          65 :                 action = dl->h->next->data.sym;
    1504          65 :                 sts = action->data.lval;
    1505             : 
    1506          65 :                 if (opt_search)
    1507           0 :                         return sql_error(sql, 02, SQLSTATE(42000) "MERGE: search condition not supported");
    1508             : 
    1509          65 :                 if (token == SQL_MERGE_MATCH) {
    1510          34 :                         tokens uptdel = action->token;
    1511             : 
    1512          34 :                         if ((processed & MERGE_UPDATE_DELETE) == MERGE_UPDATE_DELETE)
    1513           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: only one WHEN MATCHED clause is allowed");
    1514          34 :                         processed |= MERGE_UPDATE_DELETE;
    1515             : 
    1516          34 :                         rel_base_use_tid(sql, bt);
    1517          34 :                         if (uptdel == SQL_UPDATE) {
    1518          20 :                                 if (!update_allowed(sql, t, tname, "MERGE", "update", 0))
    1519             :                                         return NULL;
    1520          20 :                                 if ((processed & MERGE_INSERT) == MERGE_INSERT) {
    1521           2 :                                         join_rel = rel_dup(join_rel);
    1522             :                                 } else {
    1523          18 :                                         join_rel = rel_crossproduct(sql->sa, bt, joined, op_left);
    1524          18 :                                         if (!(join_rel = rel_logical_exp(query, join_rel, search_cond, sql_where | sql_join | sql_merge)))
    1525             :                                                 return NULL;
    1526          17 :                                         set_processed(join_rel);
    1527             :                                 }
    1528             : 
    1529          19 :                                 extra_project = rel_project(sql->sa, join_rel, rel_projections(sql, join_rel, NULL, 1, 1));
    1530          19 :                                 upd_del = update_generate_assignments(query, t, extra_project, rel_dup(bt), sts->h->data.lval, "MERGE");
    1531          14 :                         } else if (uptdel == SQL_DELETE) {
    1532          14 :                                 if (!update_allowed(sql, t, tname, "MERGE", "delete", 1))
    1533             :                                         return NULL;
    1534          14 :                                 if ((processed & MERGE_INSERT) == MERGE_INSERT) {
    1535           0 :                                         join_rel = rel_dup(join_rel);
    1536             :                                 } else {
    1537          14 :                                         join_rel = rel_crossproduct(sql->sa, bt, joined, op_left);
    1538          14 :                                         if (!(join_rel = rel_logical_exp(query, join_rel, search_cond, sql_where | sql_join | sql_merge)))
    1539             :                                                 return NULL;
    1540          10 :                                         set_processed(join_rel);
    1541             :                                 }
    1542             : 
    1543          10 :                                 sql_exp *ne = exp_column(sql->sa, bt_name, TID, sql_bind_localtype("oid"), CARD_MULTI, 0, 1, 1);
    1544          10 :                                 ne->nid = rel_base_nid(bt, NULL);
    1545          10 :                                 ne->alias.label = ne->nid;
    1546          10 :                                 extra_project = rel_project(sql->sa, join_rel, list_append(new_exp_list(sql->sa), ne));
    1547          10 :                                 upd_del = rel_delete(sql->sa, rel_dup(bt), extra_project);
    1548             :                         } else {
    1549           0 :                                 assert(0);
    1550             :                         }
    1551          29 :                         if (!upd_del)
    1552             :                                 return NULL;
    1553          31 :                 } else if (token == SQL_MERGE_NO_MATCH) {
    1554          31 :                         if ((processed & MERGE_INSERT) == MERGE_INSERT)
    1555           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: only one WHEN NOT MATCHED clause is allowed");
    1556          31 :                         processed |= MERGE_INSERT;
    1557             : 
    1558          31 :                         assert(action->token == SQL_INSERT);
    1559          31 :                         if (!insert_allowed(sql, t, tname, "MERGE", "insert"))
    1560             :                                 return NULL;
    1561          31 :                         if ((processed & MERGE_UPDATE_DELETE) == MERGE_UPDATE_DELETE) {
    1562           8 :                                 join_rel = rel_dup(join_rel);
    1563             :                         } else {
    1564          23 :                                 join_rel = rel_crossproduct(sql->sa, bt, joined, op_left);
    1565          23 :                                 if (!(join_rel = rel_logical_exp(query, join_rel, search_cond, sql_where | sql_join | sql_merge)))
    1566             :                                         return NULL;
    1567          22 :                                 set_processed(join_rel);
    1568             :                         }
    1569             : 
    1570          30 :                         extra_project = rel_project(sql->sa, join_rel, rel_projections(sql, joined, NULL, 1, 0));
    1571          30 :                         if (!(insert = merge_generate_inserts(query, t, extra_project, sts->h->data.lval, sts->h->next->data.sym)))
    1572             :                                 return NULL;
    1573             : 
    1574          26 :                         sql_rel *ibt = rel_dup(bt);
    1575          26 :                         rel_base_use_all(query->sql, ibt);
    1576          26 :                         ibt = rewrite_basetable(query->sql, ibt);
    1577          26 :                         if (!(insert = rel_insert(query->sql, ibt, insert)))
    1578             :                                 return NULL;
    1579             :                 } else {
    1580           0 :                         assert(0);
    1581             :                 }
    1582             :         }
    1583             : 
    1584          44 :         if (!join_rel)
    1585           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "MERGE: an insert or update or delete clause is required");
    1586          44 :         join_rel->flag |= MERGE_LEFT;
    1587          44 :         if (processed == (MERGE_UPDATE_DELETE | MERGE_INSERT)) {
    1588          10 :                 res = rel_merge(sql->sa, rel_dup(join_rel), upd_del, insert);
    1589          34 :         } else if ((processed & MERGE_UPDATE_DELETE) == MERGE_UPDATE_DELETE) {
    1590          18 :                 res = rel_merge(sql->sa, rel_dup(join_rel), upd_del, NULL);
    1591          16 :         } else if ((processed & MERGE_INSERT) == MERGE_INSERT) {
    1592          16 :                 res = rel_merge(sql->sa, rel_dup(join_rel), insert, NULL);
    1593             :         } else {
    1594           0 :                 assert(0);
    1595             :         }
    1596             :         return res;
    1597             : }
    1598             : 
    1599             : static list *
    1600        1146 : table_column_types(allocator *sa, sql_table *t)
    1601             : {
    1602        1146 :         node *n;
    1603        1146 :         list *types = sa_list(sa);
    1604             : 
    1605       12774 :         if (ol_first_node(t->columns)) for (n = ol_first_node(t->columns); n; n = n->next) {
    1606       10482 :                 sql_column *c = n->data;
    1607       10482 :                 if (c->base.name[0] != '%')
    1608       10476 :                         append(types, &c->type);
    1609             :         }
    1610        1146 :         return types;
    1611             : }
    1612             : 
    1613             : static list *
    1614          24 : table_column_names_and_defaults(allocator *sa, sql_table *t)
    1615             : {
    1616          24 :         node *n;
    1617          24 :         list *types = sa_list(sa);
    1618             : 
    1619         182 :         if (ol_first_node(t->columns)) for (n = ol_first_node(t->columns); n; n = n->next) {
    1620         134 :                 sql_column *c = n->data;
    1621         134 :                 append(types, &c->base.name);
    1622         134 :                 append(types, c->def);
    1623             :         }
    1624          24 :         return types;
    1625             : }
    1626             : 
    1627             : static sql_rel *
    1628        1122 : rel_import(mvc *sql, sql_table *t, const char *tsep, const char *rsep, const char *ssep, const char *ns, const char *filename, lng nr, lng offset, int best_effort, dlist *fwf_widths, int onclient, int escape, const char* decsep, const char *decskip)
    1629             : {
    1630        1122 :         sql_rel *res;
    1631        1122 :         list *exps, *args;
    1632        1122 :         node *n;
    1633        1122 :         sql_subtype tpe;
    1634        1122 :         sql_exp *import;
    1635        1122 :         sql_subfunc *f = sql_find_func(sql, "sys", "copyfrom", 14, F_UNION, true, NULL);
    1636        1122 :         char *fwf_string = NULL;
    1637             : 
    1638        1122 :         assert(f); /* we do expect copyfrom to be there */
    1639        1122 :         f->res = table_column_types(sql->sa, t);
    1640        1122 :         sql_find_subtype(&tpe, "varchar", 0, 0);
    1641        1122 :         args = new_exp_list(sql->sa);
    1642        1122 :         append(args, exp_atom_ptr(sql->sa, t));
    1643        1122 :         append(args, exp_atom_str(sql->sa, tsep, &tpe));
    1644        1122 :         append(args, exp_atom_str(sql->sa, rsep, &tpe));
    1645        1122 :         append(args, exp_atom_str(sql->sa, ssep, &tpe));
    1646        1122 :         append(args, exp_atom_str(sql->sa, ns, &tpe));
    1647             : 
    1648        1122 :         if (fwf_widths && dlist_length(fwf_widths) > 0) {
    1649           2 :                 dnode *dn;
    1650           2 :                 int ncol = 0;
    1651           2 :                 char *fwf_string_cur = fwf_string = sa_alloc(sql->sa, 20 * dlist_length(fwf_widths) + 1); /* a 64 bit int needs 19 characters in decimal representation plus the separator */
    1652             : 
    1653           2 :                 if (!fwf_string)
    1654             :                         return NULL;
    1655          36 :                 for (dn = fwf_widths->h; dn; dn = dn->next) {
    1656          34 :                         fwf_string_cur += sprintf(fwf_string_cur, LLFMT"%c", dn->data.l_val, STREAM_FWF_FIELD_SEP);
    1657          34 :                         ncol++;
    1658             :                 }
    1659           2 :                 if (list_length(f->res) != ncol)
    1660           0 :                         return sql_error(sql, 02, SQLSTATE(3F000) "COPY INTO: fixed width import for %d columns but %d widths given.", list_length(f->res), ncol);
    1661           2 :                 *fwf_string_cur = '\0';
    1662             :         }
    1663             : 
    1664        1122 :         append(args, exp_atom_str(sql->sa, filename, &tpe));
    1665        1122 :         append(args, exp_atom_lng(sql->sa, nr));
    1666        1122 :         append(args, exp_atom_lng(sql->sa, offset));
    1667        1122 :         append(args, exp_atom_int(sql->sa, best_effort));
    1668        1122 :         append(args, exp_atom_str(sql->sa, fwf_string, &tpe));
    1669        1122 :         append(args, exp_atom_int(sql->sa, onclient));
    1670        1122 :         append(args, exp_atom_int(sql->sa, escape));
    1671        1122 :         append(args, exp_atom_str(sql->sa, decsep, &tpe));
    1672        1122 :         append(args, exp_atom_str(sql->sa, decskip, &tpe));
    1673             : 
    1674        1122 :         import = exp_op(sql->sa, args, f);
    1675             : 
    1676        1122 :         exps = new_exp_list(sql->sa);
    1677        1122 :         sql_alias *ta = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
    1678       11470 :         for (n = ol_first_node(t->columns); n; n = n->next) {
    1679       10348 :                 sql_column *c = n->data;
    1680       10348 :                 if (c->base.name[0] != '%') {
    1681       10342 :                         sql_exp *e = exp_column(sql->sa, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
    1682             : 
    1683       10342 :                         e->alias.label = -(sql->nid++);
    1684       10342 :                         append(exps, e);
    1685             :                 }
    1686             :         }
    1687        1122 :         res = rel_table_func(sql->sa, NULL, import, exps, TABLE_PROD_FUNC);
    1688        1122 :         return res;
    1689             : }
    1690             : 
    1691             : static bool
    1692        1132 : valid_decsep(const char *s)
    1693             : {
    1694        1132 :         if (strlen(s) != 1)
    1695             :                 return false;
    1696        1132 :         int c = s[0];
    1697        1132 :         if (c <= ' ' || c >= 127)
    1698             :                 return false;
    1699        1132 :         if (c == '-' || c == '+')
    1700             :                 return false;
    1701        1132 :         if (c >= '0' && c <= '9')
    1702           0 :                 return false;
    1703             :         return true;
    1704             : }
    1705             : 
    1706             : static sql_rel *
    1707        1126 : copyfrom(sql_query *query, dlist *qname, dlist *columns, dlist *files, dlist *headers, dlist *seps, dlist *nr_offset, str null_string, int best_effort, dlist *fwf_widths, int onclient, int escape, dlist *decimal_seps)
    1708             : {
    1709        1126 :         mvc *sql = query->sql;
    1710        1126 :         sql_rel *rel = NULL;
    1711        1126 :         char *sname = qname_schema(qname);
    1712        1126 :         char *tname = qname_schema_object(qname);
    1713        1126 :         sql_table *t = NULL, *nt = NULL;
    1714        1126 :         const char *tsep = seps->h->data.sval;
    1715        1126 :         char *rsep = seps->h->next->data.sval; /* not const, might need adjusting */
    1716        1126 :         const char *ssep = (seps->h->next->next)?seps->h->next->next->data.sval:NULL;
    1717        1126 :         const char *ns = (null_string)?null_string:"null";
    1718        1126 :         lng nr = (nr_offset)?nr_offset->h->data.l_val:-1;
    1719        1060 :         lng offset = (nr_offset)?nr_offset->h->next->data.l_val:0;
    1720        1126 :         list *collist;
    1721        1126 :         int reorder = 0;
    1722        1126 :         const char *decsep = decimal_seps->h->data.sval;
    1723        1126 :         const char *decskip = decimal_seps->h->next ? decimal_seps->h->next->data.sval: NULL;
    1724             : 
    1725        1126 :         assert(!nr_offset || nr_offset->h->type == type_lng);
    1726        1060 :         assert(!nr_offset || nr_offset->h->next->type == type_lng);
    1727             : 
    1728        1126 :         if (strcmp(rsep, "\r\n") == 0) {
    1729             :                 /* silently fix it */
    1730           1 :                 rsep[0] = '\n';
    1731           1 :                 rsep[1] = '\0';
    1732        1125 :         } else if (strstr(rsep, "\r\n") != NULL) {
    1733           0 :                 return sql_error(sql, 02, SQLSTATE(42000)
    1734             :                                 "COPY INTO: record separator contains '\\r\\n' but "
    1735             :                                 "that will never match, use '\\n' instead");
    1736             :         }
    1737             : 
    1738        1126 :         if (!valid_decsep(decsep))
    1739           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: invalid decimal separator");
    1740        1126 :         if (decskip && !valid_decsep(decskip))
    1741           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: invalid thousands separator");
    1742           6 :         if (decskip && strcmp(decsep, decskip) == 0)
    1743           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: decimal separator and thousands separator must be different");
    1744             : 
    1745        1126 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COPY INTO", false);
    1746        1126 :         if (insert_allowed(sql, t, tname, "COPY INTO", "copy into") == NULL)
    1747             :                 return NULL;
    1748             : 
    1749        1122 :         collist = check_table_columns(sql, t, columns, "COPY INTO", tname);
    1750        1122 :         if (!collist)
    1751             :                 return NULL;
    1752             :         /* If we have a header specification use intermediate table, for
    1753             :          * column specification other then the default list we need to reorder
    1754             :          */
    1755        1122 :         nt = t;
    1756        1122 :         if (headers || collist != t->columns->l)
    1757          74 :                 reorder = 1;
    1758          34 :         if (headers) {
    1759          34 :                 int has_formats = 0;
    1760             : 
    1761          34 :                 switch (mvc_create_table(&nt, sql, t->s, tname, tt_table, 0, SQL_DECLARED_TABLE, CA_COMMIT, -1, 0)) {
    1762           0 :                         case -1:
    1763           0 :                                 return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1764           0 :                         case -2:
    1765             :                         case -3:
    1766           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: transaction conflict detected");
    1767             :                         default:
    1768          34 :                                 break;
    1769             :                 }
    1770         130 :                 for (dnode *n = headers->h; n; n = n->next) {
    1771          96 :                         dnode *dn = n->data.lval->h;
    1772          96 :                         char *cname = dn->data.sval;
    1773          96 :                         char *format = NULL;
    1774          96 :                         sql_column *cs = NULL;
    1775          96 :                         int res = LOG_OK;
    1776             : 
    1777          96 :                         if (dn->next)
    1778           1 :                                 format = dn->next->data.sval;
    1779          96 :                         if (!list_find_name(collist, cname)) {
    1780           6 :                                 char *name;
    1781           6 :                                 size_t len = strlen(cname) + 2;
    1782           6 :                                 sql_subtype *ctype = sql_bind_localtype("oid");
    1783             : 
    1784           6 :                                 name = sa_alloc(sql->sa, len);
    1785           6 :                                 snprintf(name, len, "%%cname");
    1786           6 :                                 res = mvc_create_column(&cs, sql, nt, name, ctype);
    1787          90 :                         } else if (!format) {
    1788          89 :                                 cs = find_sql_column(t, cname);
    1789          89 :                                 res = mvc_create_column(&cs, sql, nt, cname, &cs->type);
    1790             :                         } else { /* load as string, parse later */
    1791           1 :                                 sql_subtype *ctype = sql_bind_localtype("str");
    1792           1 :                                 res = mvc_create_column(&cs, sql, nt, cname, ctype);
    1793           1 :                                 has_formats = 1;
    1794             :                         }
    1795          96 :                         switch (res) {
    1796           0 :                                 case -1:
    1797           0 :                                         return sql_error(sql, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1798           0 :                                 case -2:
    1799             :                                 case -3:
    1800           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: transaction conflict detected");
    1801             :                                 default:
    1802          96 :                                         break;
    1803             :                         }
    1804             :                 }
    1805          34 :                 if (!has_formats)
    1806          40 :                         headers = NULL;
    1807             :                 reorder = 1;
    1808             :         }
    1809        1122 :         if (files) {
    1810         335 :                 dnode *n = files->h;
    1811             : 
    1812         335 :                 if (!onclient && !copy_allowed(sql, 1)) {
    1813           2 :                         return sql_error(sql, 02, SQLSTATE(42000)
    1814             :                                          "COPY INTO: insufficient privileges: "
    1815             :                                          "COPY INTO from file(s) requires database administrator rights, "
    1816             :                                          "use 'COPY INTO \"%s\" FROM file ON CLIENT' instead", tname);
    1817             :                 }
    1818             : 
    1819         668 :                 for (; n; n = n->next) {
    1820         337 :                         const char *fname = n->data.sval;
    1821         337 :                         sql_rel *nrel;
    1822             : 
    1823         337 :                         if (!onclient && fname && !MT_path_absolute(fname)) {
    1824           2 :                                 char *fn = ATOMformat(TYPE_str, fname);
    1825           2 :                                 sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: filename must "
    1826             :                                           "have absolute path: %s", fn);
    1827           2 :                                 GDKfree(fn);
    1828           2 :                                 return NULL;
    1829             :                         }
    1830             : 
    1831         335 :                         nrel = rel_import(sql, nt, tsep, rsep, ssep, ns, fname, nr, offset, best_effort, fwf_widths, onclient, escape, decsep, decskip);
    1832             : 
    1833         335 :                         if (!rel)
    1834             :                                 rel = nrel;
    1835             :                         else {
    1836           4 :                                 rel = rel_setop(sql->sa, rel, nrel, op_union);
    1837           4 :                                 rel_setop_set_exps(sql, rel, rel_projections(sql, rel, NULL, 0, 1), false);
    1838           4 :                                 set_processed(rel);
    1839             :                         }
    1840         335 :                         if (!rel)
    1841             :                                 return rel;
    1842             :                 }
    1843             :         } else {
    1844         787 :                 assert(onclient == 0);
    1845         787 :                 rel = rel_import(sql, nt, tsep, rsep, ssep, ns, NULL, nr, offset, best_effort, NULL, onclient, escape, decsep, decskip);
    1846             :         }
    1847        1118 :         if (headers) {
    1848           1 :                 dnode *n;
    1849           1 :                 node *m = rel->exps->h;
    1850           1 :                 list *nexps = sa_list(sql->sa);
    1851             : 
    1852           1 :                 assert(is_project(rel->op) || is_base(rel->op));
    1853          10 :                 for (n = headers->h; n; n = n->next) {
    1854           9 :                         dnode *dn = n->data.lval->h;
    1855           9 :                         char *cname = dn->data.sval;
    1856           9 :                         sql_exp *e, *ne;
    1857             : 
    1858           9 :                         if (!list_find_name(collist, cname))
    1859           0 :                                 continue;
    1860           9 :                         e = m->data;
    1861           9 :                         if (dn->next) {
    1862           1 :                                 char *format = dn->next->data.sval;
    1863           1 :                                 sql_column *cs = find_sql_column(t, cname);
    1864           1 :                                 sql_subtype st;
    1865           1 :                                 sql_subfunc *f;
    1866           1 :                                 list *args = sa_list(sql->sa);
    1867           1 :                                 size_t l = strlen(cs->type.type->base.name);
    1868           1 :                                 char *fname = sa_alloc(sql->sa, l+8);
    1869             : 
    1870           1 :                                 snprintf(fname, l+8, "str_to_%s", strcmp(cs->type.type->base.name, "timestamptz") == 0 ? "timestamp" : cs->type.type->base.name);
    1871           1 :                                 sql_find_subtype(&st, "varchar", 0, 0);
    1872           1 :                                 if (!(f = sql_bind_func_result(sql, "sys", fname, F_FUNC, true, &cs->type, 2, &st, &st)))
    1873           0 :                                         return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: '%s' missing for type %s", fname, cs->type.type->base.name);
    1874           1 :                                 append(args, exp_ref(sql, e));
    1875           1 :                                 append(args, exp_atom_clob(sql->sa, format));
    1876           1 :                                 ne = exp_op(sql->sa, args, f);
    1877           1 :                                 exp_setalias(ne, e->alias.label, exp_relname(e), exp_name(e));
    1878             :                         } else {
    1879           8 :                                 ne = exp_ref(sql, e);
    1880             :                         }
    1881           9 :                         append(nexps, ne);
    1882           9 :                         m = m->next;
    1883             :                 }
    1884           1 :                 rel = rel_project(sql->sa, rel, nexps);
    1885           1 :                 reorder = 0;
    1886             :         }
    1887             : 
    1888        1118 :         if (!rel)
    1889             :                 return rel;
    1890        1118 :         if (reorder) {
    1891          40 :                 list *exps = rel_inserts(sql, t, rel, collist, 1, 1, "COPY INTO");
    1892          40 :                 if(!exps)
    1893             :                         return NULL;
    1894          40 :                 rel = rel_project(sql->sa, rel, exps);
    1895             :         } else {
    1896        1078 :                 rel->exps = rel_inserts(sql, t, rel, collist, 1, 0, "COPY INTO");
    1897        1078 :                 if(!rel->exps)
    1898             :                         return NULL;
    1899             :         }
    1900        1118 :         rel = rel_insert_table(query, t, tname, rel);
    1901        1118 :         return rel;
    1902             : }
    1903             : 
    1904             : static sql_rel *
    1905         101 : bincopyfrom(sql_query *query, dlist *qname, dlist *columns, dlist *files, int onclient, endianness endian)
    1906             : {
    1907         101 :         mvc *sql = query->sql;
    1908         101 :         char *sname = qname_schema(qname);
    1909         101 :         char *tname = qname_schema_object(qname);
    1910         101 :         sql_table *t = NULL;
    1911         101 :         dnode *dn;
    1912         101 :         node *n;
    1913         101 :         sql_rel *res;
    1914         101 :         list *exps, *args;
    1915         101 :         sql_subtype strtpe;
    1916         101 :         sql_exp *import;
    1917         101 :         sql_subfunc *f = sql_find_func(sql, "sys", "copyfrombinary", 3, F_UNION, true, NULL);
    1918         101 :         list *collist;
    1919         101 :         list *typelist;
    1920             : 
    1921         101 :         assert(f);
    1922         101 :         if (!copy_allowed(sql, 1))
    1923           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: insufficient privileges: "
    1924             :                                 "binary COPY INTO requires database administrator rights");
    1925             : 
    1926         101 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COPY INTO", false);
    1927         101 :         if (insert_allowed(sql, t, tname, "COPY INTO", "copy into") == NULL)
    1928             :                 return NULL;
    1929         101 :         if (files == NULL)
    1930           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: must specify files");
    1931             : 
    1932         101 :         bool do_byteswap = (endian != endian_native && endian != OUR_ENDIANNESS);
    1933             : 
    1934         101 :         typelist = sa_list(sql->sa);
    1935         101 :         collist = check_table_columns(sql, t, columns, "COPY BINARY INTO", tname);
    1936         101 :         if (!collist || !typelist)
    1937             :                 return NULL;
    1938             : 
    1939          99 :         int column_count = list_length(collist);
    1940          99 :         int file_count = dlist_length(files);
    1941          99 :         if (column_count != file_count) {
    1942           4 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY BINARY INTO: "
    1943             :                         "number of files does not match number of columns: "
    1944             :                         "%d files, %d columns",
    1945             :                         file_count, column_count);
    1946             :         }
    1947             : 
    1948         313 :         for (node *n = collist->h; n; n = n->next) {
    1949         218 :                 sql_column *c = n->data;
    1950         218 :                 sa_list_append(sql->sa, typelist, &c->type);
    1951             :         }
    1952          95 :         f->res = typelist;
    1953             : 
    1954          95 :         sql_find_subtype(&strtpe, "varchar", 0, 0);
    1955          95 :         args = append( append( append( append( new_exp_list(sql->sa),
    1956             :                 exp_atom_str(sql->sa, t->s?t->s->base.name:NULL, &strtpe)),
    1957             :                 exp_atom_str(sql->sa, t->base.name, &strtpe)),
    1958             :                 exp_atom_int(sql->sa, onclient)),
    1959             :                 exp_atom_bool(sql->sa, do_byteswap));
    1960             : 
    1961         313 :         for (dn = files->h; dn; dn = dn->next) {
    1962         218 :                 char *filename = dn->data.sval;
    1963         218 :                 append(args, exp_atom_str(sql->sa, filename, &strtpe));
    1964             :         }
    1965             : 
    1966          95 :         import = exp_op(sql->sa, args, f);
    1967             : 
    1968          95 :         exps = new_exp_list(sql->sa);
    1969          95 :         sql_alias *ta = table_alias(sql->sa, t, schema_alias(sql->sa, t->s));
    1970         313 :         for (n = collist->h; n; n = n->next) {
    1971         218 :                 sql_column *c = n->data;
    1972         218 :                 sql_exp *e = exp_column(sql->sa, ta, c->base.name, &c->type, CARD_MULTI, c->null, is_column_unique(c), 0);
    1973         218 :                 e->alias.label = -(sql->nid++);
    1974         218 :                 append(exps, e);
    1975             :         }
    1976          95 :         res = rel_table_func(sql->sa, NULL, import, exps, TABLE_PROD_FUNC);
    1977             : 
    1978          95 :         exps = rel_inserts(sql, t, res, collist, 1, 1, "COPY BINARY INTO");
    1979          95 :         if(!exps)
    1980             :                 return NULL;
    1981          94 :         res = rel_project(sql->sa, res, exps);
    1982             : 
    1983          94 :         res = rel_insert_table(query, t, t->base.name, res);
    1984          94 :         return res;
    1985             : }
    1986             : 
    1987             : static sql_rel *
    1988          25 : copyfromloader(sql_query *query, dlist *qname, symbol *fcall)
    1989             : {
    1990          25 :         mvc *sql = query->sql;
    1991          25 :         char *sname = qname_schema(qname);
    1992          25 :         char *tname = qname_schema_object(qname);
    1993          25 :         sql_subfunc *loader = NULL;
    1994          25 :         sql_rel *rel = NULL;
    1995          25 :         sql_table *t;
    1996          25 :         list *mts;
    1997             : 
    1998          25 :         if (!copy_allowed(sql, 1))
    1999           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY LOADER INTO: insufficient privileges: "
    2000             :                                 "COPY LOADER INTO requires database administrator rights");
    2001          25 :         t = find_table_or_view_on_scope(sql, NULL, sname, tname, "COPY INTO", false);
    2002             :         //TODO the COPY LOADER INTO should return an insert relation (instead of ddl) to handle partitioned tables properly
    2003          25 :         if (insert_allowed(sql, t, tname, "COPY LOADER INTO", "copy loader into") == NULL)
    2004             :                 return NULL;
    2005          25 :         if (isPartitionedByColumnTable(t) || isPartitionedByExpressionTable(t))
    2006           1 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY LOADER INTO: not possible for partitioned tables at the moment");
    2007          24 :         if ((mts = partition_find_mergetables(sql, t))) {
    2008           0 :                 for (node *n = mts->h ; n ; n = n->next) {
    2009           0 :                         sql_part *pt = n->data;
    2010             : 
    2011           0 :                         if ((isPartitionedByColumnTable(pt->t) || isPartitionedByExpressionTable(pt->t)))
    2012           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "COPY LOADER INTO: not possible for tables child of partitioned tables at the moment");
    2013             :                 }
    2014             :         }
    2015             : 
    2016          24 :         rel = rel_loader_function(query, fcall, new_exp_list(sql->sa), &loader);
    2017          24 :         if (!rel || !loader)
    2018             :                 return NULL;
    2019             : 
    2020          24 :         loader->sname = t->s ? sa_strdup(sql->sa, t->s->base.name) : NULL;
    2021          24 :         loader->tname = tname ? sa_strdup(sql->sa, tname) : NULL;
    2022          24 :         loader->coltypes = table_column_types(sql->sa, t);
    2023          24 :         loader->colnames = table_column_names_and_defaults(sql->sa, t);
    2024             : 
    2025          24 :         return rel;
    2026             : }
    2027             : 
    2028             : static sql_rel *
    2029          35 : copyto(sql_query *query, symbol *sq, const char *filename, dlist *seps, const char *null_string, int onclient)
    2030             : {
    2031          35 :         mvc *sql = query->sql;
    2032          35 :         const char *tsep = seps->h->data.sval;
    2033          35 :         const char *rsep = seps->h->next->data.sval;
    2034          35 :         const char *ssep = (seps->h->next->next)?seps->h->next->next->data.sval:"\"";
    2035          35 :         const char *ns = (null_string)?null_string:"null";
    2036          35 :         sql_exp *tsep_e, *rsep_e, *ssep_e, *ns_e, *fname_e, *oncl_e;
    2037          35 :         exp_kind ek = {type_value, card_relation, TRUE};
    2038          35 :         sql_rel *r = rel_subquery(query, sq, ek);
    2039             : 
    2040          35 :         if (!r)
    2041             :                 return NULL;
    2042          34 :         r = rel_project(sql->sa, r, rel_projections(sql, r, NULL, 1, 0));
    2043          34 :         if (!(r->exps = check_distinct_exp_names(sql, r->exps)))
    2044           0 :                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: duplicate column names in subquery column list");
    2045             : 
    2046          34 :         tsep_e = exp_atom_clob(sql->sa, tsep);
    2047          34 :         rsep_e = exp_atom_clob(sql->sa, rsep);
    2048          34 :         ssep_e = exp_atom_clob(sql->sa, ssep);
    2049          34 :         ns_e = exp_atom_clob(sql->sa, ns);
    2050          34 :         oncl_e = exp_atom_int(sql->sa, onclient);
    2051          34 :         fname_e = filename?exp_atom_clob(sql->sa, filename):NULL;
    2052             : 
    2053          34 :         if (!onclient && filename) {
    2054           6 :                 struct stat fs;
    2055           6 :                 if (!copy_allowed(sql, 0))
    2056           2 :                         return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: insufficient privileges: "
    2057             :                                          "COPY INTO file requires database administrator rights, "
    2058             :                                          "use 'COPY ... INTO file ON CLIENT' instead");
    2059           4 :                 if (filename && !MT_path_absolute(filename))
    2060           0 :                         return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO ON SERVER: filename must "
    2061             :                                          "have absolute path: %s", filename);
    2062           4 :                 if (lstat(filename, &fs) == 0)
    2063           0 :                         return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO ON SERVER: file already "
    2064             :                                          "exists: %s", filename);
    2065             :         }
    2066             : 
    2067          32 :         sql_rel *rel = rel_create(sql->sa);
    2068          32 :         list *exps = new_exp_list(sql->sa);
    2069          32 :         if(!rel || !exps)
    2070             :                 return NULL;
    2071             : 
    2072             :         /* With regular COPY INTO <file>, the first argument is a string.
    2073             :            With COPY INTO BINARY, it is an int. */
    2074          32 :         append(exps, tsep_e);
    2075          32 :         append(exps, rsep_e);
    2076          32 :         append(exps, ssep_e);
    2077          32 :         append(exps, ns_e);
    2078          32 :         if (fname_e) {
    2079          23 :                 append(exps, fname_e);
    2080          23 :                 append(exps, oncl_e);
    2081             :         }
    2082          32 :         rel->l = r;
    2083          32 :         rel->r = NULL;
    2084          32 :         rel->op = op_ddl;
    2085          32 :         rel->flag = ddl_output;
    2086          32 :         rel->exps = exps;
    2087          32 :         rel->card = 0;
    2088          32 :         rel->nrcols = 0;
    2089          32 :         return rel;
    2090             : }
    2091             : 
    2092             : static sql_rel *
    2093          42 : bincopyto(sql_query *query, symbol *qry, endianness endian, dlist *filenames, int on_client)
    2094             : {
    2095          42 :         mvc *sql = query->sql;
    2096             : 
    2097             :         /* First emit code for the subquery.
    2098             :            Don't know what this is for, copy pasted it from copyto(): */
    2099          42 :         exp_kind ek = { type_value, card_relation, TRUE};
    2100          42 :         sql_rel *sub = rel_subquery(query, qry, ek);
    2101          42 :         if (!sub)
    2102             :                 return NULL;
    2103             :         /* Again, copy-pasted. copyto() uses this to check for duplicate column names
    2104             :            but we don't care about that here. */
    2105          42 :         sub = rel_project(sql->sa, sub, rel_projections(sql, sub, NULL, 1, 0));
    2106             : 
    2107          42 :         sql_rel *rel = rel_create(sql->sa);
    2108          42 :         list *exps = new_exp_list(sql->sa);
    2109          42 :         if (!rel || !exps)
    2110             :                 return NULL;
    2111             : 
    2112             :         /* With regular COPY INTO <file>, the first argument is a string.
    2113             :            With COPY INTO BINARY, it is an int. */
    2114          42 :         append(exps, exp_atom_int(sql->sa, endian));
    2115          42 :         append(exps, exp_atom_int(sql->sa, on_client));
    2116             : 
    2117         192 :         for (dnode *n = filenames->h; n != NULL; n = n->next) {
    2118         150 :                 const char *filename = n->data.sval;
    2119             :                 /* Again, copied from copyto() */
    2120         150 :                 if (!on_client && filename) {
    2121          75 :                         struct stat fs;
    2122          75 :                         if (!copy_allowed(sql, 0))
    2123           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO: insufficient privileges: "
    2124             :                                                 "COPY INTO file requires database administrator rights, "
    2125             :                                                 "use 'COPY ... INTO file ON CLIENT' instead");
    2126          75 :                         if (filename && !MT_path_absolute(filename))
    2127           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO ON SERVER: filename must "
    2128             :                                                 "have absolute path: %s", filename);
    2129          75 :                         if (lstat(filename, &fs) == 0)
    2130           0 :                                 return sql_error(sql, 02, SQLSTATE(42000) "COPY INTO ON SERVER: file already "
    2131             :                                                 "exists: %s", filename);
    2132             :                 }
    2133         150 :                 append(exps, exp_atom_clob(sql->sa, filename));
    2134             :         }
    2135             : 
    2136          42 :         rel->l = sub;
    2137          42 :         rel->r = NULL;
    2138          42 :         rel->op = op_ddl;
    2139          42 :         rel->flag = ddl_output;
    2140          42 :         rel->exps = exps;
    2141          42 :         rel->card = 0;
    2142          42 :         rel->nrcols = 0;
    2143             : 
    2144          42 :         return rel;
    2145             : }
    2146             : 
    2147             : sql_exp *
    2148        1325 : rel_parse_val(mvc *m, sql_schema *sch, char *query, sql_subtype *tpe, char emode, sql_rel *from)
    2149             : {
    2150        1325 :         sql_exp *e = NULL;
    2151        1325 :         buffer *b;
    2152        1325 :         char *n;
    2153        1325 :         size_t len = _strlen(query);
    2154        1325 :         exp_kind ek = {type_value, card_value, FALSE};
    2155        1325 :         stream *s;
    2156        1325 :         bstream *bs;
    2157             : 
    2158        1325 :         b = malloc(sizeof(buffer));
    2159        1325 :         len += 8; /* add 'select ;' */
    2160        1325 :         n = malloc(len + 1 + 1);
    2161        1325 :         if(!b || !n) {
    2162           0 :                 free(b);
    2163           0 :                 free(n);
    2164           0 :                 return sql_error(m, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2165             :         }
    2166        1325 :         snprintf(n, len + 2, "select %s;\n", query);
    2167        1325 :         len++;
    2168        1325 :         buffer_init(b, n, len);
    2169        1325 :         s = buffer_rastream(b, "sqlstatement");
    2170        1325 :         if(!s) {
    2171           0 :                 buffer_destroy(b);
    2172           0 :                 return sql_error(m, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2173             :         }
    2174        1325 :         bs = bstream_create(s, b->len);
    2175        1325 :         if(bs == NULL) {
    2176           0 :                 buffer_destroy(b);
    2177           0 :                 return sql_error(m, 02, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2178             :         }
    2179        1325 :         mvc o = *m;
    2180        1325 :         scanner_init(&m->scanner, bs, NULL);
    2181        1325 :         m->scanner.mode = LINE_1;
    2182        1325 :         bstream_next(m->scanner.rs);
    2183             : 
    2184        1325 :         m->qc = NULL;
    2185        1325 :         if (sch)
    2186        1325 :                 m->session->schema = sch;
    2187        1325 :         m->emode = emode;
    2188        1325 :         m->params = NULL;
    2189        1325 :         m->sym = NULL;
    2190        1325 :         m->errstr[0] = '\0';
    2191        1325 :         m->session->status = 0;
    2192             :         /* via views we give access to protected objects */
    2193        1325 :         m->user_id = USER_MONETDB;
    2194             : 
    2195        1325 :         (void) sqlparse(m);
    2196             : 
    2197             :         /* get out the single value as we don't want an enclosing projection! */
    2198        1325 :         if (m->sym && m->sym->token == SQL_SELECT) {
    2199        1325 :                 SelectNode *sn = (SelectNode *)m->sym;
    2200        1325 :                 if (sn->selection->h->data.sym->token == SQL_COLUMN || sn->selection->h->data.sym->token == SQL_IDENT) {
    2201        1325 :                         sql_rel *r = from;
    2202        1325 :                         symbol* sq = sn->selection->h->data.sym->data.lval->h->data.sym;
    2203        1325 :                         sql_query *query = query_create(m);
    2204        1325 :                         e = rel_value_exp2(query, &r, sq, sql_sel | sql_values, ek);
    2205        1325 :                         if (e && tpe)
    2206        1230 :                                 e = exp_check_type(m, tpe, from, e, type_cast);
    2207             :                 }
    2208             :         }
    2209        1325 :         buffer_destroy(b);
    2210        1325 :         bstream_destroy(m->scanner.rs);
    2211             : 
    2212        1325 :         m->sym = NULL;
    2213        1325 :         o.frames = m->frames;        /* may have been realloc'ed */
    2214        1325 :         o.sizeframes = m->sizeframes;
    2215        1325 :         if (m->session->status || m->errstr[0]) {
    2216           3 :                 int status = m->session->status;
    2217             : 
    2218           3 :                 strcpy(o.errstr, m->errstr);
    2219           3 :                 *m = o;
    2220           3 :                 m->session->status = status;
    2221             :         } else {
    2222        1322 :                 unsigned int label = m->label;
    2223             : 
    2224        1322 :                 while (m->topframes > o.topframes)
    2225           0 :                         clear_frame(m, m->frames[--m->topframes]);
    2226        1322 :                 *m = o;
    2227        1322 :                 m->label = label;
    2228             :         }
    2229             :         return e;
    2230             : }
    2231             : 
    2232             : sql_rel *
    2233      169608 : rel_updates(sql_query *query, symbol *s)
    2234             : {
    2235      169608 :         mvc *sql = query->sql;
    2236      169608 :         sql_rel *ret = NULL;
    2237             : 
    2238      169608 :         switch (s->token) {
    2239        1126 :         case SQL_COPYFROM:
    2240             :         {
    2241        1126 :                 dlist *l = s->data.lval;
    2242             : 
    2243        2252 :                 ret = copyfrom(query,
    2244        1126 :                                 l->h->data.lval,
    2245        1126 :                                 l->h->next->data.lval,
    2246        1126 :                                 l->h->next->next->data.lval,
    2247        1126 :                                 l->h->next->next->next->data.lval,
    2248        1126 :                                 l->h->next->next->next->next->data.lval,
    2249        1126 :                                 l->h->next->next->next->next->next->data.lval,
    2250             :                                 l->h->next->next->next->next->next->next->data.sval,
    2251             :                                 l->h->next->next->next->next->next->next->next->data.i_val,
    2252        1126 :                                 l->h->next->next->next->next->next->next->next->next->data.lval,
    2253             :                                 l->h->next->next->next->next->next->next->next->next->next->data.i_val,
    2254             :                                 l->h->next->next->next->next->next->next->next->next->next->next->data.i_val,
    2255        1126 :                                 l->h->next->next->next->next->next->next->next->next->next->next->next->data.lval);
    2256        1126 :                 sql->type = Q_UPDATE;
    2257             :         }
    2258        1126 :                 break;
    2259         101 :         case SQL_BINCOPYFROM:
    2260             :         {
    2261         101 :                 dlist *l = s->data.lval;
    2262             : 
    2263         101 :                 ret = bincopyfrom(query, l->h->data.lval, l->h->next->data.lval, l->h->next->next->data.lval, l->h->next->next->next->data.i_val, (endianness) l->h->next->next->next->next->data.i_val);
    2264         101 :                 sql->type = Q_UPDATE;
    2265             :         }
    2266         101 :                 break;
    2267          25 :         case SQL_COPYLOADER:
    2268             :         {
    2269          25 :                 dlist *l = s->data.lval;
    2270          25 :                 dlist *qname = l->h->data.lval;
    2271          25 :                 symbol *sym = l->h->next->data.sym;
    2272          25 :                 sql_rel *rel = copyfromloader(query, qname, sym);
    2273             : 
    2274          25 :                 if (rel)
    2275          24 :                         ret = rel_psm_stmt(sql->sa, exp_rel(sql, rel));
    2276          25 :                 sql->type = Q_SCHEMA;
    2277             :         }
    2278          25 :                 break;
    2279          35 :         case SQL_COPYINTO:
    2280             :         {
    2281          35 :                 dlist *l = s->data.lval;
    2282             : 
    2283          35 :                 ret = copyto(query, l->h->data.sym, l->h->next->data.sval, l->h->next->next->data.lval, l->h->next->next->next->data.sval, l->h->next->next->next->next->data.i_val);
    2284          35 :                 sql->type = Q_UPDATE;
    2285             :         }
    2286          35 :                 break;
    2287          42 :         case SQL_BINCOPYINTO:
    2288             :         {
    2289          42 :                 dlist *l = s->data.lval;
    2290          42 :                 symbol *qry = l->h->data.sym;
    2291          42 :                 endianness endian = l->h->next->data.i_val;
    2292          42 :                 dlist *files = l->h->next->next->data.lval;
    2293          42 :                 int on_client = l->h->next->next->next->data.i_val;
    2294             : 
    2295          42 :                 ret = bincopyto(query, qry, endian, files, on_client);
    2296          42 :                 sql->type = Q_UPDATE;
    2297             :         }
    2298          42 :                 break;
    2299      121010 :         case SQL_INSERT:
    2300             :         {
    2301      121010 :                 dlist *l = s->data.lval;
    2302             : 
    2303      121010 :                 ret = insert_into(query, l->h->data.lval, l->h->next->data.lval, l->h->next->next->data.sym, l->h->next->next->next->data.lval);
    2304      120814 :                 sql->type = Q_UPDATE;
    2305             :         }
    2306      120814 :                 break;
    2307        4065 :         case SQL_UPDATE:
    2308             :         {
    2309        4065 :                 dlist *l = s->data.lval;
    2310             : 
    2311        8130 :                 ret = update_table(query, l->h->data.lval, l->h->next->data.sval, l->h->next->next->data.lval,
    2312        4065 :                                                    l->h->next->next->next->data.sym, l->h->next->next->next->next->data.sym, l->h->next->next->next->next->next->data.lval);
    2313        4065 :                 sql->type = Q_UPDATE;
    2314             :         }
    2315        4065 :                 break;
    2316         999 :         case SQL_DELETE:
    2317             :         {
    2318         999 :                 dlist *l = s->data.lval;
    2319             : 
    2320         999 :                 ret = delete_table(query, l->h->data.lval, l->h->next->data.sval, l->h->next->next->data.sym, l->h->next->next->next->data.lval);
    2321         999 :                 sql->type = Q_UPDATE;
    2322             :         }
    2323         999 :                 break;
    2324       42149 :         case SQL_TRUNCATE:
    2325             :         {
    2326       42149 :                 dlist *l = s->data.lval;
    2327             : 
    2328       42149 :                 int restart_sequences = l->h->next->data.i_val;
    2329       42149 :                 int drop_action = l->h->next->next->data.i_val;
    2330       42149 :                 ret = truncate_table(sql, l->h->data.lval, restart_sequences, drop_action);
    2331       42194 :                 sql->type = Q_UPDATE;
    2332             :         }
    2333       42194 :                 break;
    2334          56 :         case SQL_MERGE:
    2335             :         {
    2336          56 :                 dlist *l = s->data.lval;
    2337             : 
    2338         112 :                 ret = merge_into_table(query, l->h->data.lval, l->h->next->data.sval, l->h->next->next->data.sym,
    2339          56 :                                                            l->h->next->next->next->data.sym, l->h->next->next->next->next->data.lval);
    2340          56 :                 sql->type = Q_UPDATE;
    2341          56 :         } break;
    2342           0 :         default:
    2343           0 :                 return sql_error(sql, 01, SQLSTATE(42000) "Updates statement unknown Symbol(%p)->token = %s", s, token2string(s->token));
    2344             :         }
    2345      169457 :         query_processed(query);
    2346      169457 :         return ret;
    2347             : }

Generated by: LCOV version 1.14