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