LCOV - code coverage report
Current view: top level - sql/server - rel_updates.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1059 1167 90.7 %
Date: 2021-10-13 02:24:04 Functions: 41 41 100.0 %

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

Generated by: LCOV version 1.14