LCOV - code coverage report
Current view: top level - sql/server - rel_updates.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1327 1443 92.0 %
Date: 2025-03-24 23:16:36 Functions: 42 42 100.0 %

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

Generated by: LCOV version 1.14