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

Generated by: LCOV version 1.14