LCOV - code coverage report
Current view: top level - sql/backends/monet5 - dict.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 606 1009 60.1 %
Date: 2024-10-07 21:21:43 Functions: 18 22 81.8 %

          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          53 : BATmaxminpos_bte(BAT *o, bte m)
      31             : {
      32          53 :         BUN minpos = BUN_NONE, maxpos = BUN_NONE, p, q;
      33          53 :         bte minval = m<0?GDK_bte_min:0; /* Later once nils use a bitmask we can include -128 in the range */
      34          51 :         bte maxval = m<0?GDK_bte_max:m;
      35             : 
      36          53 :         o->tnil = m<0?true:false;
      37          53 :         o->tnonil = m<=0?false:true;
      38          53 :         bte *op = (bte*)Tloc(o, 0);
      39         510 :         BATloop(o, p, q) {
      40         501 :                 if (op[p] == minval) {
      41             :                         minpos = p;
      42             :                         break;
      43             :                 }
      44             :         }
      45        1046 :         BATloop(o, p, q) {
      46        1038 :                 if (op[p] == maxval) {
      47             :                         maxpos = p;
      48             :                         break;
      49             :                 }
      50             :         }
      51          53 :         o->tminpos = minpos;
      52          53 :         o->tmaxpos = maxpos;
      53          53 : }
      54             : 
      55             : static void
      56          34 : BATmaxminpos_sht(BAT *o, sht m)
      57             : {
      58          34 :         BUN minpos = BUN_NONE, maxpos = BUN_NONE, p, q;
      59          34 :         sht minval = m<0?GDK_sht_min:0; /* Later once nils use a bitmask we can include -32768 in the range */
      60          34 :         sht maxval = m<0?GDK_sht_max:m;
      61             : 
      62          34 :         assert(o->ttype == TYPE_sht);
      63          34 :         o->tnil = m<0?true:false;
      64          34 :         o->tnonil = m<=0?false:true;
      65          34 :         sht *op = (sht*)Tloc(o, 0);
      66       67814 :         BATloop(o, p, q) {
      67       67798 :                 if (op[p] == minval) {
      68             :                         minpos = p;
      69             :                         break;
      70             :                 }
      71             :         }
      72       34865 :         BATloop(o, p, q) {
      73       34849 :                 if (op[p] == maxval) {
      74             :                         maxpos = p;
      75             :                         break;
      76             :                 }
      77             :         }
      78          34 :         o->tminpos = minpos;
      79          34 :         o->tmaxpos = maxpos;
      80          34 : }
      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         482 : DICTdecompress_(BAT *o, BAT *u, role_t role)
     353             : {
     354         482 :         bool nils = false;
     355         482 :         BAT *b = COLnew(o->hseqbase, u->ttype, BATcount(o), role);
     356             : 
     357         482 :         if (!b)
     358             :                 return NULL;
     359         482 :         BUN p, q;
     360         482 :         BATiter oi = bat_iterator(o);
     361         481 :         BATiter ui = bat_iterator_nolock(u);
     362         481 :         if (o->ttype == TYPE_bte) {
     363         354 :                 unsigned char *op = Tloc(o, 0);
     364             : 
     365         638 :                 switch (ATOMbasetype(u->ttype)) {
     366         108 :                 case TYPE_int:
     367       70857 :                         decompress_loop(int);
     368         108 :                         break;
     369         155 :                 case TYPE_lng:
     370      191554 :                         decompress_loop(lng);
     371         155 :                         break;
     372             : #ifdef HAVE_HGE
     373           0 :                 case TYPE_hge:
     374           0 :                         decompress_loop(hge);
     375           0 :                         break;
     376             : #endif
     377          91 :                 default:
     378        2064 :                         BATloop(o, p, q) {
     379        1973 :                                 BUN up = op[p];
     380        1973 :                                 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         127 :         } else if (o->ttype == TYPE_sht) {
     388         127 :                 unsigned short *op = Tloc(o, 0);
     389             : 
     390         150 :                 switch (ATOMbasetype(u->ttype)) {
     391         125 :                 case TYPE_int:
     392      332764 :                         decompress_loop(int);
     393         124 :                         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         480 :         bat_iterator_end(&oi);
     443         480 :         return b;
     444             : }
     445             : 
     446             : str
     447         475 : DICTdecompress(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     448             : {
     449         475 :         (void)cntxt;
     450         475 :         (void)mb;
     451         475 :         bat *r = getArgReference_bat(stk, pci, 0);
     452         475 :         bat O = *getArgReference_bat(stk, pci, 1);
     453         475 :         bat U = *getArgReference_bat(stk, pci, 2);
     454             : 
     455         475 :         BAT *o = BATdescriptor(O);
     456         479 :         BAT *u = BATdescriptor(U);
     457         482 :         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         482 :         BAT *b = DICTdecompress_(o, u, TRANSIENT);
     463         479 :         bat_destroy(o);
     464         482 :         bat_destroy(u);
     465         482 :         if (!b)
     466           0 :                 throw(SQL, "dict.decompress", GDK_EXCEPTION);
     467         482 :         *r = b->batCacheid;
     468         482 :         BBPkeepref(b);
     469         482 :         return MAL_SUCCEED;
     470             : }
     471             : 
     472             : static BAT *
     473          16 : convert_oid( BAT *o, int rt)
     474             : {
     475          16 :         BUN p, q;
     476          16 :         BATiter oi = bat_iterator(o);
     477          16 :         BAT *b = COLnew(o->hseqbase, rt, oi.count, TRANSIENT);
     478          16 :         int brokenrange = 0, nil = 0;
     479             : 
     480          16 :         if (!b) {
     481           0 :                 bat_iterator_end(&oi);
     482           0 :                 return NULL;
     483             :         }
     484          16 :         if (rt == TYPE_bte) {
     485          16 :                 unsigned char *rp = Tloc(b, 0);
     486          16 :                 if (oi.type == TYPE_void) {
     487         350 :                         BATloop(o, p, q) {
     488         336 :                                 rp[p] = (unsigned char) (p+o->tseqbase);
     489         336 :                                 brokenrange |= ((bte)rp[p] < 0);
     490         336 :                                 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          16 :         BATsetcount(b, oi.count);
     536          16 :         BATnegateprops(b);
     537          16 :         if (!brokenrange)
     538          13 :                 b->tsorted = oi.sorted;
     539          16 :         b->tkey = oi.key;
     540          16 :         if (nil) {
     541           2 :                 b->tnil = true;
     542           2 :                 b->tnonil = false;
     543             :         } else {
     544          14 :                 b->tnil = false;
     545          14 :                 b->tnonil = true;
     546             :         }
     547          16 :         bat_iterator_end(&oi);
     548          16 :         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          10 : DICTjoin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     701             : {
     702          10 :         (void)cntxt;
     703          10 :         (void)mb;
     704          10 :         bat *R0 = getArgReference_bat(stk, pci, 0);
     705          10 :         bat *R1 = getArgReference_bat(stk, pci, 1);
     706          10 :         bat LO = *getArgReference_bat(stk, pci, 2);
     707          10 :         bat LV = *getArgReference_bat(stk, pci, 3);
     708          10 :         bat RO = *getArgReference_bat(stk, pci, 4);
     709          10 :         bat RV = *getArgReference_bat(stk, pci, 5);
     710          10 :         bat LC = *getArgReference_bat(stk, pci, 6);
     711          10 :         bat RC = *getArgReference_bat(stk, pci, 7);
     712          10 :         BAT *lc = NULL, *rc = NULL, *r0 = NULL, *r1 = NULL;
     713          10 :         bit nil_matches = *getArgReference_bit(stk, pci, 8);
     714          10 :         lng estimate = *getArgReference_lng(stk, pci, 9);
     715          10 :         str res = NULL;
     716          10 :         int err = 0;
     717             : 
     718          10 :         BAT *lo = BATdescriptor(LO);
     719          10 :         BAT *lv = BATdescriptor(LV);
     720          10 :         BAT *ro = BATdescriptor(RO);
     721          10 :         BAT *rv = BATdescriptor(RV);
     722             : 
     723          10 :         if (!is_bat_nil(LC))
     724           0 :                 lc = BATdescriptor(LC);
     725          10 :         if (!is_bat_nil(RC))
     726           0 :                 rc = BATdescriptor(RC);
     727          10 :         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          10 :         if (lv->batCacheid != rv->batCacheid) {
     739             :                 /* first join values of the dicts */
     740          10 :                 BAT *rv0 = NULL, *rv1 = NULL;
     741             : 
     742          10 :                 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          10 :                         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          10 :                         bat_destroy(rv0);
     761          10 :                         bat_destroy(rv1);
     762             :                 }
     763             :         }
     764          10 :         if (!err) {
     765          10 :                 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          10 :         bat_destroy(lo);
     769          10 :         bat_destroy(lv);
     770          10 :         bat_destroy(ro);
     771          10 :         bat_destroy(rv);
     772          10 :         bat_destroy(lc);
     773          10 :         bat_destroy(rc);
     774          10 :         if (r0) {
     775          10 :                 *R0 = r0->batCacheid;
     776          10 :                 BBPkeepref(r0);
     777             :         }
     778          10 :         if (r1) {
     779          10 :                 *R1 = r1->batCacheid;
     780          10 :                 BBPkeepref(r1);
     781             :         }
     782          10 :         if (err)
     783           0 :                 throw(MAL, "BATjoin", GDK_EXCEPTION);
     784             :         return res;
     785             : }
     786             : 
     787             : str
     788         279 : DICTthetaselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     789             : {
     790         279 :         (void)cntxt;
     791         279 :         (void)mb;
     792         279 :         bat *R0 = getArgReference_bat(stk, pci, 0);
     793         279 :         bat LO = *getArgReference_bat(stk, pci, 1);
     794         279 :         bat LC = *getArgReference_bat(stk, pci, 2);
     795         279 :         bat LV = *getArgReference_bat(stk, pci, 3);
     796         279 :         ptr v = getArgReference(stk, pci, 4);
     797         279 :         const char *op = *getArgReference_str(stk, pci, 5);
     798             : 
     799         279 :         BAT *lc = NULL, *bn = NULL;
     800         279 :         BAT *lo = BATdescriptor(LO);
     801         285 :         BAT *lv = BATdescriptor(LV);
     802         285 :         BATiter loi = bat_iterator(lo);
     803         285 :         BATiter lvi = bat_iterator(lv);
     804             : 
     805         284 :         if (!is_bat_nil(LC))
     806         248 :                 lc = BATdescriptor(LC);
     807         284 :         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         284 :         BUN max_cnt = lvi.type == TYPE_bte?256:(64*1024);
     817         284 :         if ((lvi.key && (op[0] == '=' || op[0] == '!')) || ((op[0] == '<' || op[0] == '>') && lvi.sorted && BATcount(lv) < (max_cnt/2))) {
     818         270 :                 BUN p = BUN_NONE;
     819         270 :                 if (ATOMextern(lvi.type))
     820         188 :                         v = *(ptr*)v;
     821         270 :                 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         269 :                         if (op[0] == '=' || op[0] == '!') {
     826         213 :                                 p =  BUNfnd(lv, v);
     827          56 :                         } else if (op[0] == '<' || op[0] == '>') {
     828          56 :                                 p = SORTfndfirst(lv, v);
     829          56 :                                 if (p != BUN_NONE && op[0] == '<' && op[1] == '=') {
     830          17 :                                         if (ATOMcmp(lvi.type, v, BUNtail(lvi, p)) != 0)
     831           3 :                                                 p--;
     832          39 :                                 } else if (p != BUN_NONE && op[0] == '>' && !op[1]) {
     833          16 :                                         if (ATOMcmp(lvi.type, v, BUNtail(lvi, p)) != 0)
     834         270 :                                                 op = ">=";
     835             :                                 }
     836             :                         }
     837         270 :                         if (p != BUN_NONE) {
     838         251 :                                 if (loi.type == TYPE_bte) {
     839         234 :                                         bte val = (bte)p;
     840         234 :                                         bn =  BATthetaselect(lo, lc, &val, op);
     841          17 :                                 } else if (loi.type == TYPE_sht) {
     842          17 :                                         sht val = (sht)p;
     843          17 :                                         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         250 :                                 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          19 :                         } 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          11 :                                 bn = BATdense(0, 0, 0);
     895             :                         }
     896             :                 }
     897             :         } else { /* select + intersect */
     898          14 :                 if (ATOMextern(lvi.type))
     899           1 :                         v = *(ptr*)v;
     900          14 :                 bn = BATthetaselect(lv, NULL, v, op);
     901             :                 /* call dict convert */
     902          14 :                 if (bn) {
     903          14 :                         BAT *c = convert_oid(bn, loi.type);
     904          14 :                         bat_destroy(bn);
     905          14 :                         bn = c;
     906             :                 }
     907          14 :                 if (bn) {
     908          14 :                         BAT *n = BATintersect(lo, bn, lc, NULL, true, true, BATcount(lo));
     909          14 :                         bat_destroy(bn);
     910          14 :                         bn = n;
     911             :                 }
     912             :         }
     913         284 :         bat_iterator_end(&loi);
     914         285 :         bat_iterator_end(&lvi);
     915         284 :         bat_destroy(lo);
     916         284 :         bat_destroy(lv);
     917         285 :         bat_destroy(lc);
     918         285 :         if (!bn)
     919           0 :                 throw(SQL, "dict.thetaselect", GDK_EXCEPTION);
     920         285 :         *R0 = bn->batCacheid;
     921         285 :         BBPkeepref(bn);
     922         285 :         return MAL_SUCCEED;
     923             : }
     924             : 
     925             : str
     926         109 : DICTselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     927             : {
     928         109 :         (void)cntxt;
     929         109 :         (void)mb;
     930         109 :         bat *R0 = getArgReference_bat(stk, pci, 0);
     931         109 :         bat LO = *getArgReference_bat(stk, pci, 1);
     932         109 :         bat LC = *getArgReference_bat(stk, pci, 2);
     933         109 :         bat LV = *getArgReference_bat(stk, pci, 3);
     934         109 :         ptr l = getArgReference(stk, pci, 4);
     935         109 :         ptr h = getArgReference(stk, pci, 5);
     936         111 :         bit li = *getArgReference_bit(stk, pci, 6);
     937         111 :         bit hi = *getArgReference_bit(stk, pci, 7);
     938         111 :         bit anti = *getArgReference_bit(stk, pci, 8);
     939         111 :         bit unknown = *getArgReference_bit(stk, pci, 9);
     940             : 
     941         111 :         if (!unknown ||
     942         111 :                 (li != 0 && li != 1) ||
     943         111 :                 (hi != 0 && hi != 1) ||
     944         111 :                 (anti != 0 && anti != 1)) {
     945           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     946             :         }
     947             : 
     948         113 :         BAT *lc = NULL, *bn = NULL;
     949         113 :         BAT *lo = BATdescriptor(LO);
     950         117 :         BAT *lv = BATdescriptor(LV);
     951         118 :         BATiter loi = bat_iterator(lo);
     952         118 :         BATiter lvi = bat_iterator(lv);
     953             : 
     954         118 :         if (!is_bat_nil(LC))
     955         118 :                 lc = BATdescriptor(LC);
     956         118 :         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         118 :         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         118 :         if (!anti) {
     972         118 :                 const void *nilptr = ATOMnilptr(lvi.type);
     973         118 :                 if (li == 1 && ATOMcmp(lvi.type, l, nilptr) == 0) {
     974           0 :                         l = h;
     975           0 :                         li = 0;
     976             :                 }
     977         118 :                 if (hi == 1 && ATOMcmp(lvi.type, h, nilptr) == 0) {
     978           0 :                         h = l;
     979           0 :                         hi = 0;
     980             :                 }
     981         118 :                 if (ATOMcmp(lvi.type, l, h) == 0 && ATOMcmp(lvi.type, h, nilptr) == 0) /* ugh sql nil != nil */
     982         118 :                         anti = 1;
     983             :         }
     984         118 :         BUN max_cnt = lvi.type == TYPE_bte?256:(64*1024);
     985         118 :         if (!anti && lvi.key && lvi.sorted && BATcount(lv) < (max_cnt/2)) { /* ie select(lo, lc, find(lv, l), find(lv, h), ...) */
     986         118 :                 BUN p = li?SORTfndfirst(lv, l):SORTfndlast(lv, l);
     987         118 :                 BUN q = SORTfnd(lv, h);
     988             : 
     989         118 :                 if (q == BUN_NONE) {
     990           1 :                         q = SORTfndfirst(lv, h);
     991           1 :                         q--;
     992             :                 }
     993             : 
     994         118 :                 if (p != BUN_NONE) {
     995         118 :                         if (loi.type == TYPE_bte) {
     996          65 :                                 bte lpos = (bte)p;
     997          65 :                                 bte hpos = (bte)q;
     998          65 :                                 bn =  BATselect(lo, lc, &lpos, &hpos, true, hi, anti, false);
     999          53 :                         } else if (loi.type == TYPE_sht) {
    1000          53 :                                 sht lpos = (sht)p;
    1001          53 :                                 sht hpos = (sht)q;
    1002          53 :                                 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         118 :         bat_iterator_end(&loi);
    1028         118 :         bat_iterator_end(&lvi);
    1029         118 :         bat_destroy(lo);
    1030         118 :         bat_destroy(lv);
    1031         118 :         bat_destroy(lc);
    1032         118 :         if (!bn)
    1033           0 :                 throw(SQL, "dict.select", GDK_EXCEPTION);
    1034         118 :         *R0 = bn->batCacheid;
    1035         118 :         BBPkeepref(bn);
    1036         118 :         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          33 : DICTrenumber(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1090             : {
    1091             :         /* r[p] = n[o[p]] */
    1092          33 :         (void)cntxt;
    1093          33 :         (void)mb;
    1094          33 :         bat *R = getArgReference_bat(stk, pci, 0);
    1095          33 :         bat O = *getArgReference_bat(stk, pci, 1);
    1096          33 :         bat M = *getArgReference_bat(stk, pci, 2);
    1097             : 
    1098          33 :         BAT *o = BATdescriptor(O);
    1099          35 :         BAT *m = BATdescriptor(M);
    1100             : 
    1101          35 :         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          35 :         BUN cnt = BATcount(o);
    1107          35 :         BAT *n = COLnew(o->hseqbase, o->ttype, cnt, TRANSIENT);
    1108          35 :         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          35 :         assert(o->ttype == TYPE_bte || o->ttype == TYPE_sht || o->ttype == TYPE_int);
    1114          35 :         bool havenil = false;
    1115          35 :         if (o->ttype == TYPE_bte) {
    1116          11 :                 unsigned char *np = Tloc(n, 0);
    1117          11 :                 unsigned char *op = Tloc(o, 0);
    1118          11 :                 unsigned char *mp = Tloc(m, 0);
    1119          49 :                 for(BUN i = 0; i<cnt; i++) {
    1120          38 :                         np[i] = mp[op[i]];
    1121          38 :                         havenil |= np[i] == 128;
    1122             :                 }
    1123          24 :         } else if (o->ttype == TYPE_sht) {
    1124          24 :                 unsigned short *np = Tloc(n, 0);
    1125          24 :                 unsigned short *op = Tloc(o, 0);
    1126          24 :                 unsigned short *mp = Tloc(m, 0);
    1127        3322 :                 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          35 :         BATsetcount(n, cnt);
    1141          35 :         BATnegateprops(n);
    1142          35 :         n->tnil = havenil;
    1143          35 :         n->tnonil = !havenil;
    1144          35 :         if (o->ttype == TYPE_bte) {
    1145          11 :                 unsigned char *mp = Tloc(m, 0);
    1146          11 :                 unsigned char mm = 0;
    1147         145 :                 for(BUN i = 0; i<BATcount(m); i++)
    1148         134 :                         if (mp[i] > mm)
    1149             :                                 mm = mp[i];
    1150          11 :                 BATmaxminpos_bte(n, mm);
    1151          24 :         } else if (o->ttype == TYPE_sht) {
    1152          24 :                 unsigned short *mp = Tloc(m, 0);
    1153          24 :                 unsigned short mm = 0;
    1154       58584 :                 for(BUN i = 0; i<BATcount(m); i++)
    1155       58560 :                         if (mp[i] > mm)
    1156             :                                 mm = mp[i];
    1157          24 :                 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          35 :         bat_destroy(o);
    1167          35 :         bat_destroy(m);
    1168          35 :         *R = n->batCacheid;
    1169          35 :         BBPkeepref(n);
    1170          35 :         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             : }

Generated by: LCOV version 1.14