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