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