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