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