LCOV - code coverage report
Current view: top level - sql/backends/monet5 - dict.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 595 809 73.5 %
Date: 2024-11-14 20:04:02 Functions: 18 19 94.7 %

          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         309 : DICTdecompress_(BAT *o, BAT *u, role_t role)
     308             : {
     309         309 :         bool nils = false;
     310         309 :         BAT *b = COLnew(o->hseqbase, u->ttype, BATcount(o), role);
     311             : 
     312         309 :         if (!b)
     313             :                 return NULL;
     314         309 :         BUN p, q;
     315         309 :         BATiter oi = bat_iterator(o);
     316         309 :         BATiter ui = bat_iterator_nolock(u);
     317         309 :         if (o->ttype == TYPE_bte) {
     318         238 :                 unsigned char *op = Tloc(o, 0);
     319             : 
     320         426 :                 switch (ATOMbasetype(u->ttype)) {
     321          87 :                 case TYPE_int:
     322       70836 :                         decompress_loop(int);
     323          87 :                         break;
     324          84 :                 case TYPE_lng:
     325      191483 :                         decompress_loop(lng);
     326          84 :                         break;
     327             : #ifdef HAVE_HGE
     328           0 :                 case TYPE_hge:
     329           0 :                         decompress_loop(hge);
     330           0 :                         break;
     331             : #endif
     332          67 :                 default:
     333        2039 :                         BATloop(o, p, q) {
     334        1972 :                                 BUN up = op[p];
     335        1972 :                                 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          71 :                 assert(o->ttype == TYPE_sht);
     344          71 :                 unsigned short *op = Tloc(o, 0);
     345             : 
     346          86 :                 switch (ATOMbasetype(u->ttype)) {
     347          69 :                 case TYPE_int:
     348      407928 :                         decompress_loop(int);
     349          69 :                         break;
     350           1 :                 case TYPE_lng:
     351          10 :                         decompress_loop(lng);
     352           1 :                         break;
     353             : #ifdef HAVE_HGE
     354           0 :                 case TYPE_hge:
     355           0 :                         decompress_loop(hge);
     356           0 :                         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         309 :         bat_iterator_end(&oi);
     370         309 :         return b;
     371             : }
     372             : 
     373             : str
     374         309 : DICTdecompress(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     375             : {
     376         309 :         (void)cntxt;
     377         309 :         (void)mb;
     378         309 :         bat *r = getArgReference_bat(stk, pci, 0);
     379         309 :         bat O = *getArgReference_bat(stk, pci, 1);
     380         309 :         bat U = *getArgReference_bat(stk, pci, 2);
     381             : 
     382         309 :         BAT *o = BATdescriptor(O);
     383         309 :         BAT *u = BATdescriptor(U);
     384         309 :         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         309 :         BAT *b = DICTdecompress_(o, u, TRANSIENT);
     390         309 :         bat_destroy(o);
     391         309 :         bat_destroy(u);
     392         309 :         if (!b)
     393           0 :                 throw(SQL, "dict.decompress", GDK_EXCEPTION);
     394         309 :         *r = b->batCacheid;
     395         309 :         BBPkeepref(b);
     396         309 :         return MAL_SUCCEED;
     397             : }
     398             : 
     399             : static BAT *
     400          12 : convert_oid( BAT *o, int rt)
     401             : {
     402          12 :         BUN p, q;
     403          12 :         BATiter oi = bat_iterator(o);
     404          12 :         BAT *b = COLnew(o->hseqbase, rt, oi.count, TRANSIENT);
     405          12 :         int brokenrange = 0, nil = 0;
     406             : 
     407          12 :         if (!b) {
     408           0 :                 bat_iterator_end(&oi);
     409           0 :                 return NULL;
     410             :         }
     411          12 :         if (rt == TYPE_bte) {
     412          12 :                 unsigned char *rp = Tloc(b, 0);
     413          12 :                 if (oi.type == TYPE_void) {
     414         246 :                         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          12 :         BATsetcount(b, oi.count);
     447          12 :         BATnegateprops(b);
     448          12 :         if (!brokenrange)
     449           9 :                 b->tsorted = oi.sorted;
     450          12 :         b->tkey = oi.key;
     451          12 :         if (nil) {
     452           2 :                 b->tnil = true;
     453           2 :                 b->tnonil = false;
     454             :         } else {
     455          10 :                 b->tnil = false;
     456          10 :                 b->tnonil = true;
     457             :         }
     458          12 :         bat_iterator_end(&oi);
     459          12 :         return b;
     460             : }
     461             : 
     462             : str
     463           5 : DICTconvert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     464             : {
     465             :         /* convert candidates into bte,sht,int offsets */
     466           5 :         (void)cntxt;
     467           5 :         bat *r = getArgReference_bat(stk, pci, 0);
     468           5 :         bat O = *getArgReference_bat(stk, pci, 1);
     469           5 :         int rt = getBatType(getArgType(mb, pci, 0));
     470             : 
     471           5 :         BAT *o = BATdescriptor(O);
     472           5 :         if (!o)
     473           0 :                 throw(SQL, "dict.convert", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     474             : 
     475           5 :         BAT *b = convert_oid(o, rt);
     476           5 :         if (!b) {
     477           0 :                 bat_destroy(o);
     478           0 :                 throw(SQL, "dict.convert", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     479             :         }
     480             : 
     481           5 :         *r = b->batCacheid;
     482           5 :         BBPkeepref(b);
     483           5 :         bat_destroy(o);
     484           5 :         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         182 : DICTthetaselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     689             : {
     690         182 :         (void)cntxt;
     691         182 :         (void)mb;
     692         182 :         bat *R0 = getArgReference_bat(stk, pci, 0);
     693         182 :         bat LO = *getArgReference_bat(stk, pci, 1);
     694         182 :         bat LC = *getArgReference_bat(stk, pci, 2);
     695         182 :         bat LV = *getArgReference_bat(stk, pci, 3);
     696         182 :         ptr v = getArgReference(stk, pci, 4);
     697         182 :         const char *op = *getArgReference_str(stk, pci, 5);
     698             : 
     699         182 :         BAT *lc = NULL, *bn = NULL;
     700         182 :         BAT *lo = BATdescriptor(LO);
     701         182 :         BAT *lv = BATdescriptor(LV);
     702         182 :         BATiter loi = bat_iterator(lo);
     703         182 :         BATiter lvi = bat_iterator(lv);
     704             : 
     705         182 :         if (!is_bat_nil(LC))
     706         164 :                 lc = BATdescriptor(LC);
     707         182 :         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         182 :         BUN max_cnt = lvi.type == TYPE_bte?256:(64*1024);
     717         182 :         if ((lvi.key && (op[0] == '=' || op[0] == '!')) || ((op[0] == '<' || op[0] == '>') && lvi.sorted && BATcount(lv) < (max_cnt/2))) {
     718         175 :                 BUN p = BUN_NONE;
     719         175 :                 if (ATOMextern(lvi.type))
     720         105 :                         v = *(ptr*)v;
     721         175 :                 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         174 :                         if (op[0] == '=' || op[0] == '!') {
     726         130 :                                 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         174 :                                                 op = ">=";
     735             :                                 }
     736             :                         }
     737         174 :                         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           6 :                                         p = BUNfnd(lv, ATOMnilptr(lvi.type));
     748           6 :                                         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          15 :                         } else if (op[0] == '!') {
     763           8 :                                 if (!lvi.nonil || lvi.nil) { /* find a possible NULL value */
     764           7 :                                         p = BUNfnd(lv, ATOMnilptr(lvi.type));
     765             :                                 } else {
     766             :                                         p = BUN_NONE;
     767             :                                 }
     768             : 
     769           7 :                                 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           1 :                                 } 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           0 :                                         bn = BATdense(0, 0, BATcount(lo));
     783             :                                 }
     784             :                         } else {
     785           7 :                                 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         182 :         bat_iterator_end(&loi);
     805         182 :         bat_iterator_end(&lvi);
     806         182 :         bat_destroy(lo);
     807         182 :         bat_destroy(lv);
     808         182 :         bat_destroy(lc);
     809         182 :         if (!bn)
     810           0 :                 throw(SQL, "dict.thetaselect", GDK_EXCEPTION);
     811         182 :         *R0 = bn->batCacheid;
     812         182 :         BBPkeepref(bn);
     813         182 :         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       29292 :                 for(BUN i = 0; i<BATcount(m); i++)
    1007       29280 :                         if (mp[i] > mm)
    1008             :                                 mm = mp[i];
    1009          12 :                 BATmaxminpos_sht(n, mm);
    1010             :         }
    1011          19 :         bat_destroy(o);
    1012          19 :         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             : }

Generated by: LCOV version 1.14