1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#include "bat_table.h"
11#include "bat_utils.h"
12#include "bat_storage.h"
13
14static BAT *
15_delta_cands(sql_trans *tr, sql_table *t)
16{
17 sql_column *c = t->columns.set->h->data;
18 /* create void,void bat with length and oid's set */
19 size_t nr = store_funcs.count_col(tr, c, 1);
20 BAT *tids = BATdense(0, 0, (BUN) nr);
21
22 if (!tids)
23 return NULL;
24
25 if (store_funcs.count_del(tr, t)) {
26 BAT *d, *diff = NULL;
27
28 if ((d = store_funcs.bind_del(tr, t, RD_INS)) != NULL) {
29 diff = BATdiff(tids, d, NULL, NULL, false, false, BUN_NONE);
30 bat_destroy(d);
31 }
32 bat_destroy(tids);
33 tids = diff;
34 }
35 return tids;
36}
37
38static BAT *
39delta_cands(sql_trans *tr, sql_table *t)
40{
41 sql_dbat *d;
42 BAT *tids;
43
44 if (!t->data) {
45 sql_table *ot = tr_find_table(tr->parent, t);
46 t->data = timestamp_dbat(ot->data, tr->stime);
47 }
48 d = t->data;
49 if (!store_initialized && d->cached)
50 return temp_descriptor(d->cached->batCacheid);
51 tids = _delta_cands(tr, t);
52 if (!store_initialized && !d->cached) /* only cache during catalog loading */
53 d->cached = temp_descriptor(tids->batCacheid);
54 return tids;
55}
56
57static BAT *
58delta_full_bat_( sql_column *c, sql_delta *bat, int temp)
59{
60 /* return full normalized column bat
61 * b := b.copy()
62 b := b.append(i);
63 b := b.replace(u);
64 */
65 BAT *r, *b, *ui, *uv, *i = temp_descriptor(bat->ibid);
66 int needcopy = 1;
67
68 if (!i)
69 return NULL;
70 r = i;
71 if (temp)
72 return r;
73 b = temp_descriptor(bat->bid);
74 if (!b) {
75 b = i;
76 } else {
77 if (BATcount(i)) {
78 r = COLcopy(b, b->ttype, true, TRANSIENT);
79 bat_destroy(b);
80 if (r == NULL) {
81 bat_destroy(i);
82 return NULL;
83 }
84 b = r;
85 if (BATappend(b, i, NULL, true) != GDK_SUCCEED) {
86 bat_destroy(b);
87 bat_destroy(i);
88 return NULL;
89 }
90 needcopy = 0;
91 }
92 bat_destroy(i);
93 }
94 if (bat->uibid && bat->ucnt) {
95 ui = temp_descriptor(bat->uibid);
96 uv = temp_descriptor(bat->uvbid);
97 if (ui && BATcount(ui)) {
98 if (needcopy) {
99 r = COLcopy(b, b->ttype, true, TRANSIENT);
100 bat_destroy(b);
101 b = r;
102 if(b == NULL) {
103 bat_destroy(ui);
104 bat_destroy(uv);
105 return NULL;
106 }
107 }
108 if (void_replace_bat(b, ui, uv, true) != GDK_SUCCEED) {
109 bat_destroy(ui);
110 bat_destroy(uv);
111 bat_destroy(b);
112 return NULL;
113 }
114 }
115 bat_destroy(ui);
116 bat_destroy(uv);
117 }
118 (void)c;
119 if (!store_initialized && !bat->cached)
120 bat->cached = b;
121 return b;
122}
123
124static BAT *
125delta_full_bat( sql_column *c, sql_delta *bat, int temp)
126{
127 if (!store_initialized && bat->cached)
128 return bat->cached;
129 return delta_full_bat_( c, bat, temp);
130}
131
132static BAT *
133full_column(sql_trans *tr, sql_column *c)
134{
135 if (!c->data) {
136 sql_column *oc = tr_find_column(tr->parent, c);
137 c->data = timestamp_delta(oc->data, tr->stime);
138 }
139 return delta_full_bat(c, c->data, isTemp(c));
140}
141
142static void
143full_destroy(sql_column *c, BAT *b)
144{
145 sql_delta *d = c->data;
146 assert(d);
147 if (d->cached != b)
148 bat_destroy(b);
149}
150
151static oid
152column_find_row(sql_trans *tr, sql_column *c, const void *value, ...)
153{
154 va_list va;
155 BAT *b = NULL, *s = NULL, *r = NULL;
156 oid rid = oid_nil;
157 sql_column *n = NULL;
158
159 va_start(va, value);
160 s = delta_cands(tr, c->t);
161 if (!s)
162 goto return_nil;
163 b = full_column(tr, c);
164 if (!b) {
165 bat_destroy(s);
166 goto return_nil;
167 }
168 r = BATselect(b, s, value, NULL, true, false, false);
169 bat_destroy(s);
170 full_destroy(c, b);
171 if (!r)
172 goto return_nil;
173 s = r;
174 while ((n = va_arg(va, sql_column *)) != NULL) {
175 value = va_arg(va, void *);
176 c = n;
177
178 b = full_column(tr, c);
179 if (!b) {
180 bat_destroy(s);
181 goto return_nil;
182 }
183 r = BATselect(b, s, value, NULL, true, false, false);
184 bat_destroy(s);
185 full_destroy(c, b);
186 if (!r)
187 goto return_nil;
188 s = r;
189 }
190 va_end(va);
191 if (BATcount(s) == 1) {
192 rid = BUNtoid(s, 0);
193 }
194 bat_destroy(s);
195 return rid;
196 return_nil:
197 va_end(va);
198 return oid_nil;
199}
200
201static void *
202column_find_value(sql_trans *tr, sql_column *c, oid rid)
203{
204 BUN q = BUN_NONE;
205 BAT *b;
206 void *res = NULL;
207
208 b = full_column(tr, c);
209 if (b) {
210 if (rid < b->hseqbase || rid >= b->hseqbase + BATcount(b))
211 q = BUN_NONE;
212 else
213 q = rid - b->hseqbase;
214 }
215 if (q != BUN_NONE) {
216 BATiter bi = bat_iterator(b);
217 const void *r;
218 size_t sz;
219
220 r = BUNtail(bi, q);
221 sz = ATOMlen(b->ttype, r);
222 res = GDKmalloc(sz);
223 if (res)
224 memcpy(res, r, sz);
225 }
226 full_destroy(c, b);
227 return res;
228}
229
230static int
231column_update_value(sql_trans *tr, sql_column *c, oid rid, void *value)
232{
233 assert(!is_oid_nil(rid));
234
235 return store_funcs.update_col(tr, c, &rid, value, c->type.type->localtype);
236}
237
238static int
239table_insert(sql_trans *tr, sql_table *t, ...)
240{
241 va_list va;
242 node *n = cs_first_node(&t->columns);
243 void *val = NULL;
244 int cnt = 0;
245 int ok = LOG_OK;
246
247 va_start(va, t);
248 for (; n; n = n->next) {
249 sql_column *c = n->data;
250 val = va_arg(va, void *);
251 if (!val)
252 break;
253 ok = store_funcs.append_col(tr, c, val, c->type.type->localtype);
254 if (ok != LOG_OK)
255 return ok;
256 cnt++;
257 }
258 va_end(va);
259 if (n) {
260 fprintf(stderr, "called table_insert(%s) with wrong number of args (%d,%d)\n", t->base.name, list_length(t->columns.set), cnt);
261 assert(0);
262 return LOG_ERR;
263 }
264 return LOG_OK;
265}
266
267static int
268table_delete(sql_trans *tr, sql_table *t, oid rid)
269{
270 assert(!is_oid_nil(rid));
271
272 return store_funcs.delete_tab(tr, t, &rid, TYPE_oid);
273}
274
275
276
277/* returns table rids, for the given select ranges */
278static rids *
279rids_select( sql_trans *tr, sql_column *key, const void *key_value_low, const void *key_value_high, ...)
280{
281 va_list va;
282 BAT *b = NULL, *r = NULL, *s = NULL;
283 rids *rs = ZNEW(rids);
284 const void *kvl = key_value_low, *kvh = key_value_high;
285 /* if pointers are equal, make it an inclusive select */
286 bool hi = key_value_low == key_value_high;
287
288 if(!rs)
289 return NULL;
290 s = delta_cands(tr, key->t);
291 if (s == NULL) {
292 GDKfree(rs);
293 return NULL;
294 }
295 b = full_column(tr, key);
296 if (b == NULL) {
297 bat_destroy(s);
298 GDKfree(rs);
299 return NULL;
300 }
301 if (!kvl)
302 kvl = ATOMnilptr(b->ttype);
303 if (!kvh && kvl != ATOMnilptr(b->ttype))
304 kvh = ATOMnilptr(b->ttype);
305 if (key_value_low) {
306 BAThash(b);
307 r = BATselect(b, s, kvl, kvh, true, hi, false);
308 bat_destroy(s);
309 s = r;
310 }
311 full_destroy(key, b);
312 if (s == NULL) {
313 GDKfree(rs);
314 return NULL;
315 }
316 if (key_value_low || key_value_high) {
317 va_start(va, key_value_high);
318 while ((key = va_arg(va, sql_column *)) != NULL) {
319 kvl = va_arg(va, void *);
320 kvh = va_arg(va, void *);
321
322 b = full_column(tr, key);
323 if (!kvl)
324 kvl = ATOMnilptr(b->ttype);
325 if (!kvh && kvl != ATOMnilptr(b->ttype))
326 kvh = ATOMnilptr(b->ttype);
327 assert(kvh);
328 r = BATselect(b, s, kvl, kvh, true, hi, false);
329 bat_destroy(s);
330 s = r;
331 full_destroy(key, b);
332 if (s == NULL) {
333 GDKfree(rs);
334 va_end(va);
335 return NULL;
336 }
337 }
338 va_end(va);
339 }
340 rs->data = s;
341 rs->cur = 0;
342 return rs;
343}
344
345/* order rids by orderby_column values */
346static rids *
347rids_orderby(sql_trans *tr, rids *r, sql_column *orderby_col)
348{
349 BAT *b, *s, *o;
350
351 b = full_column(tr, orderby_col);
352 s = BATproject(r->data, b);
353 full_destroy(orderby_col, b);
354 if (BATsort(NULL, &o, NULL, s, NULL, NULL, false, false, false) != GDK_SUCCEED) {
355 bat_destroy(s);
356 return NULL;
357 }
358 bat_destroy(s);
359 s = BATproject(o, r->data);
360 bat_destroy(o);
361 if (s == NULL)
362 return NULL;
363 bat_destroy(r->data);
364 r->data = s;
365 return r;
366}
367
368
369/* return table rids from result of rids_select, return (oid_nil) when done */
370static oid
371rids_next(rids *r)
372{
373 if (r->cur < BATcount((BAT *) r->data)) {
374 return BUNtoid((BAT *) r->data, r->cur++);
375 }
376 return oid_nil;
377}
378
379/* clean up the resources taken by the result of rids_select */
380static void
381rids_destroy(rids *r)
382{
383 bat_destroy(r->data);
384 _DELETE(r);
385}
386
387static int
388rids_empty(rids *r )
389{
390 BAT *b = r->data;
391 return BATcount(b) <= 0;
392}
393
394static rids *
395rids_join(sql_trans *tr, rids *l, sql_column *lc, rids *r, sql_column *rc)
396{
397 BAT *lcb, *rcb, *s = NULL, *d = NULL;
398 gdk_return ret;
399
400 lcb = full_column(tr, lc);
401 rcb = full_column(tr, rc);
402 ret = BATjoin(&s, &d, lcb, rcb, l->data, r->data, false, BATcount(lcb));
403 bat_destroy(l->data);
404 bat_destroy(d);
405 if (ret != GDK_SUCCEED) {
406 l->data = NULL;
407 } else {
408 l->data = s;
409 }
410 full_destroy(lc, lcb);
411 full_destroy(rc, rcb);
412 return l;
413}
414
415static subrids *
416subrids_create(sql_trans *tr, rids *t1, sql_column *rc, sql_column *lc, sql_column *obc)
417{
418 /* join t1.rc with lc order by obc */
419 subrids *r;
420 BAT *lcb, *rcb, *s, *obb, *d = NULL, *o, *g, *ids, *rids = NULL;
421 gdk_return ret;
422
423 lcb = full_column(tr, lc);
424 rcb = full_column(tr, rc);
425 s = delta_cands(tr, lc->t);
426 if (lcb == NULL || rcb == NULL || s == NULL) {
427 if (lcb)
428 full_destroy(rc, lcb);
429 if (rcb)
430 full_destroy(rc, rcb);
431 bat_destroy(s);
432 return NULL;
433 }
434
435 ret = BATjoin(&rids, &d, lcb, rcb, s, t1->data, false, BATcount(lcb));
436 bat_destroy(s);
437 full_destroy(rc, rcb);
438 if (ret != GDK_SUCCEED) {
439 full_destroy(rc, lcb);
440 return NULL;
441 }
442 bat_destroy(d);
443
444 s = BATproject(rids, lcb);
445 full_destroy(lc, lcb);
446 if (s == NULL) {
447 bat_destroy(rids);
448 return NULL;
449 }
450 lcb = s;
451
452 if ((obb = full_column(tr, obc)) == NULL) {
453 bat_destroy(lcb);
454 bat_destroy(rids);
455 return NULL;
456 }
457 s = BATproject(rids, obb);
458 full_destroy(obc, obb);
459 if (s == NULL) {
460 bat_destroy(lcb);
461 bat_destroy(rids);
462 return NULL;
463 }
464 obb = s;
465
466 /* need id, obc */
467 ids = o = g = NULL;
468 ret = BATsort(&ids, &o, &g, lcb, NULL, NULL, false, false, false);
469 bat_destroy(lcb);
470 if (ret != GDK_SUCCEED) {
471 bat_destroy(obb);
472 bat_destroy(rids);
473 return NULL;
474 }
475
476 s = NULL;
477 ret = BATsort(NULL, &s, NULL, obb, o, g, false, false, false);
478 bat_destroy(obb);
479 bat_destroy(o);
480 bat_destroy(g);
481 if (ret != GDK_SUCCEED) {
482 bat_destroy(ids);
483 bat_destroy(rids);
484 return NULL;
485 }
486
487 o = BATproject(s, rids);
488 bat_destroy(rids);
489 bat_destroy(s);
490 if (o == NULL) {
491 bat_destroy(ids);
492 return NULL;
493 }
494 rids = o;
495
496 assert(ids->ttype == TYPE_int && ATOMtype(rids->ttype) == TYPE_oid);
497 r = ZNEW(subrids);
498 if (r == NULL) {
499 bat_destroy(ids);
500 bat_destroy(rids);
501 return NULL;
502 }
503 r->id = 0;
504 r->pos = 0;
505 r->ids = ids;
506 r->rids = rids;
507 return r;
508}
509
510static oid
511subrids_next(subrids *r)
512{
513 if (r->pos < BATcount((BAT *) r->ids)) {
514 BATiter ii = bat_iterator((BAT *) r->ids);
515 sqlid id = *(sqlid*)BUNtloc(ii, r->pos);
516 if (id == r->id)
517 return BUNtoid((BAT *) r->rids, r->pos++);
518 }
519 return oid_nil;
520}
521
522static sqlid
523subrids_nextid(subrids *r)
524{
525 if (r->pos < BATcount((BAT *) r->ids)) {
526 BATiter ii = bat_iterator((BAT *) r->ids);
527 r->id = *(sqlid*)BUNtloc(ii, r->pos);
528 return r->id;
529 }
530 return -1;
531}
532
533static void
534subrids_destroy(subrids *r )
535{
536 if (r->ids)
537 bat_destroy(r->ids);
538 if (r->rids)
539 bat_destroy(r->rids);
540 _DELETE(r);
541}
542
543/* get the non - join results */
544static rids *
545rids_diff(sql_trans *tr, rids *l, sql_column *lc, subrids *r, sql_column *rc )
546{
547 BAT *lcb = full_column(tr, lc), *s, *d, *rids, *diff;
548 BAT *rcb = full_column(tr, rc);
549 gdk_return ret;
550
551 if (lcb == NULL || rcb == NULL) {
552 if (lcb)
553 full_destroy(rc, lcb);
554 if (rcb)
555 full_destroy(rc, rcb);
556 return NULL;
557 }
558 s = BATproject(r->rids, rcb);
559 full_destroy(rc, rcb);
560 if (s == NULL) {
561 full_destroy(rc, lcb);
562 return NULL;
563 }
564 rcb = s;
565
566 s = BATproject(l->data, lcb);
567 if (s == NULL) {
568 full_destroy(rc, lcb);
569 bat_destroy(rcb);
570 return NULL;
571 }
572
573 diff = BATdiff(s, rcb, NULL, NULL, false, false, BUN_NONE);
574 bat_destroy(rcb);
575 if (diff == NULL) {
576 full_destroy(rc, lcb);
577 bat_destroy(s);
578 return NULL;
579 }
580
581 ret = BATjoin(&rids, &d, lcb, s, NULL, diff, false, BATcount(s));
582 bat_destroy(diff);
583 full_destroy(lc, lcb);
584 bat_destroy(s);
585 if (ret != GDK_SUCCEED)
586 return NULL;
587
588 bat_destroy(d);
589 bat_destroy(l->data);
590 l->data = rids;
591 return l;
592}
593
594static int
595table_vacuum(sql_trans *tr, sql_table *t)
596{
597 BAT *tids = delta_cands(tr, t);
598 BAT **cols;
599 node *n;
600
601 if (!tids)
602 return SQL_ERR;
603 cols = NEW_ARRAY(BAT*, cs_size(&t->columns));
604 if (!cols) {
605 bat_destroy(tids);
606 return SQL_ERR;
607 }
608 for (n = t->columns.set->h; n; n = n->next) {
609 sql_column *c = n->data;
610 BAT *v = store_funcs.bind_col(tr, c, RDONLY);
611
612 if (v == NULL ||
613 (cols[c->colnr] = BATproject(tids, v)) == NULL) {
614 BBPunfix(tids->batCacheid);
615 for (n = t->columns.set->h; n; n = n->next) {
616 if (n->data == c)
617 break;
618 bat_destroy(cols[((sql_column *) n->data)->colnr]);
619 }
620 bat_destroy(v);
621 _DELETE(cols);
622 return SQL_ERR;
623 }
624 BBPunfix(v->batCacheid);
625 }
626 BBPunfix(tids->batCacheid);
627 sql_trans_clear_table(tr, t);
628 for (n = t->columns.set->h; n; n = n->next) {
629 sql_column *c = n->data;
630 int ok;
631
632 ok = store_funcs.append_col(tr, c, cols[c->colnr], TYPE_bat);
633 BBPunfix(cols[c->colnr]->batCacheid);
634 if (ok != LOG_OK) {
635 for (n = n->next; n; n = n->next) {
636 c = n->data;
637 BBPunfix(cols[c->colnr]->batCacheid);
638 }
639 _DELETE(cols);
640 return SQL_ERR;
641 }
642 }
643 _DELETE(cols);
644 return SQL_OK;
645}
646
647void
648bat_table_init( table_functions *tf )
649{
650 tf->column_find_row = column_find_row;
651 tf->column_find_value = column_find_value;
652
653 tf->column_update_value = column_update_value;
654 tf->table_insert = table_insert;
655 tf->table_delete = table_delete;
656 tf->table_vacuum = table_vacuum;
657
658 tf->rids_select = rids_select;
659 tf->rids_orderby = rids_orderby;
660 tf->rids_join = rids_join;
661 tf->rids_next = rids_next;
662 tf->rids_destroy = rids_destroy;
663 tf->rids_empty = rids_empty;
664
665 tf->subrids_create = subrids_create;
666 tf->subrids_next = subrids_next;
667 tf->subrids_nextid = subrids_nextid;
668 tf->subrids_destroy = subrids_destroy;
669 tf->rids_diff = rids_diff;
670}
671