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