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