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 | |
14 | static 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 | |
38 | static BAT * |
39 | delta_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 | |
57 | static BAT * |
58 | delta_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 | |
124 | static BAT * |
125 | delta_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 | |
132 | static BAT * |
133 | full_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 | |
142 | static void |
143 | full_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 | |
151 | static oid |
152 | column_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 | |
201 | static void * |
202 | column_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 | |
230 | static int |
231 | column_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 | |
238 | static int |
239 | table_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 | |
267 | static int |
268 | table_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 */ |
278 | static rids * |
279 | rids_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 */ |
346 | static rids * |
347 | rids_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 */ |
370 | static oid |
371 | rids_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 */ |
380 | static void |
381 | rids_destroy(rids *r) |
382 | { |
383 | bat_destroy(r->data); |
384 | _DELETE(r); |
385 | } |
386 | |
387 | static int |
388 | rids_empty(rids *r ) |
389 | { |
390 | BAT *b = r->data; |
391 | return BATcount(b) <= 0; |
392 | } |
393 | |
394 | static rids * |
395 | rids_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 | |
415 | static subrids * |
416 | subrids_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 | |
510 | static oid |
511 | subrids_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 | |
522 | static sqlid |
523 | subrids_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 | |
533 | static void |
534 | subrids_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 */ |
544 | static rids * |
545 | rids_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 | |
594 | static int |
595 | table_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 | |
647 | void |
648 | bat_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 | |