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