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