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/*
10 * authors M Kersten, N Nes
11 * SQL support implementation
12 * This module contains the wrappers around the SQL
13 * multi-version-catalog and support routines copied
14 * from the Version 4 code base.
15 */
16#include "monetdb_config.h"
17#include "sql.h"
18#include "streams.h"
19#include "sql_result.h"
20#include "sql_gencode.h"
21#include "sql_storage.h"
22#include "sql_scenario.h"
23#include "store_sequence.h"
24#include "sql_optimizer.h"
25#include "sql_datetime.h"
26#include "sql_partition.h"
27#include "rel_unnest.h"
28#include "rel_optimizer.h"
29#include "rel_partition.h"
30#include "rel_distribute.h"
31#include "rel_select.h"
32#include "rel_rel.h"
33#include "rel_exp.h"
34#include "rel_dump.h"
35#include "rel_bin.h"
36#include "bbp.h"
37#include "opt_pipes.h"
38#include "orderidx.h"
39#include "clients.h"
40#include "mal_instruction.h"
41#include "mal_resource.h"
42#include "mal_authorize.h"
43#include "gdk_cand.h"
44
45static int
46rel_is_table(sql_rel *rel)
47{
48 if (!rel || is_base(rel->op))
49 return 1;
50 return 0;
51}
52
53static int
54exp_is_point_select(sql_exp *e)
55{
56 if (!e)
57 return 1;
58 if (e->type == e_cmp && !e->f && e->flag == (int) cmp_equal) {
59 sql_exp *r = e->r;
60 sql_exp *l = e->l;
61
62 if (!is_func(l->type) && r->card <= CARD_AGGR)
63 return 1;
64 }
65 return 0;
66}
67
68static int
69rel_no_mitosis(sql_rel *rel)
70{
71 int is_point = 0;
72
73 if (!rel || is_basetable(rel->op))
74 return 1;
75 if (is_topn(rel->op) || rel->op == op_project)
76 return rel_no_mitosis(rel->l);
77 if (is_modify(rel->op) && rel->card <= CARD_AGGR)
78 return rel_no_mitosis(rel->r);
79 if (is_select(rel->op) && rel_is_table(rel->l) && rel->exps) {
80 is_point = 0;
81 /* just one point expression makes this a point query */
82 if (rel->exps->h)
83 if (exp_is_point_select(rel->exps->h->data))
84 is_point = 1;
85 }
86 return is_point;
87}
88
89static int
90rel_need_distinct_query(sql_rel *rel)
91{
92 int need_distinct = 0;
93
94 while (!need_distinct && rel && is_project(rel->op) && !is_groupby(rel->op))
95 rel = rel->l;
96 if (!need_distinct && rel && is_groupby(rel->op) && rel->exps) {
97 node *n, *m;
98 for (n = rel->exps->h; n && !need_distinct; n = n->next) {
99 sql_exp *e = n->data;
100 if (e->type == e_aggr) {
101 list *l = e->l;
102
103 if (l)
104 for (m = l->h; m && !need_distinct; m = m->next) {
105 sql_exp *a = m->data;
106
107 if (need_distinct(a))
108 need_distinct = 1;
109 }
110 }
111 }
112 }
113 return need_distinct;
114}
115
116sql_rel *
117sql_symbol2relation(mvc *c, symbol *sym)
118{
119 sql_rel *r;
120 sql_query *query = query_create(c);
121
122 r = rel_semantic(query, sym);
123 if (r)
124 r = rel_unnest(c, r);
125 if (r)
126 r = rel_optimizer(c, r, 1);
127 if (r)
128 r = rel_distribute(c, r);
129 if (r)
130 r = rel_partition(c, r);
131 if (r && (rel_no_mitosis(r) || rel_need_distinct_query(r)))
132 c->no_mitosis = 1;
133 return r;
134}
135
136/*
137 * After the SQL statement has been executed, its data structures
138 * should be garbage collected. For successful actions we have to finish
139 * the transaction as well, e.g. commit or rollback.
140 */
141int
142sqlcleanup(mvc *c, int err)
143{
144 sql_destroy_params(c);
145 sql_destroy_args(c);
146
147 if ((c->emod & mod_locked) == mod_locked) {
148 /* here we should commit the transaction */
149 if (!err) {
150 sql_trans_commit(c->session->tr);
151 /* write changes to disk */
152 sql_trans_end(c->session);
153 store_apply_deltas(true);
154 sql_trans_begin(c->session);
155 }
156 store_unlock();
157 c->emod = 0;
158 }
159 /* some statements dynamically disable caching */
160 c->sym = NULL;
161 if (c->sa)
162 c->sa = sa_reset(c->sa);
163 if (err >0)
164 c->session->status = -err;
165 if (err <0)
166 c->session->status = err;
167 c->label = 0;
168 c->no_mitosis = 0;
169 scanner_query_processed(&(c->scanner));
170 return err;
171}
172
173/*
174 * The internal administration of the SQL compilation and execution state
175 * is administered by a state descriptor accessible in each phase.
176 * Failure to find the state descriptor aborts the session.
177 */
178
179str
180checkSQLContext(Client cntxt)
181{
182 backend *be;
183
184 if (cntxt == NULL)
185 throw(SQL, "mvc", SQLSTATE(42005) "No client record");
186 if (cntxt->sqlcontext == NULL)
187 throw(SQL, "mvc", SQLSTATE(42006) "SQL module not initialized");
188 be = (backend *) cntxt->sqlcontext;
189 if (be->mvc == NULL)
190 throw(SQL, "mvc", SQLSTATE(42006) "SQL module not initialized, mvc struct missing");
191 return MAL_SUCCEED;
192}
193
194str
195getSQLContext(Client cntxt, MalBlkPtr mb, mvc **c, backend **b)
196{
197 backend *be;
198 (void) mb;
199 str msg;
200
201 if ((msg = checkSQLContext(cntxt)) != MAL_SUCCEED)
202 return msg;
203 be = (backend *) cntxt->sqlcontext;
204 if (c)
205 *c = be->mvc;
206 if (b)
207 *b = be;
208 return MAL_SUCCEED;
209}
210
211str
212SQLmvc(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
213{
214 mvc *sql = NULL;
215 str msg;
216 int *res = getArgReference_int(stk, pci, 0);
217
218 if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL)
219 return msg;
220 if ((msg = checkSQLContext(cntxt)) != NULL)
221 return msg;
222 *res = 0;
223 return MAL_SUCCEED;
224}
225
226str
227SQLcommit(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
228{
229 mvc *sql = NULL;
230 str msg;
231 (void) stk;
232 (void) pci;
233
234 if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL)
235 return msg;
236 if ((msg = checkSQLContext(cntxt)) != NULL)
237 return msg;
238
239 if (sql->session->auto_commit != 0)
240 throw(SQL, "sql.trans", SQLSTATE(2DM30) "COMMIT not allowed in auto commit mode");
241 return mvc_commit(sql, 0, 0, false);
242}
243
244str
245SQLabort(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
246{
247 mvc *sql = NULL;
248 str msg;
249 (void) stk;
250 (void) pci;
251
252 if ((msg = getSQLContext(cntxt, mb, &sql, NULL)) != NULL)
253 return msg;
254 if ((msg = checkSQLContext(cntxt)) != NULL)
255 return msg;
256
257 if (sql->session->tr->active) {
258 msg = mvc_rollback(sql, 0, NULL, false);
259 }
260 return msg;
261}
262
263str
264SQLshutdown_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
265{
266 str msg;
267
268 if ((msg = CLTshutdown(cntxt, mb, stk, pci)) == MAL_SUCCEED) {
269 /* administer the shutdown in the system log*/
270 fprintf(stderr, "#Shutdown:%s\n", *getArgReference_str(stk, pci, 0));
271 }
272 return msg;
273}
274
275str
276create_table_or_view(mvc *sql, char* sname, char *tname, sql_table *t, int temp)
277{
278 sql_allocator *osa;
279 sql_schema *s = mvc_bind_schema(sql, sname);
280 sql_table *nt = NULL;
281 node *n;
282 int check = 0;
283
284 if (STORE_READONLY)
285 return sql_error(sql, 06, SQLSTATE(25006) "schema statements cannot be executed on a readonly database.");
286
287 if (!s)
288 return sql_message(SQLSTATE(3F000) "CREATE %s: schema '%s' doesn't exist", (t->query) ? "TABLE" : "VIEW", sname);
289 if (mvc_bind_table(sql, s, t->base.name)) {
290 char *cd = (temp == SQL_DECLARED_TABLE) ? "DECLARE" : "CREATE";
291 return sql_message(SQLSTATE(42S01) "%s TABLE: name '%s' already in use", cd, t->base.name);
292 } else if (temp != SQL_DECLARED_TABLE && (!mvc_schema_privs(sql, s) && !(isTempSchema(s) && temp == SQL_LOCAL_TEMP))) {
293 return sql_message(SQLSTATE(42000) "CREATE TABLE: insufficient privileges for user '%s' in schema '%s'", stack_get_string(sql, "current_user"), s->base.name);
294 } else if (temp == SQL_DECLARED_TABLE && !list_empty(t->keys.set)) {
295 return sql_message(SQLSTATE(42000) "DECLARE TABLE: '%s' cannot have constraints", t->base.name);
296 }
297
298 osa = sql->sa;
299 sql->sa = NULL;
300
301 nt = sql_trans_create_table(sql->session->tr, s, tname, t->query, t->type, t->system, temp, t->commit_action,
302 t->sz, t->properties);
303
304 /* first check default values */
305 for (n = t->columns.set->h; n; n = n->next) {
306 sql_column *c = n->data;
307
308 if (c->def) {
309 char *buf, *typestr;
310 sql_rel *r = NULL;
311 list *id_l;
312
313 sql->sa = sa_create();
314 if (!sql->sa) {
315 sql->sa = osa;
316 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
317 }
318 buf = sa_alloc(sql->sa, strlen(c->def) + 8);
319 if (!buf) {
320 sa_destroy(sql->sa);
321 sql->sa = osa;
322 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
323 }
324 typestr = subtype2string2(&c->type);
325 if (!typestr) {
326 sa_destroy(sql->sa);
327 sql->sa = osa;
328 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
329 }
330 snprintf(buf, BUFSIZ, "select cast(%s as %s);", c->def, typestr);
331 _DELETE(typestr);
332 r = rel_parse(sql, s, buf, m_deps);
333 if (!r || !is_project(r->op) || !r->exps || list_length(r->exps) != 1 ||
334 rel_check_type(sql, &c->type, r, r->exps->h->data, type_equal) == NULL) {
335 if (r)
336 rel_destroy(r);
337 sa_destroy(sql->sa);
338 sql->sa = osa;
339 if (strlen(sql->errstr) > 6 && sql->errstr[5] == '!')
340 throw(SQL, "sql.catalog", "%s", sql->errstr);
341 else
342 throw(SQL, "sql.catalog", SQLSTATE(42000) "%s", sql->errstr);
343 }
344 id_l = rel_dependencies(sql, r);
345 mvc_create_dependencies(sql, id_l, nt->base.id, FUNC_DEPENDENCY);
346 rel_destroy(r);
347 sa_destroy(sql->sa);
348 sql->sa = NULL;
349 }
350 }
351
352 for (n = t->columns.set->h; n; n = n->next) {
353 sql_column *c = n->data, *copied = mvc_copy_column(sql, nt, c);
354
355 if (copied == NULL) {
356 sql->sa = osa;
357 throw(SQL, "sql.catalog", SQLSTATE(42000) "CREATE TABLE: %s_%s_%s conflicts", s->base.name, t->base.name, c->base.name);
358 }
359 if (isPartitionedByColumnTable(t) && c->base.id == t->part.pcol->base.id)
360 nt->part.pcol = copied;
361 }
362 if (isPartitionedByExpressionTable(t)) {
363 char *err = NULL;
364
365 nt->part.pexp->exp = sa_strdup(sql->session->tr->sa, t->part.pexp->exp);
366
367 sql->sa = sa_create();
368 if (!sql->sa) {
369 sql->sa = osa;
370 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
371 }
372
373 err = bootstrap_partition_expression(sql, sql->session->tr->sa, nt, 1);
374 sa_destroy(sql->sa);
375 sql->sa = NULL;
376 if (err) {
377 sql->sa = osa;
378 return err;
379 }
380 }
381 check = sql_trans_set_partition_table(sql->session->tr, nt);
382 if (check == -1) {
383 sql->sa = osa;
384 throw(SQL, "sql.catalog", SQLSTATE(42000) "CREATE TABLE: %s_%s: the partition's expression is too long", s->base.name, t->base.name);
385 } else if (check) {
386 sql->sa = osa;
387 throw(SQL, "sql.catalog", SQLSTATE(42000) "CREATE TABLE: %s_%s: an internal error occurred", s->base.name, t->base.name);
388 }
389
390 if (t->idxs.set) {
391 for (n = t->idxs.set->h; n; n = n->next) {
392 sql_idx *i = n->data;
393 mvc_copy_idx(sql, nt, i);
394 }
395 }
396 if (t->keys.set) {
397 for (n = t->keys.set->h; n; n = n->next) {
398 sql_key *k = n->data;
399 char *err = NULL;
400
401 sql->sa = sa_create();
402 if(!sql->sa) {
403 sql->sa = osa;
404 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
405 }
406
407 err = sql_partition_validate_key(sql, nt, k, "CREATE");
408 sa_destroy(sql->sa);
409 sql->sa = NULL;
410 if (err) {
411 sql->sa = osa;
412 return err;
413 }
414 mvc_copy_key(sql, nt, k);
415 }
416 }
417 if (t->members.set) {
418 for (n = t->members.set->h; n; n = n->next) {
419 sql_part *pt = n->data;
420 mvc_copy_part(sql, nt, pt);
421 }
422 }
423 if (t->triggers.set) {
424 for (n = t->triggers.set->h; n; n = n->next) {
425 sql_trigger *tr = n->data;
426 mvc_copy_trigger(sql, nt, tr);
427 }
428 }
429 /* also create dependencies when not renaming */
430 if (nt->query && isView(nt)) {
431 sql_rel *r = NULL;
432
433 sql->sa = sa_create();
434 if (!sql->sa) {
435 sql->sa = osa;
436 throw(SQL, "sql.catalog",SQLSTATE(HY001) MAL_MALLOC_FAIL);
437 }
438 r = rel_parse(sql, s, nt->query, m_deps);
439 if (r)
440 r = rel_unnest(sql, r);
441 if (r)
442 r = rel_optimizer(sql, r, 0);
443 if (r) {
444 list *id_l = rel_dependencies(sql, r);
445
446 mvc_create_dependencies(sql, id_l, nt->base.id, VIEW_DEPENDENCY);
447 }
448 sa_destroy(sql->sa);
449 }
450 sql->sa = osa;
451 return MAL_SUCCEED;
452}
453
454str
455create_table_from_emit(Client cntxt, char *sname, char *tname, sql_emit_col *columns, size_t ncols)
456{
457 size_t i;
458 sql_table *t;
459 sql_schema *s;
460 mvc *sql = NULL;
461 str msg = MAL_SUCCEED;
462
463 if ((msg = getSQLContext(cntxt, NULL, &sql, NULL)) != NULL)
464 return msg;
465 if ((msg = checkSQLContext(cntxt)) != NULL)
466 return msg;
467
468 /* for some reason we don't have an allocator here, so make one */
469 if (!(sql->sa = sa_create())) {
470 msg = sql_error(sql, 02, SQLSTATE(HY001) "CREATE TABLE: %s", MAL_MALLOC_FAIL);
471 goto cleanup;
472 }
473
474 if (!sname)
475 sname = "sys";
476 if (!(s = mvc_bind_schema(sql, sname))) {
477 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: no such schema '%s'", sname);
478 goto cleanup;
479 }
480 if (!(t = mvc_create_table(sql, s, tname, tt_table, 0, SQL_DECLARED_TABLE, CA_COMMIT, -1, 0))) {
481 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not create table '%s'", tname);
482 goto cleanup;
483 }
484
485 for (i = 0; i < ncols; i++) {
486 BAT *b = columns[i].b;
487 str atoname = ATOMname(b->ttype);
488 sql_subtype tpe;
489 sql_column *col = NULL;
490
491 if (!strcmp(atoname, "str"))
492 sql_find_subtype(&tpe, "clob", 0, 0);
493 else {
494 sql_subtype *t = sql_bind_localtype(atoname);
495 if (!t) {
496 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not find type for column");
497 goto cleanup;
498 }
499 tpe = *t;
500 }
501
502 if (!(col = mvc_create_column(sql, t, columns[i].name, &tpe))) {
503 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not create column %s", columns[i].name);
504 goto cleanup;
505 }
506 }
507 if ((msg = create_table_or_view(sql, sname, t->base.name, t, 0)) != MAL_SUCCEED)
508 goto cleanup;
509 if (!(t = mvc_bind_table(sql, s, tname))) {
510 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind table %s", tname);
511 goto cleanup;
512 }
513 for (i = 0; i < ncols; i++) {
514 BAT *b = columns[i].b;
515 sql_column *col = NULL;
516
517 if (!(col = mvc_bind_column(sql, t, columns[i].name))) {
518 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind column %s", columns[i].name);
519 goto cleanup;
520 }
521 if ((msg = mvc_append_column(sql->session->tr, col, b)) != MAL_SUCCEED)
522 goto cleanup;
523 }
524
525cleanup:
526 if(sql->sa) {
527 sa_destroy(sql->sa);
528 sql->sa = NULL;
529 }
530 return msg;
531}
532
533str
534append_to_table_from_emit(Client cntxt, char *sname, char *tname, sql_emit_col *columns, size_t ncols)
535{
536 size_t i;
537 sql_table *t;
538 sql_schema *s;
539 mvc *sql = NULL;
540 str msg = MAL_SUCCEED;
541
542 if ((msg = getSQLContext(cntxt, NULL, &sql, NULL)) != NULL)
543 return msg;
544 if ((msg = checkSQLContext(cntxt)) != NULL)
545 return msg;
546
547 /* for some reason we don't have an allocator here, so make one */
548 if (!(sql->sa = sa_create())) {
549 msg = sql_error(sql, 02, SQLSTATE(HY001) "CREATE TABLE: %s", MAL_MALLOC_FAIL);
550 goto cleanup;
551 }
552
553 if (!sname)
554 sname = "sys";
555 if (!(s = mvc_bind_schema(sql, sname))) {
556 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: no such schema '%s'", sname);
557 goto cleanup;
558 }
559 if (!(t = mvc_bind_table(sql, s, tname))) {
560 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind table %s", tname);
561 goto cleanup;
562 }
563 for (i = 0; i < ncols; i++) {
564 BAT *b = columns[i].b;
565 sql_column *col = NULL;
566
567 if (!(col = mvc_bind_column(sql,t, columns[i].name))) {
568 msg = sql_error(sql, 02, SQLSTATE(3F000) "CREATE TABLE: could not bind column %s", columns[i].name);
569 goto cleanup;
570 }
571 if ((msg = mvc_append_column(sql->session->tr, col, b)) != MAL_SUCCEED)
572 goto cleanup;
573 }
574
575cleanup:
576 if(sql->sa) {
577 sa_destroy(sql->sa);
578 sql->sa = NULL;
579 }
580 return msg;
581}
582
583BAT *
584mvc_bind(mvc *m, const char *sname, const char *tname, const char *cname, int access)
585{
586 sql_trans *tr = m->session->tr;
587 BAT *b = NULL;
588 sql_schema *s = NULL;
589 sql_table *t = NULL;
590 sql_column *c = NULL;
591
592 s = mvc_bind_schema(m, sname);
593 if (s == NULL)
594 return NULL;
595 t = mvc_bind_table(m, s, tname);
596 if (t == NULL)
597 return NULL;
598 c = mvc_bind_column(m, t, cname);
599 if (c == NULL)
600 return NULL;
601
602 b = store_funcs.bind_col(tr, c, access);
603 return b;
604}
605
606str
607SQLcatalog(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
608{
609 (void) cntxt;
610 (void) mb;
611 (void) stk;
612 (void) pci;
613 return sql_message(SQLSTATE(25006) "Deprecated statement");
614}
615
616/* setVariable(int *ret, str *name, any value) */
617str
618setVariable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
619{
620 int *res = getArgReference_int(stk, pci, 0);
621 mvc *m = NULL;
622 str msg;
623 const char *varname = *getArgReference_str(stk, pci, 2);
624 int mtype = getArgType(mb, pci, 3);
625 ValRecord *src;
626
627 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
628 return msg;
629 if ((msg = checkSQLContext(cntxt)) != NULL)
630 return msg;
631
632 *res = 0;
633 if (mtype < 0 || mtype >= 255)
634 throw(SQL, "sql.setVariable", SQLSTATE(42100) "Variable type error");
635 if (strcmp("optimizer", varname) == 0) {
636 const char *newopt = *getArgReference_str(stk, pci, 3);
637 if (newopt) {
638 char buf[BUFSIZ];
639 if (!isOptimizerPipe(newopt) && strchr(newopt, (int) ';') == 0) {
640 throw(SQL, "sql.setVariable", SQLSTATE(42100) "optimizer '%s' unknown", newopt);
641 }
642 snprintf(buf, BUFSIZ, "user_%d", cntxt->idx);
643 if (!isOptimizerPipe(newopt) || strcmp(buf, newopt) == 0) {
644 msg = addPipeDefinition(cntxt, buf, newopt);
645 if (msg)
646 return msg;
647 if (stack_find_var(m, varname)) {
648 if(!stack_set_string(m, varname, buf))
649 throw(SQL, "sql.setVariable", SQLSTATE(HY001) MAL_MALLOC_FAIL);
650 }
651 } else if (stack_find_var(m, varname)) {
652 if(!stack_set_string(m, varname, newopt))
653 throw(SQL, "sql.setVariable", SQLSTATE(HY001) MAL_MALLOC_FAIL);
654 }
655 }
656 return MAL_SUCCEED;
657 }
658 src = &stk->stk[getArg(pci, 3)];
659 if (stack_find_var(m, varname)) {
660#ifdef HAVE_HGE
661 hge sgn = val_get_number(src);
662#else
663 lng sgn = val_get_number(src);
664#endif
665 if ((msg = sql_update_var(m, varname, src->val.sval, sgn)) != NULL)
666 return msg;
667 if(!stack_set_var(m, varname, src))
668 throw(SQL, "sql.setVariable", SQLSTATE(HY001) MAL_MALLOC_FAIL);
669 } else {
670 throw(SQL, "sql.setVariable", SQLSTATE(42100) "variable '%s' unknown", varname);
671 }
672 return MAL_SUCCEED;
673}
674
675/* getVariable(int *ret, str *name) */
676str
677getVariable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
678{
679 int mtype = getArgType(mb, pci, 0);
680 mvc *m = NULL;
681 str msg;
682 const char *varname = *getArgReference_str(stk, pci, 2);
683 atom *a;
684 ValRecord *dst, *src;
685
686 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
687 return msg;
688 if ((msg = checkSQLContext(cntxt)) != NULL)
689 return msg;
690 if (mtype < 0 || mtype >= 255)
691 throw(SQL, "sql.getVariable", SQLSTATE(42100) "Variable type error");
692 if (!(a = stack_get_var(m, varname)))
693 throw(SQL, "sql.getVariable", SQLSTATE(42100) "variable '%s' unknown", varname);
694 src = &a->data;
695 dst = &stk->stk[getArg(pci, 0)];
696 if (VALcopy(dst, src) == NULL)
697 throw(MAL, "sql.getVariable", SQLSTATE(HY001) MAL_MALLOC_FAIL);
698 return MAL_SUCCEED;
699}
700
701str
702sql_variables(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
703{
704 int i;
705 mvc *m = NULL;
706 BAT *vars;
707 str msg;
708 bat *res = getArgReference_bat(stk, pci, 0);
709
710 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
711 return msg;
712 if ((msg = checkSQLContext(cntxt)) != NULL)
713 return msg;
714
715 vars = COLnew(0, TYPE_str, m->topvars, TRANSIENT);
716 if (vars == NULL)
717 throw(SQL, "sql.variables", SQLSTATE(HY001) MAL_MALLOC_FAIL);
718 for (i = 0; i < m->topvars && !m->vars[i].frame; i++) {
719 if (BUNappend(vars, m->vars[i].name, false) != GDK_SUCCEED) {
720 BBPreclaim(vars);
721 throw(SQL, "sql.variables", SQLSTATE(HY001) MAL_MALLOC_FAIL);
722 }
723 }
724 *res = vars->batCacheid;
725 BBPkeepref(vars->batCacheid);
726 return MAL_SUCCEED;
727}
728
729/* str mvc_logfile(int *d, str *filename); */
730str
731mvc_logfile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
732{
733 mvc *m = NULL;
734 str msg;
735 const char *filename = *getArgReference_str(stk, pci, 1);
736
737 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
738 return msg;
739 if ((msg = checkSQLContext(cntxt)) != NULL)
740 return msg;
741 if (m->scanner.log) {
742 close_stream(m->scanner.log);
743 m->scanner.log = NULL;
744 }
745
746 if (strcmp(filename, str_nil)) {
747 if((m->scanner.log = open_wastream(filename)) == NULL)
748 throw(SQL, "sql.logfile", SQLSTATE(HY001) MAL_MALLOC_FAIL);
749 }
750 return MAL_SUCCEED;
751}
752
753/* str mvc_next_value(lng *res, str *sname, str *seqname); */
754str
755mvc_next_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
756{
757 mvc *m = NULL;
758 str msg;
759 sql_schema *s;
760 sql_sequence *seq;
761 lng *res = getArgReference_lng(stk, pci, 0);
762 const char *sname = *getArgReference_str(stk, pci, 1);
763 const char *seqname = *getArgReference_str(stk, pci, 2);
764
765 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
766 return msg;
767 if ((msg = checkSQLContext(cntxt)) != NULL)
768 return msg;
769 if (!(s = mvc_bind_schema(m, sname)))
770 throw(SQL, "sql.next_value", SQLSTATE(3F000) "Cannot find the schema %s", sname);
771 if (!(seq = find_sql_sequence(s, seqname)))
772 throw(SQL, "sql.next_value", SQLSTATE(HY050) "Failed to fetch sequence %s.%s", sname, seqname);
773
774 if (seq_next_value(seq, res)) {
775 m->last_id = *res;
776 stack_set_number(m, "last_id", m->last_id);
777 return MAL_SUCCEED;
778 }
779 throw(SQL, "sql.next_value", SQLSTATE(42000) "Error in fetching next value for sequence %s.%s", sname, seqname);
780}
781
782/* str mvc_get_value(lng *res, str *sname, str *seqname); */
783str
784mvc_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
785{
786 mvc *m = NULL;
787 str msg;
788 sql_schema *s;
789 sql_sequence *seq;
790 lng *res = getArgReference_lng(stk, pci, 0);
791 const char *sname = *getArgReference_str(stk, pci, 1);
792 const char *seqname = *getArgReference_str(stk, pci, 2);
793
794 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
795 return msg;
796 if ((msg = checkSQLContext(cntxt)) != NULL)
797 return msg;
798 if (!(s = mvc_bind_schema(m, sname)))
799 throw(SQL, "sql.get_value", SQLSTATE(3F000) "Cannot find the schema %s", sname);
800 if (!(seq = find_sql_sequence(s, seqname)))
801 throw(SQL, "sql.get_value", SQLSTATE(HY050) "Failed to fetch sequence %s.%s", sname, seqname);
802
803 if (seq_get_value(seq, res))
804 return MAL_SUCCEED;
805 throw(SQL, "sql.get_value", SQLSTATE(42000) "Error in fetching current value for sequence %s.%s", sname, seqname);
806}
807
808static str
809mvc_bat_next_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int (*bulk_func)(seqbulk *, lng *), const char *call, const char *action)
810{
811 mvc *m = NULL;
812 str msg = MAL_SUCCEED, sname = NULL, seqname = NULL;
813 BAT *b = NULL, *c = NULL, *r = NULL, *it;
814 BUN p, q;
815 sql_schema *s = NULL;
816 sql_sequence *seq = NULL;
817 seqbulk *sb = NULL;
818 BATiter bi, ci;
819 bat *res = getArgReference_bat(stk, pci, 0);
820 bat schid = 0, seqid = 0;
821
822 if (isaBatType(getArgType(mb, pci, 1)))
823 schid = *getArgReference_bat(stk, pci, 1);
824 else
825 sname = *getArgReference_str(stk, pci, 1);
826 if (isaBatType(getArgType(mb, pci, 2)))
827 seqid = *getArgReference_bat(stk, pci, 2);
828 else
829 seqname = *getArgReference_str(stk, pci, 2);
830
831 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
832 return msg;
833 if ((msg = checkSQLContext(cntxt)) != NULL)
834 return msg;
835
836 if (schid && !(b = BATdescriptor(schid))) {
837 msg = createException(SQL, call, SQLSTATE(HY005) "Cannot access column descriptor");
838 goto bailout;
839 }
840 if (seqid && !(c = BATdescriptor(seqid))) {
841 msg = createException(SQL, call, SQLSTATE(HY005) "Cannot access column descriptor");
842 goto bailout;
843 }
844 assert(b || c);
845 it = b ? b : c; /* Either b or c must be set */
846
847 if (!(r = COLnew(it->hseqbase, TYPE_lng, BATcount(it), TRANSIENT))) {
848 msg = createException(SQL, call, SQLSTATE(HY001) MAL_MALLOC_FAIL);
849 goto bailout;
850 }
851
852 if (!BATcount(it))
853 goto bailout; /* Success case */
854
855 if (b)
856 bi = bat_iterator(b);
857 if (c)
858 ci = bat_iterator(c);
859
860 BATloop(it, p, q) {
861 str nsname, nseqname;
862 lng l;
863
864 if (b)
865 nsname = BUNtvar(bi, p);
866 else
867 nsname = sname;
868 if (c)
869 nseqname = BUNtvar(ci, p);
870 else
871 nseqname = seqname;
872
873 if (!s || strcmp(s->base.name, nsname) != 0 || !seq || strcmp(seq->base.name, nseqname) != 0) {
874 if (sb) {
875 seqbulk_destroy(sb);
876 sb = NULL;
877 }
878 seq = NULL;
879 if ((!s || strcmp(s->base.name, nsname) != 0) && !(s = mvc_bind_schema(m, nsname))) {
880 msg = createException(SQL, call, SQLSTATE(3F000) "Cannot find the schema %s", nsname);
881 goto bailout;
882 }
883 if (!(seq = find_sql_sequence(s, nseqname)) || !(sb = seqbulk_create(seq, BATcount(it)))) {
884 msg = createException(SQL, call, SQLSTATE(HY050) "Cannot find the sequence %s.%s", nsname, nseqname);
885 goto bailout;
886 }
887 }
888 if (!bulk_func(sb, &l)) {
889 msg = createException(SQL, call, SQLSTATE(HY050) "Cannot %s sequence value %s.%s", action, nsname, nseqname);
890 goto bailout;
891 }
892 if (BUNappend(r, &l, false) != GDK_SUCCEED) {
893 msg = createException(SQL, call, SQLSTATE(HY001) MAL_MALLOC_FAIL);
894 goto bailout;
895 }
896 }
897
898bailout:
899 if (sb)
900 seqbulk_destroy(sb);
901 if (b)
902 BBPunfix(b->batCacheid);
903 if (c)
904 BBPunfix(c->batCacheid);
905 if (msg)
906 BBPreclaim(r);
907 else
908 BBPkeepref(*res = r->batCacheid);
909 return msg;
910}
911
912str
913mvc_bat_next_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
914{
915 return mvc_bat_next_get_value(cntxt, mb, stk, pci, seqbulk_next_value, "sql.next_value", "generate next");
916}
917
918str
919mvc_bat_get_value(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
920{
921 return mvc_bat_next_get_value(cntxt, mb, stk, pci, seqbulk_get_value, "sql.get_value", "get");
922}
923
924str
925mvc_getVersion(lng *version, const int *clientid)
926{
927 mvc *m = NULL;
928 Client cntxt = MCgetClient(*clientid);
929 str msg;
930
931 if ((msg = getSQLContext(cntxt, NULL, &m, NULL)) != NULL)
932 return msg;
933 if ((msg = checkSQLContext(cntxt)) != NULL)
934 return msg;
935 *version = -1;
936 if (m->session->tr)
937 *version = m->session->tr->stime;
938 return MAL_SUCCEED;
939}
940
941/* str mvc_restart_seq(lng *res, str *sname, str *seqname, lng *start); */
942str
943mvc_restart_seq(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
944{
945 mvc *m = NULL;
946 str msg;
947 sql_schema *s;
948 sql_sequence *seq;
949 lng *res = getArgReference_lng(stk, pci, 0);
950 const char *sname = *getArgReference_str(stk, pci, 1);
951 const char *seqname = *getArgReference_str(stk, pci, 2);
952 lng start = *getArgReference_lng(stk, pci, 3);
953
954 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
955 return msg;
956 if ((msg = checkSQLContext(cntxt)) != NULL)
957 return msg;
958 if (!(s = mvc_bind_schema(m, sname)))
959 throw(SQL, "sql.restart", SQLSTATE(3F000) "Cannot find the schema %s", sname);
960 if (!(seq = find_sql_sequence(s, seqname)))
961 throw(SQL, "sql.restart", SQLSTATE(HY050) "Failed to fetch sequence %s.%s", sname, seqname);
962 if (is_lng_nil(start))
963 throw(SQL, "sql.restart", SQLSTATE(HY050) "Cannot (re)start sequence %s.%s with NULL", sname, seqname);
964 if (seq->minvalue && start < seq->minvalue)
965 throw(SQL, "sql.restart", SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value lesser than the minimum ("LLFMT" < "LLFMT")", sname, seqname, start, seq->minvalue);
966 if (seq->maxvalue && start > seq->maxvalue)
967 throw(SQL, "sql.restart", SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value higher than the maximum ("LLFMT" > "LLFMT")", sname, seqname, start, seq->maxvalue);
968 if (sql_trans_sequence_restart(m->session->tr, seq, start)) {
969 *res = start;
970 return MAL_SUCCEED;
971 }
972 throw(SQL, "sql.restart", SQLSTATE(HY050) "Cannot (re)start sequence %s.%s", sname, seqname);
973}
974
975str
976mvc_bat_restart_seq(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
977{
978 mvc *m = NULL;
979 str msg = MAL_SUCCEED, sname = NULL, seqname = NULL;
980 BAT *b = NULL, *c = NULL, *d = NULL, *r = NULL, *it;
981 BUN p, q;
982 sql_schema *s = NULL;
983 sql_sequence *seq = NULL;
984 seqbulk *sb = NULL;
985 BATiter bi, ci;
986 bat *res = getArgReference_bat(stk, pci, 0);
987 bat schid = 0, seqid = 0, startid = 0;
988 lng start = 0, *di = NULL;
989
990 if (isaBatType(getArgType(mb, pci, 1)))
991 schid = *getArgReference_bat(stk, pci, 1);
992 else
993 sname = *getArgReference_str(stk, pci, 1);
994 if (isaBatType(getArgType(mb, pci, 2)))
995 seqid = *getArgReference_bat(stk, pci, 2);
996 else
997 seqname = *getArgReference_str(stk, pci, 2);
998 if (isaBatType(getArgType(mb, pci, 3)))
999 startid = *getArgReference_bat(stk, pci, 3);
1000 else
1001 start = *getArgReference_lng(stk, pci, 3);
1002
1003 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1004 return msg;
1005 if ((msg = checkSQLContext(cntxt)) != NULL)
1006 return msg;
1007
1008 if (schid && !(b = BATdescriptor(schid))) {
1009 msg = createException(SQL, "sql.restart", SQLSTATE(HY005) "Cannot access column descriptor");
1010 goto bailout;
1011 }
1012 if (seqid && !(c = BATdescriptor(seqid))) {
1013 msg = createException(SQL, "sql.restart", SQLSTATE(HY005) "Cannot access column descriptor");
1014 goto bailout;
1015 }
1016 if (startid && !(d = BATdescriptor(startid))) {
1017 msg = createException(SQL, "sql.restart", SQLSTATE(HY005) "Cannot access column descriptor");
1018 goto bailout;
1019 }
1020 assert(b || c || d);
1021 it = b ? b : c ? c : d; /* Either b, c or d must be set */
1022
1023 if (!(r = COLnew(it->hseqbase, TYPE_lng, BATcount(it), TRANSIENT))) {
1024 msg = createException(SQL, "sql.restart", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1025 goto bailout;
1026 }
1027
1028 if (!BATcount(it))
1029 goto bailout; /* Success case */
1030
1031 if (b)
1032 bi = bat_iterator(b);
1033 if (c)
1034 ci = bat_iterator(c);
1035 if (d)
1036 di = (lng *) Tloc(d, 0);
1037
1038 BATloop(it, p, q) {
1039 str nsname, nseqname;
1040 lng nstart;
1041
1042 if (b)
1043 nsname = BUNtvar(bi, p);
1044 else
1045 nsname = sname;
1046 if (c)
1047 nseqname = BUNtvar(ci, p);
1048 else
1049 nseqname = seqname;
1050 if (di)
1051 nstart = di[p];
1052 else
1053 nstart = start;
1054
1055 if (!s || strcmp(s->base.name, nsname) != 0 || !seq || strcmp(seq->base.name, nseqname) != 0) {
1056 if (sb) {
1057 seqbulk_destroy(sb);
1058 sb = NULL;
1059 }
1060 seq = NULL;
1061 if ((!s || strcmp(s->base.name, nsname) != 0) && !(s = mvc_bind_schema(m, nsname))) {
1062 msg = createException(SQL, "sql.restart", SQLSTATE(3F000) "Cannot find the schema %s", nsname);
1063 goto bailout;
1064 }
1065 if (!(seq = find_sql_sequence(s, nseqname)) || !(sb = seqbulk_create(seq, BATcount(it)))) {
1066 msg = createException(SQL, "sql.restart", SQLSTATE(HY050) "Cannot find the sequence %s.%s", nsname, nseqname);
1067 goto bailout;
1068 }
1069 }
1070 if (is_lng_nil(nstart)) {
1071 msg = createException(SQL, "sql.restart", SQLSTATE(HY050) "Cannot (re)start sequence %s.%s with NULL", sname, seqname);
1072 goto bailout;
1073 }
1074 if (seq->minvalue && nstart < seq->minvalue) {
1075 msg = createException(SQL, "sql.restart", SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value lesser than the minimum ("LLFMT" < "LLFMT")", sname, seqname, start, seq->minvalue);
1076 goto bailout;
1077 }
1078 if (seq->maxvalue && nstart > seq->maxvalue) {
1079 msg = createException(SQL, "sql.restart", SQLSTATE(HY050) "Cannot set sequence %s.%s start to a value higher than the maximum ("LLFMT" > "LLFMT")", sname, seqname, start, seq->maxvalue);
1080 goto bailout;
1081 }
1082 if (!sql_trans_seqbulk_restart(m->session->tr, sb, nstart)) {
1083 msg = createException(SQL, "sql.restart", SQLSTATE(HY050) "Cannot restart sequence %s.%s", nsname, nseqname);
1084 goto bailout;
1085 }
1086 if (BUNappend(r, &nstart, false) != GDK_SUCCEED) {
1087 msg = createException(SQL, "sql.restart", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1088 goto bailout;
1089 }
1090 }
1091
1092bailout:
1093 if (sb)
1094 seqbulk_destroy(sb);
1095 if (b)
1096 BBPunfix(b->batCacheid);
1097 if (c)
1098 BBPunfix(c->batCacheid);
1099 if (d)
1100 BBPunfix(d->batCacheid);
1101 if (msg)
1102 BBPreclaim(r);
1103 else
1104 BBPkeepref(*res = r->batCacheid);
1105 return msg;
1106}
1107
1108static BAT *
1109mvc_bind_dbat(mvc *m, const char *sname, const char *tname, int access)
1110{
1111 sql_trans *tr = m->session->tr;
1112 BAT *b = NULL;
1113 sql_schema *s = NULL;
1114 sql_table *t = NULL;
1115
1116 s = mvc_bind_schema(m, sname);
1117 if (s == NULL)
1118 return NULL;
1119 t = mvc_bind_table(m, s, tname);
1120 if (t == NULL)
1121 return NULL;
1122
1123 b = store_funcs.bind_del(tr, t, access);
1124 return b;
1125}
1126
1127BAT *
1128mvc_bind_idxbat(mvc *m, const char *sname, const char *tname, const char *iname, int access)
1129{
1130 sql_trans *tr = m->session->tr;
1131 BAT *b = NULL;
1132 sql_schema *s = NULL;
1133 sql_idx *i = NULL;
1134
1135 s = mvc_bind_schema(m, sname);
1136 if (s == NULL)
1137 return NULL;
1138 i = mvc_bind_idx(m, s, iname);
1139 if (i == NULL)
1140 return NULL;
1141
1142 (void) tname;
1143 b = store_funcs.bind_idx(tr, i, access);
1144 return b;
1145}
1146
1147/* str mvc_bind_wrap(int *bid, str *sname, str *tname, str *cname, int *access); */
1148str
1149mvc_bind_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1150{
1151 int upd = (pci->argc == 7 || pci->argc == 9);
1152 BAT *b = NULL, *bn;
1153 bat *bid = getArgReference_bat(stk, pci, 0);
1154 int coltype = getBatType(getArgType(mb, pci, 0));
1155 mvc *m = NULL;
1156 str msg;
1157 const char *sname = *getArgReference_str(stk, pci, 2 + upd);
1158 const char *tname = *getArgReference_str(stk, pci, 3 + upd);
1159 const char *cname = *getArgReference_str(stk, pci, 4 + upd);
1160 int access = *getArgReference_int(stk, pci, 5 + upd);
1161
1162 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1163 return msg;
1164 if ((msg = checkSQLContext(cntxt)) != NULL)
1165 return msg;
1166 b = mvc_bind(m, sname, tname, cname, access);
1167 if (b && b->ttype != coltype) {
1168 BBPunfix(b->batCacheid);
1169 throw(SQL,"sql.bind",SQLSTATE(42000) "Column type mismatch");
1170 }
1171 if (b) {
1172 if (pci->argc == (8 + upd) && getArgType(mb, pci, 6 + upd) == TYPE_int) {
1173 BUN cnt = BATcount(b), psz;
1174 /* partitioned access */
1175 int part_nr = *getArgReference_int(stk, pci, 6 + upd);
1176 int nr_parts = *getArgReference_int(stk, pci, 7 + upd);
1177
1178 if (access == 0) {
1179 psz = cnt ? (cnt / nr_parts) : 0;
1180 bn = BATslice(b, part_nr * psz, (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz));
1181 if(bn == NULL) {
1182 BBPunfix(b->batCacheid);
1183 throw(SQL, "sql.bind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1184 }
1185 BAThseqbase(bn, part_nr * psz);
1186 } else {
1187 /* BAT b holds the UPD_ID bat */
1188 oid l, h;
1189 BAT *c = mvc_bind(m, sname, tname, cname, 0);
1190 if (c == NULL) {
1191 BBPunfix(b->batCacheid);
1192 throw(SQL,"sql.bind",SQLSTATE(HY005) "Cannot access the update column %s.%s.%s",
1193 sname,tname,cname);
1194 }
1195 cnt = BATcount(c);
1196 psz = cnt ? (cnt / nr_parts) : 0;
1197 l = part_nr * psz;
1198 h = (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz);
1199 h--;
1200 bn = BATselect(b, NULL, &l, &h, true, true, false);
1201 BBPunfix(c->batCacheid);
1202 if(bn == NULL) {
1203 BBPunfix(b->batCacheid);
1204 throw(SQL, "sql.bind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1205 }
1206 }
1207 BBPunfix(b->batCacheid);
1208 b = bn;
1209 } else if (upd) {
1210 BAT *uv = mvc_bind(m, sname, tname, cname, RD_UPD_VAL);
1211 bat *uvl = getArgReference_bat(stk, pci, 1);
1212
1213 if (uv == NULL) {
1214 BBPunfix(b->batCacheid);
1215 throw(SQL,"sql.bind",SQLSTATE(HY005) "Cannot access the update column %s.%s.%s",
1216 sname,tname,cname);
1217 }
1218 BBPkeepref(*bid = b->batCacheid);
1219 BBPkeepref(*uvl = uv->batCacheid);
1220 return MAL_SUCCEED;
1221 }
1222 if (upd) {
1223 bat *uvl = getArgReference_bat(stk, pci, 1);
1224
1225 if (BATcount(b)) {
1226 BAT *uv = mvc_bind(m, sname, tname, cname, RD_UPD_VAL);
1227 BAT *ui = mvc_bind(m, sname, tname, cname, RD_UPD_ID);
1228 BAT *id;
1229 BAT *vl;
1230 if (ui == NULL || uv == NULL) {
1231 bat_destroy(uv);
1232 bat_destroy(ui);
1233 BBPunfix(b->batCacheid);
1234 throw(SQL,"sql.bind",SQLSTATE(HY005) "Cannot access the insert column %s.%s.%s",
1235 sname, tname, cname);
1236 }
1237 id = BATproject(b, ui);
1238 vl = BATproject(b, uv);
1239 bat_destroy(ui);
1240 bat_destroy(uv);
1241 if (id == NULL || vl == NULL) {
1242 BBPunfix(b->batCacheid);
1243 bat_destroy(id);
1244 bat_destroy(vl);
1245 throw(SQL, "sql.bind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1246 }
1247 if ( BATcount(id) != BATcount(vl)){
1248 BBPunfix(b->batCacheid);
1249 throw(SQL, "sql.bind", SQLSTATE(0000) "Inconsistent BAT count");
1250 }
1251 BBPkeepref(*bid = id->batCacheid);
1252 BBPkeepref(*uvl = vl->batCacheid);
1253 } else {
1254 sql_schema *s = mvc_bind_schema(m, sname);
1255 sql_table *t = mvc_bind_table(m, s, tname);
1256 sql_column *c = mvc_bind_column(m, t, cname);
1257
1258 *bid = e_bat(TYPE_oid);
1259 *uvl = e_bat(c->type.type->localtype);
1260 if(*bid == BID_NIL || *uvl == BID_NIL) {
1261 BBPunfix(b->batCacheid);
1262 throw(SQL, "sql.bind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1263 }
1264 }
1265 BBPunfix(b->batCacheid);
1266 } else {
1267 BBPkeepref(*bid = b->batCacheid);
1268 }
1269 return MAL_SUCCEED;
1270 }
1271 if (sname && strcmp(sname, str_nil) != 0)
1272 throw(SQL, "sql.bind", SQLSTATE(42000) "unable to find %s.%s(%s)", sname, tname, cname);
1273 throw(SQL, "sql.bind", SQLSTATE(42000) "unable to find %s(%s)", tname, cname);
1274}
1275
1276/* The output of this function are 7 columns:
1277 * - The sqlid of the column
1278 * - A flag indicating if the column's upper table is cleared or not.
1279 * - Number of read-only values of the column (inherited from the previous transaction).
1280 * - Number of inserted rows during the current transaction.
1281 * - Number of updated rows during the current transaction.
1282 * - Number of deletes of the column's table.
1283 * - the number in the transaction chain (.i.e for each savepoint a new transaction is added in the chain)
1284 * If the table is cleared, the values RDONLY, RD_INS and RD_UPD_ID and the number of deletes will be 0.
1285 */
1286
1287static str
1288mvc_insert_delta_values(mvc *m, BAT *col1, BAT *col2, BAT *col3, BAT *col4, BAT *col5, BAT *col6, BAT *col7, sql_column *c, bit cleared, lng deletes)
1289{
1290 int level = 0;
1291
1292 lng inserted = (lng) store_funcs.count_col(m->session->tr, c, 0);
1293 lng all = (lng) store_funcs.count_col(m->session->tr, c, 1);
1294 lng updates = (lng) store_funcs.count_col_upd(m->session->tr, c);
1295 lng readonly = all - inserted;
1296
1297 assert(all >= inserted);
1298
1299 if (BUNappend(col1, &c->base.id, false) != GDK_SUCCEED) {
1300 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1301 }
1302 if (BUNappend(col2, &cleared, false) != GDK_SUCCEED) {
1303 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1304 }
1305 if (BUNappend(col3, &readonly, false) != GDK_SUCCEED) {
1306 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1307 }
1308 if (BUNappend(col4, &inserted, false) != GDK_SUCCEED) {
1309 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1310 }
1311 if (BUNappend(col5, &updates, false) != GDK_SUCCEED) {
1312 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1313 }
1314 if (BUNappend(col6, &deletes, false) != GDK_SUCCEED) {
1315 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1316 }
1317 /* compute level using global transaction */
1318 if (gtrans) {
1319 sql_column *oc = tr_find_column(gtrans, c);
1320
1321 if (oc) {
1322 for(sql_delta *d = oc->data; d; d = d->next)
1323 level++;
1324 }
1325 }
1326 if (BUNappend(col7, &level, false) != GDK_SUCCEED) {
1327 return createException(SQL,"sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1328 }
1329 return MAL_SUCCEED;
1330}
1331
1332str
1333mvc_delta_values(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1334{
1335 const char *sname = *getArgReference_str(stk, pci, 7),
1336 *tname = (pci->argc > 8) ? *getArgReference_str(stk, pci, 8) : NULL,
1337 *cname = (pci->argc > 9) ? *getArgReference_str(stk, pci, 9) : NULL;
1338 mvc *m;
1339 str msg = MAL_SUCCEED;
1340 BAT *col1 = NULL, *col2 = NULL, *col3 = NULL, *col4 = NULL, *col5 = NULL, *col6 = NULL, *col7 = NULL;
1341 bat *b1 = getArgReference_bat(stk, pci, 0),
1342 *b2 = getArgReference_bat(stk, pci, 1),
1343 *b3 = getArgReference_bat(stk, pci, 2),
1344 *b4 = getArgReference_bat(stk, pci, 3),
1345 *b5 = getArgReference_bat(stk, pci, 4),
1346 *b6 = getArgReference_bat(stk, pci, 5),
1347 *b7 = getArgReference_bat(stk, pci, 6);
1348 sql_schema *s = NULL;
1349 sql_table *t = NULL;
1350 sql_column *c = NULL;
1351 node *n;
1352 bit cleared;
1353 BUN nrows = 0;
1354 lng deletes;
1355
1356 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1357 goto cleanup;
1358 if ((msg = checkSQLContext(cntxt)) != NULL)
1359 goto cleanup;
1360
1361 if (!(s = mvc_bind_schema(m, sname)))
1362 throw(SQL, "sql.delta", SQLSTATE(3F000) "No such schema '%s'", sname);
1363
1364 if (tname) {
1365 if (!(t = mvc_bind_table(m, s, tname)))
1366 throw(SQL, "sql.delta", SQLSTATE(3F000) "No such table '%s' in schema '%s'", tname, s->base.name);
1367 if (isView(t))
1368 throw(SQL, "sql.delta", SQLSTATE(42000) "Views don't have delta values");
1369 if (isMergeTable(t))
1370 throw(SQL, "sql.delta", SQLSTATE(42000) "Merge tables don't have delta values");
1371 if (isStream(t))
1372 throw(SQL, "sql.delta", SQLSTATE(42000) "Stream tables don't have delta values");
1373 if (isRemote(t))
1374 throw(SQL, "sql.delta", SQLSTATE(42000) "Remote tables don't have delta values");
1375 if (isReplicaTable(t))
1376 throw(SQL, "sql.delta", SQLSTATE(42000) "Replica tables don't have delta values");
1377 if (cname) {
1378 if (!(c = mvc_bind_column(m, t, cname)))
1379 throw(SQL, "sql.delta", SQLSTATE(3F000) "No such column '%s' in table '%s'", cname, t->base.name);
1380 nrows = 1;
1381 } else {
1382 nrows = (BUN) t->columns.set->cnt;
1383 }
1384 } else if (s->tables.set) {
1385 for (n = s->tables.set->h; n ; n = n->next) {
1386 t = (sql_table *) n->data;
1387 if (!(isView(t) || isMergeTable(t) || isStream(t) || isRemote(t) || isReplicaTable(t)))
1388 nrows += t->columns.set->cnt;
1389 }
1390 }
1391
1392 if ((col1 = COLnew(0, TYPE_int, nrows, TRANSIENT)) == NULL) {
1393 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1394 goto cleanup;
1395 }
1396 if ((col2 = COLnew(0, TYPE_bit, nrows, TRANSIENT)) == NULL) {
1397 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1398 goto cleanup;
1399 }
1400 if ((col3 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) {
1401 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1402 goto cleanup;
1403 }
1404 if ((col4 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) {
1405 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1406 goto cleanup;
1407 }
1408 if ((col5 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) {
1409 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1410 goto cleanup;
1411 }
1412 if ((col6 = COLnew(0, TYPE_lng, nrows, TRANSIENT)) == NULL) {
1413 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1414 goto cleanup;
1415 }
1416 if ((col7 = COLnew(0, TYPE_int, nrows, TRANSIENT)) == NULL) {
1417 msg = createException(SQL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1418 goto cleanup;
1419 }
1420
1421 if (nrows) {
1422 if (tname) {
1423 cleared = (t->cleared != 0);
1424 deletes = (lng) store_funcs.count_del(m->session->tr, t);
1425 if (cname) {
1426 if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7, c, cleared, deletes)) != NULL)
1427 goto cleanup;
1428 } else {
1429 for (n = t->columns.set->h; n ; n = n->next) {
1430 c = (sql_column*) n->data;
1431 if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7, c, cleared, deletes)) != NULL)
1432 goto cleanup;
1433 }
1434 }
1435 } else if (s->tables.set) {
1436 for (n = s->tables.set->h; n ; n = n->next) {
1437 t = (sql_table *) n->data;
1438 if (!(isView(t) || isMergeTable(t) || isStream(t) || isRemote(t) || isReplicaTable(t))) {
1439 cleared = (t->cleared != 0);
1440 deletes = (lng) store_funcs.count_del(m->session->tr, t);
1441
1442 for (node *nn = t->columns.set->h; nn ; nn = nn->next) {
1443 c = (sql_column*) nn->data;
1444
1445 if ((msg=mvc_insert_delta_values(m, col1, col2, col3, col4, col5, col6, col7,
1446 c, cleared, deletes)) != NULL)
1447 goto cleanup;
1448 }
1449 }
1450 }
1451 }
1452 }
1453
1454cleanup:
1455 if (msg) {
1456 if (col1)
1457 BBPreclaim(col1);
1458 if (col2)
1459 BBPreclaim(col2);
1460 if (col3)
1461 BBPreclaim(col3);
1462 if (col4)
1463 BBPreclaim(col4);
1464 if (col5)
1465 BBPreclaim(col5);
1466 if (col6)
1467 BBPreclaim(col6);
1468 if (col7)
1469 BBPreclaim(col7);
1470 } else {
1471 BBPkeepref(*b1 = col1->batCacheid);
1472 BBPkeepref(*b2 = col2->batCacheid);
1473 BBPkeepref(*b3 = col3->batCacheid);
1474 BBPkeepref(*b4 = col4->batCacheid);
1475 BBPkeepref(*b5 = col5->batCacheid);
1476 BBPkeepref(*b6 = col6->batCacheid);
1477 BBPkeepref(*b7 = col7->batCacheid);
1478 }
1479 return msg;
1480}
1481
1482/* str mvc_bind_idxbat_wrap(int *bid, str *sname, str *tname, str *iname, int *access); */
1483str
1484mvc_bind_idxbat_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1485{
1486 int upd = (pci->argc == 7 || pci->argc == 9);
1487 BAT *b = NULL, *bn;
1488 bat *bid = getArgReference_bat(stk, pci, 0);
1489 int coltype = getBatType(getArgType(mb, pci, 0));
1490 mvc *m = NULL;
1491 str msg;
1492 const char *sname = *getArgReference_str(stk, pci, 2 + upd);
1493 const char *tname = *getArgReference_str(stk, pci, 3 + upd);
1494 const char *iname = *getArgReference_str(stk, pci, 4 + upd);
1495 int access = *getArgReference_int(stk, pci, 5 + upd);
1496
1497 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1498 return msg;
1499 if ((msg = checkSQLContext(cntxt)) != NULL)
1500 return msg;
1501 b = mvc_bind_idxbat(m, sname, tname, iname, access);
1502 if (b && b->ttype != coltype)
1503 throw(SQL,"sql.bind",SQLSTATE(42000) "Column type mismatch %s.%s.%s",sname,tname,iname);
1504 if (b) {
1505 if (pci->argc == (8 + upd) && getArgType(mb, pci, 6 + upd) == TYPE_int) {
1506 BUN cnt = BATcount(b), psz;
1507 /* partitioned access */
1508 int part_nr = *getArgReference_int(stk, pci, 6 + upd);
1509 int nr_parts = *getArgReference_int(stk, pci, 7 + upd);
1510
1511 if (access == 0) {
1512 psz = cnt ? (cnt / nr_parts) : 0;
1513 bn = BATslice(b, part_nr * psz, (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz));
1514 if(bn == NULL)
1515 throw(SQL, "sql.bindidx", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1516 BAThseqbase(bn, part_nr * psz);
1517 } else {
1518 /* BAT b holds the UPD_ID bat */
1519 oid l, h;
1520 BAT *c = mvc_bind_idxbat(m, sname, tname, iname, 0);
1521 if ( c == NULL) {
1522 BBPunfix(b->batCacheid);
1523 throw(SQL,"sql.bindidx",SQLSTATE(42000) "Cannot access index column %s.%s.%s",sname,tname,iname);
1524 }
1525 cnt = BATcount(c);
1526 psz = cnt ? (cnt / nr_parts) : 0;
1527 l = part_nr * psz;
1528 h = (part_nr + 1 == nr_parts) ? cnt : ((part_nr + 1) * psz);
1529 h--;
1530 bn = BATselect(b, NULL, &l, &h, true, true, false);
1531 BBPunfix(c->batCacheid);
1532 if(bn == NULL) {
1533 BBPunfix(b->batCacheid);
1534 throw(SQL, "sql.bindidx", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1535 }
1536 }
1537 BBPunfix(b->batCacheid);
1538 b = bn;
1539 } else if (upd) {
1540 BAT *uv = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_VAL);
1541 bat *uvl = getArgReference_bat(stk, pci, 1);
1542 if ( uv == NULL)
1543 throw(SQL,"sql.bindidx",SQLSTATE(42000) "Cannot access index column %s.%s.%s",sname,tname,iname);
1544 BBPkeepref(*bid = b->batCacheid);
1545 BBPkeepref(*uvl = uv->batCacheid);
1546 return MAL_SUCCEED;
1547 }
1548 if (upd) {
1549 bat *uvl = getArgReference_bat(stk, pci, 1);
1550
1551 if (BATcount(b)) {
1552 BAT *uv = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_VAL);
1553 BAT *ui = mvc_bind_idxbat(m, sname, tname, iname, RD_UPD_ID);
1554 BAT *id, *vl;
1555 if ( ui == NULL || uv == NULL) {
1556 bat_destroy(uv);
1557 bat_destroy(ui);
1558 throw(SQL,"sql.bindidx",SQLSTATE(42000) "Cannot access index column %s.%s.%s",sname,tname,iname);
1559 }
1560 id = BATproject(b, ui);
1561 vl = BATproject(b, uv);
1562 bat_destroy(ui);
1563 bat_destroy(uv);
1564 if (id == NULL || vl == NULL) {
1565 bat_destroy(id);
1566 bat_destroy(vl);
1567 throw(SQL, "sql.idxbind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1568 }
1569 assert(BATcount(id) == BATcount(vl));
1570 BBPkeepref(*bid = id->batCacheid);
1571 BBPkeepref(*uvl = vl->batCacheid);
1572 } else {
1573 sql_schema *s = mvc_bind_schema(m, sname);
1574 sql_idx *i = mvc_bind_idx(m, s, iname);
1575
1576 *bid = e_bat(TYPE_oid);
1577 *uvl = e_bat((i->type==join_idx)?TYPE_oid:TYPE_lng);
1578 if(*bid == BID_NIL || *uvl == BID_NIL)
1579 throw(SQL, "sql.idxbind", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1580 }
1581 BBPunfix(b->batCacheid);
1582 } else {
1583 BBPkeepref(*bid = b->batCacheid);
1584 }
1585 return MAL_SUCCEED;
1586 }
1587 if (sname)
1588 throw(SQL, "sql.idxbind", SQLSTATE(HY005) "Cannot access column descriptor %s for %s.%s", iname, sname, tname);
1589 throw(SQL, "sql.idxbind", SQLSTATE(HY005) "Cannot access column descriptor %s for %s", iname, tname);
1590}
1591
1592str
1593mvc_append_column(sql_trans *t, sql_column *c, BAT *ins)
1594{
1595 int res = store_funcs.append_col(t, c, ins, TYPE_bat);
1596 if (res != 0)
1597 throw(SQL, "sql.append", SQLSTATE(42000) "Cannot append values");
1598 return MAL_SUCCEED;
1599}
1600
1601/*mvc_grow_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */
1602str
1603mvc_grow_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1604{
1605 int *res = getArgReference_int(stk, pci, 0);
1606 bat Tid = *getArgReference_bat(stk, pci, 1);
1607 ptr Ins = getArgReference(stk, pci, 2);
1608 int tpe = getArgType(mb, pci, 2);
1609 BAT *tid = 0, *ins = 0;
1610 size_t cnt = 1;
1611 oid v = 0;
1612
1613 (void)cntxt;
1614 *res = 0;
1615 if ((tid = BATdescriptor(Tid)) == NULL)
1616 throw(SQL, "sql.grow", SQLSTATE(HY005) "Cannot access descriptor");
1617 if (tpe > GDKatomcnt)
1618 tpe = TYPE_bat;
1619 if (tpe == TYPE_bat && (ins = BATdescriptor(*(bat *) Ins)) == NULL) {
1620 BBPunfix(Tid);
1621 throw(SQL, "sql.grow", SQLSTATE(HY005) "Cannot access descriptor");
1622 }
1623 if (ins) {
1624 cnt = BATcount(ins);
1625 BBPunfix(ins->batCacheid);
1626 }
1627 if (BATcount(tid)) {
1628 (void)BATmax(tid, &v);
1629 v++;
1630 }
1631 for(;cnt>0; cnt--, v++) {
1632 if (BUNappend(tid, &v, false) != GDK_SUCCEED) {
1633 BBPunfix(Tid);
1634 throw(SQL, "sql", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1635 }
1636 }
1637 BBPunfix(Tid);
1638 return MAL_SUCCEED;
1639}
1640
1641/*mvc_append_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */
1642str
1643mvc_append_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1644{
1645 int *res = getArgReference_int(stk, pci, 0);
1646 mvc *m = NULL;
1647 str msg;
1648 const char *sname = *getArgReference_str(stk, pci, 2);
1649 const char *tname = *getArgReference_str(stk, pci, 3);
1650 const char *cname = *getArgReference_str(stk, pci, 4);
1651 ptr ins = getArgReference(stk, pci, 5);
1652 int tpe = getArgType(mb, pci, 5);
1653 sql_schema *s;
1654 sql_table *t;
1655 sql_column *c;
1656 BAT *b = 0;
1657
1658 *res = 0;
1659 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1660 return msg;
1661 if ((msg = checkSQLContext(cntxt)) != NULL)
1662 return msg;
1663 if (tpe > GDKatomcnt)
1664 tpe = TYPE_bat;
1665 if (tpe == TYPE_bat && (ins = BATdescriptor(*(bat *) ins)) == NULL)
1666 throw(SQL, "sql.append", SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s",
1667 sname,tname,cname);
1668 if (ATOMextern(tpe))
1669 ins = *(ptr *) ins;
1670 if ( tpe == TYPE_bat)
1671 b = (BAT*) ins;
1672 s = mvc_bind_schema(m, sname);
1673 if (s == NULL) {
1674 if (b)
1675 BBPunfix(b->batCacheid);
1676 throw(SQL, "sql.append", SQLSTATE(3F000) "Schema missing %s",sname);
1677 }
1678 t = mvc_bind_table(m, s, tname);
1679 if (t == NULL) {
1680 if (b)
1681 BBPunfix(b->batCacheid);
1682 throw(SQL, "sql.append", SQLSTATE(42S02) "Table missing %s",tname);
1683 }
1684 if( b && BATcount(b) > 4096 && !b->batTransient)
1685 BATmsync(b);
1686 if (cname[0] != '%' && (c = mvc_bind_column(m, t, cname)) != NULL) {
1687 store_funcs.append_col(m->session->tr, c, ins, tpe);
1688 } else if (cname[0] == '%') {
1689 sql_idx *i = mvc_bind_idx(m, s, cname + 1);
1690 if (i)
1691 store_funcs.append_idx(m->session->tr, i, ins, tpe);
1692 }
1693 if (b) {
1694 BBPunfix(b->batCacheid);
1695 }
1696 return MAL_SUCCEED;
1697}
1698
1699/*mvc_update_wrap(int *bid, str *sname, str *tname, str *cname, ptr d) */
1700str
1701mvc_update_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1702{
1703 int *res = getArgReference_int(stk, pci, 0);
1704 mvc *m = NULL;
1705 str msg;
1706 const char *sname = *getArgReference_str(stk, pci, 2);
1707 const char *tname = *getArgReference_str(stk, pci, 3);
1708 const char *cname = *getArgReference_str(stk, pci, 4);
1709 bat Tids = *getArgReference_bat(stk, pci, 5);
1710 bat Upd = *getArgReference_bat(stk, pci, 6);
1711 BAT *tids, *upd;
1712 int tpe = getArgType(mb, pci, 6);
1713 sql_schema *s;
1714 sql_table *t;
1715 sql_column *c;
1716
1717 *res = 0;
1718 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1719 return msg;
1720 if ((msg = checkSQLContext(cntxt)) != NULL)
1721 return msg;
1722 if (tpe > TYPE_any)
1723 tpe = TYPE_bat;
1724 else
1725 assert(0);
1726 if (tpe != TYPE_bat)
1727 throw(SQL, "sql.update", SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s",
1728 sname,tname,cname);
1729 if ((tids = BATdescriptor(Tids)) == NULL)
1730 throw(SQL, "sql.update", SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s",
1731 sname,tname,cname);
1732 if ((upd = BATdescriptor(Upd)) == NULL) {
1733 BBPunfix(tids->batCacheid);
1734 throw(SQL, "sql.update", SQLSTATE(HY005) "Cannot access column descriptor %s.%s.%s",
1735 sname,tname,cname);
1736 }
1737 s = mvc_bind_schema(m, sname);
1738 if (s == NULL) {
1739 BBPunfix(tids->batCacheid);
1740 BBPunfix(upd->batCacheid);
1741 throw(SQL, "sql.update", SQLSTATE(3F000) "Schema missing %s",sname);
1742 }
1743 t = mvc_bind_table(m, s, tname);
1744 if (t == NULL) {
1745 BBPunfix(tids->batCacheid);
1746 BBPunfix(upd->batCacheid);
1747 throw(SQL, "sql.update", SQLSTATE(42S02) "Table missing %s.%s",sname,tname);
1748 }
1749 if( upd && BATcount(upd) > 4096 && !upd->batTransient)
1750 BATmsync(upd);
1751 if( tids && BATcount(tids) > 4096 && !tids->batTransient)
1752 BATmsync(tids);
1753 if (cname[0] != '%' && (c = mvc_bind_column(m, t, cname)) != NULL) {
1754 store_funcs.update_col(m->session->tr, c, tids, upd, TYPE_bat);
1755 } else if (cname[0] == '%') {
1756 sql_idx *i = mvc_bind_idx(m, s, cname + 1);
1757 if (i)
1758 store_funcs.update_idx(m->session->tr, i, tids, upd, TYPE_bat);
1759 }
1760 BBPunfix(tids->batCacheid);
1761 BBPunfix(upd->batCacheid);
1762 return MAL_SUCCEED;
1763}
1764
1765/* str mvc_clear_table_wrap(lng *res, str *sname, str *tname); */
1766str
1767mvc_clear_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1768{
1769 sql_schema *s;
1770 sql_table *t;
1771 mvc *m = NULL;
1772 str msg;
1773 lng *res = getArgReference_lng(stk, pci, 0);
1774 const char *sname = *getArgReference_str(stk, pci, 1);
1775 const char *tname = *getArgReference_str(stk, pci, 2);
1776
1777 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1778 return msg;
1779 if ((msg = checkSQLContext(cntxt)) != NULL)
1780 return msg;
1781 s = mvc_bind_schema(m, sname);
1782 if (s == NULL)
1783 throw(SQL, "sql.clear_table", SQLSTATE(3F000) "Schema missing %s", sname);
1784 t = mvc_bind_table(m, s, tname);
1785 if (t == NULL)
1786 throw(SQL, "sql.clear_table", SQLSTATE(42S02) "Table missing %s.%s", sname,tname);
1787 *res = mvc_clear_table(m, t);
1788 return MAL_SUCCEED;
1789}
1790
1791/*mvc_delete_wrap(int *d, str *sname, str *tname, ptr d) */
1792str
1793mvc_delete_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1794{
1795 int *res = getArgReference_int(stk, pci, 0);
1796 mvc *m = NULL;
1797 str msg;
1798 const char *sname = *getArgReference_str(stk, pci, 2);
1799 const char *tname = *getArgReference_str(stk, pci, 3);
1800 ptr ins = getArgReference(stk, pci, 4);
1801 int tpe = getArgType(mb, pci, 4);
1802 BAT *b = NULL;
1803
1804 sql_schema *s;
1805 sql_table *t;
1806
1807 *res = 0;
1808 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
1809 return msg;
1810 if ((msg = checkSQLContext(cntxt)) != NULL)
1811 return msg;
1812 if (tpe > TYPE_any)
1813 tpe = TYPE_bat;
1814 if (tpe == TYPE_bat && (b = BATdescriptor(*(bat *) ins)) == NULL)
1815 throw(SQL, "sql.delete", SQLSTATE(HY005) "Cannot access column descriptor");
1816 if (tpe != TYPE_bat || (b->ttype != TYPE_oid && b->ttype != TYPE_void)) {
1817 if (b)
1818 BBPunfix(b->batCacheid);
1819 throw(SQL, "sql.delete", SQLSTATE(HY005) "Cannot access column descriptor");
1820 }
1821 s = mvc_bind_schema(m, sname);
1822 if (s == NULL) {
1823 if (b)
1824 BBPunfix(b->batCacheid);
1825 throw(SQL, "sql.delete", SQLSTATE(3F000) "Schema missing %s",sname);
1826 }
1827 t = mvc_bind_table(m, s, tname);
1828 if (t == NULL) {
1829 if (b)
1830 BBPunfix(b->batCacheid);
1831 throw(SQL, "sql.delete", SQLSTATE(42S02) "Table missing %s.%s",sname,tname);
1832 }
1833 if( b && BATcount(b) > 4096 && !b->batTransient)
1834 BATmsync(b);
1835 store_funcs.delete_tab(m->session->tr, t, b, tpe);
1836 if (b)
1837 BBPunfix(b->batCacheid);
1838 return MAL_SUCCEED;
1839}
1840
1841static BAT *
1842setwritable(BAT *b)
1843{
1844 BAT *bn = b;
1845
1846 if (BATsetaccess(b, BAT_WRITE) != GDK_SUCCEED) {
1847 if (b->batSharecnt) {
1848 bn = COLcopy(b, b->ttype, true, TRANSIENT);
1849 if (bn != NULL)
1850 if (BATsetaccess(bn, BAT_WRITE) != GDK_SUCCEED) {
1851 BBPreclaim(bn);
1852 bn = NULL;
1853 }
1854 } else {
1855 bn = NULL;
1856 }
1857 BBPunfix(b->batCacheid);
1858 }
1859 return bn;
1860}
1861
1862str
1863DELTAbat2(bat *result, const bat *col, const bat *uid, const bat *uval)
1864{
1865 return DELTAbat(result, col, uid, uval, NULL);
1866}
1867
1868str
1869DELTAsub2(bat *result, const bat *col, const bat *cid, const bat *uid, const bat *uval)
1870{
1871 return DELTAsub(result, col, cid, uid, uval, NULL);
1872}
1873
1874str
1875DELTAproject2(bat *result, const bat *sub, const bat *col, const bat *uid, const bat *uval)
1876{
1877 return DELTAproject(result, sub, col, uid, uval, NULL);
1878}
1879
1880str
1881DELTAbat(bat *result, const bat *col, const bat *uid, const bat *uval, const bat *ins)
1882{
1883 BAT *c, *u_id, *u_val, *i = NULL, *res;
1884
1885 if ((u_id = BBPquickdesc(*uid, false)) == NULL)
1886 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1887 if (ins && (i = BBPquickdesc(*ins, false)) == NULL)
1888 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1889
1890 /* no updates, no inserts */
1891 if (BATcount(u_id) == 0 && (!i || BATcount(i) == 0)) {
1892 BBPretain(*result = *col);
1893 return MAL_SUCCEED;
1894 }
1895
1896 if ((c = BBPquickdesc(*col, false)) == NULL)
1897 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1898
1899 /* bat may change */
1900 if (i && BATcount(c) == 0 && BATcount(u_id) == 0) {
1901 BBPretain(*result = *ins);
1902 return MAL_SUCCEED;
1903 }
1904
1905 c = BATdescriptor(*col);
1906 if (c == NULL)
1907 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1908 if ((res = COLcopy(c, c->ttype, true, TRANSIENT)) == NULL) {
1909 BBPunfix(c->batCacheid);
1910 throw(MAL, "sql.delta", SQLSTATE(45002) "Cannot create copy of delta structure");
1911 }
1912 BBPunfix(c->batCacheid);
1913
1914 if ((u_val = BATdescriptor(*uval)) == NULL) {
1915 BBPunfix(res->batCacheid);
1916 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1917 }
1918 if ((u_id = BATdescriptor(*uid)) == NULL) {
1919 BBPunfix(u_val->batCacheid);
1920 BBPunfix(res->batCacheid);
1921 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1922 }
1923 assert(BATcount(u_id) == BATcount(u_val));
1924 if (BATcount(u_id) &&
1925 BATreplace(res, u_id, u_val, true) != GDK_SUCCEED) {
1926 BBPunfix(u_id->batCacheid);
1927 BBPunfix(u_val->batCacheid);
1928 BBPunfix(res->batCacheid);
1929 throw(MAL, "sql.delta", SQLSTATE(45002) "Cannot access delta structure");
1930 }
1931 BBPunfix(u_id->batCacheid);
1932 BBPunfix(u_val->batCacheid);
1933
1934 if (i && BATcount(i)) {
1935 if ((i = BATdescriptor(*ins)) == NULL) {
1936 BBPunfix(res->batCacheid);
1937 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1938 }
1939 if (BATappend(res, i, NULL, true) != GDK_SUCCEED) {
1940 BBPunfix(res->batCacheid);
1941 BBPunfix(i->batCacheid);
1942 throw(MAL, "sql.delta", SQLSTATE(45002) "Cannot access delta structure");
1943 }
1944 BBPunfix(i->batCacheid);
1945 }
1946
1947 BBPkeepref(*result = res->batCacheid);
1948 return MAL_SUCCEED;
1949}
1950
1951str
1952DELTAsub(bat *result, const bat *col, const bat *cid, const bat *uid, const bat *uval, const bat *ins)
1953{
1954 BAT *c, *cminu = NULL, *u_id, *u_val, *u, *i = NULL, *res;
1955 gdk_return ret;
1956
1957 if ((u_id = BBPquickdesc(*uid, false)) == NULL)
1958 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1959 if (ins && (i = BBPquickdesc(*ins, false)) == NULL)
1960 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1961
1962 /* no updates, no inserts */
1963 if (BATcount(u_id) == 0 && (!i || BATcount(i) == 0)) {
1964 BBPretain(*result = *col);
1965 return MAL_SUCCEED;
1966 }
1967
1968 if ((c = BBPquickdesc(*col, false)) == NULL)
1969 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1970
1971 /* bat may change */
1972 if (i && BATcount(c) == 0 && BATcount(u_id) == 0) {
1973 BBPretain(*result = *ins);
1974 return MAL_SUCCEED;
1975 }
1976
1977 c = BATdescriptor(*col);
1978 if (c == NULL)
1979 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1980 res = c;
1981 if (BATcount(u_id)) {
1982 u_id = BATdescriptor(*uid);
1983 if (!u_id) {
1984 BBPunfix(c->batCacheid);
1985 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1986 }
1987 cminu = BATdiff(c, u_id, NULL, NULL, false, false, BUN_NONE);
1988 if (!cminu) {
1989 BBPunfix(c->batCacheid);
1990 BBPunfix(u_id->batCacheid);
1991 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL " intermediate");
1992 }
1993 res = BATproject(cminu, c);
1994 BBPunfix(c->batCacheid);
1995 BBPunfix(cminu->batCacheid);
1996 cminu = NULL;
1997 if (!res) {
1998 BBPunfix(u_id->batCacheid);
1999 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL " intermediate" );
2000 }
2001 c = res;
2002
2003 if ((u_val = BATdescriptor(*uval)) == NULL) {
2004 BBPunfix(c->batCacheid);
2005 BBPunfix(u_id->batCacheid);
2006 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2007 }
2008 if (BATcount(u_val)) {
2009 u = BATproject(u_val, u_id);
2010 BBPunfix(u_val->batCacheid);
2011 BBPunfix(u_id->batCacheid);
2012 if (!u) {
2013 BBPunfix(c->batCacheid);
2014 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2015 }
2016
2017 /* check selected updated values against candidates */
2018 BAT *c_ids = BATdescriptor(*cid);
2019
2020 if (!c_ids) {
2021 BBPunfix(c->batCacheid);
2022 BBPunfix(u->batCacheid);
2023 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2024 }
2025 cminu = BATintersect(u, c_ids, NULL, NULL, false, BUN_NONE);
2026 BBPunfix(c_ids->batCacheid);
2027 if (cminu == NULL) {
2028 BBPunfix(c->batCacheid);
2029 BBPunfix(u->batCacheid);
2030 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2031 }
2032 ret = BATappend(res, u, cminu, true);
2033 BBPunfix(u->batCacheid);
2034 if (cminu)
2035 BBPunfix(cminu->batCacheid);
2036 cminu = NULL;
2037 if (ret != GDK_SUCCEED) {
2038 BBPunfix(res->batCacheid);
2039 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2040 }
2041
2042 ret = BATsort(&u, NULL, NULL, res, NULL, NULL, false, false, false);
2043 BBPunfix(res->batCacheid);
2044 if (ret != GDK_SUCCEED) {
2045 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2046 }
2047 res = u;
2048 } else {
2049 BBPunfix(u_val->batCacheid);
2050 BBPunfix(u_id->batCacheid);
2051 }
2052 }
2053
2054 if (i) {
2055 i = BATdescriptor(*ins);
2056 if (!i) {
2057 BBPunfix(res->batCacheid);
2058 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2059 }
2060 if (BATcount(u_id)) {
2061 u_id = BATdescriptor(*uid);
2062 if (!u_id) {
2063 BBPunfix(res->batCacheid);
2064 BBPunfix(i->batCacheid);
2065 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2066 }
2067 cminu = BATdiff(i, u_id, NULL, NULL, false, false, BUN_NONE);
2068 BBPunfix(u_id->batCacheid);
2069 if (!cminu) {
2070 BBPunfix(res->batCacheid);
2071 BBPunfix(i->batCacheid);
2072 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2073 }
2074 }
2075 if (isVIEW(res)) {
2076 BAT *n = COLcopy(res, res->ttype, true, TRANSIENT);
2077 BBPunfix(res->batCacheid);
2078 res = n;
2079 if (res == NULL) {
2080 BBPunfix(i->batCacheid);
2081 if (cminu)
2082 BBPunfix(cminu->batCacheid);
2083 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2084 }
2085 }
2086 ret = BATappend(res, i, cminu, true);
2087 BBPunfix(i->batCacheid);
2088 if (cminu)
2089 BBPunfix(cminu->batCacheid);
2090 if (ret != GDK_SUCCEED) {
2091 BBPunfix(res->batCacheid);
2092 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2093 }
2094
2095 ret = BATsort(&u, NULL, NULL, res, NULL, NULL, false, false, false);
2096 BBPunfix(res->batCacheid);
2097 if (ret != GDK_SUCCEED)
2098 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2099 res = u;
2100 }
2101 BATkey(res, true);
2102 BBPkeepref(*result = res->batCacheid);
2103 return MAL_SUCCEED;
2104}
2105
2106str
2107DELTAproject(bat *result, const bat *sub, const bat *col, const bat *uid, const bat *uval, const bat *ins)
2108{
2109 BAT *s, *c, *u_id, *u_val, *i = NULL, *res, *tres;
2110
2111 if ((s = BATdescriptor(*sub)) == NULL)
2112 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2113
2114 if (ins && (i = BATdescriptor(*ins)) == NULL) {
2115 BBPunfix(s->batCacheid);
2116 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2117 }
2118
2119 if (i && BATcount(s) == 0) {
2120 res = BATproject(s, i);
2121 BBPunfix(s->batCacheid);
2122 BBPunfix(i->batCacheid);
2123 if (res == NULL)
2124 throw(MAL, "sql.projectdelta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2125
2126 BBPkeepref(*result = res->batCacheid);
2127 return MAL_SUCCEED;
2128 }
2129
2130 if ((c = BATdescriptor(*col)) == NULL) {
2131 BBPunfix(s->batCacheid);
2132 if (i)
2133 BBPunfix(i->batCacheid);
2134 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2135 }
2136
2137 /* projection(sub,col).union(projection(sub,i)) */
2138 res = c;
2139 if (i && BATcount(i)) {
2140 if (BATcount(c) == 0) {
2141 res = i;
2142 i = c;
2143 } else {
2144 if ((res = COLcopy(c, c->ttype, true, TRANSIENT)) == NULL) {
2145 BBPunfix(s->batCacheid);
2146 BBPunfix(i->batCacheid);
2147 BBPunfix(c->batCacheid);
2148 throw(MAL, "sql.projectdelta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2149 }
2150 BBPunfix(c->batCacheid);
2151 if (BATappend(res, i, NULL, false) != GDK_SUCCEED) {
2152 BBPunfix(s->batCacheid);
2153 BBPunfix(i->batCacheid);
2154 throw(MAL, "sql.projectdelta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2155 }
2156 }
2157 }
2158 if (i)
2159 BBPunfix(i->batCacheid);
2160
2161 tres = BATproject(s, res);
2162 BBPunfix(res->batCacheid);
2163 if (tres == NULL) {
2164 BBPunfix(s->batCacheid);
2165 throw(MAL, "sql.projectdelta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2166 }
2167 res = tres;
2168
2169 if ((u_id = BATdescriptor(*uid)) == NULL) {
2170 BBPunfix(res->batCacheid);
2171 BBPunfix(s->batCacheid);
2172 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2173 }
2174 if (!BATcount(u_id)) {
2175 BBPunfix(u_id->batCacheid);
2176 BBPunfix(s->batCacheid);
2177 BBPkeepref(*result = res->batCacheid);
2178 return MAL_SUCCEED;
2179 }
2180 if ((u_val = BATdescriptor(*uval)) == NULL) {
2181 BBPunfix(u_id->batCacheid);
2182 BBPunfix(res->batCacheid);
2183 BBPunfix(s->batCacheid);
2184 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2185 }
2186
2187 if (BATcount(u_val)) {
2188 BAT *os, *ou;
2189 /* figure out the positions in res that we have to
2190 * replace with values from u_val */
2191 if (BATsemijoin(&ou, &os, u_id, s, NULL, NULL, false, BUN_NONE) != GDK_SUCCEED) {
2192 BBPunfix(s->batCacheid);
2193 BBPunfix(res->batCacheid);
2194 BBPunfix(u_id->batCacheid);
2195 BBPunfix(u_val->batCacheid);
2196 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2197 }
2198 /* BATcount(ou) == BATcount(os) */
2199 if (BATcount(ou) != 0) {
2200 /* ou contains the position in u_id/u_val that
2201 * contain the new values */
2202 BAT *nu_val = BATproject(ou, u_val);
2203 BBPunfix(ou->batCacheid);
2204 /* os contains the corresponding positions in
2205 * res that need to be replaced with those new
2206 * values */
2207 if ((res = setwritable(res)) == NULL ||
2208 BATreplace(res, os, nu_val, false) != GDK_SUCCEED) {
2209 if (res)
2210 BBPunfix(res->batCacheid);
2211 BBPunfix(os->batCacheid);
2212 BBPunfix(s->batCacheid);
2213 BBPunfix(u_id->batCacheid);
2214 BBPunfix(u_val->batCacheid);
2215 BBPunfix(nu_val->batCacheid);
2216 throw(MAL, "sql.delta", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2217 }
2218 BBPunfix(nu_val->batCacheid);
2219 } else {
2220 /* nothing to replace */
2221 BBPunfix(ou->batCacheid);
2222 }
2223 BBPunfix(os->batCacheid);
2224 }
2225 BBPunfix(s->batCacheid);
2226 BBPunfix(u_id->batCacheid);
2227 BBPunfix(u_val->batCacheid);
2228
2229 BBPkeepref(*result = res->batCacheid);
2230 return MAL_SUCCEED;
2231}
2232
2233str
2234BATleftproject(bat *Res, const bat *Col, const bat *L, const bat *R)
2235{
2236 BAT *c, *l, *r, *res;
2237 oid *p, *lp, *rp;
2238 BUN cnt = 0, i;
2239
2240 c = BATdescriptor(*Col);
2241 if (c)
2242 cnt = BATcount(c);
2243 l = BATdescriptor(*L);
2244 r = BATdescriptor(*R);
2245 res = COLnew(0, TYPE_oid, cnt, TRANSIENT);
2246 if (!c || !l || !r || !res) {
2247 if (c)
2248 BBPunfix(c->batCacheid);
2249 if (l)
2250 BBPunfix(l->batCacheid);
2251 if (r)
2252 BBPunfix(r->batCacheid);
2253 if (res)
2254 BBPunfix(res->batCacheid);
2255 throw(MAL, "sql.delta", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
2256 }
2257 p = (oid*)Tloc(res,0);
2258 for(i=0;i<cnt; i++)
2259 *p++ = oid_nil;
2260 BATsetcount(res, cnt);
2261
2262 cnt = BATcount(l);
2263 p = (oid*)Tloc(res, 0);
2264 lp = (oid*)Tloc(l, 0);
2265 rp = (oid*)Tloc(r, 0);
2266 if (l->ttype == TYPE_void) {
2267 oid lp = l->tseqbase;
2268 if (r->ttype == TYPE_void) {
2269 oid rp = r->tseqbase;
2270 for(i=0;i<cnt; i++, lp++, rp++)
2271 p[lp] = rp;
2272 } else {
2273 for(i=0;i<cnt; i++, lp++)
2274 p[lp] = rp[i];
2275 }
2276 }
2277 if (r->ttype == TYPE_void) {
2278 oid rp = r->tseqbase;
2279 for(i=0;i<cnt; i++, rp++)
2280 p[lp[i]] = rp;
2281 } else {
2282 for(i=0;i<cnt; i++)
2283 p[lp[i]] = rp[i];
2284 }
2285 res->tsorted = false;
2286 res->trevsorted = false;
2287 res->tnil = false;
2288 res->tnonil = false;
2289 res->tkey = false;
2290 BBPunfix(c->batCacheid);
2291 BBPunfix(l->batCacheid);
2292 BBPunfix(r->batCacheid);
2293 BBPkeepref(*Res = res->batCacheid);
2294 return MAL_SUCCEED;
2295}
2296
2297/* str SQLtid(bat *result, mvc *m, str *sname, str *tname) */
2298str
2299SQLtid(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2300{
2301 bat *res = getArgReference_bat(stk, pci, 0);
2302 mvc *m = NULL;
2303 str msg = MAL_SUCCEED;
2304 sql_trans *tr;
2305 const char *sname = *getArgReference_str(stk, pci, 2);
2306 const char *tname = *getArgReference_str(stk, pci, 3);
2307
2308 sql_schema *s;
2309 sql_table *t;
2310 sql_column *c;
2311 BAT *tids;
2312 size_t nr, inr = 0, dcnt;
2313 oid sb = 0;
2314
2315 *res = bat_nil;
2316 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2317 return msg;
2318 tr = m->session->tr;
2319 if ((msg = checkSQLContext(cntxt)) != NULL)
2320 return msg;
2321 s = mvc_bind_schema(m, sname);
2322 if (s == NULL)
2323 throw(SQL, "sql.tid", SQLSTATE(3F000) "Schema missing %s",sname);
2324 t = mvc_bind_table(m, s, tname);
2325 if (t == NULL)
2326 throw(SQL, "sql.tid", SQLSTATE(42S02) "Table missing %s.%s",sname,tname);
2327 c = t->columns.set->h->data;
2328
2329 nr = store_funcs.count_col(tr, c, 1);
2330
2331 if (isTable(t) && t->access == TABLE_WRITABLE && (!isNew(t) /* alter */ ) &&
2332 t->persistence == SQL_PERSIST && !t->commit_action)
2333 inr = store_funcs.count_col(tr, c, 0);
2334 nr -= inr;
2335 if (pci->argc == 6) { /* partitioned version */
2336 size_t cnt = nr;
2337 int part_nr = *getArgReference_int(stk, pci, 4);
2338 int nr_parts = *getArgReference_int(stk, pci, 5);
2339
2340 nr /= nr_parts;
2341 sb = (oid) (part_nr * nr);
2342 if (nr_parts == (part_nr + 1)) { /* last part gets the inserts */
2343 nr = cnt - (part_nr * nr); /* keep rest */
2344 nr += inr;
2345 }
2346 } else {
2347 nr += inr;
2348 }
2349
2350 /* create void,void bat with length and oid's set */
2351 tids = BATdense(sb, sb, (BUN) nr);
2352 if (tids == NULL)
2353 throw(SQL, "sql.tid", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2354
2355 /* V1 of the deleted list
2356 * 1) in case of deletes, bind_del, order it, put into a heap(of the tids bat)
2357 * 2) in mal recognize this type of bat.
2358 * 3) if function can handle it pass along, else fall back to first diff.
2359 * */
2360 if ((dcnt = store_funcs.count_del(tr, t)) > 0) {
2361 BAT *d = store_funcs.bind_del(tr, t, RD_INS);
2362
2363 if (d == NULL) {
2364 BBPunfix(tids->batCacheid);
2365 throw(SQL,"sql.tid", SQLSTATE(45002) "Can not bind delete column");
2366 }
2367
2368#if 1
2369 BAT *o;
2370 gdk_return ret = BATsort(&o, NULL, NULL, d, NULL, NULL, false, false, false);
2371 BBPunfix(d->batCacheid);
2372 if (ret != GDK_SUCCEED)
2373 throw(MAL, "sql.tids", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2374
2375 /* TODO handle dense o, ie full range out of the dense tids, could be at beginning or end (reduce range of tids)
2376 * else materialize */
2377 /* copy into heap */
2378 ret = BATnegcands(tids, o);
2379 BBPunfix(o->batCacheid);
2380 if (ret != GDK_SUCCEED)
2381 throw(MAL, "sql.tids", SQLSTATE(45003) "TIDdeletes failed");
2382#else
2383 BAT *diff;
2384 diff = BATdiff(tids, d, NULL, NULL, false, false, BUN_NONE);
2385 assert(pci->argc == 6 || BATcount(diff) == (nr-dcnt));
2386 //if( !(pci->argc == 6 || BATcount(diff) == (nr-dcnt)) )
2387 //msg = createException(SQL, "sql.tid", SQLSTATE(00000) "Invalid sqltid state argc=%d diff=" BUNFMT ", nr=%zd, dcnt=%zd", pci->argc, BATcount(diff), nr, dcnt);
2388 BBPunfix(d->batCacheid);
2389 BBPunfix(tids->batCacheid);
2390 if (diff == NULL)
2391 throw(SQL,"sql.tid", SQLSTATE(45002) "Cannot subtract delete column");
2392 BAThseqbase(diff, sb);
2393 tids = diff;
2394#endif
2395 }
2396 BBPkeepref(*res = tids->batCacheid);
2397 return msg;
2398}
2399
2400/* unsafe pattern resultSet(tbl:bat[:str], attr:bat[:str], tpe:bat[:str], len:bat[:int],scale:bat[:int], cols:bat[:any]...) :int */
2401/* New result set rendering infrastructure */
2402
2403static str
2404mvc_result_set_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2405{
2406 int *res_id =getArgReference_int(stk,pci,0);
2407 bat tblId= *getArgReference_bat(stk, pci,1);
2408 bat atrId= *getArgReference_bat(stk, pci,2);
2409 bat tpeId= *getArgReference_bat(stk, pci,3);
2410 bat lenId= *getArgReference_bat(stk, pci,4);
2411 bat scaleId= *getArgReference_bat(stk, pci,5);
2412 bat bid;
2413 int i,res;
2414 str tblname, colname, tpename, msg= MAL_SUCCEED;
2415 int *digits, *scaledigits;
2416 oid o = 0;
2417 BATiter itertbl,iteratr,itertpe;
2418 mvc *m = NULL;
2419 BAT *b, *tbl, *atr, *tpe,*len,*scale;
2420
2421 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2422 return msg;
2423 if ((msg = checkSQLContext(cntxt)) != NULL)
2424 return msg;
2425 bid = *getArgReference_bat(stk,pci,6);
2426 b = BATdescriptor(bid);
2427 if ( b == NULL)
2428 throw(MAL,"sql.resultset", SQLSTATE(HY005) "Cannot access column descriptor");
2429 res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 5), Q_TABLE, b);
2430 if (res < 0)
2431 msg = createException(SQL, "sql.resultSet", SQLSTATE(45000) "Result table construction failed");
2432 BBPunfix(b->batCacheid);
2433
2434 tbl = BATdescriptor(tblId);
2435 atr = BATdescriptor(atrId);
2436 tpe = BATdescriptor(tpeId);
2437 len = BATdescriptor(lenId);
2438 scale = BATdescriptor(scaleId);
2439 if( msg || tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL)
2440 goto wrapup_result_set;
2441 /* mimick the old rsColumn approach; */
2442 itertbl = bat_iterator(tbl);
2443 iteratr = bat_iterator(atr);
2444 itertpe = bat_iterator(tpe);
2445 digits = (int*) Tloc(len,0);
2446 scaledigits = (int*) Tloc(scale,0);
2447
2448 for( i = 6; msg == MAL_SUCCEED && i< pci->argc; i++, o++){
2449 bid = *getArgReference_bat(stk,pci,i);
2450 tblname = BUNtvar(itertbl,o);
2451 colname = BUNtvar(iteratr,o);
2452 tpename = BUNtvar(itertpe,o);
2453 b = BATdescriptor(bid);
2454 if ( b == NULL)
2455 msg= createException(MAL,"sql.resultset",SQLSTATE(HY005) "Cannot access column descriptor ");
2456 else if (mvc_result_column(m, tblname, colname, tpename, *digits++, *scaledigits++, b))
2457 msg = createException(SQL, "sql.resultset", SQLSTATE(42000) "Cannot access column descriptor %s.%s",tblname,colname);
2458 if( b)
2459 BBPunfix(bid);
2460 }
2461 /* now send it to the channel cntxt->fdout */
2462 if (mvc_export_result(cntxt->sqlcontext, cntxt->fdout, res, true, mb->starttime, mb->optimize))
2463 msg = createException(SQL, "sql.resultset", SQLSTATE(45000) "Result set construction failed");
2464 mb->starttime = 0;
2465 mb->optimize = 0;
2466 wrapup_result_set:
2467 if( tbl) BBPunfix(tblId);
2468 if( atr) BBPunfix(atrId);
2469 if( tpe) BBPunfix(tpeId);
2470 if( len) BBPunfix(lenId);
2471 if( scale) BBPunfix(scaleId);
2472 return msg;
2473}
2474
2475/* Copy the result set into a CSV file */
2476str
2477mvc_export_table_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2478{
2479 int *res_id =getArgReference_int(stk,pci,0);
2480 const char *filename = *getArgReference_str(stk,pci,1);
2481 const char *format = *getArgReference_str(stk,pci,2);
2482 const char *tsep = *getArgReference_str(stk, pci, 3);
2483 const char *rsep = *getArgReference_str(stk, pci, 4);
2484 const char *ssep = *getArgReference_str(stk, pci, 5);
2485 const char *ns = *getArgReference_str(stk, pci, 6);
2486 int onclient = *getArgReference_int(stk, pci, 7);
2487
2488 bat tblId= *getArgReference_bat(stk, pci,8);
2489 bat atrId= *getArgReference_bat(stk, pci,9);
2490 bat tpeId= *getArgReference_bat(stk, pci,10);
2491 bat lenId= *getArgReference_bat(stk, pci,11);
2492 bat scaleId= *getArgReference_bat(stk, pci,12);
2493 stream *s;
2494 bat bid;
2495 int i,res;
2496 str tblname, colname, tpename, msg= MAL_SUCCEED;
2497 int *digits, *scaledigits;
2498 oid o = 0;
2499 BATiter itertbl,iteratr,itertpe;
2500 mvc *m = NULL;
2501 BAT *order = NULL, *b = NULL, *tbl = NULL, *atr = NULL, *tpe = NULL,*len = NULL,*scale = NULL;
2502 res_table *t = NULL;
2503 bool tostdout;
2504 char buf[80];
2505 ssize_t sz;
2506
2507 (void) format;
2508
2509 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2510 return msg;
2511
2512 if (onclient && !cntxt->filetrans) {
2513 throw(MAL, "sql.resultSet", "cannot transfer files to client");
2514 }
2515
2516 bid = *getArgReference_bat(stk,pci,13);
2517 order = BATdescriptor(bid);
2518 if ( order == NULL)
2519 throw(MAL,"sql.resultset", SQLSTATE(HY005) "Cannot access column descriptor");
2520 res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 12), Q_TABLE, order);
2521 t = m->results;
2522 if (res < 0){
2523 msg = createException(SQL, "sql.resultSet", SQLSTATE(45000) "Result set construction failed");
2524 goto wrapup_result_set1;
2525 }
2526
2527 t->tsep = tsep;
2528 t->rsep = rsep;
2529 t->ssep = ssep;
2530 t->ns = ns;
2531
2532 tbl = BATdescriptor(tblId);
2533 atr = BATdescriptor(atrId);
2534 tpe = BATdescriptor(tpeId);
2535 len = BATdescriptor(lenId);
2536 scale = BATdescriptor(scaleId);
2537 if( tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL)
2538 goto wrapup_result_set1;
2539 /* mimick the old rsColumn approach; */
2540 itertbl = bat_iterator(tbl);
2541 iteratr = bat_iterator(atr);
2542 itertpe = bat_iterator(tpe);
2543 digits = (int*) Tloc(len,0);
2544 scaledigits = (int*) Tloc(scale,0);
2545
2546 for( i = 13; msg == MAL_SUCCEED && i< pci->argc; i++, o++){
2547 bid = *getArgReference_bat(stk,pci,i);
2548 tblname = BUNtvar(itertbl,o);
2549 colname = BUNtvar(iteratr,o);
2550 tpename = BUNtvar(itertpe,o);
2551 b = BATdescriptor(bid);
2552 if ( b == NULL)
2553 msg= createException(MAL,"sql.resultset",SQLSTATE(HY005) "Cannot access column descriptor");
2554 else if (mvc_result_column(m, tblname, colname, tpename, *digits++, *scaledigits++, b))
2555 msg = createException(SQL, "sql.resultset", SQLSTATE(42000) "Cannot access column descriptor %s.%s",tblname,colname);
2556 if( b)
2557 BBPunfix(bid);
2558 }
2559 if ( msg )
2560 goto wrapup_result_set1;
2561
2562 /* now select the file channel */
2563 if ((tostdout = strcmp(filename,"stdout") == 0)) {
2564 s = cntxt->fdout;
2565 } else if (!onclient) {
2566 if ((s = open_wastream(filename)) == NULL || mnstr_errnr(s)) {
2567 msg= createException(IO, "streams.open", SQLSTATE(42000) "could not open file '%s': %s",
2568 filename?filename:"stdout", strerror(errno));
2569 close_stream(s);
2570 goto wrapup_result_set1;
2571 }
2572 } else {
2573 while (!m->scanner.rs->eof)
2574 bstream_next(m->scanner.rs);
2575 s = m->scanner.ws;
2576 mnstr_write(s, PROMPT3, sizeof(PROMPT3) - 1, 1);
2577 mnstr_printf(s, "w %s\n", filename);
2578 mnstr_flush(s);
2579 if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) {
2580 /* non-empty line indicates failure on client */
2581 msg = createException(IO, "streams.open", "%s", buf);
2582 /* deal with ridiculously long response from client */
2583 while (buf[sz - 1] != '\n' &&
2584 (sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 0)
2585 ;
2586 goto wrapup_result_set1;
2587 }
2588 }
2589 if (mvc_export_result(cntxt->sqlcontext, s, res, tostdout, mb->starttime, mb->optimize))
2590 msg = createException(SQL, "sql.resultset", SQLSTATE(45000) "Result set construction failed");
2591 mb->starttime = 0;
2592 mb->optimize = 0;
2593 if (onclient) {
2594 mnstr_flush(s);
2595 if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) {
2596 msg = createException(IO, "streams.open", "%s", buf);
2597 }
2598 while (sz > 0)
2599 sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf));
2600 } else if (!tostdout) {
2601 close_stream(s);
2602 }
2603 wrapup_result_set1:
2604 BBPunfix(order->batCacheid);
2605 if( tbl) BBPunfix(tblId);
2606 if( atr) BBPunfix(atrId);
2607 if( tpe) BBPunfix(tpeId);
2608 if( len) BBPunfix(lenId);
2609 if( scale) BBPunfix(scaleId);
2610 return msg;
2611}
2612
2613/* unsafe pattern resultSet(tbl:bat[:str], attr:bat[:str], tpe:bat[:str], len:bat[:int],scale:bat[:int], cols:any...) :int */
2614str
2615mvc_row_result_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2616{
2617 int *res_id= getArgReference_int(stk, pci,0);
2618 bat tblId= *getArgReference_bat(stk, pci,1);
2619 bat atrId= *getArgReference_bat(stk, pci,2);
2620 bat tpeId= *getArgReference_bat(stk, pci,3);
2621 bat lenId= *getArgReference_bat(stk, pci,4);
2622 bat scaleId= *getArgReference_bat(stk, pci,5);
2623 int i, res;
2624 str tblname, colname, tpename, msg= MAL_SUCCEED;
2625 int *digits, *scaledigits;
2626 oid o = 0;
2627 BATiter itertbl,iteratr,itertpe;
2628 mvc *m = NULL;
2629 ptr v;
2630 int mtype;
2631 BAT *tbl, *atr, *tpe,*len,*scale;
2632
2633 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2634 return msg;
2635 if ((msg = checkSQLContext(cntxt)) != NULL)
2636 return msg;
2637 res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 5), Q_TABLE, NULL);
2638 if (res < 0)
2639 throw(SQL, "sql.resultset", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2640
2641 tbl = BATdescriptor(tblId);
2642 atr = BATdescriptor(atrId);
2643 tpe = BATdescriptor(tpeId);
2644 len = BATdescriptor(lenId);
2645 scale = BATdescriptor(scaleId);
2646 if( tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL)
2647 goto wrapup_result_set;
2648 /* mimick the old rsColumn approach; */
2649 itertbl = bat_iterator(tbl);
2650 iteratr = bat_iterator(atr);
2651 itertpe = bat_iterator(tpe);
2652 digits = (int*) Tloc(len,0);
2653 scaledigits = (int*) Tloc(scale,0);
2654
2655 for( i = 6; msg == MAL_SUCCEED && i< pci->argc; i++, o++){
2656 tblname = BUNtvar(itertbl,o);
2657 colname = BUNtvar(iteratr,o);
2658 tpename = BUNtvar(itertpe,o);
2659
2660 v = getArgReference(stk, pci, i);
2661 mtype = getArgType(mb, pci, i);
2662 if (ATOMextern(mtype))
2663 v = *(ptr *) v;
2664 if (mvc_result_value(m, tblname, colname, tpename, *digits++, *scaledigits++, v, mtype))
2665 throw(SQL, "sql.rsColumn", SQLSTATE(45000) "Result set construction failed");
2666 }
2667 if (mvc_export_result(cntxt->sqlcontext, cntxt->fdout, res, true, mb->starttime, mb->optimize))
2668 msg = createException(SQL, "sql.resultset", SQLSTATE(45000) "Result set construction failed");
2669 mb->starttime = 0;
2670 mb->optimize = 0;
2671 wrapup_result_set:
2672 if( tbl) BBPunfix(tblId);
2673 if( atr) BBPunfix(atrId);
2674 if( tpe) BBPunfix(tpeId);
2675 if( len) BBPunfix(lenId);
2676 if( scale) BBPunfix(scaleId);
2677 return msg;
2678}
2679
2680str
2681mvc_export_row_wrap( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2682{
2683 int *res_id= getArgReference_int(stk, pci,0);
2684 str filename = * getArgReference_str(stk,pci,1);
2685 const char *format = *getArgReference_str(stk,pci,2);
2686 const char *tsep = *getArgReference_str(stk, pci, 3);
2687 const char *rsep = *getArgReference_str(stk, pci, 4);
2688 const char *ssep = *getArgReference_str(stk, pci, 5);
2689 const char *ns = *getArgReference_str(stk, pci, 6);
2690 int onclient = *getArgReference_int(stk, pci, 7);
2691
2692 bat tblId= *getArgReference_bat(stk, pci,8);
2693 bat atrId= *getArgReference_bat(stk, pci,9);
2694 bat tpeId= *getArgReference_bat(stk, pci,10);
2695 bat lenId= *getArgReference_bat(stk, pci,11);
2696 bat scaleId= *getArgReference_bat(stk, pci,12);
2697
2698 int i, res;
2699 stream *s;
2700 str tblname, colname, tpename, msg= MAL_SUCCEED;
2701 int *digits, *scaledigits;
2702 oid o = 0;
2703 BATiter itertbl,iteratr,itertpe;
2704 mvc *m = NULL;
2705 res_table *t = NULL;
2706 ptr v;
2707 int mtype;
2708 BAT *tbl = NULL, *atr = NULL, *tpe = NULL,*len = NULL,*scale = NULL;
2709 bool tostdout;
2710 char buf[80];
2711 ssize_t sz;
2712
2713 (void) format;
2714 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2715 return msg;
2716 if ((msg = checkSQLContext(cntxt)) != NULL)
2717 return msg;
2718 if (onclient && !cntxt->filetrans) {
2719 throw(MAL, "sql.resultSet", "cannot transfer files to client");
2720 }
2721
2722 res = *res_id = mvc_result_table(m, mb->tag, pci->argc - (pci->retc + 12), Q_TABLE, NULL);
2723
2724 t = m->results;
2725 if (res < 0){
2726 msg = createException(SQL, "sql.resultSet", SQLSTATE(45000) "Result set construction failed");
2727 goto wrapup_result_set;
2728 }
2729
2730 t->tsep = tsep;
2731 t->rsep = rsep;
2732 t->ssep = ssep;
2733 t->ns = ns;
2734
2735 tbl = BATdescriptor(tblId);
2736 atr = BATdescriptor(atrId);
2737 tpe = BATdescriptor(tpeId);
2738 len = BATdescriptor(lenId);
2739 scale = BATdescriptor(scaleId);
2740 if( msg || tbl == NULL || atr == NULL || tpe == NULL || len == NULL || scale == NULL)
2741 goto wrapup_result_set;
2742 /* mimick the old rsColumn approach; */
2743 itertbl = bat_iterator(tbl);
2744 iteratr = bat_iterator(atr);
2745 itertpe = bat_iterator(tpe);
2746 digits = (int*) Tloc(len,0);
2747 scaledigits = (int*) Tloc(scale,0);
2748
2749 for( i = 13; msg == MAL_SUCCEED && i< pci->argc; i++, o++){
2750 tblname = BUNtvar(itertbl,o);
2751 colname = BUNtvar(iteratr,o);
2752 tpename = BUNtvar(itertpe,o);
2753
2754 v = getArgReference(stk, pci, i);
2755 mtype = getArgType(mb, pci, i);
2756 if (ATOMextern(mtype))
2757 v = *(ptr *) v;
2758 if (mvc_result_value(m, tblname, colname, tpename, *digits++, *scaledigits++, v, mtype))
2759 throw(SQL, "sql.rsColumn", SQLSTATE(45000) "Result set construction failed");
2760 }
2761 /* now select the file channel */
2762 if ((tostdout = strcmp(filename,"stdout") == 0)) {
2763 s = cntxt->fdout;
2764 } else if (!onclient) {
2765 if ((s = open_wastream(filename)) == NULL || mnstr_errnr(s)) {
2766 msg= createException(IO, "streams.open", SQLSTATE(42000) "could not open file '%s': %s",
2767 filename?filename:"stdout", strerror(errno));
2768 close_stream(s);
2769 goto wrapup_result_set;
2770 }
2771 } else {
2772 while (!m->scanner.rs->eof)
2773 bstream_next(m->scanner.rs);
2774 s = m->scanner.ws;
2775 mnstr_write(s, PROMPT3, sizeof(PROMPT3) - 1, 1);
2776 mnstr_printf(s, "w %s\n", filename);
2777 mnstr_flush(s);
2778 if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) {
2779 /* non-empty line indicates failure on client */
2780 msg = createException(IO, "streams.open", "%s", buf);
2781 /* deal with ridiculously long response from client */
2782 while (buf[sz - 1] != '\n' &&
2783 (sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 0)
2784 ;
2785 goto wrapup_result_set;
2786 }
2787 }
2788 if (mvc_export_result(cntxt->sqlcontext, s, res, strcmp(filename, "stdout") == 0, mb->starttime, mb->optimize))
2789 msg = createException(SQL, "sql.resultset", SQLSTATE(45000) "Result set construction failed");
2790 mb->starttime = 0;
2791 mb->optimize = 0;
2792 if (onclient) {
2793 mnstr_flush(s);
2794 if ((sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf))) > 1) {
2795 msg = createException(IO, "streams.open", "%s", buf);
2796 }
2797 while (sz > 0)
2798 sz = mnstr_readline(m->scanner.rs->s, buf, sizeof(buf));
2799 } else if (!tostdout) {
2800 close_stream(s);
2801 }
2802 wrapup_result_set:
2803 if( tbl) BBPunfix(tblId);
2804 if( atr) BBPunfix(atrId);
2805 if( tpe) BBPunfix(tpeId);
2806 if( len) BBPunfix(lenId);
2807 if( scale) BBPunfix(scaleId);
2808 return msg;
2809}
2810
2811str
2812mvc_table_result_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2813{
2814 str res = MAL_SUCCEED;
2815 BAT *order;
2816 mvc *m = NULL;
2817 str msg;
2818 int *res_id;
2819 int nr_cols;
2820 sql_query_t qtype;
2821 bat order_bid;
2822
2823 if ( pci->argc > 6)
2824 return mvc_result_set_wrap(cntxt,mb,stk,pci);
2825
2826 res_id = getArgReference_int(stk, pci, 0);
2827 nr_cols = *getArgReference_int(stk, pci, 1);
2828 qtype = (sql_query_t) *getArgReference_int(stk, pci, 2);
2829 order_bid = *getArgReference_bat(stk, pci, 3);
2830
2831 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
2832 return msg;
2833 if ((msg = checkSQLContext(cntxt)) != NULL)
2834 return msg;
2835 if ((order = BATdescriptor(order_bid)) == NULL) {
2836 throw(SQL, "sql.resultSet", SQLSTATE(HY005) "Cannot access column descriptor");
2837 }
2838 *res_id = mvc_result_table(m, mb->tag, nr_cols, qtype, order);
2839 if (*res_id < 0)
2840 res = createException(SQL, "sql.resultSet", SQLSTATE(45000) "Result set construction failed");
2841 BBPunfix(order->batCacheid);
2842 return res;
2843}
2844
2845/* str mvc_affected_rows_wrap(int *m, int m, lng *nr, str *w); */
2846str
2847mvc_affected_rows_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2848{
2849 backend *b = NULL;
2850 int *res = getArgReference_int(stk, pci, 0), error;
2851#ifndef NDEBUG
2852 int mtype = getArgType(mb, pci, 2);
2853#endif
2854 lng nr;
2855 str msg;
2856
2857 (void) mb; /* NOT USED */
2858 if ((msg = checkSQLContext(cntxt)) != NULL)
2859 return msg;
2860 *res = 0;
2861 assert(mtype == TYPE_lng);
2862 nr = *getArgReference_lng(stk, pci, 2);
2863 b = cntxt->sqlcontext;
2864 error = mvc_export_affrows(b, b->out, nr, "", mb->tag, mb->starttime, mb->optimize);
2865 mb->starttime = 0;
2866 mb->optimize = 0;
2867 if (error)
2868 throw(SQL, "sql.affectedRows", SQLSTATE(45000) "Result set construction failed");
2869 return MAL_SUCCEED;
2870}
2871
2872/* str mvc_export_head_wrap(int *ret, stream **s, int *res_id); */
2873str
2874mvc_export_head_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2875{
2876 backend *b = NULL;
2877 stream **s = (stream **) getArgReference(stk, pci, 1);
2878 int res_id = *getArgReference_int(stk, pci, 2);
2879 str msg;
2880
2881 (void) mb; /* NOT USED */
2882 if ((msg = checkSQLContext(cntxt)) != NULL)
2883 return msg;
2884 b = cntxt->sqlcontext;
2885 if (mvc_export_head(b, *s, res_id, FALSE, TRUE, mb->starttime, mb->optimize))
2886 throw(SQL, "sql.exportHead", SQLSTATE(45000) "Result set construction failed");
2887 mb->starttime = 0;
2888 mb->optimize = 0;
2889 return MAL_SUCCEED;
2890}
2891
2892/* str mvc_export_result_wrap(int *ret, stream **s, int *res_id); */
2893str
2894mvc_export_result_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2895{
2896 backend *b = NULL;
2897 stream **s = (stream **) getArgReference(stk, pci, 1);
2898 int res_id = *getArgReference_int(stk, pci, 2);
2899 str msg;
2900
2901 (void) mb; /* NOT USED */
2902 if ((msg = checkSQLContext(cntxt)) != NULL)
2903 return msg;
2904 b = cntxt->sqlcontext;
2905 if( pci->argc > 5){
2906 res_id = *getArgReference_int(stk, pci, 2);
2907 if (mvc_export_result(b, cntxt->fdout, res_id, true, mb->starttime, mb->optimize))
2908 throw(SQL, "sql.exportResult", SQLSTATE(45000) "Result set construction failed");
2909 } else if (mvc_export_result(b, *s, res_id, false, mb->starttime, mb->optimize))
2910 throw(SQL, "sql.exportResult", SQLSTATE(45000) "Result set construction failed");
2911 mb->starttime = 0;
2912 mb->optimize = 0;
2913 return MAL_SUCCEED;
2914}
2915
2916/* str mvc_export_chunk_wrap(int *ret, stream **s, int *res_id, str *w); */
2917str
2918mvc_export_chunk_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2919{
2920 backend *b = NULL;
2921 stream **s = (stream **) getArgReference(stk, pci, 1);
2922 int res_id = *getArgReference_int(stk, pci, 2);
2923 BUN offset = 0;
2924 BUN nr = 0;
2925 str msg;
2926
2927 (void) mb; /* NOT USED */
2928 if (pci->argc == 5) {
2929 offset = (BUN) *getArgReference_int(stk, pci, 3);
2930 nr = (BUN) *getArgReference_int(stk, pci, 4);
2931 }
2932
2933 if ((msg = checkSQLContext(cntxt)) != NULL)
2934 return msg;
2935 b = cntxt->sqlcontext;
2936 if (mvc_export_chunk(b, *s, res_id, offset, nr))
2937 throw(SQL, "sql.exportChunk", SQLSTATE(45000) "Result set construction failed");
2938 return NULL;
2939}
2940
2941/* str mvc_export_operation_wrap(int *ret, str *w); */
2942str
2943mvc_export_operation_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2944{
2945 backend *b = NULL;
2946 str msg;
2947
2948 (void) stk; /* NOT USED */
2949 (void) pci; /* NOT USED */
2950 if ((msg = checkSQLContext(cntxt)) != NULL)
2951 return msg;
2952 b = cntxt->sqlcontext;
2953 if (mvc_export_operation(b, b->out, "", mb->starttime, mb->optimize))
2954 throw(SQL, "sql.exportOperation", SQLSTATE(45000) "Result set construction failed");
2955 mb->starttime = 0;
2956 mb->optimize = 0;
2957 return NULL;
2958}
2959
2960str
2961/*mvc_scalar_value_wrap(int *ret, int *qtype, str tn, str name, str type, int *digits, int *scale, int *eclass, ptr p, int mtype)*/
2962mvc_scalar_value_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
2963{
2964 const char *tn = *getArgReference_str(stk, pci, 1);
2965 const char *cn = *getArgReference_str(stk, pci, 2);
2966 const char *type = *getArgReference_str(stk, pci, 3);
2967 int digits = *getArgReference_int(stk, pci, 4);
2968 int scale = *getArgReference_int(stk, pci, 5);
2969 ptr p = getArgReference(stk, pci, 7);
2970 int mtype = getArgType(mb, pci, 7);
2971 str msg;
2972 backend *b = NULL;
2973 int res_id;
2974 (void) mb; /* NOT USED */
2975 if ((msg = checkSQLContext(cntxt)) != NULL)
2976 return msg;
2977 b = cntxt->sqlcontext;
2978 if (ATOMextern(mtype))
2979 p = *(ptr *) p;
2980
2981 // scalar values are single-column result sets
2982 if ((res_id = mvc_result_table(b->mvc, mb->tag, 1, Q_TABLE, NULL)) < 0)
2983 throw(SQL, "sql.exportValue", SQLSTATE(HY001) MAL_MALLOC_FAIL);
2984 if (mvc_result_value(b->mvc, tn, cn, type, digits, scale, p, mtype))
2985 throw(SQL, "sql.exportValue", SQLSTATE(45000) "Result set construction failed");
2986 if (b->output_format == OFMT_NONE) {
2987 return MAL_SUCCEED;
2988 }
2989 if (mvc_export_result(b, b->out, res_id, true, mb->starttime, mb->optimize) < 0) {
2990 throw(SQL, "sql.exportValue", SQLSTATE(45000) "Result set construction failed");
2991 }
2992 mb->starttime = 0;
2993 mb->optimize = 0;
2994 return MAL_SUCCEED;
2995}
2996
2997static void
2998bat2return(MalStkPtr stk, InstrPtr pci, BAT **b)
2999{
3000 int i;
3001
3002 for (i = 0; i < pci->retc; i++) {
3003 *getArgReference_bat(stk, pci, i) = b[i]->batCacheid;
3004 BBPkeepref(b[i]->batCacheid);
3005 }
3006}
3007
3008#ifdef WIN32
3009static void
3010fix_windows_newline(unsigned char *s)
3011{
3012 char *p = NULL;
3013 int c = '\r';
3014
3015 if (s && (p=strchr((char*)s, c)) != NULL && p[1] == '\n') {
3016 for(; p[1]; p++)
3017 p[0] = p[1];
3018 p[0] = 0;
3019 }
3020}
3021#endif
3022
3023static char fwftsep[2] = {STREAM_FWF_FIELD_SEP, '\0'};
3024static char fwfrsep[2] = {STREAM_FWF_RECORD_SEP, '\0'};
3025
3026/* str mvc_import_table_wrap(int *res, str *sname, str *tname, unsigned char* *T, unsigned char* *R, unsigned char* *S, unsigned char* *N, str *fname, lng *sz, lng *offset, int *locked, int *besteffort, str *fixed_width, int *onclient); */
3027str
3028mvc_import_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3029{
3030 backend *be;
3031 BAT **b = NULL;
3032 ssize_t len = 0;
3033 sql_table *t = *(sql_table **) getArgReference(stk, pci, pci->retc + 0);
3034 const char *tsep = *getArgReference_str(stk, pci, pci->retc + 1);
3035 const char *rsep = *getArgReference_str(stk, pci, pci->retc + 2);
3036 const char *ssep = *getArgReference_str(stk, pci, pci->retc + 3);
3037 const char *ns = *getArgReference_str(stk, pci, pci->retc + 4);
3038 const char *fname = *getArgReference_str(stk, pci, pci->retc + 5);
3039 lng sz = *getArgReference_lng(stk, pci, pci->retc + 6);
3040 lng offset = *getArgReference_lng(stk, pci, pci->retc + 7);
3041 int locked = *getArgReference_int(stk, pci, pci->retc + 8);
3042 int besteffort = *getArgReference_int(stk, pci, pci->retc + 9);
3043 char *fixed_widths = *getArgReference_str(stk, pci, pci->retc + 10);
3044 int onclient = *getArgReference_int(stk, pci, pci->retc + 11);
3045 str msg = MAL_SUCCEED;
3046 bstream *s = NULL;
3047 stream *ss;
3048
3049 (void) mb; /* NOT USED */
3050 if ((msg = checkSQLContext(cntxt)) != NULL)
3051 return msg;
3052 if (onclient && !cntxt->filetrans) {
3053 throw(MAL, "sql.copy_from", "cannot transfer files from client");
3054 }
3055
3056 be = cntxt->sqlcontext;
3057 /* The CSV parser expects ssep to have the value 0 if the user does not
3058 * specify a quotation character
3059 */
3060 if (*ssep == 0 || strcmp(ssep, str_nil) == 0)
3061 ssep = NULL;
3062
3063 if (fname != NULL && strcmp(str_nil, fname) == 0)
3064 fname = NULL;
3065 if (fname == NULL) {
3066 msg = mvc_import_table(cntxt, &b, be->mvc, be->mvc->scanner.rs, t, tsep, rsep, ssep, ns, sz, offset, locked, besteffort, true);
3067 } else {
3068 if (onclient) {
3069 mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1);
3070 if (offset > 1 && rsep && rsep[0] == '\n' && rsep[1] == '\0') {
3071 /* only let client skip simple lines */
3072 mnstr_printf(be->mvc->scanner.ws, "r " LLFMT " %s\n",
3073 offset, fname);
3074 offset = 0;
3075 } else {
3076 mnstr_printf(be->mvc->scanner.ws, "r 0 %s\n", fname);
3077 }
3078 msg = MAL_SUCCEED;
3079 mnstr_flush(be->mvc->scanner.ws);
3080 while (!be->mvc->scanner.rs->eof)
3081 bstream_next(be->mvc->scanner.rs);
3082 ss = be->mvc->scanner.rs->s;
3083 char buf[80];
3084 if ((len = mnstr_readline(ss, buf, sizeof(buf))) > 1) {
3085 if (buf[0] == '!' && buf[6] == '!')
3086 msg = createException(IO, "sql.copy_from", "%.7s%s: %s", buf, fname, buf+7);
3087 else
3088 msg = createException(IO, "sql.copy_from", "%s: %s", fname, buf);
3089 while (buf[len - 1] != '\n' &&
3090 (len = mnstr_readline(ss, buf, sizeof(buf))) > 0)
3091 ;
3092 /* read until flush marker */
3093 while (mnstr_read(ss, buf, 1, sizeof(buf)) > 0)
3094 ;
3095 return msg;
3096 }
3097 } else {
3098 ss = open_rastream(fname);
3099 if (ss == NULL || mnstr_errnr(ss)) {
3100 msg = createException(IO, "sql.copy_from", SQLSTATE(42000) "Cannot open file '%s': %s", fname, strerror(errno));
3101 close_stream(ss);
3102 return msg;
3103 }
3104 }
3105
3106 if (fixed_widths && strcmp(fixed_widths, str_nil) != 0) {
3107 size_t ncol = 0, current_width_entry = 0, i;
3108 size_t *widths;
3109 char* val_start = fixed_widths;
3110 size_t width_len = strlen(fixed_widths);
3111 for (i = 0; i < width_len; i++) {
3112 if (fixed_widths[i] == '|') {
3113 ncol++;
3114 }
3115 }
3116 widths = malloc(sizeof(size_t) * ncol);
3117 if (!widths) {
3118 close_stream(ss);
3119 throw(MAL, "sql.copy_from", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3120 }
3121 for (i = 0; i < width_len; i++) {
3122 if (fixed_widths[i] == STREAM_FWF_FIELD_SEP) {
3123 fixed_widths[i] = '\0';
3124 widths[current_width_entry++] = (size_t) strtoll(val_start, NULL, 10);
3125 val_start = fixed_widths + i + 1;
3126 }
3127 }
3128 /* overwrite other delimiters to the ones the FWF stream uses */
3129 tsep = fwftsep;
3130 rsep = fwfrsep;
3131
3132 ss = stream_fwf_create(ss, ncol, widths, STREAM_FWF_FILLER);
3133 }
3134#if SIZEOF_VOID_P == 4
3135 s = bstream_create(ss, 0x20000);
3136#else
3137 s = bstream_create(ss, 0x200000);
3138#endif
3139 if (s != NULL) {
3140 msg = mvc_import_table(cntxt, &b, be->mvc, s, t, tsep, rsep, ssep, ns, sz, offset, locked, besteffort, false);
3141 if (onclient) {
3142 mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1);
3143 mnstr_flush(be->mvc->scanner.ws);
3144 be->mvc->scanner.rs->eof = s->eof;
3145 s->s = NULL;
3146 }
3147 bstream_destroy(s);
3148 }
3149 }
3150 if (fname && s == NULL)
3151 throw(IO, "bstreams.create", SQLSTATE(42000) "Failed to create block stream");
3152 if (b == NULL)
3153 throw(SQL, "importTable", SQLSTATE(42000) "Failed to import table '%s', %s", t->base.name, be->mvc->errstr);
3154 bat2return(stk, pci, b);
3155 GDKfree(b);
3156 return msg;
3157}
3158
3159static bool
3160read_more(bstream *in, stream *out)
3161{
3162 do {
3163 if (bstream_next(in) < 0)
3164 return false;
3165 if (in->eof) {
3166 if (mnstr_write(out, PROMPT2, sizeof(PROMPT2) - 1, 1) != 1
3167 || mnstr_flush(out) < 0)
3168 return false;
3169 in->eof = false;
3170 if (bstream_next(in) <= 0)
3171 return false;
3172 }
3173 } while (in->len <= in->pos);
3174 return true;
3175}
3176
3177static BAT *
3178BATattach_bstream(int tt, bstream *in, stream *out, BUN size)
3179{
3180 BAT *bn;
3181 size_t n;
3182 size_t asz = (size_t) ATOMsize(tt);
3183
3184 bn = COLnew(0, tt, size, TRANSIENT);
3185 if (bn == NULL)
3186 return NULL;
3187
3188 if (ATOMstorage(tt) < TYPE_str) {
3189 while (read_more(in, out)) {
3190 n = (in->len - in->pos) / asz;
3191 if (BATextend(bn, bn->batCount + n) != GDK_SUCCEED) {
3192 BBPreclaim(bn);
3193 return NULL;
3194 }
3195 memcpy(Tloc(bn, bn->batCount), in->buf + in->pos, n * asz);
3196 bn->batCount += (BUN) n;
3197 in->pos += n * asz;
3198 }
3199 BATsetcount(bn, bn->batCount);
3200 bn->tseqbase = oid_nil;
3201 bn->tnonil = bn->batCount == 0;
3202 bn->tnil = false;
3203 if (bn->batCount <= 1) {
3204 bn->tsorted = true;
3205 bn->trevsorted = true;
3206 bn->tkey = true;
3207 } else {
3208 bn->tsorted = false;
3209 bn->trevsorted = false;
3210 bn->tkey = false;
3211 }
3212 } else {
3213 assert(ATOMstorage(tt) == TYPE_str);
3214 while (read_more(in, out)) {
3215 int u;
3216 for (n = in->pos, u = 0; n < in->len; n++) {
3217 int c = in->buf[n];
3218 if (u) {
3219 if ((c & 0xC0) == 0x80)
3220 u--;
3221 else
3222 goto bailout;
3223 } else if ((c & 0xF8) == 0xF0) {
3224 u = 3;
3225 } else if ((c & 0xF0) == 0xE0) {
3226 u = 2;
3227 } else if ((c & 0xE0) == 0xC0) {
3228 u = 1;
3229 } else if ((c & 0xC0) == 0x80) {
3230 goto bailout;
3231 } else if (c == '\r') {
3232 if (n + 1 < in->len
3233 && in->buf[n + 1] == '\n') {
3234 in->buf[n] = 0;
3235 if (BUNappend(bn, in->buf + in->pos, false) != GDK_SUCCEED)
3236 goto bailout;
3237 in->buf[n] = '\r';
3238 in->pos = n + 2;
3239 n++;
3240 }
3241 } else if (c == '\n' || c == '\0') {
3242 in->buf[n] = 0;
3243 if (BUNappend(bn, in->buf + in->pos, false) != GDK_SUCCEED)
3244 goto bailout;
3245 in->buf[n] = c;
3246 in->pos = n + 1;
3247 }
3248 }
3249 }
3250 }
3251 return bn;
3252
3253 bailout:
3254 BBPreclaim(bn);
3255 return NULL;
3256}
3257
3258/* str mvc_bin_import_table_wrap(.., str *sname, str *tname, str *fname..);
3259 * binary attachment only works for simple binary types.
3260 * Non-simple types require each line to contain a valid ascii representation
3261 * of the text terminate by a new-line. These strings are passed to the corresponding
3262 * atom conversion routines to fill the column.
3263 */
3264str
3265mvc_bin_import_table_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3266{
3267 mvc *m = NULL;
3268 str msg;
3269 BUN cnt = 0;
3270 bool init = false;
3271 int i;
3272 const char *sname = *getArgReference_str(stk, pci, 0 + pci->retc);
3273 const char *tname = *getArgReference_str(stk, pci, 1 + pci->retc);
3274 int onclient = *getArgReference_int(stk, pci, 2 + pci->retc);
3275 sql_schema *s;
3276 sql_table *t;
3277 node *n;
3278
3279 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
3280 return msg;
3281 if ((msg = checkSQLContext(cntxt)) != NULL)
3282 return msg;
3283
3284 if ((s = mvc_bind_schema(m, sname)) == NULL)
3285 throw(SQL, "sql.import_table", SQLSTATE(3F000) "Schema missing %s",sname);
3286 t = mvc_bind_table(m, s, tname);
3287 if (!t)
3288 throw(SQL, "sql", SQLSTATE(42S02) "Table missing %s", tname);
3289 if (list_length(t->columns.set) != (pci->argc - (3 + pci->retc)))
3290 throw(SQL, "sql", SQLSTATE(42000) "Not enough columns found in input file");
3291 if (2 * pci->retc + 3 != pci->argc)
3292 throw(SQL, "sql", SQLSTATE(42000) "Not enough output values");
3293
3294 if (onclient && !cntxt->filetrans) {
3295 throw(MAL, "sql.copy_from", "cannot transfer files from client");
3296 }
3297
3298 backend *be = cntxt->sqlcontext;
3299
3300 for (i = 0; i < pci->retc; i++)
3301 *getArgReference_bat(stk, pci, i) = 0;
3302
3303 for (i = pci->retc + 3, n = t->columns.set->h; i < pci->argc && n; i++, n = n->next) {
3304 sql_column *col = n->data;
3305 BAT *c = NULL;
3306 int tpe = col->type.type->localtype;
3307 const char *fname = *getArgReference_str(stk, pci, i);
3308
3309 /* handle the various cases */
3310 if (strcmp(fname, str_nil) == 0) {
3311 // no filename for this column, skip for now because we potentially don't know the count yet
3312 continue;
3313 }
3314 if (ATOMvarsized(tpe) && tpe != TYPE_str) {
3315 msg = createException(SQL, "sql", SQLSTATE(42000) "Failed to attach file %s", *getArgReference_str(stk, pci, i));
3316 goto bailout;
3317 }
3318
3319 if (tpe <= TYPE_str || tpe == TYPE_date || tpe == TYPE_daytime || tpe == TYPE_timestamp) {
3320 if (onclient) {
3321 mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1);
3322 mnstr_printf(be->mvc->scanner.ws, "rb %s\n", fname);
3323 msg = MAL_SUCCEED;
3324 mnstr_flush(be->mvc->scanner.ws);
3325 while (!be->mvc->scanner.rs->eof)
3326 bstream_next(be->mvc->scanner.rs);
3327 stream *ss = be->mvc->scanner.rs->s;
3328 char buf[80];
3329 if (mnstr_readline(ss, buf, sizeof(buf)) > 1) {
3330 msg = createException(IO, "sql.attach", "%s", buf);
3331 goto bailout;
3332 }
3333 bstream *s = bstream_create(ss, 1 << 20);
3334
3335 c = BATattach_bstream(col->type.type->localtype, s, be->mvc->scanner.ws, cnt);
3336 mnstr_write(be->mvc->scanner.ws, PROMPT3, sizeof(PROMPT3)-1, 1);
3337 mnstr_flush(be->mvc->scanner.ws);
3338 be->mvc->scanner.rs->eof = s->eof;
3339 s->s = NULL;
3340 bstream_destroy(s);
3341 } else if (tpe == TYPE_str) {
3342 /* get the BAT and fill it with the strings */
3343 c = COLnew(0, TYPE_str, 0, TRANSIENT);
3344 if (c == NULL) {
3345 msg = createException(SQL, "sql", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3346 goto bailout;
3347 }
3348 /* this code should be extended to
3349 * deal with larger text strings. */
3350 FILE *f = fopen(fname, "r");
3351 if (f == NULL) {
3352 BBPreclaim(c);
3353 msg = createException(SQL, "sql", SQLSTATE(42000) "Failed to re-open file %s", fname);
3354 goto bailout;
3355 }
3356
3357#define bufsiz (128 * BLOCK)
3358 char *buf = GDKmalloc(bufsiz);
3359 if (buf == NULL) {
3360 fclose(f);
3361 BBPreclaim(c);
3362 msg = createException(SQL, "sql", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3363 goto bailout;
3364 }
3365 while (fgets(buf, bufsiz, f) != NULL) {
3366 char *t = strrchr(buf, '\n');
3367 if (t)
3368 *t = 0;
3369 if (BUNappend(c, buf, false) != GDK_SUCCEED) {
3370 BBPreclaim(c);
3371 fclose(f);
3372 msg = createException(SQL, "sql", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3373 goto bailout;
3374 }
3375 }
3376#undef bufsiz
3377 fclose(f);
3378 GDKfree(buf);
3379 } else {
3380 c = BATattach(tpe, fname, TRANSIENT);
3381 }
3382 if (c == NULL) {
3383 msg = createException(SQL, "sql", SQLSTATE(42000) "Failed to attach file %s", fname);
3384 goto bailout;
3385 }
3386 if (BATsetaccess(c, BAT_READ) != GDK_SUCCEED) {
3387 BBPreclaim(c);
3388 msg = createException(SQL, "sql", SQLSTATE(42000) "Failed to set internal access while attaching file %s", fname);
3389 goto bailout;
3390 }
3391 } else {
3392 msg = createException(SQL, "sql", SQLSTATE(42000) "Failed to attach file %s", fname);
3393 goto bailout;
3394 }
3395 if (init && cnt != BATcount(c)) {
3396 BBPunfix(c->batCacheid);
3397 msg = createException(SQL, "sql", SQLSTATE(42000) "Binary files for table '%s' have inconsistent counts", tname);
3398 goto bailout;
3399 }
3400 cnt = BATcount(c);
3401 init = true;
3402 *getArgReference_bat(stk, pci, i - (3 + pci->retc)) = c->batCacheid;
3403 BBPkeepref(c->batCacheid);
3404 }
3405 if (init) {
3406 for (i = pci->retc + 3, n = t->columns.set->h; i < pci->argc && n; i++, n = n->next) {
3407 // now that we know the BAT count, we can fill in the columns for which no parameters were passed
3408 sql_column *col = n->data;
3409 BAT *c = NULL;
3410 int tpe = col->type.type->localtype;
3411
3412 const char *fname = *getArgReference_str(stk, pci, i);
3413 if (strcmp(fname, str_nil) == 0) {
3414 // fill the new BAT with NULL values
3415 c = BATconstant(0, tpe, ATOMnilptr(tpe), cnt, TRANSIENT);
3416 if (c == NULL) {
3417 msg = createException(SQL, "sql", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3418 goto bailout;
3419 }
3420 *getArgReference_bat(stk, pci, i - (3 + pci->retc)) = c->batCacheid;
3421 BBPkeepref(c->batCacheid);
3422 }
3423 }
3424 }
3425 return MAL_SUCCEED;
3426 bailout:
3427 for (i = 0; i < pci->retc; i++) {
3428 bat bid;
3429 if ((bid = *getArgReference_bat(stk, pci, i)) != 0) {
3430 BBPrelease(bid);
3431 *getArgReference_bat(stk, pci, i) = 0;
3432 }
3433 }
3434 return msg;
3435}
3436
3437str
3438not_unique(bit *ret, const bat *bid)
3439{
3440 BAT *b;
3441
3442 if ((b = BATdescriptor(*bid)) == NULL) {
3443 throw(SQL, "not_unique", SQLSTATE(HY005) "Cannot access column descriptor");
3444 }
3445
3446 *ret = FALSE;
3447 if (BATtkey(b) || BATtdense(b) || BATcount(b) <= 1) {
3448 BBPunfix(b->batCacheid);
3449 return MAL_SUCCEED;
3450 } else if (b->tsorted) {
3451 BUN p, q;
3452 oid c = *(oid *) Tloc(b, 0);
3453
3454 for (p = 1, q = BUNlast(b); p < q; p++) {
3455 oid v = *(oid *) Tloc(b, p);
3456 if (v <= c) {
3457 *ret = TRUE;
3458 break;
3459 }
3460 c = v;
3461 }
3462 } else {
3463 BBPunfix(b->batCacheid);
3464 throw(SQL, "not_unique", SQLSTATE(42000) "Input column should be sorted");
3465 }
3466 BBPunfix(b->batCacheid);
3467 return MAL_SUCCEED;
3468}
3469
3470/* row case */
3471str
3472SQLidentity(oid *ret, const void *i)
3473{
3474 (void)i;
3475 *ret = 0;
3476 return MAL_SUCCEED;
3477}
3478
3479str
3480BATSQLidentity(bat *ret, const bat *bid)
3481{
3482 return BKCmirror(ret, bid);
3483}
3484
3485str
3486PBATSQLidentity(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3487{
3488 bat *res = getArgReference_bat(stk, pci, 0);
3489 oid *ns = getArgReference_oid(stk, pci, 1);
3490 bat bid = *getArgReference_bat(stk, pci, 2);
3491 oid s = *getArgReference_oid(stk, pci, 3);
3492 BAT *b, *bn = NULL;
3493
3494 (void) cntxt;
3495 (void) mb;
3496 if ((b = BATdescriptor(bid)) == NULL) {
3497 throw(MAL, "batcalc.identity", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
3498 }
3499 bn = BATdense(b->hseqbase, s, BATcount(b));
3500 if (bn != NULL) {
3501 *ns = s + BATcount(b);
3502 BBPunfix(b->batCacheid);
3503 BBPkeepref(*res = bn->batCacheid);
3504 return MAL_SUCCEED;
3505 }
3506 BBPunfix(b->batCacheid);
3507 throw(MAL, "batcalc.identity", SQLSTATE(45001) "Internal error");
3508
3509}
3510
3511/*
3512 * The core modules of Monet provide just a limited set of
3513 * mathematical operators. The extensions required to support
3514 * SQL-99 are shown below. At some point they also should be
3515 * moved to module code base.
3516 */
3517
3518str
3519daytime_2time_daytime(daytime *res, const daytime *v, const int *digits)
3520{
3521 int d = (*digits) ? *digits - 1 : 0;
3522
3523 /* correct fraction */
3524 *res = *v;
3525 if (!is_daytime_nil(*v) && d < 6) {
3526#ifdef TRUNCATE_NUMBERS
3527 *res = (daytime) (*res / scales[6 - d]);
3528#else
3529 *res = (daytime) ((*res + scales[5 - d]*5) / scales[6 - d]);
3530#endif
3531 *res = (daytime) (*res * scales[6 - d]);
3532 }
3533 return MAL_SUCCEED;
3534}
3535
3536str
3537second_interval_2_daytime(daytime *res, const lng *s, const int *digits)
3538{
3539 daytime d;
3540 d = daytime_add_usec(daytime_create(0, 0, 0, 0), *s * 1000);
3541 return daytime_2time_daytime(res, &d, digits);
3542}
3543
3544str
3545nil_2time_daytime(daytime *res, const void *v, const int *digits)
3546{
3547 (void) digits;
3548 (void) v;
3549 *res = daytime_nil;
3550 return MAL_SUCCEED;
3551}
3552
3553str
3554str_2time_daytimetz(daytime *res, const str *v, const int *digits, int *tz)
3555{
3556 size_t len = sizeof(daytime);
3557 ssize_t pos;
3558
3559 if (!*v || strcmp(str_nil, *v) == 0) {
3560 *res = daytime_nil;
3561 return MAL_SUCCEED;
3562 }
3563 if (*tz)
3564 pos = daytime_tz_fromstr(*v, &len, &res, false);
3565 else
3566 pos = daytime_fromstr(*v, &len, &res, false);
3567 if (pos < (ssize_t) strlen(*v) || /* includes pos < 0 */
3568 ATOMcmp(TYPE_daytime, res, ATOMnilptr(TYPE_daytime)) == 0)
3569 throw(SQL, "daytime", SQLSTATE(22007) "Daytime (%s) has incorrect format", *v);
3570 return daytime_2time_daytime(res, res, digits);
3571}
3572
3573str
3574str_2time_daytime(daytime *res, const str *v, const int *digits)
3575{
3576 int zero = 0;
3577 return str_2time_daytimetz(res, v, digits, &zero);
3578}
3579
3580str
3581timestamp_2_daytime(daytime *res, const timestamp *v, const int *digits)
3582{
3583 int d = (*digits) ? *digits - 1 : 0;
3584 daytime dt;
3585
3586 dt = timestamp_daytime(*v);
3587
3588 /* correct fraction */
3589 if (!is_daytime_nil(dt) && d < 6) {
3590#ifdef TRUNCATE_NUMBERS
3591 dt /= scales[6 - d];
3592#else
3593 dt = (dt + scales[5 - d]*5) / scales[6 - d];
3594#endif
3595 dt *= scales[6 - d];
3596 }
3597 *res = dt;
3598 return MAL_SUCCEED;
3599}
3600
3601str
3602date_2_timestamp(timestamp *res, const date *v, const int *digits)
3603{
3604 (void) digits; /* no precision needed */
3605 *res = timestamp_fromdate(*v);
3606 return MAL_SUCCEED;
3607}
3608
3609str
3610timestamp_2time_timestamp(timestamp *res, const timestamp *v, const int *digits)
3611{
3612 int d = (*digits) ? *digits - 1 : 0;
3613 date dt;
3614 daytime tm;
3615
3616 dt = timestamp_date(*v);
3617 tm = timestamp_daytime(*v);
3618 /* correct fraction */
3619 if (!is_daytime_nil(tm) && d < 6) {
3620#ifdef TRUNCATE_NUMBERS
3621 tm /= scales[6 - d];
3622#else
3623 tm = (tm + scales[5 - d]*5) / scales[6 - d];
3624#endif
3625 tm *= scales[6 - d];
3626 }
3627 *res = timestamp_create(dt, tm);
3628 return MAL_SUCCEED;
3629}
3630
3631str
3632nil_2time_timestamp(timestamp *res, const void *v, const int *digits)
3633{
3634 (void) digits;
3635 (void) v;
3636 *res = timestamp_nil;
3637 return MAL_SUCCEED;
3638}
3639
3640str
3641str_2time_timestamptz(timestamp *res, const str *v, const int *digits, int *tz)
3642{
3643 size_t len = sizeof(timestamp);
3644 ssize_t pos;
3645
3646 if (!*v || strcmp(str_nil, *v) == 0) {
3647 *res = timestamp_nil;
3648 return MAL_SUCCEED;
3649 }
3650 if (*tz)
3651 pos = timestamp_tz_fromstr(*v, &len, &res, false);
3652 else
3653 pos = timestamp_fromstr(*v, &len, &res, false);
3654 if (!pos || pos < (ssize_t) strlen(*v) || ATOMcmp(TYPE_timestamp, res, ATOMnilptr(TYPE_timestamp)) == 0)
3655 throw(SQL, "timestamp", SQLSTATE(22007) "Timestamp (%s) has incorrect format", *v);
3656 return timestamp_2time_timestamp(res, res, digits);
3657}
3658
3659str
3660str_2time_timestamp(timestamp *res, const str *v, const int *digits)
3661{
3662 int zero = 0;
3663 return str_2time_timestamptz(res, v, digits, &zero);
3664}
3665
3666str
3667SQLcst_alpha_cst(dbl *res, const dbl *decl, const dbl *theta)
3668{
3669 dbl s, c1, c2;
3670 char *msg = MAL_SUCCEED;
3671 if (is_dbl_nil(*decl) || is_dbl_nil(*theta)) {
3672 *res = dbl_nil;
3673 } else if (fabs(*decl) + *theta > 89.9) {
3674 *res = 180.0;
3675 } else {
3676 s = sin(radians(*theta));
3677 c1 = cos(radians(*decl - *theta));
3678 c2 = cos(radians(*decl + *theta));
3679 *res = degrees(fabs(atan(s / sqrt(fabs(c1 * c2)))));
3680 }
3681 return msg;
3682}
3683
3684/*
3685 sql5_export str SQLcst_alpha_cst(dbl *res, dbl *decl, dbl *theta);
3686 sql5_export str SQLbat_alpha_cst(bat *res, bat *decl, dbl *theta);
3687 sql5_export str SQLcst_alpha_bat(bat *res, dbl *decl, bat *theta);
3688*/
3689str
3690SQLbat_alpha_cst(bat *res, const bat *decl, const dbl *theta)
3691{
3692 BAT *b, *bn;
3693 BUN p, q;
3694 dbl s, c1, c2, r;
3695 char *msg = NULL;
3696
3697 if (is_dbl_nil(*theta)) {
3698 throw(SQL, "SQLbat_alpha", SQLSTATE(42000) "Parameter theta should not be nil");
3699 }
3700 if ((b = BATdescriptor(*decl)) == NULL) {
3701 throw(SQL, "alpha", SQLSTATE(HY005) "Cannot access column descriptor");
3702 }
3703 bn = COLnew(b->hseqbase, TYPE_dbl, BATcount(b), TRANSIENT);
3704 if (bn == NULL) {
3705 BBPunfix(b->batCacheid);
3706 throw(SQL, "sql.alpha", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3707 }
3708 s = sin(radians(*theta));
3709 const dbl *vals = (const dbl *) Tloc(b, 0);
3710 BATloop(b, p, q) {
3711 dbl d = vals[p];
3712 if (is_dbl_nil(d))
3713 r = dbl_nil;
3714 else if (fabs(d) + *theta > 89.9)
3715 r = 180.0;
3716 else {
3717 c1 = cos(radians(d - *theta));
3718 c2 = cos(radians(d + *theta));
3719 r = degrees(fabs(atan(s / sqrt(fabs(c1 * c2)))));
3720 }
3721 if (BUNappend(bn, &r, false) != GDK_SUCCEED) {
3722 BBPreclaim(bn);
3723 throw(SQL, "sql.alpha", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3724 }
3725 }
3726 *res = bn->batCacheid;
3727 BBPkeepref(bn->batCacheid);
3728 BBPunfix(b->batCacheid);
3729 return msg;
3730}
3731
3732str
3733SQLcst_alpha_bat(bat *res, const dbl *decl, const bat *thetabid)
3734{
3735 BAT *b, *bn;
3736 BUN p, q;
3737 dbl s, c1, c2, r;
3738 char *msg = NULL;
3739 dbl *thetas;
3740
3741 if ((b = BATdescriptor(*thetabid)) == NULL) {
3742 throw(SQL, "alpha", SQLSTATE(HY005) "Cannot access column descriptor");
3743 }
3744 thetas = (dbl *) Tloc(b, 0);
3745 bn = COLnew(b->hseqbase, TYPE_dbl, BATcount(b), TRANSIENT);
3746 if (bn == NULL) {
3747 BBPunfix(b->batCacheid);
3748 throw(SQL, "sql.alpha", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3749 }
3750 BATloop(b, p, q) {
3751 dbl d = *decl;
3752 dbl theta = thetas[p];
3753
3754 if (is_dbl_nil(d))
3755 r = dbl_nil;
3756 else if (fabs(d) + theta > 89.9)
3757 r = (dbl) 180.0;
3758 else {
3759 s = sin(radians(theta));
3760 c1 = cos(radians(d - theta));
3761 c2 = cos(radians(d + theta));
3762 r = degrees(fabs(atan(s / sqrt(fabs(c1 * c2)))));
3763 }
3764 if (BUNappend(bn, &r, false) != GDK_SUCCEED) {
3765 BBPreclaim(bn);
3766 throw(SQL, "sql.alpha", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3767 }
3768 }
3769 BBPkeepref(*res = bn->batCacheid);
3770 BBPunfix(b->batCacheid);
3771 return msg;
3772}
3773
3774str
3775month_interval_str(int *ret, const str *s, const int *d, const int *sk)
3776{
3777 lng res;
3778
3779 if (interval_from_str(*s, *d, *sk, &res) < 0)
3780 throw(SQL, "calc.month_interval", SQLSTATE(42000) "Wrong format (%s)", *s);
3781 assert((lng) GDK_int_min <= res && res <= (lng) GDK_int_max);
3782 *ret = (int) res;
3783 return MAL_SUCCEED;
3784}
3785
3786str
3787second_interval_str(lng *res, const str *s, const int *d, const int *sk)
3788{
3789 if (interval_from_str(*s, *d, *sk, res) < 0)
3790 throw(SQL, "calc.second_interval", SQLSTATE(42000) "Wrong format (%s)", *s);
3791 return MAL_SUCCEED;
3792}
3793
3794str
3795month_interval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3796{
3797 int *ret = getArgReference_int(stk, pci, 0);
3798 int k = digits2ek(*getArgReference_int(stk, pci, 2));
3799 int r;
3800
3801 (void) cntxt;
3802 (void) mb;
3803 switch (getArgType(mb, pci, 1)) {
3804 case TYPE_bte:
3805 r = stk->stk[getArg(pci, 1)].val.btval;
3806 break;
3807 case TYPE_sht:
3808 r = stk->stk[getArg(pci, 1)].val.shval;
3809 break;
3810 case TYPE_int:
3811 r = stk->stk[getArg(pci, 1)].val.ival;
3812 break;
3813 case TYPE_lng:
3814 r = (int) stk->stk[getArg(pci, 1)].val.lval;
3815 break;
3816#ifdef HAVE_HGE
3817 case TYPE_hge:
3818 r = (int) stk->stk[getArg(pci, 1)].val.hval;
3819 break;
3820#endif
3821 default:
3822 throw(ILLARG, "calc.month_interval", SQLSTATE(42000) "Illegal argument");
3823 }
3824 switch (k) {
3825 case iyear:
3826 r *= 12;
3827 break;
3828 case imonth:
3829 break;
3830 default:
3831 throw(ILLARG, "calc.month_interval", SQLSTATE(42000) "Illegal argument");
3832 }
3833 *ret = r;
3834 return MAL_SUCCEED;
3835}
3836
3837str
3838second_interval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3839{
3840 lng *ret = getArgReference_lng(stk, pci, 0), r;
3841 int k = digits2ek(*getArgReference_int(stk, pci, 2)), scale = 0, isnil = 0;
3842
3843 (void) cntxt;
3844 if (pci->argc > 3)
3845 scale = *getArgReference_int(stk, pci, 3);
3846 *ret = lng_nil;
3847 switch (getArgType(mb, pci, 1)) {
3848 case TYPE_bte:
3849 r = stk->stk[getArg(pci, 1)].val.btval;
3850 isnil = (stk->stk[getArg(pci, 1)].val.btval == bte_nil);
3851 break;
3852 case TYPE_sht:
3853 r = stk->stk[getArg(pci, 1)].val.shval;
3854 isnil = (stk->stk[getArg(pci, 1)].val.shval == sht_nil);
3855 break;
3856 case TYPE_int:
3857 r = stk->stk[getArg(pci, 1)].val.ival;
3858 isnil = (stk->stk[getArg(pci, 1)].val.ival == int_nil);
3859 break;
3860 case TYPE_lng:
3861 r = stk->stk[getArg(pci, 1)].val.lval;
3862 isnil = (stk->stk[getArg(pci, 1)].val.lval == lng_nil);
3863 break;
3864#ifdef HAVE_HGE
3865 case TYPE_hge:
3866 r = (lng) stk->stk[getArg(pci, 1)].val.hval;
3867 isnil = (stk->stk[getArg(pci, 1)].val.hval == hge_nil);
3868 break;
3869#endif
3870 default:
3871 throw(ILLARG, "calc.sec_interval", SQLSTATE(42000) "Illegal argument in second interval");
3872 }
3873 if (isnil)
3874 return MAL_SUCCEED;
3875 switch (k) {
3876 case iday:
3877 r *= 24;
3878 /* fall through */
3879 case ihour:
3880 r *= 60;
3881 /* fall through */
3882 case imin:
3883 r *= 60;
3884 /* fall through */
3885 case isec:
3886 r *= 1000;
3887 break;
3888 default:
3889 throw(ILLARG, "calc.sec_interval", SQLSTATE(42000) "Illegal argument in second interval");
3890 }
3891 if (scale) {
3892#ifndef TRUNCATE_NUMBERS
3893 r += 5*scales[scale-1];
3894#endif
3895 r /= scales[scale];
3896 }
3897 *ret = r;
3898 return MAL_SUCCEED;
3899}
3900
3901str
3902second_interval_daytime(lng *res, const daytime *s, const int *d, const int *sk)
3903{
3904 int k = digits2sk(*d);
3905 lng r = *(int *) s;
3906
3907 (void) sk;
3908 if (is_daytime_nil(*s)) {
3909 *res = lng_nil;
3910 return MAL_SUCCEED;
3911 }
3912 switch (k) {
3913 case isec:
3914 break;
3915 case imin:
3916 r /= 60000;
3917 r *= 60000;
3918 break;
3919 case ihour:
3920 r /= 3600000;
3921 r *= 3600000;
3922 break;
3923 case iday:
3924 r /= (24 * 3600000);
3925 r *= (24 * 3600000);
3926 break;
3927 default:
3928 throw(ILLARG, "calc.second_interval", SQLSTATE(42000) "Illegal argument in daytime interval");
3929 }
3930 *res = r;
3931 return MAL_SUCCEED;
3932}
3933
3934str
3935SQLcurrent_daytime(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3936{
3937 mvc *m = NULL;
3938 str msg;
3939 daytime *res = getArgReference_TYPE(stk, pci, 0, daytime);
3940
3941 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
3942 return msg;
3943
3944 *res = timestamp_daytime(timestamp_add_usec(timestamp_current(),
3945 m->timezone * LL_CONSTANT(1000)));
3946 return msg;
3947}
3948
3949str
3950SQLcurrent_timestamp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3951{
3952 mvc *m = NULL;
3953 str msg;
3954 timestamp *res = getArgReference_TYPE(stk, pci, 0, timestamp);
3955
3956 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
3957 return msg;
3958
3959 *res = timestamp_add_usec(timestamp_current(), m->timezone * LL_CONSTANT(1000));
3960 return msg;
3961}
3962
3963/* str dump_cache(int *r); */
3964str
3965dump_cache(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
3966{
3967 mvc *m = NULL;
3968 str msg;
3969 int cnt;
3970 cq *q = NULL;
3971 BAT *query, *count;
3972 bat *rquery = getArgReference_bat(stk, pci, 0);
3973 bat *rcount = getArgReference_bat(stk, pci, 1);
3974
3975 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
3976 return msg;
3977 if ((msg = checkSQLContext(cntxt)) != NULL)
3978 return msg;
3979 cnt = m->qc->id;
3980 query = COLnew(0, TYPE_str, cnt, TRANSIENT);
3981 if (query == NULL)
3982 throw(SQL, "sql.dumpcache", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3983 count = COLnew(0, TYPE_int, cnt, TRANSIENT);
3984 if (count == NULL) {
3985 BBPunfix(query->batCacheid);
3986 throw(SQL, "sql.dumpcache", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3987 }
3988
3989 for (q = m->qc->q; q; q = q->next) {
3990 if (!q->prepared) {
3991 if (BUNappend(query, q->codestring, false) != GDK_SUCCEED ||
3992 BUNappend(count, &q->count, false) != GDK_SUCCEED) {
3993 BBPunfix(query->batCacheid);
3994 BBPunfix(count->batCacheid);
3995 throw(SQL, "sql.dumpcache", SQLSTATE(HY001) MAL_MALLOC_FAIL);
3996 }
3997 }
3998 }
3999 *rquery = query->batCacheid;
4000 *rcount = count->batCacheid;
4001 BBPkeepref(*rquery);
4002 BBPkeepref(*rcount);
4003 return MAL_SUCCEED;
4004}
4005
4006/* str dump_opt_stats(int *r); */
4007str
4008dump_opt_stats(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4009{
4010 mvc *m = NULL;
4011 str msg;
4012 int cnt;
4013 BAT *rewrite, *count;
4014 bat *rrewrite = getArgReference_bat(stk, pci, 0);
4015 bat *rcount = getArgReference_bat(stk, pci, 1);
4016
4017 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL ||
4018 (msg = checkSQLContext(cntxt)) != NULL)
4019 return msg;
4020 cnt = m->qc->id;
4021 rewrite = COLnew(0, TYPE_str, cnt, TRANSIENT);
4022 count = COLnew(0, TYPE_int, cnt, TRANSIENT);
4023 if (rewrite == NULL || count == NULL) {
4024 BBPreclaim(rewrite);
4025 BBPreclaim(count);
4026 throw(SQL, "sql.optstats", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4027 }
4028
4029 if (BUNappend(rewrite, "joinidx", false) != GDK_SUCCEED ||
4030 BUNappend(count, &m->opt_stats[0], false) != GDK_SUCCEED) {
4031 BBPreclaim(rewrite);
4032 BBPreclaim(count);
4033 throw(SQL, "sql.optstats", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4034 }
4035 /* TODO add other rewrites */
4036
4037 *rrewrite = rewrite->batCacheid;
4038 *rcount = count->batCacheid;
4039 BBPkeepref(*rrewrite);
4040 BBPkeepref(*rcount);
4041 return MAL_SUCCEED;
4042}
4043
4044/* str dump_opt_stats(int *r); */
4045str
4046dump_trace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4047{
4048 int i;
4049 BAT *t[2];
4050 bat id;
4051
4052 (void) cntxt;
4053 (void) mb;
4054 if (TRACEtable(cntxt, t) != 2)
4055 throw(SQL, "sql.dump_trace", SQLSTATE(3F000) "Profiler not started");
4056 for(i=0; i< 2; i++)
4057 if( t[i]){
4058 id = t[i]->batCacheid;
4059 *getArgReference_bat(stk, pci, i) = id;
4060 BBPkeepref(id);
4061 } else
4062 throw(SQL,"dump_trace", SQLSTATE(45000) "Missing trace BAT ");
4063 return MAL_SUCCEED;
4064}
4065
4066str
4067sql_sessions_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4068{
4069 return CLTsessions(cntxt, mb, stk, pci);
4070}
4071
4072str
4073sql_rt_credentials_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4074{
4075 BAT *urib = NULL;
4076 BAT *unameb = NULL;
4077 BAT *hashb = NULL;
4078 bat *uri = getArgReference_bat(stk, pci, 0);
4079 bat *uname = getArgReference_bat(stk, pci, 1);
4080 bat *hash = getArgReference_bat(stk, pci, 2);
4081 str *table = getArgReference_str(stk, pci, 3);
4082 str uris;
4083 str unames;
4084 str hashs = NULL;
4085 str msg = MAL_SUCCEED;
4086 (void)mb;
4087 (void)cntxt;
4088
4089 urib = COLnew(0, TYPE_str, 0, TRANSIENT);
4090 unameb = COLnew(0, TYPE_str, 0, TRANSIENT);
4091 hashb = COLnew(0, TYPE_str, 0, TRANSIENT);
4092
4093 if (urib == NULL || unameb == NULL || hashb == NULL) {
4094 msg = createException(SQL, "sql.remote_table_credentials", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4095 goto bailout;
4096 }
4097
4098 if ((msg = AUTHgetRemoteTableCredentials(*table, &uris, &unames, &hashs)) != MAL_SUCCEED)
4099 goto bailout;
4100
4101 MT_lock_set(&mal_contextLock);
4102 if (BUNappend(urib, uris, false) != GDK_SUCCEED)
4103 goto lbailout;
4104 if (BUNappend(unameb, unames, false) != GDK_SUCCEED)
4105 goto lbailout;
4106 if (BUNappend(hashb, hashs, false) != GDK_SUCCEED)
4107 goto lbailout;
4108 MT_lock_unset(&mal_contextLock);
4109 BBPkeepref(*uri = urib->batCacheid);
4110 BBPkeepref(*uname = unameb->batCacheid);
4111 BBPkeepref(*hash = hashb->batCacheid);
4112
4113 if (hashs) GDKfree(hashs);
4114 return MAL_SUCCEED;
4115
4116 lbailout:
4117 MT_lock_unset(&mal_contextLock);
4118 msg = createException(SQL, "sql.remote_table_credentials", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4119 bailout:
4120 if (hashs) GDKfree(hashs);
4121 if (urib) BBPunfix(urib->batCacheid);
4122 if (unameb) BBPunfix(unameb->batCacheid);
4123 if (hashb) BBPunfix(hashb->batCacheid);
4124 return msg;
4125}
4126
4127
4128str
4129sql_querylog_catalog(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4130{
4131 int i;
4132 BAT *t[8];
4133 str msg;
4134
4135 (void) cntxt;
4136 (void) mb;
4137 msg = QLOGcatalog(t);
4138 if( msg != MAL_SUCCEED)
4139 return msg;
4140 for (i = 0; i < 8; i++)
4141 if( t[i]){
4142 bat id = t[i]->batCacheid;
4143
4144 *getArgReference_bat(stk, pci, i) = id;
4145 BBPkeepref(id);
4146 } else
4147 throw(SQL,"sql.querylog", SQLSTATE(45000) "Missing query catalog BAT");
4148 return MAL_SUCCEED;
4149}
4150
4151str
4152sql_querylog_calls(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4153{
4154 int i;
4155 BAT *t[10];
4156 str msg;
4157
4158 (void) cntxt;
4159 (void) mb;
4160 msg = QLOGcalls(t);
4161 if( msg != MAL_SUCCEED)
4162 return msg;
4163 for (i = 0; i < 9; i++)
4164 if( t[i]){
4165 bat id = t[i]->batCacheid;
4166
4167 *getArgReference_bat(stk, pci, i) = id;
4168 BBPkeepref(id);
4169 } else
4170 throw(SQL,"sql.querylog", SQLSTATE(45000) "Missing query call BAT");
4171 return MAL_SUCCEED;
4172}
4173
4174str
4175sql_querylog_empty(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4176{
4177 (void) cntxt;
4178 (void) mb;
4179 (void) stk;
4180 (void) pci;
4181 return QLOGempty(NULL);
4182}
4183
4184/* str sql_rowid(oid *rid, ptr v, str *sname, str *tname); */
4185str
4186sql_rowid(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4187{
4188 BAT *b;
4189 mvc *m = NULL;
4190 str msg;
4191 sql_schema *s = NULL;
4192 sql_table *t = NULL;
4193 sql_column *c = NULL;
4194 sql_delta *d;
4195 oid *rid = getArgReference_oid(stk, pci, 0);
4196 const char *sname = *getArgReference_str(stk, pci, 2);
4197 const char *tname = *getArgReference_str(stk, pci, 3);
4198
4199 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4200 return msg;
4201 if ((msg = checkSQLContext(cntxt)) != NULL)
4202 return msg;
4203 s = mvc_bind_schema(m, sname);
4204 if (s == NULL)
4205 throw(SQL, "sql.rowid", SQLSTATE(3F000) "Schema missing %s", sname);
4206 t = mvc_bind_table(m, s, tname);
4207 if (t == NULL)
4208 throw(SQL, "sql.rowid", SQLSTATE(42S02) "Table missing %s.%s",sname,tname);
4209 if (!s || !t || !t->columns.set->h)
4210 throw(SQL, "calc.rowid", SQLSTATE(42S22) "Column missing %s.%s",sname,tname);
4211 c = t->columns.set->h->data;
4212 /* HACK, get insert bat */
4213 b = store_funcs.bind_col(m->session->tr, c, RD_INS);
4214 if( b == NULL)
4215 throw(SQL,"sql.rowid", SQLSTATE(HY005) "Canot access column descriptor");
4216 /* UGH (move into storage backends!!) */
4217 d = c->data;
4218 *rid = d->ibase + BATcount(b);
4219 BBPunfix(b->batCacheid);
4220 return MAL_SUCCEED;
4221}
4222
4223static str
4224do_sql_rank_grp(bat *rid, const bat *bid, const bat *gid, int nrank, int dense, const char *name)
4225{
4226 BAT *r, *b, *g;
4227 BUN p, q;
4228 BATiter bi, gi;
4229 int (*ocmp) (const void *, const void *);
4230 int (*gcmp) (const void *, const void *);
4231 const void *oc, *gc, *on, *gn;
4232 int rank = 1;
4233 int c;
4234
4235 if ((b = BATdescriptor(*bid)) == NULL)
4236 throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor");
4237 if ((g = BATdescriptor(*gid)) == NULL) {
4238 BBPunfix(b->batCacheid);
4239 throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor");
4240 }
4241 bi = bat_iterator(b);
4242 gi = bat_iterator(g);
4243 ocmp = ATOMcompare(b->ttype);
4244 gcmp = ATOMcompare(g->ttype);
4245 oc = BUNtail(bi, 0);
4246 gc = BUNtail(gi, 0);
4247 if (!ALIGNsynced(b, g)) {
4248 BBPunfix(b->batCacheid);
4249 BBPunfix(g->batCacheid);
4250 throw(SQL, name, SQLSTATE(45000) "Internal error, columns not aligned");
4251 }
4252/*
4253 if (!BATtordered(b)) {
4254 BBPunfix(b->batCacheid);
4255 BBPunfix(g->batCacheid);
4256 throw(SQL, name, SQLSTATE(45000) "Internal error, columns not sorted");
4257 }
4258*/
4259 r = COLnew(b->hseqbase, TYPE_int, BATcount(b), TRANSIENT);
4260 if (r == NULL) {
4261 BBPunfix(b->batCacheid);
4262 BBPunfix(g->batCacheid);
4263 throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
4264 }
4265 BATloop(b, p, q) {
4266 on = BUNtail(bi, p);
4267 gn = BUNtail(gi, p);
4268
4269 if ((c = ocmp(on, oc)) != 0)
4270 rank = nrank;
4271 if (gcmp(gn, gc) != 0)
4272 c = rank = nrank = 1;
4273 oc = on;
4274 gc = gn;
4275 if (BUNappend(r, &rank, false) != GDK_SUCCEED) {
4276 BBPunfix(b->batCacheid);
4277 BBPunfix(g->batCacheid);
4278 BBPunfix(r->batCacheid);
4279 throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
4280 }
4281 nrank += !dense || c;
4282 }
4283 BBPunfix(b->batCacheid);
4284 BBPunfix(g->batCacheid);
4285 BBPkeepref(*rid = r->batCacheid);
4286 return MAL_SUCCEED;
4287}
4288
4289static str
4290do_sql_rank(bat *rid, const bat *bid, int nrank, int dense, const char *name)
4291{
4292 BAT *r, *b;
4293 BATiter bi;
4294 int (*cmp) (const void *, const void *);
4295 const void *cur, *n;
4296 BUN p, q;
4297 int rank = 1;
4298 int c;
4299
4300 if ((b = BATdescriptor(*bid)) == NULL)
4301 throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor");
4302 if (!BATtordered(b) && !BATtrevordered(b)) {
4303 BBPunfix(b->batCacheid);
4304 throw(SQL, name, SQLSTATE(45000) "Internal error, columns not sorted");
4305 }
4306
4307 bi = bat_iterator(b);
4308 cmp = ATOMcompare(b->ttype);
4309 cur = BUNtail(bi, 0);
4310 r = COLnew(b->hseqbase, TYPE_int, BATcount(b), TRANSIENT);
4311 if (r == NULL) {
4312 BBPunfix(b->batCacheid);
4313 throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
4314 }
4315 if (BATtdense(b)) {
4316 BATloop(b, p, q) {
4317 if (BUNappend(r, &rank, false) != GDK_SUCCEED)
4318 goto bailout;
4319 rank++;
4320 }
4321 } else {
4322 BATloop(b, p, q) {
4323 n = BUNtail(bi, p);
4324 if ((c = cmp(n, cur)) != 0)
4325 rank = nrank;
4326 cur = n;
4327 if (BUNappend(r, &rank, false) != GDK_SUCCEED)
4328 goto bailout;
4329 nrank += !dense || c;
4330 }
4331 }
4332 BBPunfix(b->batCacheid);
4333 BBPkeepref(*rid = r->batCacheid);
4334 return MAL_SUCCEED;
4335 bailout:
4336 BBPunfix(b->batCacheid);
4337 BBPunfix(r->batCacheid);
4338 throw(SQL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
4339}
4340
4341str
4342sql_rank_grp(bat *rid, const bat *bid, const bat *gid, const bat *gpe)
4343{
4344 (void) gpe;
4345 return do_sql_rank_grp(rid, bid, gid, 1, 0, "sql.rank_grp");
4346}
4347
4348str
4349sql_dense_rank_grp(bat *rid, const bat *bid, const bat *gid, const bat *gpe)
4350{
4351 (void) gpe;
4352 return do_sql_rank_grp(rid, bid, gid, 2, 1, "sql.dense_rank_grp");
4353}
4354
4355str
4356sql_rank(bat *rid, const bat *bid)
4357{
4358 return do_sql_rank(rid, bid, 1, 0, "sql.rank");
4359}
4360
4361str
4362sql_dense_rank(bat *rid, const bat *bid)
4363{
4364 return do_sql_rank(rid, bid, 2, 1, "sql.dense_rank");
4365}
4366
4367str
4368SQLargRecord(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4369{
4370 str s, t, *ret;
4371
4372 (void) cntxt;
4373 ret = getArgReference_str(stk, pci, 0);
4374 s = instruction2str(mb, stk, getInstrPtr(mb, 0), LIST_MAL_ALL);
4375 if(s == NULL)
4376 throw(SQL, "sql.argRecord", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4377 t = strchr(s, ' ');
4378 *ret = GDKstrdup(t ? t + 1 : s);
4379 GDKfree(s);
4380 if(*ret == NULL)
4381 throw(SQL, "sql.argRecord", SQLSTATE(HY001) MAL_MALLOC_FAIL);
4382 return MAL_SUCCEED;
4383}
4384
4385/*
4386 * Vacuum cleaning tables
4387 * Shrinking and re-using space to vacuum clean the holes in the relations.
4388 */
4389static str
4390vacuum(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str (*func) (bat *, const bat *, const bat *), const char *name)
4391{
4392 const char *sch = *getArgReference_str(stk, pci, 1);
4393 const char *tbl = *getArgReference_str(stk, pci, 2);
4394 sql_trans *tr;
4395 sql_schema *s;
4396 sql_table *t;
4397 sql_column *c;
4398 mvc *m = NULL;
4399 str msg;
4400 bat bid;
4401 BAT *b, *del;
4402 node *o;
4403 int i, bids[2049];
4404
4405 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4406 return msg;
4407 if ((msg = checkSQLContext(cntxt)) != NULL)
4408 return msg;
4409 s = mvc_bind_schema(m, sch);
4410 if (s == NULL)
4411 throw(SQL, name, SQLSTATE(3F000) "Schema missing %s",sch);
4412 t = mvc_bind_table(m, s, tbl);
4413 if (t == NULL)
4414 throw(SQL, name, SQLSTATE(42S02) "Table missing %s.%s",sch,tbl);
4415
4416 if (m->user_id != USER_MONETDB)
4417 throw(SQL, name, SQLSTATE(42000) "Insufficient privileges");
4418 if ((!list_empty(t->idxs.set) || !list_empty(t->keys.set)))
4419 throw(SQL, name, SQLSTATE(42000) "%s not allowed on tables with indices", name + 4);
4420 if (t->system)
4421 throw(SQL, name, SQLSTATE(42000) "%s not allowed on system tables", name + 4);
4422
4423 if (has_snapshots(m->session->tr))
4424 throw(SQL, name, SQLSTATE(42000) "%s not allowed on snapshots", name + 4);
4425 if (!m->session->auto_commit)
4426 throw(SQL, name, SQLSTATE(42000) "%s only allowed in auto commit mode", name + 4);
4427
4428 tr = m->session->tr;
4429
4430 /* get the deletions BAT */
4431 del = mvc_bind_dbat(m, sch, tbl, RD_INS);
4432 if (BATcount(del) == 0) {
4433 BBPunfix(del->batCacheid);
4434 return MAL_SUCCEED;
4435 }
4436
4437
4438 i = 0;
4439 bids[i] = 0;
4440 for (o = t->columns.set->h; o; o = o->next, i++) {
4441 c = o->data;
4442 b = store_funcs.bind_col(tr, c, RDONLY);
4443 if (b == NULL || (msg = (*func) (&bid, &b->batCacheid, &del->batCacheid)) != NULL) {
4444 for (i--; i >= 0; i--)
4445 BBPrelease(bids[i]);
4446 if (b)
4447 BBPunfix(b->batCacheid);
4448 BBPunfix(del->batCacheid);
4449 if (!msg)
4450 throw(SQL, name, SQLSTATE(HY005) "Cannot access column descriptor");
4451 return msg;
4452 }
4453 BBPunfix(b->batCacheid);
4454 if (i < 2048) {
4455 bids[i] = bid;
4456 bids[i + 1] = 0;
4457 }
4458 }
4459 if (i >= 2048) {
4460 for (i--; i >= 0; i--)
4461 BBPrelease(bids[i]);
4462 throw(SQL, name, SQLSTATE(42000) "Too many columns to handle, use copy instead");
4463 }
4464 BBPunfix(del->batCacheid);
4465
4466 mvc_clear_table(m, t);
4467 for (o = t->columns.set->h, i = 0; o; o = o->next, i++) {
4468 sql_column *c = o->data;
4469 BAT *ins = BATdescriptor(bids[i]); /* use the insert bat */
4470
4471 if( ins){
4472 store_funcs.append_col(tr, c, ins, TYPE_bat);
4473 BBPunfix(ins->batCacheid);
4474 }
4475 BBPrelease(bids[i]);
4476 }
4477 /* TODO indices */
4478 return MAL_SUCCEED;
4479}
4480
4481str
4482SQLshrink(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4483{
4484 return vacuum(cntxt, mb, stk, pci, BKCshrinkBAT, "sql.shrink");
4485}
4486
4487str
4488SQLreuse(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4489{
4490 return vacuum(cntxt, mb, stk, pci, BKCreuseBAT, "sql.reuse");
4491}
4492
4493/*
4494 * The vacuum operation inspects the table for ordered properties and
4495 * will keep them. To avoid expensive shuffles, the reorganisation is
4496 * balanced by the number of outstanding deletions.
4497 */
4498str
4499SQLvacuum(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4500{
4501 const char *sch = *getArgReference_str(stk, pci, 1);
4502 const char *tbl = *getArgReference_str(stk, pci, 2);
4503 sql_trans *tr;
4504 sql_schema *s;
4505 sql_table *t;
4506 sql_column *c;
4507 mvc *m = NULL;
4508 str msg;
4509 BAT *b, *del;
4510 node *o;
4511 int ordered = 0;
4512 BUN cnt = 0;
4513 BUN dcnt;
4514
4515 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4516 return msg;
4517 if ((msg = checkSQLContext(cntxt)) != NULL)
4518 return msg;
4519 s = mvc_bind_schema(m, sch);
4520 if (s == NULL)
4521 throw(SQL, "sql.vacuum", SQLSTATE(3F000) "Schema missing %s",sch);
4522 t = mvc_bind_table(m, s, tbl);
4523 if (t == NULL)
4524 throw(SQL, "sql.vacuum", SQLSTATE(42S02) "Table missing %s.%s",sch,tbl);
4525
4526 if (m->user_id != USER_MONETDB)
4527 throw(SQL, "sql.vacuum", SQLSTATE(42000) "insufficient privileges");
4528 if ((!list_empty(t->idxs.set) || !list_empty(t->keys.set)))
4529 throw(SQL, "sql.vacuum", SQLSTATE(42000) "vacuum not allowed on tables with indices");
4530 if (t->system)
4531 throw(SQL, "sql.vacuum", SQLSTATE(42000) "vacuum not allowed on system tables");
4532
4533 if (has_snapshots(m->session->tr))
4534 throw(SQL, "sql.vacuum", SQLSTATE(42000) "vacuum not allowed on snapshots");
4535
4536 if (!m->session->auto_commit)
4537 throw(SQL, "sql.vacuum", SQLSTATE(42000) "vacuum only allowed in auto commit mode");
4538 tr = m->session->tr;
4539
4540 for (o = t->columns.set->h; o && ordered == 0; o = o->next) {
4541 c = o->data;
4542 b = store_funcs.bind_col(tr, c, RDONLY);
4543 if (b == NULL)
4544 throw(SQL, "sql.vacuum", SQLSTATE(HY005) "Cannot access column descriptor");
4545 ordered |= BATtordered(b);
4546 cnt = BATcount(b);
4547 BBPunfix(b->batCacheid);
4548 }
4549
4550 /* get the deletions BAT */
4551 del = mvc_bind_dbat(m, sch, tbl, RD_INS);
4552 if( del == NULL)
4553 throw(SQL, "sql.vacuum", SQLSTATE(HY005) "Cannot access deletion column");
4554
4555 dcnt = BATcount(del);
4556 BBPunfix(del->batCacheid);
4557 if (dcnt > 0) {
4558 /* now decide on the algorithm */
4559 if (ordered) {
4560 if (dcnt > cnt / 20)
4561 return SQLshrink(cntxt, mb, stk, pci);
4562 } else {
4563 return SQLreuse(cntxt, mb, stk, pci);
4564 }
4565 }
4566 return MAL_SUCCEED;
4567}
4568
4569/*
4570 * The drop_hash operation cleans up any hash indices on any of the tables columns.
4571 */
4572str
4573SQLdrop_hash(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4574{
4575 const char *sch = *getArgReference_str(stk, pci, 1);
4576 const char *tbl = *getArgReference_str(stk, pci, 2);
4577 sql_schema *s;
4578 sql_table *t;
4579 sql_column *c;
4580 mvc *m = NULL;
4581 str msg;
4582 BAT *b;
4583 node *o;
4584
4585 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4586 return msg;
4587 if ((msg = checkSQLContext(cntxt)) != NULL)
4588 return msg;
4589 s = mvc_bind_schema(m, sch);
4590 if (s == NULL)
4591 throw(SQL, "sql.drop_hash", SQLSTATE(3F000) "Schema missing %s",sch);
4592 t = mvc_bind_table(m, s, tbl);
4593 if (t == NULL)
4594 throw(SQL, "sql.drop_hash", SQLSTATE(42S02) "Table missing %s.%s",sch, tbl);
4595
4596 for (o = t->columns.set->h; o; o = o->next) {
4597 c = o->data;
4598 b = store_funcs.bind_col(m->session->tr, c, RDONLY);
4599 if (b == NULL)
4600 throw(SQL, "sql.drop_hash", SQLSTATE(HY005) "Cannot access column descriptor");
4601 HASHdestroy(b);
4602 BBPunfix(b->batCacheid);
4603 }
4604 return MAL_SUCCEED;
4605}
4606
4607
4608/* after an update on the optimizer catalog, we have to change
4609 * the internal optimizer pipe line administration
4610 * The minimal and default pipelines may not be changed.
4611 */
4612str
4613SQLoptimizersUpdate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4614{
4615 mvc *m = NULL;
4616 str msg;
4617
4618 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4619 return msg;
4620 if ((msg = checkSQLContext(cntxt)) != NULL)
4621 return msg;
4622 /* find the optimizer pipeline */
4623 (void) stk;
4624 (void) pci;
4625 throw(SQL, "updateOptimizer", SQLSTATE(0A000) PROGRAM_NYI);
4626}
4627
4628/*
4629 * Inspection of the actual storage footprint is a recurring question of users.
4630 * This is modelled as a generic SQL table producing function.
4631 * create function storage()
4632 * returns table ("schema" string, "table" string, "column" string, "type" string, "mode" string, location string, "count" bigint, width int, columnsize bigint, heapsize bigint indices bigint, sorted int)
4633 * external name sql.storage;
4634 */
4635str
4636sql_storage(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
4637{
4638 BAT *sch, *tab, *col, *type, *loc, *cnt, *atom, *size, *heap, *indices, *phash, *sort, *imprints, *mode, *revsort, *key, *oidx;
4639 mvc *m = NULL;
4640 str msg;
4641 sql_trans *tr;
4642 node *nsch, *ntab, *ncol;
4643 int w;
4644 bit bitval;
4645 bat *rsch = getArgReference_bat(stk, pci, 0);
4646 bat *rtab = getArgReference_bat(stk, pci, 1);
4647 bat *rcol = getArgReference_bat(stk, pci, 2);
4648 bat *rtype = getArgReference_bat(stk, pci, 3);
4649 bat *rmode = getArgReference_bat(stk, pci, 4);
4650 bat *rloc = getArgReference_bat(stk, pci, 5);
4651 bat *rcnt = getArgReference_bat(stk, pci, 6);
4652 bat *ratom = getArgReference_bat(stk, pci, 7);
4653 bat *rsize = getArgReference_bat(stk, pci, 8);
4654 bat *rheap = getArgReference_bat(stk, pci, 9);
4655 bat *rindices = getArgReference_bat(stk, pci, 10);
4656 bat *rphash = getArgReference_bat(stk, pci, 11);
4657 bat *rimprints = getArgReference_bat(stk, pci, 12);
4658 bat *rsort = getArgReference_bat(stk, pci, 13);
4659 bat *rrevsort = getArgReference_bat(stk, pci, 14);
4660 bat *rkey = getArgReference_bat(stk, pci, 15);
4661 bat *roidx = getArgReference_bat(stk, pci, 16);
4662 str sname = 0;
4663 str tname = 0;
4664 str cname = 0;
4665
4666 if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
4667 return msg;
4668 if ((msg = checkSQLContext(cntxt)) != NULL)
4669 return msg;
4670
4671 tr = m->session->tr;
4672 sch = COLnew(0, TYPE_str, 0, TRANSIENT);
4673 tab = COLnew(0, TYPE_str, 0, TRANSIENT);
4674 col = COLnew(0, TYPE_str, 0, TRANSIENT);
4675 type = COLnew(0, TYPE_str, 0, TRANSIENT);
4676 mode = COLnew(0, TYPE_str, 0, TRANSIENT);
4677 loc = COLnew(0, TYPE_str, 0, TRANSIENT);
4678 cnt = COLnew(0, TYPE_lng, 0, TRANSIENT);
4679 atom = COLnew(0, TYPE_int, 0, TRANSIENT);
4680 size = COLnew(0, TYPE_lng, 0, TRANSIENT);
4681 heap = COLnew(0, TYPE_lng, 0, TRANSIENT);
4682 indices = COLnew(0, TYPE_lng, 0, TRANSIENT);
4683 phash = COLnew(0, TYPE_bit, 0, TRANSIENT);
4684 imprints = COLnew(0, TYPE_lng, 0, TRANSIENT);
4685 sort = COLnew(0, TYPE_bit, 0, TRANSIENT);
4686 revsort = COLnew(0, TYPE_bit, 0, TRANSIENT);
4687 key = COLnew(0, TYPE_bit, 0, TRANSIENT);
4688 oidx = COLnew(0, TYPE_lng, 0, TRANSIENT);
4689
4690 if (sch == NULL || tab == NULL || col == NULL || type == NULL || mode == NULL || loc == NULL || imprints == NULL ||
4691 sort == NULL || cnt == NULL || atom == NULL || size == NULL || heap == NULL || indices == NULL || phash == NULL ||
4692 revsort == NULL || key == NULL || oidx == NULL) {
4693 goto bailout;
4694 }
4695 if( pci->argc - pci->retc >= 1)
4696 sname = *getArgReference_str(stk, pci, pci->retc);
4697 if( pci->argc - pci->retc >= 2)
4698 tname = *getArgReference_str(stk, pci, pci->retc + 1);
4699 if( pci->argc - pci->retc >= 3)
4700 cname = *getArgReference_str(stk, pci, pci->retc + 2);
4701
4702 /* check for limited storage tables */
4703 for (nsch = tr->schemas.set->h; nsch; nsch = nsch->next) {
4704 sql_base *b = nsch->data;
4705 sql_schema *s = (sql_schema *) nsch->data;
4706 if( sname && strcmp(b->name, sname) )
4707 continue;
4708 if (isalpha((unsigned char) b->name[0]))
4709 if (s->tables.set)
4710 for (ntab = (s)->tables.set->h; ntab; ntab = ntab->next) {
4711 sql_base *bt = ntab->data;
4712 sql_table *t = (sql_table *) bt;
4713 if( tname && strcmp(bt->name, tname) )
4714 continue;
4715 if (isTable(t))
4716 if (t->columns.set)
4717 for (ncol = (t)->columns.set->h; ncol; ncol = ncol->next) {
4718 sql_base *bc = ncol->data;
4719 sql_column *c = (sql_column *) ncol->data;
4720 BAT *bn;
4721 lng sz;
4722
4723 if( cname && strcmp(bc->name, cname) )
4724 continue;
4725 bn = store_funcs.bind_col(tr, c, RDONLY);
4726 if (bn == NULL)
4727 throw(SQL, "sql.storage", SQLSTATE(HY005) "Cannot access column descriptor");
4728
4729 /*printf("schema %s.%s.%s" , b->name, bt->name, bc->name); */
4730 if (BUNappend(sch, b->name, false) != GDK_SUCCEED ||
4731 BUNappend(tab, bt->name, false) != GDK_SUCCEED ||
4732 BUNappend(col, bc->name, false) != GDK_SUCCEED)
4733 goto bailout;
4734 if (c->t->access == TABLE_WRITABLE) {
4735 if (BUNappend(mode, "writable", false) != GDK_SUCCEED)
4736 goto bailout;
4737 } else if (c->t->access == TABLE_APPENDONLY) {
4738 if (BUNappend(mode, "appendonly", false) != GDK_SUCCEED)
4739 goto bailout;
4740 } else if (c->t->access == TABLE_READONLY) {
4741 if (BUNappend(mode, "readonly", false) != GDK_SUCCEED)
4742 goto bailout;
4743 } else {
4744 if (BUNappend(mode, str_nil, false) != GDK_SUCCEED)
4745 goto bailout;
4746 }
4747 if (BUNappend(type, c->type.type->sqlname, false) != GDK_SUCCEED)
4748 goto bailout;
4749
4750 /*printf(" cnt "BUNFMT, BATcount(bn)); */
4751 sz = BATcount(bn);
4752 if (BUNappend(cnt, &sz, false) != GDK_SUCCEED)
4753 goto bailout;
4754
4755 /*printf(" loc %s", BBP_physical(bn->batCacheid)); */
4756 if (BUNappend(loc, BBP_physical(bn->batCacheid), false) != GDK_SUCCEED)
4757 goto bailout;
4758 /*printf(" width %d", bn->twidth); */
4759 w = bn->twidth;
4760 if (bn->ttype == TYPE_str) {
4761 BUN p, q;
4762 double sum = 0;
4763 BATiter bi = bat_iterator(bn);
4764 lng cnt1, cnt2 = cnt1 = (lng) BATcount(bn);
4765
4766 /* just take a sample */
4767 if (cnt1 > 512)
4768 cnt1 = cnt2 = 512;
4769 BATloop(bn, p, q) {
4770 str s = BUNtvar(bi, p);
4771 if (s != NULL && strcmp(s, str_nil))
4772 sum += strlen(s);
4773 if (--cnt1 <= 0)
4774 break;
4775 }
4776 if (cnt2)
4777 w = (int) (sum / cnt2);
4778 } else if (ATOMvarsized(bn->ttype)) {
4779 sz = BATcount(bn);
4780 if (sz > 0)
4781 w = (int) ((bn->tvheap->free + sz / 2) / sz);
4782 else
4783 w = 0;
4784 }
4785 if (BUNappend(atom, &w, false) != GDK_SUCCEED)
4786 goto bailout;
4787
4788 sz = BATcount(bn) * bn->twidth;
4789 if (BUNappend(size, &sz, false) != GDK_SUCCEED)
4790 goto bailout;
4791
4792 sz = heapinfo(bn->tvheap, bn->batCacheid);
4793 if (BUNappend(heap, &sz, false) != GDK_SUCCEED)
4794 goto bailout;
4795
4796 sz = hashinfo(bn->thash, bn->batCacheid);
4797 if (BUNappend(indices, &sz, false) != GDK_SUCCEED)
4798 goto bailout;
4799
4800 bitval = 0; /* HASHispersistent(bn); */
4801 if (BUNappend(phash, &bitval, false) != GDK_SUCCEED)
4802 goto bailout;
4803
4804 sz = IMPSimprintsize(bn);
4805 if (BUNappend(imprints, &sz, false) != GDK_SUCCEED)
4806 goto bailout;
4807 /*printf(" indices "BUNFMT, bn->thash?bn->thash->heap.size:0); */
4808 /*printf("\n"); */
4809
4810 bitval = BATtordered(bn);
4811 if (!bitval && bn->tnosorted == 0)
4812 bitval = bit_nil;
4813 if (BUNappend(sort, &bitval, false) != GDK_SUCCEED)
4814 goto bailout;
4815
4816 bitval = BATtrevordered(bn);
4817 if (!bitval && bn->tnorevsorted == 0)
4818 bitval = bit_nil;
4819 if (BUNappend(revsort, &bitval, false) != GDK_SUCCEED)
4820 goto bailout;
4821
4822 bitval = BATtkey(bn);
4823 if (!bitval && bn->tnokey[0] == 0 && bn->tnokey[1] == 0)
4824 bitval = bit_nil;
4825 if (BUNappend(key, &bitval, false) != GDK_SUCCEED)
4826 goto bailout;
4827
4828 sz = bn->torderidx && bn->torderidx != (Heap *) 1 ? bn->torderidx->free : 0;
4829 if (BUNappend(oidx, &sz, false) != GDK_SUCCEED)
4830 goto bailout;
4831 BBPunfix(bn->batCacheid);
4832 }
4833
4834 if (isTable(t))
4835 if (t->idxs.set)
4836 for (ncol = (t)->idxs.set->h; ncol; ncol = ncol->next) {
4837 sql_base *bc = ncol->data;
4838 sql_idx *c = (sql_idx *) ncol->data;
4839 if (idx_has_column(c->type)) {
4840 BAT *bn = store_funcs.bind_idx(tr, c, RDONLY);
4841 lng sz;
4842
4843 if (bn == NULL)
4844 throw(SQL, "sql.storage", SQLSTATE(HY005) "Cannot access column descriptor");
4845 if( cname && strcmp(bc->name, cname) )
4846 continue;
4847 /*printf("schema %s.%s.%s" , b->name, bt->name, bc->name); */
4848 if (BUNappend(sch, b->name, false) != GDK_SUCCEED ||
4849 BUNappend(tab, bt->name, false) != GDK_SUCCEED ||
4850 BUNappend(col, bc->name, false) != GDK_SUCCEED)
4851 goto bailout;
4852 if (c->t->access == TABLE_WRITABLE) {
4853 if (BUNappend(mode, "writable", false) != GDK_SUCCEED)
4854 goto bailout;
4855 } else if (c->t->access == TABLE_APPENDONLY) {
4856 if (BUNappend(mode, "appendonly", false) != GDK_SUCCEED)
4857 goto bailout;
4858 } else if (c->t->access == TABLE_READONLY) {
4859 if (BUNappend(mode, "readonly", false) != GDK_SUCCEED)
4860 goto bailout;
4861 } else {
4862 if (BUNappend(mode, str_nil, false) != GDK_SUCCEED)
4863 goto bailout;
4864 }
4865 if (BUNappend(type, "oid", false) != GDK_SUCCEED)
4866 goto bailout;
4867
4868 /*printf(" cnt "BUNFMT, BATcount(bn)); */
4869 sz = BATcount(bn);
4870 if (BUNappend(cnt, &sz, false) != GDK_SUCCEED)
4871 goto bailout;
4872
4873 /*printf(" loc %s", BBP_physical(bn->batCacheid)); */
4874 if (BUNappend(loc, BBP_physical(bn->batCacheid), false) != GDK_SUCCEED)
4875 goto bailout;
4876 /*printf(" width %d", bn->twidth); */
4877 w = bn->twidth;
4878 if (bn->ttype == TYPE_str) {
4879 BUN p, q;
4880 double sum = 0;
4881 BATiter bi = bat_iterator(bn);
4882 lng cnt1, cnt2 = cnt1 = BATcount(bn);
4883
4884 /* just take a sample */
4885 if (cnt1 > 512)
4886 cnt1 = cnt2 = 512;
4887 BATloop(bn, p, q) {
4888 str s = BUNtvar(bi, p);
4889 if (s != NULL && strcmp(s, str_nil))
4890 sum += strlen(s);
4891 if (--cnt1 <= 0)
4892 break;
4893 }
4894 if (cnt2)
4895 w = (int) (sum / cnt2);
4896 }
4897 if (BUNappend(atom, &w, false) != GDK_SUCCEED)
4898 goto bailout;
4899 /*printf(" size "BUNFMT, tailsize(bn,BATcount(bn)) + (bn->tvheap? bn->tvheap->size:0)); */
4900 sz = tailsize(bn, BATcount(bn));
4901 if (BUNappend(size, &sz, false) != GDK_SUCCEED)
4902 goto bailout;
4903
4904 sz = bn->tvheap ? bn->tvheap->size : 0;
4905 if (BUNappend(heap, &sz, false) != GDK_SUCCEED)
4906 goto bailout;
4907
4908 sz = bn->thash && bn->thash != (Hash *) 1 ? bn->thash->heap.size : 0; /* HASHsize() */
4909 if (BUNappend(indices, &sz, false) != GDK_SUCCEED)
4910 goto bailout;
4911 bitval = 0; /* HASHispersistent(bn); */
4912 if (BUNappend(phash, &bitval, false) != GDK_SUCCEED)
4913 goto bailout;
4914
4915 sz = IMPSimprintsize(bn);
4916 if (BUNappend(imprints, &sz, false) != GDK_SUCCEED)
4917 goto bailout;
4918 /*printf(" indices "BUNFMT, bn->thash?bn->thash->heap.size:0); */
4919 /*printf("\n"); */
4920 bitval = BATtordered(bn);
4921 if (!bitval && bn->tnosorted == 0)
4922 bitval = bit_nil;
4923 if (BUNappend(sort, &bitval, false) != GDK_SUCCEED)
4924 goto bailout;
4925 bitval = BATtrevordered(bn);
4926 if (!bitval && bn->tnorevsorted == 0)
4927 bitval = bit_nil;
4928 if (BUNappend(revsort, &bitval, false) != GDK_SUCCEED)
4929 goto bailout;
4930 bitval = BATtkey(bn);
4931 if (!bitval && bn->tnokey[0] == 0 && bn->tnokey[1] == 0)
4932 bitval = bit_nil;
4933 if (BUNappend(key, &bitval, false) != GDK_SUCCEED)
4934 goto bailout;
4935 sz = bn->torderidx && bn->torderidx != (Heap *) 1 ? bn->torderidx->free : 0;
4936 if (BUNappend(oidx, &sz, false) != GDK_SUCCEED)
4937 goto bailout;
4938 BBPunfix(bn->batCacheid);
4939 }
4940 }
4941
4942 }
4943 }
4944
4945 BBPkeepref(*rsch = sch->batCacheid);
4946 BBPkeepref(*rtab = tab->batCacheid);
4947 BBPkeepref(*rcol = col->batCacheid);
4948 BBPkeepref(*rmode = mode->batCacheid);
4949 BBPkeepref(*rloc = loc->batCacheid);
4950 BBPkeepref(*rtype = type->batCacheid);
4951 BBPkeepref(*rcnt = cnt->batCacheid);
4952 BBPkeepref(*ratom = atom->batCacheid);
4953 BBPkeepref(*rsize = size->batCacheid);
4954 BBPkeepref(*rheap = heap->batCacheid);
4955 BBPkeepref(*rindices = indices->batCacheid);
4956 BBPkeepref(*rphash = phash->batCacheid);
4957 BBPkeepref(*rimprints = imprints->batCacheid);
4958 BBPkeepref(*rsort = sort->batCacheid);
4959 BBPkeepref(*rrevsort = revsort->batCacheid);
4960 BBPkeepref(*rkey = key->batCacheid);
4961 BBPkeepref(*roidx = oidx->batCacheid);
4962 return MAL_SUCCEED;
4963
4964 bailout:
4965 if (sch)
4966 BBPunfix(sch->batCacheid);
4967 if (tab)
4968 BBPunfix(tab->batCacheid);
4969 if (col)
4970 BBPunfix(col->batCacheid);
4971 if (mode)
4972 BBPunfix(mode->batCacheid);
4973 if (loc)
4974 BBPunfix(loc->batCacheid);
4975 if (cnt)
4976 BBPunfix(cnt->batCacheid);
4977 if (type)
4978 BBPunfix(type->batCacheid);
4979 if (atom)
4980 BBPunfix(atom->batCacheid);
4981 if (size)
4982 BBPunfix(size->batCacheid);
4983 if (heap)
4984 BBPunfix(heap->batCacheid);
4985 if (indices)
4986 BBPunfix(indices->batCacheid);
4987 if (phash)
4988 BBPunfix(phash->batCacheid);
4989 if (imprints)
4990 BBPunfix(imprints->batCacheid);
4991 if (sort)
4992 BBPunfix(sort->batCacheid);
4993 if (revsort)
4994 BBPunfix(revsort->batCacheid);
4995 if (key)
4996 BBPunfix(key->batCacheid);
4997 if (oidx)
4998 BBPunfix(oidx->batCacheid);
4999 throw(SQL, "sql.storage", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5000}
5001
5002void
5003freeVariables(Client c, MalBlkPtr mb, MalStkPtr glb, int start)
5004{
5005 int i;
5006
5007 for (i = start; i < mb->vtop;) {
5008 if (glb) {
5009 if (isVarCleanup(mb, i))
5010 garbageElement(c, &glb->stk[i]);
5011 /* clean stack entry */
5012 glb->stk[i].vtype = TYPE_int;
5013 glb->stk[i].val.ival = 0;
5014 glb->stk[i].len = 0;
5015 }
5016 clearVariable(mb, i);
5017 i++;
5018 }
5019 mb->vtop = start;
5020}
5021
5022/* if at least (2*SIZEOF_BUN), also store length (heaps are then
5023 * incompatible) */
5024#define EXTRALEN ((SIZEOF_BUN + GDK_VARALIGN - 1) & ~(GDK_VARALIGN - 1))
5025
5026str
5027STRindex_int(int *i, const str *src, const bit *u)
5028{
5029 (void)src; (void)u;
5030 *i = 0;
5031 return MAL_SUCCEED;
5032}
5033
5034str
5035BATSTRindex_int(bat *res, const bat *src, const bit *u)
5036{
5037 BAT *s, *r;
5038
5039 if ((s = BATdescriptor(*src)) == NULL)
5040 throw(SQL, "calc.index", SQLSTATE(HY005) "Cannot access column descriptor");
5041
5042 if (*u) {
5043 Heap *h = s->tvheap;
5044 size_t pad, pos;
5045 const size_t extralen = h->hashash ? EXTRALEN : 0;
5046 int v;
5047
5048 r = COLnew(0, TYPE_int, 1024, TRANSIENT);
5049 if (r == NULL) {
5050 BBPunfix(s->batCacheid);
5051 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5052 }
5053 pos = GDK_STRHASHSIZE;
5054 while (pos < h->free) {
5055 const char *p;
5056
5057 pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1));
5058 if (pad < sizeof(stridx_t))
5059 pad += GDK_VARALIGN;
5060 pos += pad + extralen;
5061 p = h->base + pos;
5062 v = (int) (pos - GDK_STRHASHSIZE);
5063 if (BUNappend(r, &v, false) != GDK_SUCCEED) {
5064 BBPreclaim(r);
5065 BBPunfix(s->batCacheid);
5066 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5067 }
5068 pos += GDK_STRLEN(p);
5069 }
5070 } else {
5071 r = VIEWcreate(s->hseqbase, s);
5072 if (r == NULL) {
5073 BBPunfix(s->batCacheid);
5074 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5075 }
5076 r->ttype = TYPE_int;
5077 r->tvarsized = false;
5078 r->tvheap = NULL;
5079 }
5080 BBPunfix(s->batCacheid);
5081 BBPkeepref((*res = r->batCacheid));
5082 return MAL_SUCCEED;
5083}
5084
5085str
5086STRindex_sht(sht *i, const str *src, const bit *u)
5087{
5088 (void)src; (void)u;
5089 *i = 0;
5090 return MAL_SUCCEED;
5091}
5092
5093str
5094BATSTRindex_sht(bat *res, const bat *src, const bit *u)
5095{
5096 BAT *s, *r;
5097
5098 if ((s = BATdescriptor(*src)) == NULL)
5099 throw(SQL, "calc.index", SQLSTATE(HY005) "Cannot access column descriptor");
5100
5101 if (*u) {
5102 Heap *h = s->tvheap;
5103 size_t pad, pos;
5104 const size_t extralen = h->hashash ? EXTRALEN : 0;
5105 sht v;
5106
5107 r = COLnew(0, TYPE_sht, 1024, TRANSIENT);
5108 if (r == NULL) {
5109 BBPunfix(s->batCacheid);
5110 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5111 }
5112 pos = GDK_STRHASHSIZE;
5113 while (pos < h->free) {
5114 const char *s;
5115
5116 pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1));
5117 if (pad < sizeof(stridx_t))
5118 pad += GDK_VARALIGN;
5119 pos += pad + extralen;
5120 s = h->base + pos;
5121 v = (sht) (pos - GDK_STRHASHSIZE);
5122 if (BUNappend(r, &v, false) != GDK_SUCCEED) {
5123 BBPreclaim(r);
5124 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5125 }
5126 pos += GDK_STRLEN(s);
5127 }
5128 } else {
5129 r = VIEWcreate(s->hseqbase, s);
5130 if (r == NULL) {
5131 BBPunfix(s->batCacheid);
5132 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5133 }
5134 r->ttype = TYPE_sht;
5135 r->tvarsized = false;
5136 r->tvheap = NULL;
5137 }
5138 BBPunfix(s->batCacheid);
5139 BBPkeepref((*res = r->batCacheid));
5140 return MAL_SUCCEED;
5141}
5142
5143str
5144STRindex_bte(bte *i, const str *src, const bit *u)
5145{
5146 (void)src; (void)u;
5147 *i = 0;
5148 return MAL_SUCCEED;
5149}
5150
5151str
5152BATSTRindex_bte(bat *res, const bat *src, const bit *u)
5153{
5154 BAT *s, *r;
5155
5156 if ((s = BATdescriptor(*src)) == NULL)
5157 throw(SQL, "calc.index", SQLSTATE(HY005) "Cannot access column descriptor");
5158
5159 if (*u) {
5160 Heap *h = s->tvheap;
5161 size_t pad, pos;
5162 const size_t extralen = h->hashash ? EXTRALEN : 0;
5163 bte v;
5164
5165 r = COLnew(0, TYPE_bte, 64, TRANSIENT);
5166 if (r == NULL) {
5167 BBPunfix(s->batCacheid);
5168 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5169 }
5170 pos = GDK_STRHASHSIZE;
5171 while (pos < h->free) {
5172 const char *p;
5173
5174 pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1));
5175 if (pad < sizeof(stridx_t))
5176 pad += GDK_VARALIGN;
5177 pos += pad + extralen;
5178 p = h->base + pos;
5179 v = (bte) (pos - GDK_STRHASHSIZE);
5180 if (BUNappend(r, &v, false) != GDK_SUCCEED) {
5181 BBPreclaim(r);
5182 BBPunfix(s->batCacheid);
5183 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5184 }
5185 pos += GDK_STRLEN(p);
5186 }
5187 } else {
5188 r = VIEWcreate(s->hseqbase, s);
5189 if (r == NULL) {
5190 BBPunfix(s->batCacheid);
5191 throw(SQL, "calc.index", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5192 }
5193 r->ttype = TYPE_bte;
5194 r->tvarsized = false;
5195 r->tvheap = NULL;
5196 }
5197 BBPunfix(s->batCacheid);
5198 BBPkeepref((*res = r->batCacheid));
5199 return MAL_SUCCEED;
5200}
5201
5202str
5203STRstrings(str *i, const str *src)
5204{
5205 (void)src;
5206 *i = 0;
5207 return MAL_SUCCEED;
5208}
5209
5210str
5211BATSTRstrings(bat *res, const bat *src)
5212{
5213 BAT *s, *r;
5214 Heap *h;
5215 size_t pad, pos;
5216 size_t extralen;
5217
5218 if ((s = BATdescriptor(*src)) == NULL)
5219 throw(SQL, "calc.strings", SQLSTATE(HY005) "Cannot access column descriptor");
5220
5221 h = s->tvheap;
5222 extralen = h->hashash ? EXTRALEN : 0;
5223 r = COLnew(0, TYPE_str, 1024, TRANSIENT);
5224 if (r == NULL) {
5225 BBPunfix(s->batCacheid);
5226 throw(SQL, "calc.strings", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5227 }
5228 pos = GDK_STRHASHSIZE;
5229 while (pos < h->free) {
5230 const char *p;
5231
5232 pad = GDK_VARALIGN - (pos & (GDK_VARALIGN - 1));
5233 if (pad < sizeof(stridx_t))
5234 pad += GDK_VARALIGN;
5235 pos += pad + extralen;
5236 p = h->base + pos;
5237 if (BUNappend(r, p, false) != GDK_SUCCEED) {
5238 BBPreclaim(r);
5239 BBPunfix(s->batCacheid);
5240 throw(SQL, "calc.strings", SQLSTATE(HY001) MAL_MALLOC_FAIL);
5241 }
5242 pos += GDK_STRLEN(p);
5243 }
5244 BBPunfix(s->batCacheid);
5245 BBPkeepref((*res = r->batCacheid));
5246 return MAL_SUCCEED;
5247}
5248
5249str
5250SQLflush_log(void *ret)
5251{
5252 (void)ret;
5253 store_flush_log();
5254 return MAL_SUCCEED;
5255}
5256
5257str
5258SQLresume_log_flushing(void *ret)
5259{
5260 (void)ret;
5261 store_resume_log();
5262 return MAL_SUCCEED;
5263}
5264
5265str
5266SQLsuspend_log_flushing(void *ret)
5267{
5268 (void)ret;
5269 store_suspend_log();
5270 return MAL_SUCCEED;
5271}
5272
5273str
5274SQLhot_snapshot(void *ret, const str *tarfile_arg)
5275{
5276 (void)ret;
5277 char *tarfile = *tarfile_arg;
5278 lng result = store_hot_snapshot(tarfile);
5279 if (result)
5280 return MAL_SUCCEED;
5281 else
5282 throw(SQL, "sql.hot_snapshot", GDK_EXCEPTION);
5283}
5284