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