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

Generated by: LCOV version 1.14