LCOV - code coverage report
Current view: top level - sql/server - rel_updates.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1284 1400 91.7 %
Date: 2024-12-19 20:05:57 Functions: 42 42 100.0 %

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

Generated by: LCOV version 1.14