Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "sql.h"
15 : #include "mal.h"
16 : #include "mal_client.h"
17 :
18 : #include "dict.h"
19 :
20 : static sql_column *
21 53 : get_newcolumn(sql_trans *tr, sql_column *c)
22 : {
23 53 : sql_table *t = find_sql_table_id(tr, c->t->s, c->t->base.id);
24 53 : if (t)
25 53 : return find_sql_column(t, c->base.name);
26 : return NULL;
27 : }
28 :
29 : static void
30 49 : BATmaxminpos_bte(BAT *o, bte m)
31 : {
32 49 : BUN minpos = BUN_NONE, maxpos = BUN_NONE, p, q;
33 49 : bte minval = m<0?GDK_bte_min:0; /* Later once nils use a bitmask we can include -128 in the range */
34 47 : bte maxval = m<0?GDK_bte_max:m;
35 :
36 49 : assert(o->ttype == TYPE_bte);
37 49 : o->tnil = m<0?true:false;
38 49 : o->tnonil = m<=0?false:true;
39 49 : bte *op = (bte*)Tloc(o, 0);
40 504 : BATloop(o, p, q) {
41 499 : if (op[p] == minval) {
42 : minpos = p;
43 : break;
44 : }
45 : }
46 1042 : BATloop(o, p, q) {
47 1038 : if (op[p] == maxval) {
48 : maxpos = p;
49 : break;
50 : }
51 : }
52 49 : o->tminpos = minpos;
53 49 : o->tmaxpos = maxpos;
54 49 : }
55 :
56 : static void
57 22 : BATmaxminpos_sht(BAT *o, sht m)
58 : {
59 22 : BUN minpos = BUN_NONE, maxpos = BUN_NONE, p, q;
60 22 : sht minval = m<0?GDK_sht_min:0; /* Later once nils use a bitmask we can include -32768 in the range */
61 22 : sht maxval = m<0?GDK_sht_max:m;
62 :
63 22 : assert(o->ttype == TYPE_sht);
64 22 : o->tnil = m<0?true:false;
65 22 : o->tnonil = m<=0?false:true;
66 22 : sht *op = (sht*)Tloc(o, 0);
67 67775 : BATloop(o, p, q) {
68 67767 : if (op[p] == minval) {
69 : minpos = p;
70 : break;
71 : }
72 : }
73 34791 : BATloop(o, p, q) {
74 34783 : if (op[p] == maxval) {
75 : maxpos = p;
76 : break;
77 : }
78 : }
79 22 : o->tminpos = minpos;
80 22 : o->tmaxpos = maxpos;
81 22 : }
82 :
83 : static str
84 59 : DICTcompress_intern(BAT **O, BAT **U, BAT *b, bool ordered, bool persists, bool smallest_type)
85 : {
86 : /* for now use all rows */
87 59 : BAT *u = BATunique(b, NULL), *uu = NULL;
88 59 : if (!u)
89 0 : throw(SQL, "dict.compress", GDK_EXCEPTION);
90 59 : assert(u->tkey);
91 :
92 59 : BUN cnt = BATcount(u);
93 : /* create hash on u */
94 59 : int tt = (cnt<256)?TYPE_bte:TYPE_sht;
95 59 : if (!smallest_type) {
96 6 : BUN cnt = BATcount(b);
97 6 : tt = (cnt<256)?TYPE_bte:TYPE_sht;
98 : }
99 59 : if (cnt >= 64*1024) {
100 0 : bat_destroy(u);
101 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "dict compress: too many values");
102 : }
103 59 : BAT *uv = BATproject(u, b); /* get values */
104 59 : bat_destroy(u);
105 59 : if (!uv)
106 0 : throw(SQL, "dict.compress", GDK_EXCEPTION);
107 59 : uv->tkey = true;
108 :
109 59 : if (ordered) {
110 39 : if (BATsort(&uu, NULL, NULL, uv, NULL, NULL, false, false, false) != GDK_SUCCEED) {
111 0 : bat_destroy(uv);
112 0 : throw(SQL, "dict.compress", GDK_EXCEPTION);
113 : }
114 39 : bat_destroy(uv);
115 39 : uv = uu;
116 : }
117 59 : u = uv;
118 59 : if (persists) {
119 53 : uu = COLcopy(uv, uv->ttype, true, PERSISTENT);
120 53 : bat_destroy(uv);
121 53 : if (!uu)
122 0 : throw(SQL, "dict.compress", GDK_EXCEPTION);
123 53 : assert(uu->tkey);
124 : u = uu;
125 : }
126 :
127 59 : BAT *o = COLnew(b->hseqbase, tt, BATcount(b), persists?PERSISTENT:TRANSIENT);
128 59 : if (!o || BAThash(u) != GDK_SUCCEED) {
129 0 : bat_destroy(o);
130 0 : bat_destroy(u);
131 0 : throw(SQL, "dict.compress", GDK_EXCEPTION);
132 : }
133 :
134 59 : BUN p, q;
135 59 : BATiter bi = bat_iterator(b);
136 59 : BATiter ui = bat_iterator_nolock(u);
137 59 : if (tt == TYPE_bte) {
138 49 : bte *op = (bte*)Tloc(o, 0);
139 49 : bool havenil = false;
140 479684 : BATloop(b, p, q) {
141 479635 : BUN up = 0;
142 982576 : HASHloop(ui, ui.b->thash, up, BUNtail(bi, p)) {
143 479635 : op[p] = (bte)up;
144 479635 : havenil |= is_bte_nil(op[p]);
145 : }
146 : }
147 49 : BATsetcount(o, BATcount(b));
148 49 : o->tsorted = (u->tsorted && bi.sorted);
149 49 : o->trevsorted = false;
150 49 : o->tnil = havenil;
151 49 : o->tnonil = !havenil;
152 49 : o->tkey = bi.key;
153 :
154 49 : if (BATcount(u) > 0)
155 42 : BATmaxminpos_bte(o, (bte) (BATcount(u)-1));
156 : } else {
157 10 : sht *op = (sht*)Tloc(o, 0);
158 10 : bool havenil = false;
159 227855 : BATloop(b, p, q) {
160 227845 : BUN up = 0;
161 552624 : HASHloop(ui, ui.b->thash, up, BUNtail(bi, p)) {
162 227845 : op[p] = (sht)up;
163 227845 : havenil |= is_sht_nil(op[p]);
164 : }
165 : }
166 10 : BATsetcount(o, BATcount(b));
167 10 : o->tsorted = (u->tsorted && bi.sorted);
168 10 : o->trevsorted = false;
169 10 : o->tnil = havenil;
170 10 : o->tnonil = !havenil;
171 10 : o->tkey = bi.key;
172 :
173 10 : if (BATcount(u) > 0)
174 10 : BATmaxminpos_sht(o, (sht) (BATcount(u)-1));
175 : }
176 59 : bat_iterator_end(&bi);
177 59 : *O = o;
178 59 : *U = u;
179 59 : return MAL_SUCCEED;
180 : }
181 :
182 : str
183 6 : DICTcompress(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
184 : {
185 6 : (void)cntxt;
186 6 : (void)mb;
187 : /* (o,v) = dict.compress(c) */
188 6 : bat *RO = getArgReference_bat(stk, pci, 0);
189 6 : bat *RV = getArgReference_bat(stk, pci, 1);
190 6 : bat C = *getArgReference_bat(stk, pci, 2);
191 :
192 6 : BAT *c = BATdescriptor(C), *O, *V;
193 :
194 6 : if (!c)
195 0 : throw(SQL, "dict.compress", SQLSTATE(HY013) MAL_MALLOC_FAIL);
196 6 : str msg = DICTcompress_intern(&O, &V, c, false, false, false /*output type matches input*/);
197 6 : bat_destroy(c);
198 6 : if (msg == MAL_SUCCEED) {
199 6 : *RO = O->batCacheid;
200 6 : BBPkeepref(O);
201 6 : *RV = V->batCacheid;
202 6 : BBPkeepref(V);
203 : }
204 : return msg;
205 : }
206 :
207 : str
208 54 : DICTcompress_col(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
209 : {
210 54 : (void)mb;
211 : /* always assume one result */
212 54 : str msg = MAL_SUCCEED;
213 54 : const char *sname = *getArgReference_str(stk, pci, 1);
214 54 : const char *tname = *getArgReference_str(stk, pci, 2);
215 54 : const char *cname = *getArgReference_str(stk, pci, 3);
216 54 : const bit ordered = (pci->argc > 4)?*getArgReference_bit(stk, pci, 4):FALSE;
217 54 : backend *be = NULL;
218 54 : sql_trans *tr = NULL;
219 :
220 54 : if (!sname || !tname || !cname)
221 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "dict compress: invalid column name");
222 54 : if (strNil(sname))
223 0 : throw(SQL, "dict.compress", SQLSTATE(42000) "Schema name cannot be NULL");
224 54 : if (strNil(tname))
225 0 : throw(SQL, "dict.compress", SQLSTATE(42000) "Table name cannot be NULL");
226 54 : if (strNil(cname))
227 0 : throw(SQL, "dict.compress", SQLSTATE(42000) "Column name cannot be NULL");
228 54 : if ((msg = getBackendContext(cntxt, &be)) != MAL_SUCCEED)
229 : return msg;
230 54 : tr = be->mvc->session->tr;
231 :
232 54 : sql_schema *s = find_sql_schema(tr, sname);
233 54 : if (!s)
234 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "schema '%s' unknown", sname);
235 54 : sql_table *t = find_sql_table(tr, s, tname);
236 54 : if (!t)
237 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "table '%s.%s' unknown", sname, tname);
238 54 : if (!isTable(t))
239 0 : throw(SQL, "dict.compress", SQLSTATE(42000) "%s '%s' is not persistent",
240 0 : TABLE_TYPE_DESCRIPTION(t->type, t->properties), t->base.name);
241 54 : if (isTempTable(t))
242 1 : throw(SQL, "dict.compress", SQLSTATE(42000) "columns from temporary tables cannot be compressed");
243 53 : if (t->system)
244 0 : throw(SQL, "dict.compress", SQLSTATE(42000) "columns from system tables cannot be compressed");
245 53 : sql_column *c = find_sql_column(t, cname);
246 53 : if (!c)
247 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "column '%s.%s.%s' unknown", sname, tname, cname);
248 53 : if (c->storage_type)
249 0 : throw(SQL, "dict.compress", SQLSTATE(3F000) "column '%s.%s.%s' already compressed", sname, tname, cname);
250 :
251 53 : sqlstore *store = tr->store;
252 53 : BAT *b = store->storage_api.bind_col(tr, c, RDONLY), *o, *u;
253 53 : if( b == NULL)
254 0 : throw(SQL,"dict.compress", SQLSTATE(HY005) "Cannot access column descriptor");
255 :
256 53 : msg = DICTcompress_intern(&o, &u, b, ordered, true, true);
257 53 : bat_destroy(b);
258 53 : if (msg == MAL_SUCCEED) {
259 53 : switch (sql_trans_alter_storage(tr, c, "DICT")) {
260 0 : case -1:
261 0 : msg = createException(SQL, "dict.compress", SQLSTATE(HY013) MAL_MALLOC_FAIL);
262 0 : break;
263 0 : case -2:
264 : case -3:
265 0 : msg = createException(SQL, "dict.compress", SQLSTATE(42000) "transaction conflict detected");
266 0 : break;
267 : default:
268 : break;
269 : }
270 53 : if (msg == MAL_SUCCEED && !(c = get_newcolumn(tr, c)))
271 0 : msg = createException(SQL, "dict.compress", SQLSTATE(HY013) "alter_storage failed");
272 0 : if (msg == MAL_SUCCEED) {
273 53 : switch (store->storage_api.col_compress(tr, c, ST_DICT, o, u)) {
274 0 : case -1:
275 0 : msg = createException(SQL, "dict.compress", SQLSTATE(HY013) MAL_MALLOC_FAIL);
276 0 : break;
277 0 : case -2:
278 : case -3:
279 0 : msg = createException(SQL, "dict.compress", SQLSTATE(42000) "transaction conflict detected");
280 0 : break;
281 : default:
282 : break;
283 : }
284 : }
285 53 : bat_destroy(u);
286 53 : bat_destroy(o);
287 : }
288 : return msg;
289 : }
290 :
291 : #define decompress_loop(TPE) \
292 : do { \
293 : TPE *up = Tloc(u, 0); \
294 : TPE *restrict bp = Tloc(b, 0); \
295 : BATloop(o, p, q) { \
296 : TPE v = up[op[p]]; \
297 : nils |= is_##TPE##_nil(v); \
298 : bp[p] = v; \
299 : } \
300 : BATsetcount(b, BATcount(o)); \
301 : BATnegateprops(b); \
302 : b->tnil = nils; \
303 : b->tnonil = !nils; \
304 : } while (0)
305 :
306 : BAT *
307 302 : DICTdecompress_(BAT *o, BAT *u, role_t role)
308 : {
309 302 : bool nils = false;
310 302 : BAT *b = COLnew(o->hseqbase, u->ttype, BATcount(o), role);
311 :
312 302 : if (!b)
313 : return NULL;
314 302 : BUN p, q;
315 302 : BATiter oi = bat_iterator(o);
316 302 : BATiter ui = bat_iterator_nolock(u);
317 302 : if (o->ttype == TYPE_bte) {
318 247 : unsigned char *op = Tloc(o, 0);
319 :
320 450 : switch (ATOMbasetype(u->ttype)) {
321 95 : case TYPE_int:
322 55813 : decompress_loop(int);
323 95 : break;
324 88 : case TYPE_lng:
325 251511 : decompress_loop(lng);
326 88 : break;
327 : #ifdef HAVE_HGE
328 4 : case TYPE_hge:
329 4 : decompress_loop(hge);
330 4 : break;
331 : #endif
332 60 : default:
333 2013 : BATloop(o, p, q) {
334 1953 : BUN up = op[p];
335 1953 : if (BUNappend(b, BUNtail(ui, up), false) != GDK_SUCCEED) {
336 0 : bat_iterator_end(&oi);
337 0 : bat_destroy(b);
338 0 : return NULL;
339 : }
340 : }
341 : }
342 : } else {
343 55 : assert(o->ttype == TYPE_sht);
344 55 : unsigned short *op = Tloc(o, 0);
345 :
346 70 : switch (ATOMbasetype(u->ttype)) {
347 52 : case TYPE_int:
348 332128 : decompress_loop(int);
349 52 : break;
350 1 : case TYPE_lng:
351 10 : decompress_loop(lng);
352 1 : break;
353 : #ifdef HAVE_HGE
354 1 : case TYPE_hge:
355 46 : decompress_loop(hge);
356 1 : break;
357 : #endif
358 1 : default:
359 10 : BATloop(o, p, q) {
360 9 : BUN up = op[p];
361 9 : if (BUNappend(b, BUNtail(ui, up), false) != GDK_SUCCEED) {
362 0 : bat_iterator_end(&oi);
363 0 : bat_destroy(b);
364 0 : return NULL;
365 : }
366 : }
367 : }
368 : }
369 302 : bat_iterator_end(&oi);
370 302 : return b;
371 : }
372 :
373 : str
374 302 : DICTdecompress(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
375 : {
376 302 : (void)cntxt;
377 302 : (void)mb;
378 302 : bat *r = getArgReference_bat(stk, pci, 0);
379 302 : bat O = *getArgReference_bat(stk, pci, 1);
380 302 : bat U = *getArgReference_bat(stk, pci, 2);
381 :
382 302 : BAT *o = BATdescriptor(O);
383 302 : BAT *u = BATdescriptor(U);
384 302 : if (!o || !u) {
385 0 : bat_destroy(o);
386 0 : bat_destroy(u);
387 0 : throw(SQL, "dict.decompress", SQLSTATE(HY013) MAL_MALLOC_FAIL);
388 : }
389 302 : BAT *b = DICTdecompress_(o, u, TRANSIENT);
390 302 : bat_destroy(o);
391 302 : bat_destroy(u);
392 302 : if (!b)
393 0 : throw(SQL, "dict.decompress", GDK_EXCEPTION);
394 302 : *r = b->batCacheid;
395 302 : BBPkeepref(b);
396 302 : return MAL_SUCCEED;
397 : }
398 :
399 : static BAT *
400 13 : convert_oid( BAT *o, int rt)
401 : {
402 13 : BUN p, q;
403 13 : BATiter oi = bat_iterator(o);
404 13 : BAT *b = COLnew(o->hseqbase, rt, oi.count, TRANSIENT);
405 13 : int brokenrange = 0, nil = 0;
406 :
407 13 : if (!b) {
408 0 : bat_iterator_end(&oi);
409 0 : return NULL;
410 : }
411 13 : if (rt == TYPE_bte) {
412 13 : unsigned char *rp = Tloc(b, 0);
413 13 : if (oi.type == TYPE_void) {
414 247 : BATloop(o, p, q) {
415 236 : rp[p] = (unsigned char) (p+o->tseqbase);
416 236 : brokenrange |= ((bte)rp[p] < 0);
417 236 : nil |= ((bte)rp[p] == bte_nil);
418 : }
419 : } else {
420 2 : oid *op = Tloc(o, 0);
421 177 : BATloop(o, p, q) {
422 175 : rp[p] = (unsigned char) op[p];
423 175 : brokenrange |= ((bte)rp[p] < 0);
424 175 : nil |= ((bte)rp[p] == bte_nil);
425 : }
426 : }
427 0 : } else if (rt == TYPE_sht) {
428 0 : unsigned short *rp = Tloc(b, 0);
429 0 : if (oi.type == TYPE_void) {
430 0 : BATloop(o, p, q) {
431 0 : rp[p] = (unsigned short) (p+o->tseqbase);
432 0 : brokenrange |= ((short)rp[p] < 0);
433 0 : nil |= ((short)rp[p] == sht_nil);
434 : }
435 : } else {
436 0 : oid *op = Tloc(o, 0);
437 0 : BATloop(o, p, q) {
438 0 : rp[p] = (unsigned short) op[p];
439 0 : brokenrange |= ((short)rp[p] < 0);
440 0 : nil |= ((short)rp[p] == sht_nil);
441 : }
442 : }
443 : } else {
444 0 : assert(0);
445 : }
446 13 : BATsetcount(b, oi.count);
447 13 : BATnegateprops(b);
448 13 : if (!brokenrange)
449 10 : b->tsorted = oi.sorted;
450 13 : b->tkey = oi.key;
451 13 : if (nil) {
452 2 : b->tnil = true;
453 2 : b->tnonil = false;
454 : } else {
455 11 : b->tnil = false;
456 11 : b->tnonil = true;
457 : }
458 13 : bat_iterator_end(&oi);
459 13 : return b;
460 : }
461 :
462 : str
463 6 : DICTconvert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
464 : {
465 : /* convert candidates into bte,sht,int offsets */
466 6 : (void)cntxt;
467 6 : bat *r = getArgReference_bat(stk, pci, 0);
468 6 : bat O = *getArgReference_bat(stk, pci, 1);
469 6 : int rt = getBatType(getArgType(mb, pci, 0));
470 :
471 6 : BAT *o = BATdescriptor(O);
472 6 : if (!o)
473 0 : throw(SQL, "dict.convert", SQLSTATE(HY013) MAL_MALLOC_FAIL);
474 :
475 6 : BAT *b = convert_oid(o, rt);
476 6 : if (!b) {
477 0 : bat_destroy(o);
478 0 : throw(SQL, "dict.convert", SQLSTATE(HY013) MAL_MALLOC_FAIL);
479 : }
480 :
481 6 : *r = b->batCacheid;
482 6 : BBPkeepref(b);
483 6 : bat_destroy(o);
484 6 : return MAL_SUCCEED;
485 : }
486 :
487 : /* renumber lo iff rv0 is sorted and dense directly lookup in rv1
488 : * if not dense (ie missing matches on the right side), first check (ie output
489 : * too large values for a match ie BATcount(rv1))
490 : * else sort rv0 -> reorder (project) rv1, then lookup etc in rv1
491 : * */
492 : static BAT *
493 1 : DICTrenumber_intern( BAT *o, BAT *lc, BAT *rc, BUN offcnt)
494 : {
495 1 : BAT *olc = lc, *orc = rc, *no = NULL;
496 1 : BATiter oi = bat_iterator(o);
497 1 : BUN cnt = oi.count;
498 :
499 1 : if (!lc->tsorted) {
500 0 : BAT *nlc = NULL, *nrc = NULL;
501 0 : int ret = BATsort(&nlc, &nrc, NULL, lc, NULL, NULL, false, false, false);
502 :
503 0 : if (ret != GDK_SUCCEED || !nlc || !nrc) {
504 0 : bat_iterator_end(&oi);
505 0 : bat_destroy(nlc);
506 0 : bat_destroy(nrc);
507 0 : return no;
508 : }
509 0 : lc = nlc;
510 0 : rc = nrc;
511 : }
512 : /* dense or cheap dense check */
513 1 : if (!BATtdense(lc) && !(lc->tsorted && lc->tkey && BATcount(lc) == offcnt && *(oid*)Tloc(lc, offcnt-1) == offcnt-1)) {
514 1 : BAT *nrc = COLnew(0, ATOMtype(rc->ttype), offcnt, TRANSIENT);
515 1 : if (!nrc) {
516 0 : bat_iterator_end(&oi);
517 0 : if (lc != olc)
518 0 : bat_destroy(lc);
519 0 : if (rc != orc)
520 0 : bat_destroy(rc);
521 0 : return no;
522 : }
523 :
524 : /* create map with holes filled in */
525 1 : oid *restrict op = Tloc(nrc, 0);
526 1 : unsigned char *lp = Tloc(lc, 0);
527 1 : if (BATtvoid(rc)) {
528 : oid seq = rc->tseqbase, j = 0;
529 5 : for(BUN i = 0; i<offcnt; i++) {
530 4 : if (lp[j] > i) {
531 0 : op[i] = offcnt;
532 : } else {
533 4 : op[i] = seq + j;
534 4 : j++;
535 : }
536 : }
537 : } else {
538 0 : oid *ip = Tloc(rc, 0);
539 0 : for(BUN i = 0, j = 0; i<offcnt; i++) {
540 0 : if (lp[j] > i) {
541 0 : op[i] = offcnt;
542 : } else {
543 0 : op[i] = ip[j++];
544 : }
545 : }
546 : }
547 1 : BATsetcount(nrc, offcnt);
548 1 : BATnegateprops(nrc);
549 1 : nrc->tkey = rc->tkey;
550 1 : if (orc != rc)
551 0 : bat_destroy(rc);
552 : rc = nrc;
553 : }
554 :
555 1 : no = COLnew(o->hseqbase, oi.type, cnt, TRANSIENT);
556 1 : if (!no) {
557 0 : bat_iterator_end(&oi);
558 0 : if (lc != olc)
559 0 : bat_destroy(lc);
560 0 : if (rc != orc)
561 0 : bat_destroy(rc);
562 0 : return no;
563 : }
564 1 : if (oi.type == TYPE_bte) {
565 1 : bte *op = Tloc(no, 0);
566 1 : oid *c = Tloc(rc, 0);
567 1 : unsigned char *ip = (unsigned char *) oi.base;
568 :
569 1 : for(BUN i = 0; i<cnt; i++) {
570 0 : op[i] = (bte) ((BUN)ip[i]==offcnt?offcnt:c[ip[i]]);
571 : }
572 1 : BATsetcount(no, cnt);
573 1 : BATnegateprops(no);
574 1 : no->tkey = oi.key;
575 0 : } else if (oi.type == TYPE_sht) {
576 0 : sht *op = Tloc(no, 0);
577 0 : oid *c = Tloc(rc, 0);
578 0 : unsigned short *ip = (unsigned short *) oi.base;
579 :
580 0 : for(BUN i = 0; i<cnt; i++) {
581 0 : op[i] = (sht) ((BUN)ip[i]==offcnt?offcnt:c[ip[i]]);
582 : }
583 0 : BATsetcount(no, cnt);
584 0 : BATnegateprops(no);
585 0 : no->tkey = oi.key;
586 : } else {
587 0 : assert(0);
588 : }
589 1 : bat_iterator_end(&oi);
590 1 : if (olc != lc)
591 0 : bat_destroy(lc);
592 1 : if (orc != rc)
593 1 : bat_destroy(rc);
594 : return no;
595 : }
596 :
597 : /* simple join operator with on both sides a (different) dictionary
598 : * (r0, r1) = dict.join(lo, lv, ro, rv, lcand, rcand, ... ) */
599 : str
600 6 : DICTjoin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
601 : {
602 6 : (void)cntxt;
603 6 : (void)mb;
604 6 : bat *R0 = getArgReference_bat(stk, pci, 0);
605 6 : bat *R1 = getArgReference_bat(stk, pci, 1);
606 6 : bat LO = *getArgReference_bat(stk, pci, 2);
607 6 : bat LV = *getArgReference_bat(stk, pci, 3);
608 6 : bat RO = *getArgReference_bat(stk, pci, 4);
609 6 : bat RV = *getArgReference_bat(stk, pci, 5);
610 6 : bat LC = *getArgReference_bat(stk, pci, 6);
611 6 : bat RC = *getArgReference_bat(stk, pci, 7);
612 6 : BAT *lc = NULL, *rc = NULL, *r0 = NULL, *r1 = NULL;
613 6 : bit nil_matches = *getArgReference_bit(stk, pci, 8);
614 6 : lng estimate = *getArgReference_lng(stk, pci, 9);
615 6 : str res = NULL;
616 6 : int err = 0;
617 :
618 6 : BAT *lo = BATdescriptor(LO);
619 6 : BAT *lv = BATdescriptor(LV);
620 6 : BAT *ro = BATdescriptor(RO);
621 6 : BAT *rv = BATdescriptor(RV);
622 :
623 6 : if (!is_bat_nil(LC))
624 0 : lc = BATdescriptor(LC);
625 6 : if (!is_bat_nil(RC))
626 0 : rc = BATdescriptor(RC);
627 6 : if (!lo || !lv || !ro || !rv || (!is_bat_nil(LC) && !lc) || (!is_bat_nil(RC) && !rc)) {
628 0 : bat_destroy(lo);
629 0 : bat_destroy(lv);
630 0 : bat_destroy(ro);
631 0 : bat_destroy(rv);
632 0 : bat_destroy(lc);
633 0 : bat_destroy(rc);
634 0 : throw(SQL, "dict.join", SQLSTATE(HY013) MAL_MALLOC_FAIL);
635 : }
636 :
637 : /* if both are the same, continue with join on indices */
638 6 : if (lv->batCacheid != rv->batCacheid) {
639 : /* first join values of the dicts */
640 6 : BAT *rv0 = NULL, *rv1 = NULL;
641 :
642 6 : if (BATjoin(&rv0, &rv1, lv, rv, NULL, NULL, nil_matches, BATcount(lv)) != GDK_SUCCEED) {
643 : err = 1;
644 : } else {
645 : /* input was unique, ie we do expect at least one dense candidate list */
646 6 : if (!BATtdense(rv0) || !BATtdense(rv1)) { /* the same again */
647 : /* smallest offset needs renumbering */
648 1 : if (BATcount(lo) < BATcount(ro)) {
649 0 : BAT *nlo = DICTrenumber_intern(lo, rv0, rv1, BATcount(lv));
650 0 : bat_destroy(lo);
651 0 : lo = nlo;
652 : } else {
653 1 : BAT *nro = DICTrenumber_intern(ro, rv1, rv0, BATcount(rv));
654 1 : bat_destroy(ro);
655 1 : ro = nro;
656 : }
657 1 : if (!lo || !ro)
658 0 : err = 1;
659 : }
660 6 : bat_destroy(rv0);
661 6 : bat_destroy(rv1);
662 : }
663 : }
664 6 : if (!err) {
665 6 : if (BATjoin(&r0, &r1, lo, ro, lc, rc, TRUE /* nil offset should match */, is_lng_nil(estimate) ? BUN_NONE : (BUN) estimate) != GDK_SUCCEED)
666 0 : err = 1;
667 : }
668 6 : bat_destroy(lo);
669 6 : bat_destroy(lv);
670 6 : bat_destroy(ro);
671 6 : bat_destroy(rv);
672 6 : bat_destroy(lc);
673 6 : bat_destroy(rc);
674 6 : if (r0) {
675 6 : *R0 = r0->batCacheid;
676 6 : BBPkeepref(r0);
677 : }
678 6 : if (r1) {
679 6 : *R1 = r1->batCacheid;
680 6 : BBPkeepref(r1);
681 : }
682 6 : if (err)
683 0 : throw(MAL, "BATjoin", GDK_EXCEPTION);
684 : return res;
685 : }
686 :
687 : str
688 184 : DICTthetaselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
689 : {
690 184 : (void)cntxt;
691 184 : (void)mb;
692 184 : bat *R0 = getArgReference_bat(stk, pci, 0);
693 184 : bat LO = *getArgReference_bat(stk, pci, 1);
694 184 : bat LC = *getArgReference_bat(stk, pci, 2);
695 184 : bat LV = *getArgReference_bat(stk, pci, 3);
696 184 : ptr v = getArgReference(stk, pci, 4);
697 184 : const char *op = *getArgReference_str(stk, pci, 5);
698 :
699 184 : BAT *lc = NULL, *bn = NULL;
700 184 : BAT *lo = BATdescriptor(LO);
701 184 : BAT *lv = BATdescriptor(LV);
702 184 : BATiter loi = bat_iterator(lo);
703 184 : BATiter lvi = bat_iterator(lv);
704 :
705 184 : if (!is_bat_nil(LC))
706 164 : lc = BATdescriptor(LC);
707 184 : if (!lo || !lv || (!is_bat_nil(LC) && !lc)) {
708 0 : bat_iterator_end(&loi);
709 0 : bat_iterator_end(&lvi);
710 0 : bat_destroy(lo);
711 0 : bat_destroy(lv);
712 0 : bat_destroy(lc);
713 0 : throw(SQL, "dict.thetaselect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
714 : }
715 :
716 184 : BUN max_cnt = lvi.type == TYPE_bte?256:(64*1024);
717 184 : if ((lvi.key && (op[0] == '=' || op[0] == '!')) || ((op[0] == '<' || op[0] == '>') && lvi.sorted && BATcount(lv) < (max_cnt/2))) {
718 177 : BUN p = BUN_NONE;
719 177 : if (ATOMextern(lvi.type))
720 105 : v = *(ptr*)v;
721 177 : if (ATOMcmp(lvi.type, v, ATOMnilptr(lvi.type)) == 0) {
722 : /* corner case, if v is NULL skip any calculations */
723 1 : bn = BATdense(0, 0, 0);
724 : } else {
725 176 : if (op[0] == '=' || op[0] == '!') {
726 132 : p = BUNfnd(lv, v);
727 44 : } else if (op[0] == '<' || op[0] == '>') {
728 44 : p = SORTfndfirst(lv, v);
729 44 : if (p != BUN_NONE && op[0] == '<' && op[1] == '=') {
730 13 : if (ATOMcmp(lvi.type, v, BUNtail(lvi, p)) != 0)
731 3 : p--;
732 31 : } else if (p != BUN_NONE && op[0] == '>' && !op[1]) {
733 12 : if (ATOMcmp(lvi.type, v, BUNtail(lvi, p)) != 0)
734 176 : op = ">=";
735 : }
736 : }
737 176 : if (p != BUN_NONE) {
738 159 : if (loi.type == TYPE_bte) {
739 150 : bte val = (bte)p;
740 150 : bn = BATthetaselect(lo, lc, &val, op);
741 9 : } else if (loi.type == TYPE_sht) {
742 9 : sht val = (sht)p;
743 9 : bn = BATthetaselect(lo, lc, &val, op);
744 : } else
745 0 : assert(0);
746 159 : if (bn && (op[0] == '<' || op[0] == '>' || op[0] == '!') && (!lvi.nonil || lvi.nil)) { /* filter the NULL value out */
747 34 : p = BUNfnd(lv, ATOMnilptr(lvi.type));
748 34 : if (p != BUN_NONE) {
749 6 : BAT *nbn = NULL;
750 6 : if (loi.type == TYPE_bte) {
751 6 : bte val = (bte)p;
752 6 : nbn = BATthetaselect(lo, bn, &val, "<>");
753 0 : } else if (loi.type == TYPE_sht) {
754 0 : sht val = (sht)p;
755 0 : nbn = BATthetaselect(lo, bn, &val, "<>");
756 : } else
757 : assert(0);
758 6 : BBPreclaim(bn);
759 6 : bn = nbn;
760 : }
761 : }
762 17 : } else if (op[0] == '!') {
763 9 : if (!lvi.nonil || lvi.nil) { /* find a possible NULL value */
764 8 : p = BUNfnd(lv, ATOMnilptr(lvi.type));
765 : } else {
766 : p = BUN_NONE;
767 : }
768 :
769 8 : if (p != BUN_NONE) { /* filter the NULL value out */
770 7 : if (loi.type == TYPE_bte) {
771 7 : bte val = (bte)p;
772 7 : bn = BATthetaselect(lo, lc, &val, op);
773 0 : } else if (loi.type == TYPE_sht) {
774 0 : sht val = (sht)p;
775 0 : bn = BATthetaselect(lo, lc, &val, op);
776 : } else
777 0 : assert(0);
778 2 : } else if (lc) { /* all rows pass, use input candidate list */
779 1 : bn = lc;
780 1 : BBPfix(lc->batCacheid); /* give one extra physical reference to keep the count in the end */
781 : } else { /* otherwise return all rows */
782 1 : bn = BATdense(0, 0, BATcount(lo));
783 : }
784 : } else {
785 8 : bn = BATdense(0, 0, 0);
786 : }
787 : }
788 : } else { /* select + intersect */
789 7 : if (ATOMextern(lvi.type))
790 0 : v = *(ptr*)v;
791 7 : bn = BATthetaselect(lv, NULL, v, op);
792 : /* call dict convert */
793 7 : if (bn) {
794 7 : BAT *c = convert_oid(bn, loi.type);
795 7 : bat_destroy(bn);
796 7 : bn = c;
797 : }
798 7 : if (bn) {
799 7 : BAT *n = BATintersect(lo, bn, lc, NULL, true, true, BATcount(lo));
800 7 : bat_destroy(bn);
801 7 : bn = n;
802 : }
803 : }
804 184 : bat_iterator_end(&loi);
805 184 : bat_iterator_end(&lvi);
806 184 : bat_destroy(lo);
807 184 : bat_destroy(lv);
808 184 : bat_destroy(lc);
809 184 : if (!bn)
810 0 : throw(SQL, "dict.thetaselect", GDK_EXCEPTION);
811 184 : *R0 = bn->batCacheid;
812 184 : BBPkeepref(bn);
813 184 : return MAL_SUCCEED;
814 : }
815 :
816 : str
817 62 : DICTselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
818 : {
819 62 : (void)cntxt;
820 62 : (void)mb;
821 62 : bat *R0 = getArgReference_bat(stk, pci, 0);
822 62 : bat LO = *getArgReference_bat(stk, pci, 1);
823 62 : bat LC = *getArgReference_bat(stk, pci, 2);
824 62 : bat LV = *getArgReference_bat(stk, pci, 3);
825 62 : ptr l = getArgReference(stk, pci, 4);
826 62 : ptr h = getArgReference(stk, pci, 5);
827 62 : bit li = *getArgReference_bit(stk, pci, 6);
828 62 : bit hi = *getArgReference_bit(stk, pci, 7);
829 62 : bit anti = *getArgReference_bit(stk, pci, 8);
830 62 : bit unknown = *getArgReference_bit(stk, pci, 9);
831 :
832 62 : if (!unknown ||
833 62 : (li != 0 && li != 1) ||
834 62 : (hi != 0 && hi != 1) ||
835 62 : (anti != 0 && anti != 1)) {
836 0 : throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
837 : }
838 :
839 62 : BAT *lc = NULL, *bn = NULL;
840 62 : BAT *lo = BATdescriptor(LO);
841 62 : BAT *lv = BATdescriptor(LV);
842 62 : BATiter loi = bat_iterator(lo);
843 62 : BATiter lvi = bat_iterator(lv);
844 :
845 62 : if (!is_bat_nil(LC))
846 62 : lc = BATdescriptor(LC);
847 62 : if (!lo || !lv || (!is_bat_nil(LC) && !lc)) {
848 0 : bat_iterator_end(&loi);
849 0 : bat_iterator_end(&lvi);
850 0 : bat_destroy(lo);
851 0 : bat_destroy(lv);
852 0 : bat_destroy(lc);
853 0 : throw(SQL, "dict.select", SQLSTATE(HY013) MAL_MALLOC_FAIL);
854 : }
855 :
856 62 : if (ATOMextern(lvi.type)) {
857 0 : l = *(ptr*)l;
858 0 : h = *(ptr*)h;
859 : }
860 :
861 : /* here we don't need open ended parts with nil */
862 62 : if (!anti) {
863 62 : const void *nilptr = ATOMnilptr(lvi.type);
864 62 : if (li == 1 && ATOMcmp(lvi.type, l, nilptr) == 0) {
865 0 : l = h;
866 0 : li = 0;
867 : }
868 62 : if (hi == 1 && ATOMcmp(lvi.type, h, nilptr) == 0) {
869 0 : h = l;
870 0 : hi = 0;
871 : }
872 62 : if (ATOMcmp(lvi.type, l, h) == 0 && ATOMcmp(lvi.type, h, nilptr) == 0) /* ugh sql nil != nil */
873 62 : anti = 1;
874 : }
875 62 : BUN max_cnt = lvi.type == TYPE_bte?256:(64*1024);
876 62 : if (!anti && lvi.key && lvi.sorted && BATcount(lv) < (max_cnt/2)) { /* ie select(lo, lc, find(lv, l), find(lv, h), ...) */
877 62 : BUN p = li?SORTfndfirst(lv, l):SORTfndlast(lv, l);
878 62 : BUN q = SORTfnd(lv, h);
879 :
880 62 : if (q == BUN_NONE) {
881 1 : q = SORTfndfirst(lv, h);
882 1 : q--;
883 : }
884 :
885 62 : if (p != BUN_NONE) {
886 62 : if (loi.type == TYPE_bte) {
887 33 : bte lpos = (bte)p;
888 33 : bte hpos = (bte)q;
889 33 : bn = BATselect(lo, lc, &lpos, &hpos, 1, hi, anti);
890 29 : } else if (loi.type == TYPE_sht) {
891 29 : sht lpos = (sht)p;
892 29 : sht hpos = (sht)q;
893 29 : bn = BATselect(lo, lc, &lpos, &hpos, 1, hi, anti);
894 : } else
895 0 : assert(0);
896 : } else {
897 0 : bn = BATdense(0, 0, 0);
898 : }
899 : } else {
900 0 : bn = BATselect(lv, NULL, l, h, li, hi, anti);
901 :
902 : /* call dict convert */
903 0 : if (bn) {
904 0 : BAT *c = convert_oid(bn, loi.type);
905 0 : bat_destroy(bn);
906 0 : bn = c;
907 : }
908 0 : if (bn) {
909 0 : BAT *n = BATintersect(lo, bn, lc, NULL, true, true, BATcount(lo));
910 0 : bat_destroy(bn);
911 0 : bn = n;
912 : }
913 : }
914 62 : bat_iterator_end(&loi);
915 62 : bat_iterator_end(&lvi);
916 62 : bat_destroy(lo);
917 62 : bat_destroy(lv);
918 62 : bat_destroy(lc);
919 62 : if (!bn)
920 0 : throw(SQL, "dict.select", GDK_EXCEPTION);
921 62 : *R0 = bn->batCacheid;
922 62 : BBPkeepref(bn);
923 62 : return MAL_SUCCEED;
924 : }
925 :
926 :
927 : BAT *
928 2 : DICTenlarge(BAT *offsets, BUN cnt, BUN sz, role_t role)
929 : {
930 2 : BAT *n = COLnew(offsets->hseqbase, TYPE_sht, sz, role);
931 :
932 2 : if (!n)
933 : return NULL;
934 2 : unsigned char *o = Tloc(offsets, 0);
935 2 : unsigned short *no = Tloc(n, 0);
936 227 : for(BUN i = 0; i<cnt; i++) {
937 225 : no[i] = o[i];
938 : }
939 2 : BATnegateprops(n);
940 2 : n->tnil = offsets->tnil;
941 2 : n->tnonil = offsets->tnonil;
942 2 : n->tkey = offsets->tkey;
943 2 : n->tsorted = offsets->tsorted;
944 2 : n->trevsorted = offsets->trevsorted;
945 2 : return n;
946 : }
947 :
948 : str
949 19 : DICTrenumber(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
950 : {
951 : /* r[p] = n[o[p]] */
952 19 : (void)cntxt;
953 19 : (void)mb;
954 19 : bat *R = getArgReference_bat(stk, pci, 0);
955 19 : bat O = *getArgReference_bat(stk, pci, 1);
956 19 : bat M = *getArgReference_bat(stk, pci, 2);
957 :
958 19 : BAT *o = BATdescriptor(O);
959 19 : BAT *m = BATdescriptor(M);
960 :
961 19 : if (!o || !m) {
962 0 : bat_destroy(o);
963 0 : bat_destroy(m);
964 0 : throw(SQL, "dict.renumber", SQLSTATE(HY013) MAL_MALLOC_FAIL);
965 : }
966 19 : BUN cnt = BATcount(o);
967 19 : BAT *n = COLnew(o->hseqbase, o->ttype, cnt, TRANSIENT);
968 19 : if (!n) {
969 0 : bat_destroy(o);
970 0 : bat_destroy(m);
971 0 : throw(SQL, "dict.renumber", SQLSTATE(HY013) MAL_MALLOC_FAIL);
972 : }
973 19 : assert(o->ttype == TYPE_bte || o->ttype == TYPE_sht);
974 19 : bool havenil = false;
975 19 : if (o->ttype == TYPE_bte) {
976 7 : unsigned char *np = Tloc(n, 0);
977 7 : unsigned char *op = Tloc(o, 0);
978 7 : unsigned char *mp = Tloc(m, 0);
979 45 : for(BUN i = 0; i<cnt; i++) {
980 38 : np[i] = mp[op[i]];
981 38 : havenil |= np[i] == 128;
982 : }
983 : } else {
984 12 : unsigned short *np = Tloc(n, 0);
985 12 : unsigned short *op = Tloc(o, 0);
986 12 : unsigned short *mp = Tloc(m, 0);
987 3310 : for(BUN i = 0; i<cnt; i++) {
988 3298 : np[i] = mp[op[i]];
989 3298 : havenil |= np[i] == 32768;
990 : }
991 : }
992 19 : BATsetcount(n, cnt);
993 19 : BATnegateprops(n);
994 19 : n->tnil = havenil;
995 19 : n->tnonil = !havenil;
996 19 : if (o->ttype == TYPE_bte) {
997 7 : unsigned char *mp = Tloc(m, 0);
998 7 : unsigned char mm = 0;
999 89 : for(BUN i = 0; i<BATcount(m); i++)
1000 82 : if (mp[i] > mm)
1001 : mm = mp[i];
1002 7 : BATmaxminpos_bte(n, mm);
1003 : } else {
1004 12 : unsigned short *mp = Tloc(m, 0);
1005 12 : unsigned short mm = 0;
1006 26774 : for(BUN i = 0; i<BATcount(m); i++)
1007 26762 : if (mp[i] > mm)
1008 : mm = mp[i];
1009 12 : BATmaxminpos_sht(n, mm);
1010 : }
1011 19 : bat_destroy(o);
1012 18 : bat_destroy(m);
1013 19 : *R = n->batCacheid;
1014 19 : BBPkeepref(n);
1015 19 : return MAL_SUCCEED;
1016 : }
1017 :
1018 : /* for each val in vals compute its offset in dict (return via noffsets),
1019 : * any missing value in dict will be added to the dict.
1020 : * Possible side-effects:
1021 : * dict is nolonger sorted
1022 : * increase of the dict could mean the offset type overflows, then the output is
1023 : * an offset bat with a larger type, unless the larger type is int then abort.
1024 : *
1025 : * Returns < 0 on error.
1026 : */
1027 : int
1028 17 : DICTprepare4append(BAT **noffsets, BAT *vals, BAT *dict)
1029 : {
1030 17 : int tt = BATcount(dict)>=256?TYPE_sht:TYPE_bte;
1031 17 : BUN sz = BATcount(vals), nf = 0;
1032 17 : BAT *n = COLnew(0, tt, sz, TRANSIENT);
1033 17 : bool havenil = false;
1034 :
1035 17 : if (!n || BAThash(dict) != GDK_SUCCEED) {
1036 0 : bat_destroy(n);
1037 0 : return -1;
1038 : }
1039 :
1040 17 : BATiter bi = bat_iterator(vals);
1041 17 : BATiter ui = bat_iterator_nolock(dict);
1042 :
1043 17 : if (tt == TYPE_bte) {
1044 17 : bte *op = (bte*)Tloc(n, 0);
1045 275 : for(BUN i = 0; i<sz; i++) {
1046 259 : BUN up = 0;
1047 259 : int f = 0;
1048 334 : HASHloop(ui, ui.b->thash, up, BUNtail(bi, i)) {
1049 19 : op[i] = (bte)up;
1050 19 : f = 1;
1051 : }
1052 259 : if (!f) {
1053 240 : if (BATcount(dict) >= 255) {
1054 1 : BAT *nn = DICTenlarge(n, i, sz, TRANSIENT);
1055 1 : bat_destroy(n);
1056 1 : if (!nn) {
1057 0 : bat_iterator_end(&bi);
1058 0 : return -1;
1059 : }
1060 : n = nn;
1061 : nf = i;
1062 : tt = TYPE_sht;
1063 : break;
1064 : } else {
1065 239 : if (BUNappend(dict, BUNtail(bi, i), true) != GDK_SUCCEED ||
1066 239 : (!dict->thash && BAThash(dict) != GDK_SUCCEED)) {
1067 0 : assert(0);
1068 : bat_destroy(n);
1069 : bat_iterator_end(&bi);
1070 : return -1;
1071 : }
1072 : /* reinitialize */
1073 239 : ui = bat_iterator_nolock(dict);
1074 239 : op[i] = (bte) (BATcount(dict)-1);
1075 239 : havenil |= is_bte_nil(op[i]);
1076 : }
1077 : }
1078 : }
1079 : }
1080 17 : if (tt == TYPE_sht) {
1081 1 : sht *op = (sht*)Tloc(n, 0);
1082 2 : for(BUN i = nf; i<sz; i++) {
1083 1 : BUN up = 0;
1084 1 : int f = 0;
1085 2 : HASHloop(ui, ui.b->thash, up, BUNtail(bi, i)) {
1086 0 : op[i] = (sht)up;
1087 0 : f = 1;
1088 : }
1089 1 : if (!f) {
1090 1 : if (BATcount(dict) >= (64*1024)-1) {
1091 0 : assert(0);
1092 : bat_destroy(n);
1093 : bat_iterator_end(&bi);
1094 : return -2;
1095 : } else {
1096 1 : if (BUNappend(dict, BUNtail(bi, i), true) != GDK_SUCCEED ||
1097 1 : (!dict->thash && BAThash(dict) != GDK_SUCCEED)) {
1098 0 : assert(0);
1099 : bat_destroy(n);
1100 : bat_iterator_end(&bi);
1101 : return -1;
1102 : }
1103 : /* reinitialize */
1104 1 : ui = bat_iterator_nolock(dict);
1105 1 : op[i] = (sht) (BATcount(dict)-1);
1106 1 : havenil |= is_sht_nil(op[i]);
1107 : }
1108 : }
1109 : }
1110 : }
1111 17 : bat_iterator_end(&bi);
1112 17 : BATsetcount(n, sz);
1113 17 : BATnegateprops(n);
1114 17 : n->tnil = havenil;
1115 17 : n->tnonil = !havenil;
1116 17 : *noffsets = n;
1117 17 : return 0;
1118 : }
1119 :
1120 : static sht *
1121 0 : DICTenlarge_vals(bte *offsets, BUN cnt, BUN sz)
1122 : {
1123 0 : sht *n = GDKmalloc(sizeof(sht) * sz);
1124 :
1125 0 : if (!n)
1126 : return NULL;
1127 : unsigned char *o = (unsigned char*)offsets;
1128 : unsigned short *no = (unsigned short*)n;
1129 0 : for(BUN i = 0; i<cnt; i++) {
1130 0 : no[i] = o[i];
1131 : }
1132 : return n;
1133 : }
1134 :
1135 : int
1136 4 : DICTprepare4append_vals(void **noffsets, void *vals, BUN cnt, BAT *dict)
1137 : {
1138 4 : int tt = BATcount(dict)>=256?TYPE_sht:TYPE_bte;
1139 8 : BUN sz = cnt, nf = 0;
1140 4 : void *n = GDKmalloc((tt==TYPE_bte?sizeof(bte):sizeof(sht)) * sz);
1141 :
1142 4 : if (!n || BAThash(dict) != GDK_SUCCEED) {
1143 0 : GDKfree(n);
1144 0 : return -1;
1145 : }
1146 :
1147 4 : int varsized = ATOMvarsized(dict->ttype);
1148 4 : int wd = (varsized?sizeof(char*):dict->twidth);
1149 4 : char *vp = vals;
1150 4 : BATiter ui = bat_iterator_nolock(dict);
1151 4 : if (tt == TYPE_bte) {
1152 : bte *op = (bte*)n;
1153 8 : for(BUN i = 0; i<sz; i++, vp += wd) {
1154 4 : BUN up = 0;
1155 4 : int f = 0;
1156 4 : void *val = (void*)vp;
1157 4 : if (varsized)
1158 0 : val = *(void**)vp;
1159 6 : HASHloop(ui, ui.b->thash, up, val) {
1160 0 : op[i] = (bte)up;
1161 0 : f = 1;
1162 : }
1163 4 : if (!f) {
1164 4 : if (BATcount(dict) >= 255) {
1165 0 : sht *nn = DICTenlarge_vals(n, i, sz);
1166 0 : GDKfree(n);
1167 0 : if (!nn)
1168 : return -1;
1169 : n = nn;
1170 : nf = i;
1171 : tt = TYPE_sht;
1172 : break;
1173 : } else {
1174 4 : if (BUNappend(dict, val, true) != GDK_SUCCEED ||
1175 4 : (!dict->thash && BAThash(dict) != GDK_SUCCEED)) {
1176 0 : assert(0);
1177 : GDKfree(n);
1178 : return -1;
1179 : }
1180 : /* reinitialize */
1181 4 : ui = bat_iterator_nolock(dict);
1182 4 : op[i] = (bte) (BATcount(dict)-1);
1183 : }
1184 : }
1185 : }
1186 : }
1187 4 : if (tt == TYPE_sht) {
1188 : sht *op = (sht*)n;
1189 0 : for(BUN i = nf; i<sz; i++) {
1190 0 : BUN up = 0;
1191 0 : int f = 0;
1192 0 : void *val = (void*)vp;
1193 0 : if (varsized)
1194 0 : val = *(void**)vp;
1195 0 : HASHloop(ui, ui.b->thash, up, val) {
1196 0 : op[i] = (sht)up;
1197 0 : f = 1;
1198 : }
1199 0 : if (!f) {
1200 0 : if (BATcount(dict) >= (64*1024)-1) {
1201 0 : assert(0);
1202 : GDKfree(n);
1203 : return -2;
1204 : } else {
1205 0 : if (BUNappend(dict, val, true) != GDK_SUCCEED ||
1206 0 : (!dict->thash && BAThash(dict) != GDK_SUCCEED)) {
1207 0 : assert(0);
1208 : GDKfree(n);
1209 : return -1;
1210 : }
1211 : /* reinitialize */
1212 0 : ui = bat_iterator_nolock(dict);
1213 0 : op[i] = (sht) (BATcount(dict)-1);
1214 : }
1215 : }
1216 : }
1217 : }
1218 4 : *noffsets = n;
1219 4 : return 0;
1220 : }
|