LCOV - code coverage report
Current view: top level - gdk - gdk_select.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1043 1305 79.9 %
Date: 2024-11-13 19:37:10 Functions: 24 25 96.0 %

          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 "gdk.h"
      15             : #include "gdk_private.h"
      16             : 
      17             : /* auxiliary functions and structs for imprints */
      18             : #include "gdk_imprints.h"
      19             : 
      20             : static inline oid *
      21   105664222 : buninsfix(BAT *bn, oid *a, BUN i, oid v, BUN g, BUN m)
      22             : {
      23   105664222 :         if (i == BATcapacity(bn)) {
      24          32 :                 BATsetcount(bn, i);
      25          32 :                 if (BATextend(bn, MIN(BATcapacity(bn) + g, m)) != GDK_SUCCEED)
      26             :                         return NULL;
      27          32 :                 a = (oid *) Tloc(bn, 0);
      28             :         }
      29   105664222 :         a[i] = v;
      30   105664222 :         return a;
      31             : }
      32             : 
      33             : BAT *
      34     2160478 : virtualize(BAT *bn)
      35             : {
      36             :         /* input must be a valid candidate list or NULL */
      37     2160478 :         if (bn == NULL)
      38             :                 return NULL;
      39     2160478 :         if ((bn->ttype != TYPE_void && bn->ttype != TYPE_oid) || !bn->tkey || !bn->tsorted) {
      40           0 :                 fprintf(stderr, "#bn type %d nil %d key %d sorted %d\n",
      41           0 :                         bn->ttype, is_oid_nil(bn->tseqbase),
      42           0 :                         bn->tkey, bn->tsorted);
      43           0 :                 fflush(stderr);
      44             :         }
      45     2161263 :         assert(((bn->ttype == TYPE_void && !is_oid_nil(bn->tseqbase)) ||
      46             :                 bn->ttype == TYPE_oid) &&
      47             :                bn->tkey && bn->tsorted);
      48     2161263 :         assert(BBP_refs(bn->batCacheid) == 1);
      49     2161263 :         assert(BBP_lrefs(bn->batCacheid) == 0);
      50             :         /* since bn has unique and strictly ascending values, we can
      51             :          * easily check whether the column is dense */
      52     2161263 :         if (bn->ttype == TYPE_oid &&
      53     1493524 :             (BATcount(bn) <= 1 ||
      54      409525 :              * (const oid *) Tloc(bn, 0) + BATcount(bn) - 1 ==
      55      409525 :              * (const oid *) Tloc(bn, BATcount(bn) - 1))) {
      56             :                 /* column is dense, replace by virtual oid */
      57     1126976 :                 oid tseq;       /* work around bug in Intel compiler */
      58     1126976 :                 if (BATcount(bn) == 0)
      59             :                         tseq = 0;
      60             :                 else
      61      433660 :                         tseq = * (const oid *) Tloc(bn, 0);
      62     1126976 :                 TRC_DEBUG(ALGO, ALGOBATFMT ",seq=" OIDFMT "\n",
      63             :                           ALGOBATPAR(bn), tseq);
      64     1126735 :                 bn->tseqbase = tseq;
      65     1126735 :                 if (VIEWtparent(bn)) {
      66          12 :                         Heap *h = GDKmalloc(sizeof(Heap));
      67          12 :                         if (h == NULL) {
      68           0 :                                 BBPunfix(bn->batCacheid);
      69           0 :                                 return NULL;
      70             :                         }
      71          12 :                         *h = *bn->theap;
      72          12 :                         settailname(h, BBP_physical(bn->batCacheid), TYPE_oid, 0);
      73          12 :                         h->parentid = bn->batCacheid;
      74          12 :                         h->base = NULL;
      75          12 :                         h->hasfile = false;
      76          12 :                         ATOMIC_INIT(&h->refs, 1);
      77          12 :                         if (bn->theap->parentid != bn->batCacheid)
      78          12 :                                 BBPrelease(bn->theap->parentid);
      79          12 :                         HEAPdecref(bn->theap, false);
      80          12 :                         bn->theap = h;
      81             :                 } else {
      82     1126723 :                         HEAPfree(bn->theap, true);
      83             :                 }
      84     1126926 :                 bn->theap->storage = bn->theap->newstorage = STORE_MEM;
      85     1126926 :                 bn->theap->size = 0;
      86     1126926 :                 bn->ttype = TYPE_void;
      87     1126926 :                 bn->twidth = 0;
      88     1126926 :                 bn->tshift = 0;
      89             :         }
      90             : 
      91             :         return bn;
      92             : }
      93             : 
      94             : #define HASHloop_bound(bi, h, hb, v, lo, hi)            \
      95             :         for (hb = HASHget(h, HASHprobe((h), v));        \
      96             :              hb != BUN_NONE;                            \
      97             :              hb = HASHgetlink(h,hb))                    \
      98             :                 if (hb >= (lo) && hb < (hi) &&            \
      99             :                     (cmp == NULL ||                     \
     100             :                      (*cmp)(v, BUNtail(bi, hb)) == 0))
     101             : 
     102             : static BAT *
     103       65039 : hashselect(BATiter *bi, struct canditer *restrict ci, BAT *bn,
     104             :            const void *tl, BUN maximum, bool havehash, bool phash,
     105             :            const char **algo)
     106             : {
     107       65039 :         BUN i, cnt;
     108       65039 :         oid o, *restrict dst;
     109       65039 :         BUN l, h, d = 0;
     110       65039 :         oid seq;
     111       65039 :         int (*cmp)(const void *, const void *);
     112       65039 :         BAT *b2 = NULL;
     113       65039 :         BATiter pbi = {0};
     114             : 
     115       65039 :         size_t counter = 0;
     116       65039 :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();
     117             : 
     118       65145 :         assert(bn->ttype == TYPE_oid);
     119       65145 :         seq = bi->b->hseqbase;
     120       65145 :         l = ci->seq - seq;
     121       65145 :         h = canditer_last(ci) + 1 - seq;
     122             : 
     123       64954 :         *algo = "hashselect";
     124       64954 :         if (phash && (b2 = BATdescriptor(VIEWtparent(bi->b))) != NULL) {
     125       64432 :                 *algo = "hashselect on parent";
     126       64432 :                 TRC_DEBUG(ALGO, ALGOBATFMT
     127             :                           " using parent(" ALGOBATFMT ") "
     128             :                           "for hash\n",
     129             :                           ALGOBATPAR(bi->b),
     130             :                           ALGOBATPAR(b2));
     131       64432 :                 d = bi->baseoff - b2->tbaseoff;
     132       64432 :                 l += d;
     133       64432 :                 h += d;
     134       64432 :                 pbi = bat_iterator(b2);
     135       64432 :                 bi = &pbi;
     136             :         } else {
     137             :                 phash = false;
     138             :         }
     139             : 
     140       65226 :         if (!havehash) {
     141           3 :                 if (BAThash(bi->b) != GDK_SUCCEED) {
     142           0 :                         BBPreclaim(bn);
     143           0 :                         BBPreclaim(b2);
     144           0 :                         if (phash)
     145           0 :                                 bat_iterator_end(&pbi);
     146           0 :                         return NULL;
     147             :                 }
     148           4 :                 MT_rwlock_rdlock(&bi->b->thashlock);
     149           4 :                 if (bi->b->thash == NULL) {
     150           0 :                         GDKerror("Hash destroyed before we could use it\n");
     151           0 :                         goto bailout;
     152             :                 }
     153             :         }
     154      130451 :         switch (ATOMbasetype(bi->type)) {
     155             :         case TYPE_bte:
     156             :         case TYPE_sht:
     157             :                 cmp = NULL;     /* no need to compare: "hash" is perfect */
     158             :                 break;
     159       65228 :         default:
     160       65228 :                 cmp = ATOMcompare(bi->type);
     161       65228 :                 break;
     162             :         }
     163       65227 :         dst = (oid *) Tloc(bn, 0);
     164       65227 :         cnt = 0;
     165       65227 :         if (ci->tpe != cand_dense) {
     166       40724 :                 HASHloop_bound(*bi, bi->b->thash, i, tl, l, h) {
     167       15992 :                         GDK_CHECK_TIMEOUT(qry_ctx, counter,
     168             :                                           GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
     169       15992 :                         o = (oid) (i + seq - d);
     170       15992 :                         if (canditer_contains(ci, o)) {
     171       31152 :                                 dst = buninsfix(bn, dst, cnt, o,
     172       15576 :                                                 maximum - BATcapacity(bn),
     173             :                                                 maximum);
     174       15576 :                                 if (dst == NULL)
     175           0 :                                         goto bailout;
     176       15576 :                                 cnt++;
     177             :                         }
     178             :                 }
     179             :         } else {
     180      177154 :                 HASHloop_bound(*bi, bi->b->thash, i, tl, l, h) {
     181       65280 :                         GDK_CHECK_TIMEOUT(qry_ctx, counter,
     182             :                                           GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
     183       65280 :                         o = (oid) (i + seq - d);
     184      130632 :                         dst = buninsfix(bn, dst, cnt, o,
     185       65280 :                                         maximum - BATcapacity(bn),
     186             :                                         maximum);
     187       65352 :                         if (dst == NULL)
     188           0 :                                 goto bailout;
     189       65352 :                         cnt++;
     190             :                 }
     191             :         }
     192       65236 :         MT_rwlock_rdunlock(&bi->b->thashlock);
     193       65265 :         BBPreclaim(b2);
     194       65226 :         BATsetcount(bn, cnt);
     195       65223 :         bn->tkey = true;
     196       65223 :         if (cnt > 1) {
     197             :                 /* hash chains produce results in the order high to
     198             :                  * low, so we just need to reverse */
     199       35240 :                 for (l = 0, h = BATcount(bn) - 1; l < h; l++, h--) {
     200       32302 :                         o = dst[l];
     201       32302 :                         dst[l] = dst[h];
     202       32302 :                         dst[h] = o;
     203             :                 }
     204             :         }
     205       65223 :         bn->tsorted = true;
     206       65223 :         bn->trevsorted = bn->batCount <= 1;
     207       65223 :         bn->tseqbase = bn->batCount == 0 ? 0 : bn->batCount == 1 ? *dst : oid_nil;
     208       65223 :         if (phash)
     209       64366 :                 bat_iterator_end(&pbi);
     210             :         return bn;
     211             : 
     212           0 :   bailout:
     213           0 :         MT_rwlock_rdunlock(&bi->b->thashlock);
     214           0 :         if (phash)
     215           0 :                 bat_iterator_end(&pbi);
     216           0 :         BBPreclaim(b2);
     217           0 :         BBPreclaim(bn);
     218           0 :         return NULL;
     219             : }
     220             : 
     221             : /* Imprints select code */
     222             : 
     223             : /* inner check, non-dense canditer */
     224             : #define impscheck(TEST,ADD)                                     \
     225             :         do {                                                    \
     226             :                 const oid e = (oid) (i+limit-pr_off+hseq);      \
     227             :                 if (im[icnt] & mask) {                              \
     228             :                         if ((im[icnt] & ~innermask) == 0) { \
     229             :                                 while (p < ncand && o < e) {      \
     230             :                                         v = src[o-hseq];        \
     231             :                                         if ((ADD) == NULL) {    \
     232             :                                                 goto bailout;   \
     233             :                                         }                       \
     234             :                                         cnt++;                  \
     235             :                                         p++;                    \
     236             :                                         o = canditer_next(ci);  \
     237             :                                 }                               \
     238             :                         } else {                                \
     239             :                                 while (p < ncand && o < e) {      \
     240             :                                         v = src[o-hseq];        \
     241             :                                         if ((ADD) == NULL) {    \
     242             :                                                 goto bailout;   \
     243             :                                         }                       \
     244             :                                         cnt += (TEST) != 0;     \
     245             :                                         p++;                    \
     246             :                                         o = canditer_next(ci);  \
     247             :                                 }                               \
     248             :                         }                                       \
     249             :                 } else {                                        \
     250             :                         while (p < ncand && o < e) {              \
     251             :                                 p++;                            \
     252             :                                 o = canditer_next(ci);          \
     253             :                         }                                       \
     254             :                 }                                               \
     255             :         } while (false)
     256             : 
     257             : /* inner check, dense canditer */
     258             : #define impscheck_dense(TEST,ADD)                                       \
     259             :         do {                                                            \
     260             :                 const oid e = (oid) (i+limit-pr_off+hseq);              \
     261             :                 if (im[icnt] & mask) {                                      \
     262             :                         if ((im[icnt] & ~innermask) == 0) {         \
     263             :                                 while (p < ncand && o < e) {              \
     264             :                                         v = src[o-hseq];                \
     265             :                                         if ((ADD) == NULL) {            \
     266             :                                                 goto bailout;           \
     267             :                                         }                               \
     268             :                                         cnt++;                          \
     269             :                                         p++;                            \
     270             :                                         o = canditer_next_dense(ci);    \
     271             :                                 }                                       \
     272             :                         } else {                                        \
     273             :                                 while (p < ncand && o < e) {              \
     274             :                                         v = src[o-hseq];                \
     275             :                                         if ((ADD) == NULL) {            \
     276             :                                                 goto bailout;           \
     277             :                                         }                               \
     278             :                                         cnt += (TEST) != 0;             \
     279             :                                         p++;                            \
     280             :                                         o = canditer_next_dense(ci);    \
     281             :                                 }                                       \
     282             :                         }                                               \
     283             :                 } else {                                                \
     284             :                         BUN skip_sz = MIN(ncand - p, e - o);            \
     285             :                         p += skip_sz;                                   \
     286             :                         o += skip_sz;                                   \
     287             :                         ci->next += skip_sz;                         \
     288             :                 }                                                       \
     289             :         } while (false)
     290             : 
     291             : /* main loop for imprints */
     292             : /*
     293             :  * icnt is the iterator for imprints
     294             :  * dcnt is the iterator for dictionary entries
     295             :  * i    is the iterator for the values in imprints
     296             :  */
     297             : #define impsloop(ISDENSE,TEST,ADD)                                      \
     298             :         do {                                                            \
     299             :                 BUN dcnt, icnt, limit, i;                               \
     300             :                 const cchdc_t *restrict d = (cchdc_t *) imprints->dict;      \
     301             :                 const uint8_t rpp = ATOMelmshift(IMPS_PAGE >> bi->shift); \
     302             :                 o = canditer_next(ci);                                  \
     303             :                 for (i = 0, dcnt = 0, icnt = 0, p = 0;                  \
     304             :                      dcnt < imprints->dictcnt && i <= w - hseq + pr_off && p < ncand; \
     305             :                      dcnt++) {                                          \
     306             :                         GDK_CHECK_TIMEOUT(qry_ctx, counter, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx)); \
     307             :                         limit = ((BUN) d[dcnt].cnt) << rpp;               \
     308             :                         while (i + limit <= o - hseq + pr_off) {     \
     309             :                                 i += limit;                             \
     310             :                                 icnt += d[dcnt].repeat ? 1 : d[dcnt].cnt; \
     311             :                                 dcnt++;                                 \
     312             :                                 limit = ((BUN) d[dcnt].cnt) << rpp;       \
     313             :                         }                                               \
     314             :                         if (!d[dcnt].repeat) {                          \
     315             :                                 const BUN l = icnt + d[dcnt].cnt;       \
     316             :                                 limit = (BUN) 1 << rpp;                   \
     317             :                                 while (i + limit <= o - hseq + pr_off) { \
     318             :                                         icnt++;                         \
     319             :                                         i += limit;                     \
     320             :                                 }                                       \
     321             :                                 for (;                                  \
     322             :                                      icnt < l && i <= w - hseq + pr_off; \
     323             :                                      icnt++) {                          \
     324             :                                         impscheck##ISDENSE(TEST,ADD);   \
     325             :                                         i += limit;                     \
     326             :                                 }                                       \
     327             :                         }                                               \
     328             :                         else {                                          \
     329             :                                 impscheck##ISDENSE(TEST,ADD);           \
     330             :                                 i += limit;                             \
     331             :                                 icnt++;                                 \
     332             :                         }                                               \
     333             :                 }                                                       \
     334             :         } while (false)
     335             : 
     336             : static inline oid *
     337           0 : quickins(oid *dst, BUN cnt, oid o, BAT *bn)
     338             : {
     339           0 :         (void) bn;
     340           0 :         assert(cnt < BATcapacity(bn));
     341           0 :         dst[cnt] = o;
     342           0 :         return dst;
     343             : }
     344             : 
     345             : /* construct the mask */
     346             : #define impsmask(ISDENSE,TEST,B)                                        \
     347             :         do {                                                            \
     348             :                 const uint##B##_t *restrict im = (uint##B##_t *) imprints->imps; \
     349             :                 uint##B##_t mask = 0, innermask;                        \
     350             :                 const int tpe = ATOMbasetype(bi->type);                      \
     351             :                 const int lbin = IMPSgetbin(tpe, imprints->bits, imprints->bins, &vl); \
     352             :                 const int hbin = IMPSgetbin(tpe, imprints->bits, imprints->bins, &vh); \
     353             :                 /* note: (1<<n)-1 gives a sequence of n one bits */       \
     354             :                 /* to set bits hbin..lbin inclusive, we would do: */    \
     355             :                 /* mask = ((1 << (hbin + 1)) - 1) - ((1 << lbin) - 1); */ \
     356             :                 /* except ((1 << (hbin + 1)) - 1) is not defined if */    \
     357             :                 /* hbin == sizeof(uint##B##_t)*8 - 1 */                 \
     358             :                 /* the following does work, however */                  \
     359             :                 mask = (((((uint##B##_t) 1 << hbin) - 1) << 1) | 1) - (((uint##B##_t) 1 << lbin) - 1); \
     360             :                 innermask = mask;                                       \
     361             :                 if (vl != minval)                                       \
     362             :                         innermask = IMPSunsetBit(B, innermask, lbin);   \
     363             :                 if (vh != maxval)                                       \
     364             :                         innermask = IMPSunsetBit(B, innermask, hbin);   \
     365             :                 if (anti) {                                             \
     366             :                         uint##B##_t tmp = mask;                         \
     367             :                         mask = ~innermask;                              \
     368             :                         innermask = ~tmp;                               \
     369             :                 }                                                       \
     370             :                 /* if there are nils, we may need to check bin 0 */     \
     371             :                 if (!bi->nonil)                                              \
     372             :                         innermask = IMPSunsetBit(B, innermask, 0);      \
     373             :                                                                         \
     374             :                 if (BATcapacity(bn) < maximum) {                     \
     375             :                         impsloop(ISDENSE, TEST,                         \
     376             :                                  dst = buninsfix(bn, dst, cnt, o,       \
     377             :                                                  (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p) \
     378             :                                                         * (dbl) (ncand-p) * 1.1 + 1024), \
     379             :                                                  maximum));             \
     380             :                 } else {                                                \
     381             :                         impsloop(ISDENSE, TEST, dst = quickins(dst, cnt, o, bn)); \
     382             :                 }                                                       \
     383             :         } while (false)
     384             : 
     385             : #define checkMINMAX(B, TYPE)                                            \
     386             :         do {                                                            \
     387             :                 const BUN *restrict imp_cnt = imprints->stats + 128; \
     388             :                 imp_min = imp_max = nil;                                \
     389             :                 for (BUN ii = 0; ii < B; ii++) {                     \
     390             :                         if (is_##TYPE##_nil(imp_min) && imp_cnt[ii]) {  \
     391             :                                 imp_min = basesrc[imprints->stats[ii]];      \
     392             :                                 break;                                  \
     393             :                         }                                               \
     394             :                 }                                                       \
     395             :                 for (BUN ii = B; ii != 0; ii--) {                       \
     396             :                         if (is_##TYPE##_nil(imp_max) && imp_cnt[ii-1]) { \
     397             :                                 imp_max = basesrc[imprints->stats[64+ii-1]]; \
     398             :                                 break;                                  \
     399             :                         }                                               \
     400             :                 }                                                       \
     401             :                 assert(!is_##TYPE##_nil(imp_min) &&                     \
     402             :                        !is_##TYPE##_nil(imp_max));                      \
     403             :                 if (anti ?                                              \
     404             :                     vl < imp_min && vh > imp_max :                        \
     405             :                     vl > imp_max || vh < imp_min) {                       \
     406             :                         if (pbat)                                       \
     407             :                                 BBPunfix(pbat->batCacheid);          \
     408             :                         return 0;                                       \
     409             :                 }                                                       \
     410             :         } while (false)
     411             : 
     412             : /* choose number of bits */
     413             : #define bitswitch(ISDENSE, TEST, TYPE)                                  \
     414             :         do {                                                            \
     415             :                 BUN ncand = ci->ncand;                                       \
     416             :                 assert(imprints);                                       \
     417             :                 *algo = parent ? "parent imprints select " #TEST " (canditer_next" #ISDENSE ")" : "imprints select " #TEST " (canditer_next" #ISDENSE ")"; \
     418             :                 switch (imprints->bits) {                            \
     419             :                 case 8:                                                 \
     420             :                         checkMINMAX(8, TYPE);                           \
     421             :                         impsmask(ISDENSE,TEST,8);                       \
     422             :                         break;                                          \
     423             :                 case 16:                                                \
     424             :                         checkMINMAX(16, TYPE);                          \
     425             :                         impsmask(ISDENSE,TEST,16);                      \
     426             :                         break;                                          \
     427             :                 case 32:                                                \
     428             :                         checkMINMAX(32, TYPE);                          \
     429             :                         impsmask(ISDENSE,TEST,32);                      \
     430             :                         break;                                          \
     431             :                 case 64:                                                \
     432             :                         checkMINMAX(64, TYPE);                          \
     433             :                         impsmask(ISDENSE,TEST,64);                      \
     434             :                         break;                                          \
     435             :                 default:                                                \
     436             :                         MT_UNREACHABLE();                               \
     437             :                 }                                                       \
     438             :         } while (false)
     439             : 
     440             : /* scan select without imprints */
     441             : 
     442             : /* core scan select loop with & without candidates */
     443             : #define scanloop(NAME,canditer_next,TEST)                               \
     444             :         do {                                                            \
     445             :                 BUN ncand = ci->ncand;                                       \
     446             :                 *algo = "select: " #NAME " " #TEST " (" #canditer_next ")"; \
     447             :                 if (BATcapacity(bn) < maximum) {                     \
     448             :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {           \
     449             :                                 o = canditer_next(ci);                  \
     450             :                                 v = src[o-hseq];                        \
     451             :                                 if (TEST) {                             \
     452             :                                         dst = buninsfix(bn, dst, cnt, o, \
     453             :                                                   (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p) \
     454             :                                                          * (dbl) (ncand-p) * 1.1 + 1024), \
     455             :                                                         maximum);       \
     456             :                                         if (dst == NULL) {              \
     457             :                                                 goto bailout;           \
     458             :                                         }                               \
     459             :                                         cnt++;                          \
     460             :                                 }                                       \
     461             :                         }                                               \
     462             :                 } else {                                                \
     463             :                         TIMEOUT_LOOP(ncand, qry_ctx) {                  \
     464             :                                 o = canditer_next(ci);                  \
     465             :                                 v = src[o-hseq];                        \
     466             :                                 assert(cnt < BATcapacity(bn));               \
     467             :                                 dst[cnt] = o;                           \
     468             :                                 cnt += (TEST) != 0;                     \
     469             :                         }                                               \
     470             :                 }                                                       \
     471             :                 TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx)); \
     472             :         } while (false)
     473             : 
     474             : /* argument list for type-specific core scan select function call */
     475             : #define scanargs                                                        \
     476             :         bi, ci, bn, tl, th, li, hi, equi, anti, lval, hval, lnil,       \
     477             :         cnt, bi->b->hseqbase, dst, maximum, imprints, algo
     478             : 
     479             : #define PREVVALUEbte(x) ((x) - 1)
     480             : #define PREVVALUEsht(x) ((x) - 1)
     481             : #define PREVVALUEint(x) ((x) - 1)
     482             : #define PREVVALUElng(x) ((x) - 1)
     483             : #ifdef HAVE_HGE
     484             : #define PREVVALUEhge(x) ((x) - 1)
     485             : #endif
     486             : #define PREVVALUEoid(x) ((x) - 1)
     487             : #define PREVVALUEflt(x) nextafterf((x), -GDK_flt_max)
     488             : #define PREVVALUEdbl(x) nextafter((x), -GDK_dbl_max)
     489             : 
     490             : #define NEXTVALUEbte(x) ((x) + 1)
     491             : #define NEXTVALUEsht(x) ((x) + 1)
     492             : #define NEXTVALUEint(x) ((x) + 1)
     493             : #define NEXTVALUElng(x) ((x) + 1)
     494             : #ifdef HAVE_HGE
     495             : #define NEXTVALUEhge(x) ((x) + 1)
     496             : #endif
     497             : #define NEXTVALUEoid(x) ((x) + 1)
     498             : #define NEXTVALUEflt(x) nextafterf((x), GDK_flt_max)
     499             : #define NEXTVALUEdbl(x) nextafter((x), GDK_dbl_max)
     500             : 
     501             : #define MINVALUEbte     GDK_bte_min
     502             : #define MINVALUEsht     GDK_sht_min
     503             : #define MINVALUEint     GDK_int_min
     504             : #define MINVALUElng     GDK_lng_min
     505             : #ifdef HAVE_HGE
     506             : #define MINVALUEhge     GDK_hge_min
     507             : #endif
     508             : #define MINVALUEoid     GDK_oid_min
     509             : #define MINVALUEflt     GDK_flt_min
     510             : #define MINVALUEdbl     GDK_dbl_min
     511             : 
     512             : #define MAXVALUEbte     GDK_bte_max
     513             : #define MAXVALUEsht     GDK_sht_max
     514             : #define MAXVALUEint     GDK_int_max
     515             : #define MAXVALUElng     GDK_lng_max
     516             : #ifdef HAVE_HGE
     517             : #define MAXVALUEhge     GDK_hge_max
     518             : #endif
     519             : #define MAXVALUEoid     GDK_oid_max
     520             : #define MAXVALUEflt     GDK_flt_max
     521             : #define MAXVALUEdbl     GDK_dbl_max
     522             : 
     523             : #define choose(NAME, ISDENSE, TEST, TYPE)                               \
     524             :         do {                                                            \
     525             :                 if (imprints) {                                         \
     526             :                         bitswitch(ISDENSE, TEST, TYPE);                 \
     527             :                 } else {                                                \
     528             :                         scanloop(NAME, canditer_next##ISDENSE, TEST);   \
     529             :                 }                                                       \
     530             :         } while (false)
     531             : 
     532             : /* definition of type-specific core scan select function */
     533             : #define scanfunc(NAME, TYPE, ISDENSE)                                   \
     534             : static BUN                                                              \
     535             : NAME##_##TYPE(BATiter *bi, struct canditer *restrict ci, BAT *bn,       \
     536             :               const TYPE *tl, const TYPE *th, bool li, bool hi,         \
     537             :               bool equi, bool anti, bool lval, bool hval,               \
     538             :               bool lnil, BUN cnt, const oid hseq, oid *restrict dst,    \
     539             :               BUN maximum, Imprints *imprints, const char **algo)       \
     540             : {                                                                       \
     541             :         TYPE vl = *tl;                                                  \
     542             :         TYPE vh = *th;                                                  \
     543             :         TYPE imp_min;                                                   \
     544             :         TYPE imp_max;                                                   \
     545             :         TYPE v;                                                         \
     546             :         const TYPE nil = TYPE##_nil;                                    \
     547             :         const TYPE minval = MINVALUE##TYPE;                             \
     548             :         const TYPE maxval = MAXVALUE##TYPE;                             \
     549             :         const TYPE *src = (const TYPE *) bi->base;                   \
     550             :         const TYPE *basesrc;                                            \
     551             :         oid o, w;                                                       \
     552             :         BUN p;                                                          \
     553             :         BUN pr_off = 0;                                                 \
     554             :         bat parent = 0;                                                 \
     555             :         BAT *pbat = NULL;                                               \
     556             :         (void) li;                                                      \
     557             :         (void) hi;                                                      \
     558             :         (void) lval;                                                    \
     559             :         (void) hval;                                                    \
     560             :         size_t counter = 0;                                             \
     561             :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();                      \
     562             :         if (imprints && imprints->imprints.parentid != bi->b->batCacheid) { \
     563             :                 parent = imprints->imprints.parentid;                        \
     564             :                 pbat = BATdescriptor(parent);                           \
     565             :                 if (pbat == NULL) {                                     \
     566             :                         /* can't load parent: don't use imprints */     \
     567             :                         imprints = NULL;                                \
     568             :                         basesrc = src;                                  \
     569             :                 } else {                                                \
     570             :                         basesrc = (const TYPE *) Tloc(pbat, 0);         \
     571             :                         pr_off = (BUN) (src - basesrc);                 \
     572             :                 }                                                       \
     573             :         } else {                                                        \
     574             :                 basesrc = src;                                          \
     575             :         }                                                               \
     576             :         /* Normalize the variables li, hi, lval, hval, possibly */      \
     577             :         /* changing anti in the process.  This works for all */         \
     578             :         /* (and only) numeric types. */                                 \
     579             :                                                                         \
     580             :         /* Note that the expression x < v is equivalent to x <= */        \
     581             :         /* v' where v' is the next smaller value in the domain */       \
     582             :         /* of v (similarly for x > v).  Also note that for */                \
     583             :         /* floating point numbers there actually is such a */           \
     584             :         /* value.  In fact, there is a function in standard C */        \
     585             :         /* that calculates that value. */                               \
     586             :                                                                         \
     587             :         /* The result is: */                                            \
     588             :         /* li == !anti, hi == !anti, lval == true, hval == true */      \
     589             :         /* This means that all ranges that we check for are */          \
     590             :         /* closed ranges.  If a range is one-sided, we fill in */       \
     591             :         /* the minimum resp. maximum value in the domain so that */     \
     592             :         /* we create a closed range. */                                 \
     593             :         if (anti && li) {                                               \
     594             :                 /* -inf < x < vl === -inf < x <= vl-1 */            \
     595             :                 if (vl == MINVALUE##TYPE) {                             \
     596             :                         /* -inf < x < MIN || *th <[=] x < +inf */   \
     597             :                         /* degenerates into half range */               \
     598             :                         /* *th <[=] x < +inf */                           \
     599             :                         anti = false;                                   \
     600             :                         vl = vh;                                        \
     601             :                         li = !hi;                                       \
     602             :                         hval = false;                                   \
     603             :                         /* further dealt with below */                  \
     604             :                 } else {                                                \
     605             :                         vl = PREVVALUE##TYPE(vl);                       \
     606             :                         li = false;                                     \
     607             :                 }                                                       \
     608             :         }                                                               \
     609             :         if (anti && hi) {                                               \
     610             :                 /* vl < x < +inf === vl+1 <= x < +inf */            \
     611             :                 if (vh == MAXVALUE##TYPE) {                             \
     612             :                         /* -inf < x <[=] *tl || MAX > x > +inf */   \
     613             :                         /* degenerates into half range */               \
     614             :                         /* -inf < x <[=] *tl */                           \
     615             :                         anti = false;                                   \
     616             :                         vh = vl;                                        \
     617             :                         hi = !li;                                       \
     618             :                         lval = false;                                   \
     619             :                         /* further dealt with below */                  \
     620             :                 } else {                                                \
     621             :                         vh = NEXTVALUE##TYPE(vh);                       \
     622             :                         hi = false;                                     \
     623             :                 }                                                       \
     624             :         }                                                               \
     625             :         if (!anti) {                                                    \
     626             :                 if (lval) {                                             \
     627             :                         /* range bounded on left */                     \
     628             :                         if (!li) {                                      \
     629             :                                 /* open range on left */                \
     630             :                                 if (vl == MAXVALUE##TYPE) {             \
     631             :                                         *algo = "select: empty range";        \
     632             :                                         return 0;                       \
     633             :                                 }                                       \
     634             :                                 /* vl < x === vl+1 <= x */                \
     635             :                                 vl = NEXTVALUE##TYPE(vl);               \
     636             :                                 li = true;                              \
     637             :                         }                                               \
     638             :                 } else {                                                \
     639             :                         /* -inf, i.e. smallest value */                 \
     640             :                         vl = MINVALUE##TYPE;                            \
     641             :                         li = true;                                      \
     642             :                         lval = true;                                    \
     643             :                 }                                                       \
     644             :                 if (hval) {                                             \
     645             :                         /* range bounded on right */                    \
     646             :                         if (!hi) {                                      \
     647             :                                 /* open range on right */               \
     648             :                                 if (vh == MINVALUE##TYPE) {             \
     649             :                                         *algo = "select: empty range";        \
     650             :                                         return 0;                       \
     651             :                                 }                                       \
     652             :                                 /* x < vh === x <= vh-1 */                \
     653             :                                 vh = PREVVALUE##TYPE(vh);               \
     654             :                                 hi = true;                              \
     655             :                         }                                               \
     656             :                 } else {                                                \
     657             :                         /* +inf, i.e. largest value */                  \
     658             :                         vh = MAXVALUE##TYPE;                            \
     659             :                         hi = true;                                      \
     660             :                         hval = true;                                    \
     661             :                 }                                                       \
     662             :                 if (vl > vh) {                                               \
     663             :                         *algo = "select: empty range";                        \
     664             :                         return 0;                                       \
     665             :                 }                                                       \
     666             :         }                                                               \
     667             :         /* if anti is set, we can now check */                          \
     668             :         /* (x <= vl || x >= vh) && x != nil */                            \
     669             :         /* if anti is not set, we can check just */                     \
     670             :         /* vl <= x && x <= vh */                                  \
     671             :         /* if equi==true, the check is x == vl */                       \
     672             :         /* note that this includes the check for != nil */              \
     673             :         assert(li == !anti);                                            \
     674             :         assert(hi == !anti);                                            \
     675             :         assert(lval);                                                   \
     676             :         assert(hval);                                                   \
     677             :         w = canditer_last(ci);                                          \
     678             :         if (equi) {                                                     \
     679             :                 assert(imprints == NULL);                               \
     680             :                 if (lnil)                                               \
     681             :                         scanloop(NAME, canditer_next##ISDENSE, is_##TYPE##_nil(v)); \
     682             :                 else                                                    \
     683             :                         scanloop(NAME, canditer_next##ISDENSE, v == vl); \
     684             :         } else if (anti) {                                              \
     685             :                 if (bi->nonil) {                                     \
     686             :                         choose(NAME, ISDENSE, (v <= vl || v >= vh), TYPE); \
     687             :                 } else {                                                \
     688             :                         choose(NAME, ISDENSE, !is_##TYPE##_nil(v) && (v <= vl || v >= vh), TYPE); \
     689             :                 }                                                       \
     690             :         } else if (bi->nonil && vl == minval) {                              \
     691             :                 choose(NAME, ISDENSE, v <= vh, TYPE);                        \
     692             :         } else if (vh == maxval) {                                      \
     693             :                 choose(NAME, ISDENSE, v >= vl, TYPE);                        \
     694             :         } else {                                                        \
     695             :                 choose(NAME, ISDENSE, v >= vl && v <= vh, TYPE);  \
     696             :         }                                                               \
     697             :         if (pbat)                                                       \
     698             :                 BBPunfix(pbat->batCacheid);                          \
     699             :         return cnt;                                                     \
     700             :   bailout:                                                              \
     701             :         if (pbat)                                                       \
     702             :                 BBPunfix(pbat->batCacheid);                          \
     703             :         BBPreclaim(bn);                                                 \
     704             :         return BUN_NONE;                                                \
     705             : }
     706             : 
     707             : static BUN
     708         623 : fullscan_any(BATiter *bi, struct canditer *restrict ci, BAT *bn,
     709             :              const void *tl, const void *th,
     710             :              bool li, bool hi, bool equi, bool anti, bool lval, bool hval,
     711             :              bool lnil, BUN cnt, const oid hseq, oid *restrict dst,
     712             :              BUN maximum, Imprints *imprints, const char **algo)
     713             : {
     714         623 :         const void *v;
     715         623 :         const void *restrict nil = ATOMnilptr(bi->type);
     716         623 :         int (*cmp)(const void *, const void *) = ATOMcompare(bi->type);
     717         623 :         oid o;
     718         623 :         BUN p, ncand = ci->ncand;
     719         623 :         int c;
     720             : 
     721         623 :         (void) maximum;
     722         623 :         (void) imprints;
     723         623 :         (void) lnil;
     724         623 :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();
     725             : 
     726         623 :         if (equi) {
     727         612 :                 *algo = "select: fullscan equi";
     728         612 :                 if (ci->tpe == cand_dense) {
     729     8838721 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     730     8836833 :                                 o = canditer_next_dense(ci);
     731     8836833 :                                 v = BUNtail(*bi, o-hseq);
     732     8841443 :                                 if ((*cmp)(tl, v) == 0) {
     733     6305985 :                                         dst = buninsfix(bn, dst, cnt, o,
     734     2084450 :                                                         (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     735     2084450 :                                                                * (dbl) (ncand-p) * 1.1 + 1024),
     736             :                                                         maximum);
     737     2137085 :                                         if (dst == NULL) {
     738           0 :                                                 BBPreclaim(bn);
     739           0 :                                                 return BUN_NONE;
     740             :                                         }
     741     2137085 :                                         cnt++;
     742             :                                 }
     743             :                         }
     744             :                 } else {
     745     1682701 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     746     1681909 :                                 o = canditer_next(ci);
     747     1664229 :                                 v = BUNtail(*bi, o-hseq);
     748     1681244 :                                 if ((*cmp)(tl, v) == 0) {
     749       61797 :                                         dst = buninsfix(bn, dst, cnt, o,
     750       20598 :                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     751       20598 :                                                         * (dbl) (ncand-p) * 1.1 + 1024),
     752             :                                                 maximum);
     753       20601 :                                         if (dst == NULL) {
     754           0 :                                                 BBPreclaim(bn);
     755           0 :                                                 return BUN_NONE;
     756             :                                         }
     757       20601 :                                         cnt++;
     758             :                                 }
     759             :                         }
     760             :                 }
     761          11 :         } else if (anti) {
     762           2 :                 *algo = "select: fullscan anti";
     763           2 :                 if (ci->tpe == cand_dense) {
     764          14 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     765           8 :                                 o = canditer_next_dense(ci);
     766           8 :                                 v = BUNtail(*bi, o-hseq);
     767           8 :                                 if ((nil == NULL || (*cmp)(v, nil) != 0) &&
     768           8 :                                         ((lval &&
     769           8 :                                         ((c = (*cmp)(tl, v)) > 0 ||
     770           6 :                                         (!li && c == 0))) ||
     771           6 :                                         (hval &&
     772           6 :                                         ((c = (*cmp)(th, v)) < 0 ||
     773           4 :                                         (!hi && c == 0))))) {
     774          12 :                                         dst = buninsfix(bn, dst, cnt, o,
     775           4 :                                                         (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     776           4 :                                                                * (dbl) (ncand-p) * 1.1 + 1024),
     777             :                                                         maximum);
     778           4 :                                         if (dst == NULL) {
     779           0 :                                                 BBPreclaim(bn);
     780           0 :                                                 return BUN_NONE;
     781             :                                         }
     782           4 :                                         cnt++;
     783             :                                 }
     784             :                         }
     785             :                 } else {
     786           0 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     787           0 :                                 o = canditer_next(ci);
     788           0 :                                 v = BUNtail(*bi, o-hseq);
     789           0 :                                 if ((nil == NULL || (*cmp)(v, nil) != 0) &&
     790           0 :                                         ((lval &&
     791           0 :                                         ((c = (*cmp)(tl, v)) > 0 ||
     792           0 :                                         (!li && c == 0))) ||
     793           0 :                                         (hval &&
     794           0 :                                         ((c = (*cmp)(th, v)) < 0 ||
     795           0 :                                         (!hi && c == 0))))) {
     796           0 :                                         dst = buninsfix(bn, dst, cnt, o,
     797           0 :                                                         (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     798           0 :                                                                * (dbl) (ncand-p) * 1.1 + 1024),
     799             :                                                         maximum);
     800           0 :                                         if (dst == NULL) {
     801           0 :                                                 BBPreclaim(bn);
     802           0 :                                                 return BUN_NONE;
     803             :                                         }
     804           0 :                                         cnt++;
     805             :                                 }
     806             :                         }
     807             :                 }
     808             :         } else {
     809           9 :                 *algo = "select: fullscan range";
     810           9 :                 if (ci->tpe == cand_dense) {
     811        4910 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     812        4889 :                                 o = canditer_next_dense(ci);
     813        4889 :                                 v = BUNtail(*bi, o-hseq);
     814        4889 :                                 if ((nil == NULL || (*cmp)(v, nil) != 0) &&
     815        4027 :                                         ((!lval ||
     816        4027 :                                         (c = cmp(tl, v)) < 0 ||
     817        4889 :                                         (li && c == 0)) &&
     818        3906 :                                         (!hval ||
     819        3906 :                                         (c = cmp(th, v)) > 0 ||
     820        3662 :                                         (hi && c == 0)))) {
     821         798 :                                         dst = buninsfix(bn, dst, cnt, o,
     822         266 :                                                         (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     823         266 :                                                                * (dbl) (ncand-p) * 1.1 + 1024),
     824             :                                                         maximum);
     825         266 :                                         if (dst == NULL) {
     826           0 :                                                 BBPreclaim(bn);
     827           0 :                                                 return BUN_NONE;
     828             :                                         }
     829         266 :                                         cnt++;
     830             :                                 }
     831             :                         }
     832             :                 } else {
     833         232 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     834         226 :                                 o = canditer_next(ci);
     835         226 :                                 v = BUNtail(*bi, o-hseq);
     836         226 :                                 if ((nil == NULL || (*cmp)(v, nil) != 0) &&
     837         226 :                                         ((!lval ||
     838         226 :                                         (c = cmp(tl, v)) < 0 ||
     839         226 :                                         (li && c == 0)) &&
     840           0 :                                         (!hval ||
     841           0 :                                         (c = cmp(th, v)) > 0 ||
     842           0 :                                         (hi && c == 0)))) {
     843         474 :                                         dst = buninsfix(bn, dst, cnt, o,
     844         158 :                                                         (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     845         158 :                                                                * (dbl) (ncand-p) * 1.1 + 1024),
     846             :                                                         maximum);
     847         158 :                                         if (dst == NULL) {
     848           0 :                                                 BBPreclaim(bn);
     849           0 :                                                 return BUN_NONE;
     850             :                                         }
     851         158 :                                         cnt++;
     852             :                                 }
     853             :                         }
     854             :                 }
     855             :         }
     856         624 :         TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
     857             :         return cnt;
     858           0 :   bailout:
     859           0 :         BBPreclaim(bn);
     860             :         return BUN_NONE;
     861             : }
     862             : 
     863             : static BUN
     864      203040 : fullscan_str(BATiter *bi, struct canditer *restrict ci, BAT *bn,
     865             :              const char *tl, const char *th,
     866             :              bool li, bool hi, bool equi, bool anti, bool lval, bool hval,
     867             :              bool lnil, BUN cnt, const oid hseq, oid *restrict dst,
     868             :              BUN maximum, Imprints *imprints, const char **algo)
     869             : {
     870      203040 :         var_t pos;
     871      203040 :         BUN p, ncand = ci->ncand;
     872      203040 :         oid o;
     873      203040 :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();
     874             : 
     875      203077 :         if (anti && tl == th && !bi->nonil && GDK_ELIMDOUBLES(bi->vh) &&
     876         146 :             strcmp(tl, str_nil) != 0 &&
     877          73 :             strLocate(bi->vh, str_nil) == (var_t) -2) {
     878             :                 /* anti-equi select for non-nil value, and there are no
     879             :                  * nils, so we can use fast path; trigger by setting
     880             :                  * nonil */
     881          73 :                 bi->nonil = true;
     882             :         }
     883      203077 :         if (!((equi ||
     884         498 :                (anti && tl == th && (bi->nonil || strcmp(tl, str_nil) == 0))) &&
     885      203066 :               GDK_ELIMDOUBLES(bi->vh)))
     886         521 :                 return fullscan_any(bi, ci, bn, tl, th, li, hi, equi, anti,
     887             :                                     lval, hval, lnil, cnt, hseq, dst,
     888             :                                     maximum, imprints, algo);
     889      202556 :         if ((pos = strLocate(bi->vh, tl)) == (var_t) -2) {
     890         976 :                 if (anti) {
     891             :                         /* return the whole shebang */
     892          20 :                         *algo = "select: fullscan anti-equi strelim (all)";
     893          20 :                         if (BATextend(bn, ncand) != GDK_SUCCEED) {
     894           0 :                                 BBPreclaim(bn);
     895           0 :                                 return BUN_NONE;
     896             :                         }
     897          20 :                         dst = Tloc(bn, 0);
     898        1062 :                         TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     899        1022 :                                 dst[p] = canditer_next(ci);
     900             :                         }
     901          20 :                         TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
     902             :                         return ncand;
     903             :                 }
     904         956 :                 *algo = "select: fullscan equi strelim (nomatch)";
     905         956 :                 return 0;
     906             :         }
     907      201589 :         if (pos == (var_t) -1) {
     908           0 :                 *algo = NULL;
     909           0 :                 BBPreclaim(bn);
     910           0 :                 return BUN_NONE;
     911             :         }
     912      201589 :         *algo = anti ? "select: fullscan anti-equi strelim" : "select: fullscan equi strelim";
     913      201589 :         assert(pos >= GDK_VAROFFSET);
     914      201589 :         switch (bi->width) {
     915      162578 :         case 1: {
     916      162578 :                 const unsigned char *ptr = (const unsigned char *) bi->base;
     917      162578 :                 pos -= GDK_VAROFFSET;
     918      162578 :                 if (ci->tpe == cand_dense) {
     919      161688 :                         if (anti) {
     920        2490 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     921        2142 :                                         o = canditer_next_dense(ci);
     922        2142 :                                         if (ptr[o - hseq] != pos) {
     923        5880 :                                                 dst = buninsfix(bn, dst, cnt, o,
     924        1960 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     925        1960 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
     926             :                                                                 maximum);
     927        1960 :                                                 if (dst == NULL) {
     928           0 :                                                         BBPreclaim(bn);
     929           0 :                                                         return BUN_NONE;
     930             :                                                 }
     931        1960 :                                                 cnt++;
     932             :                                         }
     933             :                                 }
     934             :                         } else {
     935    25957789 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     936    25470897 :                                         o = canditer_next_dense(ci);
     937    25470897 :                                         if (ptr[o - hseq] == pos) {
     938    24891202 :                                                 dst = buninsfix(bn, dst, cnt, o,
     939     8297054 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     940     8297054 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
     941             :                                                                 maximum);
     942     8297094 :                                                 if (dst == NULL) {
     943           0 :                                                         BBPreclaim(bn);
     944           0 :                                                         return BUN_NONE;
     945             :                                                 }
     946     8297094 :                                                 cnt++;
     947             :                                         }
     948             :                                 }
     949             :                         }
     950             :                 } else {
     951         890 :                         if (anti) {
     952        1254 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     953        1194 :                                         o = canditer_next(ci);
     954        1194 :                                         if (ptr[o - hseq] != pos) {
     955         297 :                                                 dst = buninsfix(bn, dst, cnt, o,
     956          99 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     957          99 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
     958             :                                                                 maximum);
     959          99 :                                                 if (dst == NULL) {
     960           0 :                                                         BBPreclaim(bn);
     961           0 :                                                         return BUN_NONE;
     962             :                                                 }
     963          99 :                                                 cnt++;
     964             :                                         }
     965             :                                 }
     966             :                         } else {
     967    11656116 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     968    11652364 :                                         o = canditer_next(ci);
     969    11659966 :                                         if (ptr[o - hseq] == pos) {
     970    11745936 :                                                 dst = buninsfix(bn, dst, cnt, o,
     971     3917847 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     972     3917847 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
     973             :                                                                 maximum);
     974     3910242 :                                                 if (dst == NULL) {
     975           0 :                                                         BBPreclaim(bn);
     976           0 :                                                         return BUN_NONE;
     977             :                                                 }
     978     3910242 :                                                 cnt++;
     979             :                                         }
     980             :                                 }
     981             :                         }
     982             :                 }
     983             :                 break;
     984             :         }
     985       39008 :         case 2: {
     986       39008 :                 const unsigned short *ptr = (const unsigned short *) bi->base;
     987       39008 :                 pos -= GDK_VAROFFSET;
     988       39008 :                 if (ci->tpe == cand_dense) {
     989       31924 :                         if (anti) {
     990        1808 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
     991         896 :                                         o = canditer_next_dense(ci);
     992         896 :                                         if (ptr[o - hseq] != pos) {
     993        1920 :                                                 dst = buninsfix(bn, dst, cnt, o,
     994         640 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
     995         640 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
     996             :                                                                 maximum);
     997         640 :                                                 if (dst == NULL) {
     998           0 :                                                         BBPreclaim(bn);
     999           0 :                                                         return BUN_NONE;
    1000             :                                                 }
    1001         640 :                                                 cnt++;
    1002             :                                         }
    1003             :                                 }
    1004             :                         } else {
    1005     2477356 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1006     2382181 :                                         o = canditer_next_dense(ci);
    1007     2382181 :                                         if (ptr[o - hseq] == pos) {
    1008      162778 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1009       54221 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1010       54221 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1011             :                                                                 maximum);
    1012       54336 :                                                 if (dst == NULL) {
    1013           0 :                                                         BBPreclaim(bn);
    1014           0 :                                                         return BUN_NONE;
    1015             :                                                 }
    1016       54336 :                                                 cnt++;
    1017             :                                         }
    1018             :                                 }
    1019             :                         }
    1020             :                 } else {
    1021        7084 :                         if (anti) {
    1022        1832 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1023        1751 :                                         o = canditer_next(ci);
    1024        1751 :                                         if (ptr[o - hseq] != pos) {
    1025        4806 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1026        1602 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1027        1602 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1028             :                                                                 maximum);
    1029        1602 :                                                 if (dst == NULL) {
    1030           0 :                                                         BBPreclaim(bn);
    1031           0 :                                                         return BUN_NONE;
    1032             :                                                 }
    1033        1602 :                                                 cnt++;
    1034             :                                         }
    1035             :                                 }
    1036             :                         } else {
    1037     2378582 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1038     2357308 :                                         o = canditer_next(ci);
    1039     2357034 :                                         if (ptr[o - hseq] == pos) {
    1040      230461 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1041       76719 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1042       76719 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1043             :                                                                 maximum);
    1044       77023 :                                                 if (dst == NULL) {
    1045           0 :                                                         BBPreclaim(bn);
    1046           0 :                                                         return BUN_NONE;
    1047             :                                                 }
    1048       77023 :                                                 cnt++;
    1049             :                                         }
    1050             :                                 }
    1051             :                         }
    1052             :                 }
    1053             :                 break;
    1054             :         }
    1055             : #if SIZEOF_VAR_T == 8
    1056           1 :         case 4: {
    1057           1 :                 const unsigned int *ptr = (const unsigned int *) bi->base;
    1058           1 :                 if (ci->tpe == cand_dense) {
    1059           1 :                         if (anti) {
    1060           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1061           0 :                                         o = canditer_next_dense(ci);
    1062           0 :                                         if (ptr[o - hseq] != pos) {
    1063           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1064           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1065           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1066             :                                                                 maximum);
    1067           0 :                                                 if (dst == NULL) {
    1068           0 :                                                         BBPreclaim(bn);
    1069           0 :                                                         return BUN_NONE;
    1070             :                                                 }
    1071           0 :                                                 cnt++;
    1072             :                                         }
    1073             :                                 }
    1074             :                         } else {
    1075         973 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1076         970 :                                         o = canditer_next_dense(ci);
    1077         970 :                                         if (ptr[o - hseq] == pos) {
    1078         744 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1079         248 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1080         248 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1081             :                                                                 maximum);
    1082         248 :                                                 if (dst == NULL) {
    1083           0 :                                                         BBPreclaim(bn);
    1084           0 :                                                         return BUN_NONE;
    1085             :                                                 }
    1086         248 :                                                 cnt++;
    1087             :                                         }
    1088             :                                 }
    1089             :                         }
    1090             :                 } else {
    1091           0 :                         if (anti) {
    1092           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1093           0 :                                         o = canditer_next(ci);
    1094           0 :                                         if (ptr[o - hseq] != pos) {
    1095           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1096           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1097           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1098             :                                                                 maximum);
    1099           0 :                                                 if (dst == NULL) {
    1100           0 :                                                         BBPreclaim(bn);
    1101           0 :                                                         return BUN_NONE;
    1102             :                                                 }
    1103           0 :                                                 cnt++;
    1104             :                                         }
    1105             :                                 }
    1106             :                         } else {
    1107           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1108           0 :                                         o = canditer_next(ci);
    1109           0 :                                         if (ptr[o - hseq] == pos) {
    1110           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1111           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1112           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1113             :                                                                 maximum);
    1114           0 :                                                 if (dst == NULL) {
    1115           0 :                                                         BBPreclaim(bn);
    1116           0 :                                                         return BUN_NONE;
    1117             :                                                 }
    1118           0 :                                                 cnt++;
    1119             :                                         }
    1120             :                                 }
    1121             :                         }
    1122             :                 }
    1123             :                 break;
    1124             :         }
    1125             : #endif
    1126           2 :         default: {
    1127           2 :                 const var_t *ptr = (const var_t *) bi->base;
    1128           2 :                 if (ci->tpe == cand_dense) {
    1129           2 :                         if (anti) {
    1130           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1131           0 :                                         o = canditer_next_dense(ci);
    1132           0 :                                         if (ptr[o - hseq] != pos) {
    1133           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1134           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1135           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1136             :                                                                 maximum);
    1137           0 :                                                 if (dst == NULL) {
    1138           0 :                                                         BBPreclaim(bn);
    1139           0 :                                                         return BUN_NONE;
    1140             :                                                 }
    1141           0 :                                                 cnt++;
    1142             :                                         }
    1143             :                                 }
    1144             :                         } else {
    1145          26 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1146          20 :                                         o = canditer_next_dense(ci);
    1147          20 :                                         if (ptr[o - hseq] == pos) {
    1148           6 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1149           2 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1150           2 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1151             :                                                                 maximum);
    1152           2 :                                                 if (dst == NULL) {
    1153           0 :                                                         BBPreclaim(bn);
    1154           0 :                                                         return BUN_NONE;
    1155             :                                                 }
    1156           2 :                                                 cnt++;
    1157             :                                         }
    1158             :                                 }
    1159             :                         }
    1160             :                 } else {
    1161           0 :                         if (anti) {
    1162           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1163           0 :                                         o = canditer_next(ci);
    1164           0 :                                         if (ptr[o - hseq] != pos) {
    1165           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1166           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1167           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1168             :                                                                 maximum);
    1169           0 :                                                 if (dst == NULL) {
    1170           0 :                                                         BBPreclaim(bn);
    1171           0 :                                                         return BUN_NONE;
    1172             :                                                 }
    1173           0 :                                                 cnt++;
    1174             :                                         }
    1175             :                                 }
    1176             :                         } else {
    1177           0 :                                 TIMEOUT_LOOP_IDX(p, ncand, qry_ctx) {
    1178           0 :                                         o = canditer_next(ci);
    1179           0 :                                         if (ptr[o - hseq] == pos) {
    1180           0 :                                                 dst = buninsfix(bn, dst, cnt, o,
    1181           0 :                                                                 (BUN) ((dbl) cnt / (dbl) (p == 0 ? 1 : p)
    1182           0 :                                                                        * (dbl) (ncand-p) * 1.1 + 1024),
    1183             :                                                                 maximum);
    1184           0 :                                                 if (dst == NULL) {
    1185           0 :                                                         BBPreclaim(bn);
    1186           0 :                                                         return BUN_NONE;
    1187             :                                                 }
    1188           0 :                                                 cnt++;
    1189             :                                         }
    1190             :                                 }
    1191             :                         }
    1192             :                 }
    1193             :                 break;
    1194             :         }
    1195             :         }
    1196      201768 :         TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
    1197             :         return cnt;
    1198           0 :   bailout:
    1199           0 :         BBPreclaim(bn);
    1200             :         return BUN_NONE;
    1201             : }
    1202             : 
    1203             : /* scan select type switch */
    1204             : #ifdef HAVE_HGE
    1205             : #define scanfunc_hge(NAME, ISDENSE)             \
    1206             :         scanfunc(NAME, hge, ISDENSE)
    1207             : #else
    1208             : #define scanfunc_hge(NAME, ISDENSE)
    1209             : #endif
    1210             : #define scan_sel(NAME, ISDENSE)                 \
    1211             :         scanfunc(NAME, bte, ISDENSE)            \
    1212             :         scanfunc(NAME, sht, ISDENSE)            \
    1213             :         scanfunc(NAME, int, ISDENSE)            \
    1214             :         scanfunc(NAME, flt, ISDENSE)            \
    1215             :         scanfunc(NAME, dbl, ISDENSE)            \
    1216             :         scanfunc(NAME, lng, ISDENSE)            \
    1217             :         scanfunc_hge(NAME, ISDENSE)
    1218             : 
    1219             : /* scan/imprints select */
    1220   186086828 : scan_sel(fullscan, )
    1221  1274329851 : scan_sel(densescan, _dense)
    1222             : 
    1223             : #if 0
    1224             : /* some programs that produce editor tags files don't recognize the
    1225             :  * scanselect function because before it are the scan_del macro
    1226             :  * calls that don't look like function definitions or variable
    1227             :  * declarations, hence we have this hidden away function to realign the
    1228             :  * tags program */
    1229             : void
    1230             : realign_tags(void)
    1231             : {
    1232             : }
    1233             : #endif
    1234             : 
    1235             : static BAT *
    1236     1291928 : scanselect(BATiter *bi, struct canditer *restrict ci, BAT *bn,
    1237             :            const void *tl, const void *th,
    1238             :            bool li, bool hi, bool equi, bool anti, bool lval, bool hval,
    1239             :            bool lnil, BUN maximum, Imprints *imprints, const char **algo)
    1240             : {
    1241             : #ifndef NDEBUG
    1242     1291928 :         int (*cmp)(const void *, const void *);
    1243             : #endif
    1244     1291928 :         int t;
    1245     1291928 :         BUN cnt = 0;
    1246     1291928 :         oid *restrict dst;
    1247             : 
    1248     1291928 :         assert(bi->b != NULL);
    1249     1291928 :         assert(bn != NULL);
    1250     1291928 :         assert(bn->ttype == TYPE_oid);
    1251     1291928 :         assert(!lval || tl != NULL);
    1252     1291928 :         assert(!hval || th != NULL);
    1253     1291928 :         assert(!equi || (li && hi && !anti));
    1254     1291928 :         assert(!anti || lval || hval);
    1255     1291928 :         assert(bi->type != TYPE_void || equi || bi->nonil);
    1256             : 
    1257             : #ifndef NDEBUG
    1258     1291928 :         cmp = ATOMcompare(bi->type);
    1259             : #endif
    1260             : 
    1261     1291928 :         assert(!lval || !hval || tl == th || (*cmp)(tl, th) <= 0);
    1262             : 
    1263     1291925 :         dst = (oid *) Tloc(bn, 0);
    1264             : 
    1265     1291925 :         t = ATOMbasetype(bi->type);
    1266             : 
    1267             :         /* call type-specific core scan select function */
    1268     1291925 :         switch (t) {
    1269       33689 :         case TYPE_bte:
    1270       33689 :                 if (ci->tpe == cand_dense)
    1271       32189 :                         cnt = densescan_bte(scanargs);
    1272             :                 else
    1273        1500 :                         cnt = fullscan_bte(scanargs);
    1274             :                 break;
    1275        7727 :         case TYPE_sht:
    1276        7727 :                 if (ci->tpe == cand_dense)
    1277        7039 :                         cnt = densescan_sht(scanargs);
    1278             :                 else
    1279         688 :                         cnt = fullscan_sht(scanargs);
    1280             :                 break;
    1281     1044026 :         case TYPE_int:
    1282     1044026 :                 if (ci->tpe == cand_dense)
    1283      747117 :                         cnt = densescan_int(scanargs);
    1284             :                 else
    1285      296909 :                         cnt = fullscan_int(scanargs);
    1286             :                 break;
    1287          18 :         case TYPE_flt:
    1288          18 :                 if (ci->tpe == cand_dense)
    1289          17 :                         cnt = densescan_flt(scanargs);
    1290             :                 else
    1291           1 :                         cnt = fullscan_flt(scanargs);
    1292             :                 break;
    1293         128 :         case TYPE_dbl:
    1294         128 :                 if (ci->tpe == cand_dense)
    1295         119 :                         cnt = densescan_dbl(scanargs);
    1296             :                 else
    1297           9 :                         cnt = fullscan_dbl(scanargs);
    1298             :                 break;
    1299        3024 :         case TYPE_lng:
    1300        3024 :                 if (ci->tpe == cand_dense)
    1301        3012 :                         cnt = densescan_lng(scanargs);
    1302             :                 else
    1303          12 :                         cnt = fullscan_lng(scanargs);
    1304             :                 break;
    1305             : #ifdef HAVE_HGE
    1306         115 :         case TYPE_hge:
    1307         115 :                 if (ci->tpe == cand_dense)
    1308         106 :                         cnt = densescan_hge(scanargs);
    1309             :                 else
    1310           9 :                         cnt = fullscan_hge(scanargs);
    1311             :                 break;
    1312             : #endif
    1313      203096 :         case TYPE_str:
    1314      203096 :                 cnt = fullscan_str(scanargs);
    1315      203096 :                 break;
    1316         102 :         default:
    1317         102 :                 cnt = fullscan_any(scanargs);
    1318         102 :                 break;
    1319             :         }
    1320     1292093 :         if (cnt == BUN_NONE) {
    1321             :                 return NULL;
    1322             :         }
    1323     1292093 :         assert(bn->batCapacity >= cnt);
    1324             : 
    1325     1292093 :         BATsetcount(bn, cnt);
    1326     1292261 :         bn->tsorted = true;
    1327     1292261 :         bn->trevsorted = bn->batCount <= 1;
    1328     1292261 :         bn->tkey = true;
    1329     1292261 :         bn->tseqbase = cnt == 0 ? 0 : cnt == 1 || cnt == bi->count ? bi->b->hseqbase : oid_nil;
    1330             : 
    1331     1292261 :         return bn;
    1332             : }
    1333             : 
    1334             : #if SIZEOF_BUN == SIZEOF_INT
    1335             : #define CALC_ESTIMATE(TPE)                                              \
    1336             :         do {                                                            \
    1337             :                 if (*(TPE*)tl < 1) {                                 \
    1338             :                         if ((int) BUN_MAX + *(TPE*)tl >= *(TPE*)th)  \
    1339             :                                 estimate = (BUN) ((int) *(TPE*)th - *(TPE*)tl); \
    1340             :                 } else {                                                \
    1341             :                         if (-(int) BUN_MAX + *(TPE*)tl <= *(TPE*)th) \
    1342             :                                 estimate = (BUN) ((int) *(TPE*)th - *(TPE*)tl); \
    1343             :                 }                                                       \
    1344             :         } while (0)
    1345             : #else
    1346             : #define CALC_ESTIMATE(TPE)                                              \
    1347             :         do {                                                            \
    1348             :                 if (*(TPE*)tl < 1) {                                 \
    1349             :                         if ((lng) BUN_MAX + *(TPE*)tl >= *(TPE*)th)  \
    1350             :                                 estimate = (BUN) ((lng) *(TPE*)th - *(TPE*)tl); \
    1351             :                 } else {                                                \
    1352             :                         if (-(lng) BUN_MAX + *(TPE*)tl <= *(TPE*)th) \
    1353             :                                 estimate = (BUN) ((lng) *(TPE*)th - *(TPE*)tl); \
    1354             :                 }                                                       \
    1355             :         } while (0)
    1356             : #endif
    1357             : 
    1358             : static enum range_comp_t
    1359     1895860 : BATrange(BATiter *bi, const void *tl, const void *th, bool li, bool hi)
    1360             : {
    1361     1895860 :         enum range_comp_t range;
    1362     1895860 :         const ValRecord *minprop = NULL, *maxprop = NULL;
    1363     1895860 :         const void *minval = NULL, *maxval = NULL;
    1364     1895860 :         bool maxincl = true;
    1365     1895860 :         BAT *pb = NULL;
    1366     1895860 :         int c;
    1367     1895860 :         int (*atomcmp) (const void *, const void *) = ATOMcompare(bi->type);
    1368     1895860 :         BATiter bi2 = *bi;
    1369             : 
    1370     1895860 :         if (tl && (*atomcmp)(tl, ATOMnilptr(bi->type)) == 0)
    1371       13943 :                 tl = NULL;
    1372     1896290 :         if (th && (*atomcmp)(th, ATOMnilptr(bi->type)) == 0)
    1373       11890 :                 th = NULL;
    1374     1897409 :         if (tl == NULL && th == NULL)
    1375             :                 return range_contains; /* looking for everything */
    1376             : 
    1377     1889737 :         if (VIEWtparent(bi->b))
    1378     1706821 :                 pb = BATdescriptor(VIEWtparent(bi->b));
    1379             : 
    1380             :         /* keep locked while we look at the property values */
    1381     1890012 :         MT_lock_set(&bi->b->theaplock);
    1382     1889554 :         if (bi->sorted && (bi->nonil || atomcmp(BUNtail(*bi, 0), ATOMnilptr(bi->type)) != 0))
    1383      318653 :                 minval = BUNtail(*bi, 0);
    1384     1570903 :         else if (bi->revsorted && (bi->nonil || atomcmp(BUNtail(*bi, bi->count - 1), ATOMnilptr(bi->type)) != 0))
    1385      132049 :                 minval = BUNtail(*bi, bi->count - 1);
    1386     1438854 :         else if (bi->minpos != BUN_NONE)
    1387       26769 :                 minval = BUNtail(*bi, bi->minpos);
    1388     1412085 :         else if ((minprop = BATgetprop_nolock(bi->b, GDK_MIN_BOUND)) != NULL)
    1389           0 :                 minval = VALptr(minprop);
    1390     1889459 :         if (bi->sorted && (bi->nonil || atomcmp(BUNtail(bi2, bi->count - 1), ATOMnilptr(bi->type)) != 0)) {
    1391      319075 :                 maxval = BUNtail(bi2, bi->count - 1);
    1392             :                 maxincl = true;
    1393     1570113 :         } else if (bi->revsorted && (bi->nonil || atomcmp(BUNtail(bi2, 0), ATOMnilptr(bi->type)) != 0)) {
    1394      132706 :                 maxval = BUNtail(bi2, 0);
    1395             :                 maxincl = true;
    1396     1437408 :         } else if (bi->maxpos != BUN_NONE) {
    1397       26713 :                 maxval = BUNtail(bi2, bi->maxpos);
    1398             :                 maxincl = true;
    1399     1410695 :         } else if ((maxprop = BATgetprop_nolock(bi->b, GDK_MAX_BOUND)) != NULL) {
    1400           0 :                 maxval = VALptr(maxprop);
    1401           0 :                 maxincl = false;
    1402             :         }
    1403     1889225 :         bool keep = false;      /* keep lock on parent bat? */
    1404     1889225 :         if (minval == NULL || maxval == NULL) {
    1405     1411727 :                 if (pb != NULL) {
    1406     1320994 :                         MT_lock_set(&pb->theaplock);
    1407     1321233 :                         if (minval == NULL && (minprop = BATgetprop_nolock(pb, GDK_MIN_BOUND)) != NULL) {
    1408           6 :                                 keep = true;
    1409           6 :                                 minval = VALptr(minprop);
    1410             :                         }
    1411     1321219 :                         if (maxval == NULL && (maxprop = BATgetprop_nolock(pb, GDK_MAX_BOUND)) != NULL) {
    1412           2 :                                 keep = true;
    1413           2 :                                 maxval = VALptr(maxprop);
    1414           2 :                                 maxincl = true;
    1415             :                         }
    1416     1321179 :                         if (!keep) {
    1417     1321216 :                                 MT_lock_unset(&pb->theaplock);
    1418             :                         }
    1419             :                 }
    1420             :         }
    1421             : 
    1422     1889513 :         if (minval == NULL && maxval == NULL) {
    1423             :                 range = range_inside; /* strictly: unknown */
    1424      478323 :         } else if (maxval &&
    1425      472404 :                    tl &&
    1426      472236 :                    ((c = atomcmp(tl, maxval)) > 0 ||
    1427         856 :                     ((!maxincl || !li) && c == 0))) {
    1428             :                 range = range_after;
    1429      406165 :         } else if (minval &&
    1430      404832 :                    th &&
    1431      404825 :                    ((c = atomcmp(th, minval)) < 0 ||
    1432      361000 :                     (!hi && c == 0))) {
    1433             :                 range = range_before;
    1434      362271 :         } else if (tl == NULL) {
    1435        5874 :                 if (minval == NULL) {
    1436          16 :                         c = atomcmp(th, maxval);
    1437          16 :                         if (c < 0 || ((maxincl || !hi) && c == 0))
    1438             :                                 range = range_atstart;
    1439             :                         else
    1440        6469 :                                 range = range_contains;
    1441             :                 } else {
    1442        5858 :                         c = atomcmp(th, minval);
    1443        5858 :                         if (c < 0 || (!hi && c == 0))
    1444             :                                 range = range_before;
    1445        5858 :                         else if (maxval == NULL)
    1446             :                                 range = range_atstart;
    1447             :                         else {
    1448        5856 :                                 c = atomcmp(th, maxval);
    1449        5856 :                                 if (c < 0 || ((maxincl || !hi) && c == 0))
    1450             :                                         range = range_atstart;
    1451             :                                 else
    1452        6469 :                                         range = range_contains;
    1453             :                         }
    1454             :                 }
    1455      356397 :         } else if (th == NULL) {
    1456         863 :                 if (maxval == NULL) {
    1457           2 :                         c = atomcmp(tl, minval);
    1458           2 :                         if (c >= 0)
    1459             :                                 range = range_atend;
    1460             :                         else
    1461        6469 :                                 range = range_contains;
    1462             :                 } else {
    1463         861 :                         c = atomcmp(tl, maxval);
    1464         861 :                         if (c > 0 || ((!maxincl || !li) && c == 0))
    1465             :                                 range = range_after;
    1466         861 :                         else if (minval == NULL)
    1467             :                                 range = range_atend;
    1468             :                         else {
    1469         801 :                                 c = atomcmp(tl, minval);
    1470         800 :                                 if (c >= 0)
    1471             :                                         range = range_atend;
    1472             :                                 else
    1473        6469 :                                         range = range_contains;
    1474             :                         }
    1475             :                 }
    1476      355534 :         } else if (minval == NULL) {
    1477         480 :                 c = atomcmp(th, maxval);
    1478         480 :                 if (c < 0 || ((maxincl || !hi) && c == 0))
    1479             :                         range = range_inside;
    1480             :                 else
    1481       21819 :                         range = range_atend;
    1482      355054 :         } else if (maxval == NULL) {
    1483           6 :                 c = atomcmp(tl, minval);
    1484           6 :                 if (c >= 0)
    1485             :                         range = range_inside;
    1486             :                 else
    1487         243 :                         range = range_atstart;
    1488             :         } else {
    1489      355048 :                 c = atomcmp(tl, minval);
    1490      355084 :                 if (c >= 0) {
    1491      354527 :                         c = atomcmp(th, maxval);
    1492      354553 :                         if (c < 0 || ((maxincl || !hi) && c == 0))
    1493             :                                 range = range_inside;
    1494             :                         else
    1495       21819 :                                 range = range_atend;
    1496             :                 } else {
    1497         557 :                         c = atomcmp(th, maxval);
    1498         558 :                         if (c < 0 || ((maxincl || !hi) && c == 0))
    1499             :                                 range = range_atstart;
    1500             :                         else
    1501        6469 :                                 range = range_contains;
    1502             :                 }
    1503             :         }
    1504             : 
    1505     1889750 :         MT_lock_unset(&bi->b->theaplock);
    1506     1890199 :         if (pb) {
    1507     1707103 :                 if (keep)
    1508           6 :                         MT_lock_unset(&pb->theaplock);
    1509     1707103 :                 BBPreclaim(pb);
    1510             :         }
    1511             : 
    1512             :         return range;
    1513             : }
    1514             : 
    1515             : /* generic range select
    1516             :  *
    1517             :  * Return a BAT with the OID values of b for qualifying tuples.  The
    1518             :  * return BAT is sorted (i.e. in the same order as the input BAT).
    1519             :  *
    1520             :  * If s is non-NULL, it is a list of candidates.  s must be sorted.
    1521             :  *
    1522             :  * tl may not be NULL, li, hi, and anti must be either 0 or 1.
    1523             :  *
    1524             :  * If th is NULL, hi is ignored.
    1525             :  *
    1526             :  * If anti is 0, qualifying tuples are those whose value is between tl
    1527             :  * and th (as in x >[=] tl && x <[=] th, where equality depends on li
    1528             :  * and hi--so if tl > th, nothing will be returned).  If li or hi is
    1529             :  * 1, the respective boundary is inclusive, otherwise exclusive.  If
    1530             :  * th is NULL it is taken to be equal to tl, turning this into an
    1531             :  * equi- or point-select.  Note that for a point select to return
    1532             :  * anything, li (and hi if th was not NULL) must be 1.  There is a
    1533             :  * special case if tl is nil and th is NULL.  This is the only way to
    1534             :  * select for nil values.
    1535             :  *
    1536             :  * If anti is 1, the result is the complement of what the result would
    1537             :  * be if anti were 0, except that nils are filtered out.
    1538             :  *
    1539             :  * In brief:
    1540             :  * - if tl==nil and th==NULL and anti==0, return all nils (only way to
    1541             :  *   get nils);
    1542             :  * - it tl==nil and th==nil, return all but nils;
    1543             :  * - if tl==nil and th!=NULL, no lower bound;
    1544             :  * - if th==NULL or tl==th, point (equi) select;
    1545             :  * - if th==nil, no upper bound
    1546             :  *
    1547             :  * A complete breakdown of the various arguments follows.  Here, v, v1
    1548             :  * and v2 are values from the appropriate domain, and
    1549             :  * v != nil, v1 != nil, v2 != nil, v1 < v2.
    1550             :  *      tl      th      li      hi      anti    result list of OIDs for values
    1551             :  *      -----------------------------------------------------------------
    1552             :  *      nil     NULL    true    ignored false   x == nil (only way to get nil)
    1553             :  *      nil     NULL    false   ignored false   NOTHING
    1554             :  *      nil     NULL    ignored ignored true    x != nil
    1555             :  *      nil     nil     ignored ignored false   x != nil
    1556             :  *      nil     nil     ignored ignored true    NOTHING
    1557             :  *      nil     v       ignored false   false   x < v
    1558             :  *      nil     v       ignored true    false   x <= v
    1559             :  *      nil     v       ignored false   true    x >= v
    1560             :  *      nil     v       ignored true    true    x > v
    1561             :  *      v       nil     false   ignored false   x > v
    1562             :  *      v       nil     true    ignored false   x >= v
    1563             :  *      v       nil     false   ignored true    x <= v
    1564             :  *      v       nil     true    ignored true    x < v
    1565             :  *      v       NULL    false   ignored false   NOTHING
    1566             :  *      v       NULL    true    ignored false   x == v
    1567             :  *      v       NULL    false   ignored true    x != nil
    1568             :  *      v       NULL    true    ignored true    x != v
    1569             :  *      v       v       false   false   false   NOTHING
    1570             :  *      v       v       true    false   false   NOTHING
    1571             :  *      v       v       false   true    false   NOTHING
    1572             :  *      v       v       true    true    false   x == v
    1573             :  *      v       v       false   false   true    x != nil
    1574             :  *      v       v       true    false   true    x != nil
    1575             :  *      v       v       false   true    true    x != nil
    1576             :  *      v       v       true    true    true    x != v
    1577             :  *      v1      v2      false   false   false   v1 < x < v2
    1578             :  *      v1      v2      true    false   false   v1 <= x < v2
    1579             :  *      v1      v2      false   true    false   v1 < x <= v2
    1580             :  *      v1      v2      true    true    false   v1 <= x <= v2
    1581             :  *      v1      v2      false   false   true    x <= v1 or x >= v2
    1582             :  *      v1      v2      true    false   true    x < v1 or x >= v2
    1583             :  *      v1      v2      false   true    true    x <= v1 or x > v2
    1584             :  *      v1      v2      true    true    true    x < v1 or x > v2
    1585             :  *      v2      v1      ignored ignored false   NOTHING
    1586             :  *      v2      v1      ignored ignored true    x != nil
    1587             :  */
    1588             : BAT *
    1589     3363512 : BATselect(BAT *b, BAT *s, const void *tl, const void *th,
    1590             :              bool li, bool hi, bool anti)
    1591             : {
    1592     3363512 :         bool lval;              /* low value used for comparison */
    1593     3363512 :         bool lnil;              /* low value is nil */
    1594     3363512 :         bool hval;              /* high value used for comparison */
    1595     3363512 :         bool equi;              /* select for single value (not range) */
    1596     3363512 :         bool antiequi = false;  /* select for all but single value */
    1597     3363512 :         bool wanthash = false;  /* use hash (equi must be true) */
    1598     3363512 :         bool havehash = false;  /* we have a hash (and the hashlock) */
    1599     3363512 :         bool phash = false;     /* use hash on parent BAT (if view) */
    1600     3363512 :         int t;                  /* data type */
    1601     3363512 :         bat parent;             /* b's parent bat (if b is a view) */
    1602     3363512 :         const void *nil;
    1603     3363512 :         BAT *bn;
    1604     3363512 :         struct canditer ci;
    1605     3363512 :         BUN estimate = BUN_NONE, maximum = BUN_NONE;
    1606     3363512 :         oid vwl = 0, vwh = 0;
    1607     3363512 :         lng vwo = 0;
    1608     3363512 :         Heap *oidxh = NULL;
    1609     3363512 :         const char *algo;
    1610     3363512 :         enum range_comp_t range;
    1611     3363512 :         const bool notnull = BATgetprop(b, GDK_NOT_NULL) != NULL;
    1612     3367285 :         lng t0 = GDKusec();
    1613             : 
    1614     3366391 :         BATcheck(b, NULL);
    1615     3366391 :         if (tl == NULL) {
    1616           0 :                 GDKerror("tl value required");
    1617           0 :                 return NULL;
    1618             :         }
    1619             : 
    1620     3366391 :         if (s && s->ttype != TYPE_msk && !s->tsorted) {
    1621           0 :                 GDKerror("invalid argument: s must be sorted.\n");
    1622           0 :                 return NULL;
    1623             :         }
    1624             : 
    1625     3366391 :         canditer_init(&ci, b, s);
    1626     3365337 :         if (ci.ncand == 0) {
    1627             :                 /* trivially empty result */
    1628     1445666 :                 MT_thread_setalgorithm("select: trivially empty");
    1629     1446109 :                 bn = BATdense(0, 0, 0);
    1630     1443403 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1631             :                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1632             :                           " (" LLFMT " usec): "
    1633             :                           "trivially empty\n",
    1634             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1635             :                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1636     1443403 :                 return bn;
    1637             :         }
    1638             : 
    1639     1919671 :         BATiter bi = bat_iterator(b);
    1640             : 
    1641     1920279 :         t = bi.type;
    1642     1920279 :         nil = ATOMnilptr(t);
    1643             :         /* can we use the base type? */
    1644     1920279 :         t = ATOMbasetype(t);
    1645     1920279 :         lnil = nil && ATOMcmp(t, tl, nil) == 0; /* low value = nil? */
    1646             : 
    1647     1919762 :         if (!lnil && th != NULL && (!li || !hi) && !anti && ATOMcmp(t, tl, th) == 0) {
    1648             :                 /* upper and lower bound of range are equal and we
    1649             :                  * want an interval that's open on at least one
    1650             :                  * side */
    1651          59 :                 MT_thread_setalgorithm("select: empty interval");
    1652          59 :                 bn = BATdense(0, 0, 0);
    1653          59 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1654             :                           ",s=" ALGOOPTBATFMT ",li=%d,hi=%d,anti=%d -> "
    1655             :                           ALGOOPTBATFMT " (" LLFMT " usec): "
    1656             :                           "empty interval\n",
    1657             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s),
    1658             :                           li, hi, anti, ALGOOPTBATPAR(bn), GDKusec() - t0);
    1659          59 :                 bat_iterator_end(&bi);
    1660          59 :                 return bn;
    1661             :         }
    1662             : 
    1663     1919706 :         lval = !lnil || th == NULL;      /* low value used for comparison */
    1664     1919706 :         equi = th == NULL || (lval && ATOMcmp(t, tl, th) == 0); /* point select? */
    1665     1919751 :         if (equi) {
    1666     1876121 :                 assert(lval);
    1667     1876121 :                 if (th == NULL)
    1668     1688721 :                         hi = li;
    1669             :                 th = tl;
    1670             :                 hval = true;
    1671       43630 :         } else if (nil == NULL) {
    1672             :                 hval = true;
    1673             :         } else {
    1674       43630 :                 hval = ATOMcmp(t, th, nil) != 0;
    1675             :         }
    1676     1919767 :         if (anti) {
    1677       78627 :                 if (lval != hval) {
    1678             :                         /* one of the end points is nil and the other
    1679             :                          * isn't: swap sub-ranges */
    1680          47 :                         const void *tv;
    1681          47 :                         bool ti;
    1682          47 :                         assert(!equi);
    1683          47 :                         ti = li;
    1684          47 :                         li = !hi;
    1685          47 :                         hi = !ti;
    1686          47 :                         tv = tl;
    1687          47 :                         tl = th;
    1688          47 :                         th = tv;
    1689          47 :                         ti = lval;
    1690          47 :                         lval = hval;
    1691          47 :                         hval = ti;
    1692          47 :                         lnil = ATOMcmp(t, tl, nil) == 0;
    1693          47 :                         anti = false;
    1694          47 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1695             :                                   ",s=" ALGOOPTBATFMT ",anti=%d "
    1696             :                                   "anti: switch ranges...\n",
    1697             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
    1698             :                                   anti);
    1699       78580 :                 } else if (!lval && !hval) {
    1700             :                         /* antiselect for nil-nil range: all non-nil
    1701             :                          * values are in range; we must return all
    1702             :                          * other non-nil values, i.e. nothing */
    1703          26 :                         MT_thread_setalgorithm("select: anti: nil-nil range, nonil");
    1704          26 :                         bn = BATdense(0, 0, 0);
    1705          25 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1706             :                                   ",s=" ALGOOPTBATFMT ",anti=%d -> "
    1707             :                                   ALGOOPTBATFMT " (" LLFMT " usec): "
    1708             :                                   "anti: nil-nil range, nonil\n",
    1709             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
    1710             :                                   anti, ALGOOPTBATPAR(bn), GDKusec() - t0);
    1711          25 :                         bat_iterator_end(&bi);
    1712          25 :                         return bn;
    1713       78554 :                 } else if ((equi && (lnil || !(li && hi))) || ATOMcmp(t, tl, th) > 0) {
    1714             :                         /* various ways to select for everything except nil */
    1715             : 
    1716        7970 :                         bn = BATselect(b, s, nil, NULL, true, true, false);
    1717        8003 :                         if (bn == NULL) {
    1718           0 :                                 bat_iterator_end(&bi);
    1719           0 :                                 return NULL;
    1720             :                         }
    1721        8003 :                         BAT *bn2;
    1722        8003 :                         if (s) {
    1723        4801 :                                 bn2 = BATdiffcand(s, bn);
    1724             :                         } else {
    1725        3202 :                                 bn2 = BATnegcands2(ci.seq, bi.count, bn);
    1726             :                         }
    1727        8002 :                         bat_iterator_end(&bi);
    1728        8004 :                         BBPreclaim(bn);
    1729        7999 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1730             :                                   ",s=" ALGOOPTBATFMT ",anti=1,equi=%d -> "
    1731             :                                   ALGOOPTBATFMT " (" LLFMT " usec): "
    1732             :                                   "everything except nil\n",
    1733             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
    1734             :                                   equi, ALGOOPTBATPAR(bn2), GDKusec() - t0);
    1735        7999 :                         return bn2; /* also if NULL */
    1736             :                 } else {
    1737             :                         antiequi = equi;
    1738             :                         equi = false;
    1739             :                 }
    1740             :         }
    1741             : 
    1742             :         /* if equi set, then so are both lval and hval */
    1743     1911768 :         assert(!equi || (lval && hval));
    1744             : 
    1745     1911768 :         if (hval && (equi ? !li || !hi : ATOMcmp(t, tl, th) > 0)) {
    1746             :                 /* empty range */
    1747          31 :                 MT_thread_setalgorithm("select: empty range");
    1748          31 :                 bn = BATdense(0, 0, 0);
    1749          31 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1750             :                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1751             :                           " (" LLFMT " usec) "
    1752             :                           "empty range\n",
    1753             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1754             :                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1755          31 :                 bat_iterator_end(&bi);
    1756          31 :                 return bn;
    1757             :         }
    1758     1911756 :         if (equi && lnil && (notnull || bi.nonil)) {
    1759             :                 /* return all nils, but there aren't any */
    1760       14963 :                 MT_thread_setalgorithm("select: equi-nil, nonil");
    1761       14965 :                 bn = BATdense(0, 0, 0);
    1762       14965 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1763             :                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1764             :                           " (" LLFMT " usec): "
    1765             :                           "equi-nil, nonil\n",
    1766             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1767             :                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1768       14965 :                 bat_iterator_end(&bi);
    1769       14965 :                 return bn;
    1770             :         }
    1771             : 
    1772     1896793 :         if (!equi && !lval && !hval && lnil && (notnull || bi.nonil)) {
    1773             :                 /* return all non-nils from a BAT that doesn't have
    1774             :                  * any: i.e. return everything */
    1775           0 :                 MT_thread_setalgorithm("select: everything, nonil");
    1776           0 :                 bn = canditer_slice(&ci, 0, ci.ncand);
    1777           0 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1778             :                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1779             :                           " (" LLFMT " usec): "
    1780             :                           "everything, nonil\n",
    1781             :                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1782             :                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1783           0 :                 bat_iterator_end(&bi);
    1784           0 :                 return bn;
    1785             :         }
    1786             : 
    1787             :         /* figure out how the searched for range compares with the known
    1788             :          * minimum and maximum values */
    1789     1907307 :         range = BATrange(&bi, lval ? tl : NULL, hval ? th : NULL, li, hi);
    1790     1896689 :         if (anti) {
    1791       70538 :                 switch (range) {
    1792         218 :                 case range_contains:
    1793             :                         /* MIN..MAX range of values in BAT fully inside
    1794             :                          * tl..th range, so nothing left over for
    1795             :                          * anti */
    1796         218 :                         MT_thread_setalgorithm("select: nothing, out of range");
    1797         218 :                         bn = BATdense(0, 0, 0);
    1798         218 :                         TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1799             :                                   ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1800             :                                   " (" LLFMT " usec): "
    1801             :                                   "nothing, out of range\n",
    1802             :                                   ALGOBATPAR(b), ALGOOPTBATPAR(s), anti, ALGOOPTBATPAR(bn), GDKusec() - t0);
    1803         218 :                         bat_iterator_end(&bi);
    1804         218 :                         return bn;
    1805        6347 :                 case range_before:
    1806             :                 case range_after:
    1807        6347 :                         if (notnull || b->tnonil) {
    1808             :                                 /* search range does not overlap with BAT range,
    1809             :                                  * and there are no nils, so we can return
    1810             :                                  * everything */
    1811        6175 :                                 MT_thread_setalgorithm("select: everything, anti, nonil");
    1812        6175 :                                 bn = canditer_slice(&ci, 0, ci.ncand);
    1813        6173 :                                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1814             :                                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1815             :                                           " (" LLFMT " usec): "
    1816             :                                           "everything, nonil\n",
    1817             :                                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1818             :                                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1819        6173 :                                 bat_iterator_end(&bi);
    1820        6173 :                                 return bn;
    1821             :                         }
    1822             :                         break;
    1823             :                 default:
    1824             :                         break;
    1825             :                 }
    1826     1826151 :         } else if (!equi || !lnil) {
    1827     1818661 :                 switch (range) {
    1828      109886 :                 case range_before:
    1829             :                 case range_after:
    1830             :                         /* range we're looking for either completely
    1831             :                          * before or complete after the range of values
    1832             :                          * in the BAT */
    1833      109886 :                         MT_thread_setalgorithm("select: nothing, out of range");
    1834      109902 :                         bn = BATdense(0, 0, 0);
    1835      109832 :                         TRC_DEBUG(ALGO, "b="
    1836             :                                   ALGOBATFMT ",s="
    1837             :                                   ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1838             :                                   " (" LLFMT " usec): "
    1839             :                                   "nothing, out of range\n",
    1840             :                                   ALGOBATPAR(b),
    1841             :                                   ALGOOPTBATPAR(s), anti,
    1842             :                                   ALGOOPTBATPAR(bn), GDKusec() - t0);
    1843      109832 :                         bat_iterator_end(&bi);
    1844      109832 :                         return bn;
    1845        6264 :                 case range_contains:
    1846        6264 :                         if (notnull || b->tnonil) {
    1847             :                                 /* search range contains BAT range, and
    1848             :                                  * there are no nils, so we can return
    1849             :                                  * everything */
    1850        6193 :                                 MT_thread_setalgorithm("select: everything, nonil");
    1851        6192 :                                 bn = canditer_slice(&ci, 0, ci.ncand);
    1852        6192 :                                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT
    1853             :                                           ",s=" ALGOOPTBATFMT ",anti=%d -> " ALGOOPTBATFMT
    1854             :                                           " (" LLFMT " usec): "
    1855             :                                           "everything, nonil\n",
    1856             :                                           ALGOBATPAR(b), ALGOOPTBATPAR(s), anti,
    1857             :                                           ALGOOPTBATPAR(bn), GDKusec() - t0);
    1858        6192 :                                 bat_iterator_end(&bi);
    1859        6192 :                                 return bn;
    1860             :                         }
    1861             :                         break;
    1862             :                 default:
    1863             :                         break;
    1864             :                 }
    1865             :         }
    1866             : 
    1867     1774217 :         parent = VIEWtparent(b);
    1868     1614111 :         assert(parent >= 0);
    1869     1774217 :         BAT *pb;
    1870     1774217 :         BATiter pbi;
    1871     1774217 :         if (parent > 0)
    1872     1614121 :                 pb = BATdescriptor(parent);
    1873             :         else
    1874             :                 pb = NULL;
    1875     1774741 :         pbi = bat_iterator(pb);
    1876             :         /* use hash only for equi-join if the bat is not sorted, but
    1877             :          * only if b or its parent already has a hash, or if b or its
    1878             :          * parent is persistent and the total size wouldn't be too
    1879             :          * large; check for existence of hash last since that may
    1880             :          * involve I/O */
    1881     1773715 :         if ((equi || antiequi) && !bi.sorted && !bi.revsorted) {
    1882     1426544 :                 double cost = joincost(b, 1, &ci, &havehash, &phash, NULL);
    1883     1425943 :                 if (cost > 0 && cost < ci.ncand) {
    1884       89968 :                         wanthash = true;
    1885       89968 :                         if (havehash) {
    1886       65227 :                                 if (phash) {
    1887       64408 :                                         MT_rwlock_rdlock(&pb->thashlock);
    1888       64446 :                                         if (pb->thash == NULL) {
    1889           0 :                                                 MT_rwlock_rdunlock(&pb->thashlock);
    1890           0 :                                                 havehash = false;
    1891             :                                         }
    1892             :                                 } else {
    1893         819 :                                         MT_rwlock_rdlock(&b->thashlock);
    1894         820 :                                         if (b->thash == NULL) {
    1895           0 :                                                 MT_rwlock_rdunlock(&b->thashlock);
    1896           0 :                                                 havehash = false;
    1897             :                                         }
    1898             :                                 }
    1899             :                         }
    1900       90007 :                         if (wanthash && !havehash && b->batRole != PERSISTENT) {
    1901           0 :                                 MT_lock_set(&b->theaplock);
    1902           0 :                                 if (++b->selcnt > 1000)
    1903           0 :                                         b->selcnt = 1000; /* limit value */
    1904             :                                 else
    1905             :                                         wanthash = false;
    1906           0 :                                 MT_lock_unset(&b->theaplock);
    1907             :                         }
    1908             :                 } else {
    1909     1335975 :                         wanthash = havehash = false;
    1910             :                 }
    1911             :         }
    1912             : 
    1913             :         /* at this point, if havehash is set, we have the hash lock
    1914             :          * the lock is on the parent if phash is set, on b itself if not
    1915             :          * also, if havehash is set, then so is wanthash (but not v.v.) */
    1916             : 
    1917     1773153 :         if (!havehash) {
    1918             :                 /* make sure tsorted and trevsorted flags are set, but
    1919             :                  * we only need to know if we're not yet sure that we're
    1920             :                  * going for the hash (i.e. it already exists) */
    1921     1708993 :                 (void) BATordered(b);
    1922     1710045 :                 (void) BATordered_rev(b);
    1923             :                 /* reinitialize iterator since properties may have changed */
    1924     1710119 :                 bat_iterator_end(&bi);
    1925     1709988 :                 bi = bat_iterator(b);
    1926             :         }
    1927             : 
    1928             :         /* If there is an order index or it is a view and the parent
    1929             :          * has an ordered index, and the bat is not tsorted or
    1930             :          * trevstorted then use the order index.  And there is no cand
    1931             :          * list or if there is one, it is dense.
    1932             :          * TODO: we do not support anti-select with order index */
    1933     1774251 :         bool poidx = false;
    1934     1774251 :         if (!anti &&
    1935     1711034 :             !havehash &&
    1936     1649302 :             !bi.sorted &&
    1937     1394510 :             !bi.revsorted &&
    1938     1272309 :             ci.tpe == cand_dense) {
    1939      978584 :                 BAT *view = NULL;
    1940      978584 :                 (void) BATcheckorderidx(b);
    1941      978723 :                 MT_lock_set(&b->batIdxLock);
    1942      978586 :                 if ((oidxh = b->torderidx) != NULL)
    1943          39 :                         HEAPincref(oidxh);
    1944      978586 :                 MT_lock_unset(&b->batIdxLock);
    1945      978628 :                 if (oidxh == NULL && pb != NULL) {
    1946      915845 :                         (void) BATcheckorderidx(pb);
    1947      915852 :                         MT_lock_set(&pb->batIdxLock);
    1948      915832 :                         if ((oidxh = pb->torderidx) != NULL) {
    1949           9 :                                 HEAPincref(oidxh);
    1950           9 :                                 view = b;
    1951           9 :                                 b = pb;
    1952             :                         }
    1953      915832 :                         MT_lock_unset(&pb->batIdxLock);
    1954             :                 }
    1955      978626 :                 if (oidxh) {
    1956             :                         /* Is query selective enough to use the ordered index ? */
    1957             :                         /* TODO: Test if this heuristic works in practice */
    1958             :                         /*if ((ORDERfnd(b, th) - ORDERfnd(b, tl)) < ((BUN)1000 < bi.count/1000 ? (BUN)1000: bi.count/1000))*/
    1959          48 :                         if ((ORDERfnd(b, oidxh, th) - ORDERfnd(b, oidxh, tl)) < bi.count/3) {
    1960          19 :                                 if (view) {
    1961           4 :                                         bat_iterator_end(&bi);
    1962           4 :                                         bi = bat_iterator(b);
    1963           4 :                                         poidx = true; /* using parent oidx */
    1964           4 :                                         vwo = (lng) (view->tbaseoff - bi.baseoff);
    1965           4 :                                         vwl = b->hseqbase + (oid) vwo + ci.seq - view->hseqbase;
    1966           4 :                                         vwh = vwl + canditer_last(&ci) - ci.seq;
    1967           4 :                                         vwo = (lng) view->hseqbase - (lng) b->hseqbase - vwo;
    1968           4 :                                         TRC_DEBUG(ALGO, "Switch from " ALGOBATFMT " to " ALGOBATFMT " " OIDFMT "-" OIDFMT " hseq " LLFMT "\n", ALGOBATPAR(view), ALGOBATPAR(b), vwl, vwh, vwo);
    1969             :                                 } else {
    1970          15 :                                         vwl = ci.seq;
    1971          15 :                                         vwh = canditer_last(&ci);
    1972             :                                 }
    1973             :                         } else {
    1974          29 :                                 if (view) {
    1975           5 :                                         b = view;
    1976           5 :                                         view = NULL;
    1977             :                                 }
    1978          29 :                                 HEAPdecref(oidxh, false);
    1979          29 :                                 oidxh = NULL;
    1980             :                         }
    1981             :                 }
    1982             :         }
    1983             : 
    1984     1774293 :         if (bi.sorted || bi.revsorted || (!havehash && oidxh != NULL)) {
    1985      416225 :                 BUN low = 0;
    1986      416225 :                 BUN high = bi.count;
    1987             : 
    1988      416225 :                 if (BATtdensebi(&bi)) {
    1989             :                         /* positional */
    1990             :                         /* we expect nonil to be set, in which case we
    1991             :                          * already know that we're not dealing with a
    1992             :                          * nil equiselect (dealt with above) */
    1993       24703 :                         assert(bi.nonil);
    1994       24703 :                         assert(bi.sorted);
    1995       24703 :                         assert(oidxh == NULL);
    1996       24703 :                         algo = "select: dense";
    1997       24703 :                         if (hval) {
    1998       24853 :                                 oid h = * (oid *) th + hi;
    1999       24853 :                                 if (h > bi.tseq)
    2000       24859 :                                         h -= bi.tseq;
    2001             :                                 else
    2002             :                                         h = 0;
    2003       24853 :                                 if ((BUN) h < high)
    2004       24703 :                                         high = (BUN) h;
    2005             :                         }
    2006             : 
    2007       24703 :                         if (lval) {
    2008       24868 :                                 oid l = *(oid *) tl + !li;
    2009       24868 :                                 if (l > bi.tseq)
    2010        4586 :                                         l -= bi.tseq;
    2011             :                                 else
    2012             :                                         l = 0;
    2013        4586 :                                 if ((BUN) l > low)
    2014        4586 :                                         low = (BUN) l;
    2015        4586 :                                 if (low > high)
    2016             :                                         low = high;
    2017             :                         }
    2018      391522 :                 } else if (bi.sorted) {
    2019      268979 :                         assert(oidxh == NULL);
    2020      268979 :                         algo = "select: sorted";
    2021      268979 :                         if (lval) {
    2022      268868 :                                 if (li)
    2023      268005 :                                         low = SORTfndfirst(b, tl);
    2024             :                                 else
    2025         863 :                                         low = SORTfndlast(b, tl);
    2026             :                         } else {
    2027             :                                 /* skip over nils at start of column */
    2028         111 :                                 low = SORTfndlast(b, nil);
    2029             :                         }
    2030      269310 :                         if (hval) {
    2031      267920 :                                 if (hi)
    2032      267345 :                                         high = SORTfndlast(b, th);
    2033             :                                 else
    2034         575 :                                         high = SORTfndfirst(b, th);
    2035             :                         }
    2036      122543 :                 } else if (bi.revsorted) {
    2037      122524 :                         assert(oidxh == NULL);
    2038      122524 :                         algo = "select: reverse sorted";
    2039      122524 :                         if (lval) {
    2040      122503 :                                 if (li)
    2041      122470 :                                         high = SORTfndlast(b, tl);
    2042             :                                 else
    2043          33 :                                         high = SORTfndfirst(b, tl);
    2044             :                         } else {
    2045             :                                 /* skip over nils at end of column */
    2046          21 :                                 high = SORTfndfirst(b, nil);
    2047             :                         }
    2048      122555 :                         if (hval) {
    2049      122452 :                                 if (hi)
    2050      122404 :                                         low = SORTfndfirst(b, th);
    2051             :                                 else
    2052          48 :                                         low = SORTfndlast(b, th);
    2053             :                         }
    2054             :                 } else {
    2055          19 :                         assert(oidxh != NULL);
    2056          19 :                         algo = poidx ? "select: parent orderidx" : "select: orderidx";
    2057          19 :                         if (lval) {
    2058          14 :                                 if (li)
    2059          14 :                                         low = ORDERfndfirst(b, oidxh, tl);
    2060             :                                 else
    2061           0 :                                         low = ORDERfndlast(b, oidxh, tl);
    2062             :                         } else {
    2063             :                                 /* skip over nils at start of column */
    2064           5 :                                 low = ORDERfndlast(b, oidxh, nil);
    2065             :                         }
    2066          19 :                         if (hval) {
    2067          16 :                                 if (hi)
    2068          14 :                                         high = ORDERfndlast(b, oidxh, th);
    2069             :                                 else
    2070           2 :                                         high = ORDERfndfirst(b, oidxh, th);
    2071             :                         }
    2072             :                 }
    2073      416629 :                 if (anti) {
    2074       39865 :                         assert(oidxh == NULL);
    2075       39865 :                         if (bi.sorted) {
    2076       39506 :                                 BUN first = SORTfndlast(b, nil);
    2077             :                                 /* match: [first..low) + [high..last) */
    2078       39523 :                                 bn = canditer_slice2val(&ci,
    2079             :                                                         first + b->hseqbase,
    2080             :                                                         low + b->hseqbase,
    2081       39523 :                                                         high + b->hseqbase,
    2082             :                                                         oid_nil);
    2083             :                         } else {
    2084         359 :                                 BUN last = SORTfndfirst(b, nil);
    2085             :                                 /* match: [first..low) + [high..last) */
    2086         359 :                                 bn = canditer_slice2val(&ci,
    2087             :                                                         oid_nil,
    2088             :                                                         low + b->hseqbase,
    2089             :                                                         high + b->hseqbase,
    2090         359 :                                                         last + b->hseqbase);
    2091             :                         }
    2092             :                 } else {
    2093      376764 :                         if (bi.sorted || bi.revsorted) {
    2094      376745 :                                 assert(oidxh == NULL);
    2095             :                                 /* match: [low..high) */
    2096      376745 :                                 bn = canditer_sliceval(&ci,
    2097             :                                                        low + b->hseqbase,
    2098      376745 :                                                        high + b->hseqbase);
    2099             :                         } else {
    2100          19 :                                 BUN i;
    2101          19 :                                 BUN cnt = 0;
    2102          19 :                                 const oid *rs;
    2103          19 :                                 oid *rbn;
    2104             : 
    2105          19 :                                 rs = (const oid *) oidxh->base + ORDERIDXOFF;
    2106          19 :                                 rs += low;
    2107          19 :                                 bn = COLnew(0, TYPE_oid, high-low, TRANSIENT);
    2108          19 :                                 if (bn == NULL) {
    2109           0 :                                         HEAPdecref(oidxh, false);
    2110           0 :                                         bat_iterator_end(&bi);
    2111           0 :                                         bat_iterator_end(&pbi);
    2112           0 :                                         BBPreclaim(pb);
    2113           0 :                                         return NULL;
    2114             :                                 }
    2115             : 
    2116          19 :                                 rbn = (oid *) Tloc((bn), 0);
    2117             : 
    2118          86 :                                 for (i = low; i < high; i++) {
    2119          67 :                                         if (vwl <= *rs && *rs <= vwh) {
    2120          52 :                                                 *rbn++ = (oid) ((lng) *rs + vwo);
    2121          52 :                                                 cnt++;
    2122             :                                         }
    2123          67 :                                         rs++;
    2124             :                                 }
    2125          19 :                                 HEAPdecref(oidxh, false);
    2126          19 :                                 BATsetcount(bn, cnt);
    2127             : 
    2128             :                                 /* output must be sorted */
    2129          19 :                                 GDKqsort(Tloc(bn, 0), NULL, NULL, (size_t) bn->batCount, sizeof(oid), 0, TYPE_oid, false, false);
    2130          19 :                                 bn->tsorted = true;
    2131          19 :                                 bn->trevsorted = bn->batCount <= 1;
    2132          19 :                                 bn->tkey = true;
    2133          19 :                                 bn->tseqbase = bn->batCount == 0 ? 0 : bn->batCount == 1 ? * (oid *) Tloc(bn, 0) : oid_nil;
    2134          19 :                                 bn->tnil = false;
    2135          19 :                                 bn->tnonil = true;
    2136          19 :                                 if (s) {
    2137           4 :                                         s = BATintersectcand(bn, s);
    2138           4 :                                         BBPunfix(bn->batCacheid);
    2139           4 :                                         bn = s;
    2140             :                                 }
    2141             :                         }
    2142             :                 }
    2143             : 
    2144      416624 :                 bn = virtualize(bn);
    2145      416118 :                 MT_thread_setalgorithm(algo);
    2146      416711 :                 TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",anti=%s -> "
    2147             :                           ALGOOPTBATFMT " %s (" LLFMT " usec)\n",
    2148             :                           ALGOBATPAR(b), anti ? "true" : "false",
    2149             :                           ALGOOPTBATPAR(bn), algo,
    2150             :                           GDKusec() - t0);
    2151             : 
    2152      416711 :                 bat_iterator_end(&bi);
    2153      416709 :                 bat_iterator_end(&pbi);
    2154      416286 :                 BBPreclaim(pb);
    2155      416692 :                 return bn;
    2156             :         }
    2157             : 
    2158       65167 :         assert(oidxh == NULL);
    2159             :         /* upper limit for result size */
    2160     1358068 :         maximum = ci.ncand;
    2161     1358068 :         if ((equi || antiequi) && havehash) {
    2162             :                 /* we can look in the hash struct to see whether all
    2163             :                  * values are distinct and set estimate accordingly */
    2164       65249 :                 if (phash) {
    2165       64429 :                         if (pb->thash->nunique == pbi.count)
    2166             :                                 estimate = 1;
    2167         820 :                 } else if (b->thash->nunique == bi.count)
    2168             :                         estimate = 1;
    2169             :         }
    2170     1352285 :         if (estimate == BUN_NONE && (bi.key || (pb != NULL && pbi.key))) {
    2171             :                 /* exact result size in special cases */
    2172         370 :                 if (equi || (antiequi && wanthash)) {
    2173             :                         estimate = 1;
    2174          13 :                 } else if (!anti && lval && hval) {
    2175           0 :                         switch (t) {
    2176           0 :                         case TYPE_bte:
    2177           0 :                                 estimate = (BUN) (*(bte *) th - *(bte *) tl);
    2178           0 :                                 break;
    2179           0 :                         case TYPE_sht:
    2180           0 :                                 estimate = (BUN) (*(sht *) th - *(sht *) tl);
    2181           0 :                                 break;
    2182           0 :                         case TYPE_int:
    2183           0 :                                 CALC_ESTIMATE(int);
    2184             :                                 break;
    2185           0 :                         case TYPE_lng:
    2186           0 :                                 CALC_ESTIMATE(lng);
    2187             :                                 break;
    2188             : #ifdef HAVE_HGE
    2189           0 :                         case TYPE_hge:
    2190           0 :                                 CALC_ESTIMATE(hge);
    2191             :                                 break;
    2192             : #endif
    2193             :                         }
    2194           0 :                         if (estimate == BUN_NONE)
    2195           0 :                                 estimate += li + hi - 1;
    2196             :                 }
    2197             :         }
    2198             :         /* refine upper limit by exact size (if known) */
    2199     1358068 :         maximum = MIN(maximum, estimate);
    2200     1358068 :         if (wanthash && !havehash && estimate == BUN_NONE) {
    2201             :                 /* no exact result size, but we need estimate to
    2202             :                  * choose between hash- & scan-select (if we already
    2203             :                  * have a hash, it's a no-brainer: we use it) */
    2204       24694 :                 if (ci.ncand <= 10000) {
    2205             :                         /* "small" input: don't bother about more accurate
    2206             :                          * estimate */
    2207             :                         estimate = maximum;
    2208             :                 } else {
    2209             :                         /* layman's quick "pseudo-sample" of 1000 tuples,
    2210             :                          * i.e., 333 from begin, middle & end of BAT */
    2211           3 :                         BUN smpl_cnt = 0, slct_cnt = 0, pos, skip, delta;
    2212           3 :                         BAT *smpl, *slct;
    2213             : 
    2214           3 :                         delta = 1000 / 3 / 2;
    2215           3 :                         skip = (bi.count - (2 * delta)) / 2;
    2216          12 :                         for (pos = delta; pos < bi.count; pos += skip) {
    2217           9 :                                 smpl = BATslice(b, pos - delta, pos + delta);
    2218           9 :                                 if (smpl) {
    2219           9 :                                         slct = BATselect(smpl, NULL, tl,
    2220             :                                                             th, li, hi, anti);
    2221           9 :                                         if (slct) {
    2222           9 :                                                 smpl_cnt += BATcount(smpl);
    2223           9 :                                                 slct_cnt += BATcount(slct);
    2224           9 :                                                 BBPreclaim(slct);
    2225             :                                         }
    2226           9 :                                         BBPreclaim(smpl);
    2227             :                                 }
    2228             :                         }
    2229           3 :                         if (smpl_cnt > 0 && slct_cnt > 0) {
    2230             :                                 /* linear extrapolation plus 10% margin */
    2231           2 :                                 estimate = (BUN) ((dbl) slct_cnt / (dbl) smpl_cnt
    2232           2 :                                                   * (dbl) bi.count * 1.1);
    2233           1 :                         } else if (smpl_cnt > 0 && slct_cnt == 0) {
    2234             :                                 /* estimate low enough to trigger hash select */
    2235           1 :                                 estimate = (ci.ncand / 100) - 1;
    2236             :                         }
    2237             :                 }
    2238       24694 :                 wanthash = estimate < ci.ncand / 100;
    2239             :         }
    2240     1358067 :         if (estimate == BUN_NONE) {
    2241             :                 /* no better estimate possible/required:
    2242             :                  * (pre-)allocate 1M tuples, i.e., avoid/delay extend
    2243             :                  * without too much overallocation */
    2244     1327220 :                 estimate = 1000000;
    2245             :         }
    2246             :         /* limit estimation by upper limit */
    2247     1358068 :         estimate = MIN(estimate, maximum);
    2248             : 
    2249     1358068 :         bn = COLnew(0, TYPE_oid, estimate, TRANSIENT);
    2250     1358179 :         if (bn == NULL) {
    2251           0 :                 if (havehash) {
    2252           0 :                         if (phash)
    2253           0 :                                 MT_rwlock_rdunlock(&pb->thashlock);
    2254             :                         else
    2255           0 :                                 MT_rwlock_rdunlock(&b->thashlock);
    2256             :                 }
    2257           0 :                 bat_iterator_end(&bi);
    2258           0 :                 bat_iterator_end(&pbi);
    2259           0 :                 BBPreclaim(pb);
    2260           0 :                 return NULL;
    2261             :         }
    2262             : 
    2263     1358179 :         if (wanthash) {
    2264             :                 /* hashselect unlocks the hash lock */
    2265       65224 :                 bn = hashselect(&bi, &ci, bn, tl, maximum, havehash, phash, &algo);
    2266       65243 :                 if (bn && antiequi) {
    2267        3514 :                         BAT *bn2;
    2268        3514 :                         if (s) {
    2269        3514 :                                 bn2 = BATdiffcand(s, bn);
    2270             :                         } else {
    2271           0 :                                 bn2 = BATnegcands2(ci.seq, bi.count, bn);
    2272             :                         }
    2273        3516 :                         BBPreclaim(bn);
    2274        3514 :                         bn = bn2;
    2275        3514 :                         if (!bi.nonil) {
    2276           8 :                                 bn2 = BATselect(b, s, nil, NULL, true, true, false);
    2277           8 :                                 if (bn2 == NULL) {
    2278           0 :                                         BBPreclaim(bn);
    2279           0 :                                         return NULL;
    2280             :                                 }
    2281           8 :                                 BAT *bn3 = BATdiffcand(bn, bn2);
    2282           8 :                                 BBPreclaim(bn2);
    2283           8 :                                 BBPreclaim(bn);
    2284             :                                 bn = bn3;
    2285             :                         }
    2286             :                 }
    2287             :         } else {
    2288     1292955 :                 assert(!havehash);
    2289             :                 /* use imprints if
    2290             :                  *   i) bat is persistent, or parent is persistent
    2291             :                  *  ii) it is not an equi-select, and
    2292             :                  * iii) imprints are supported.
    2293             :                  */
    2294     1292955 :                 Imprints *imprints = NULL;
    2295     1292955 :                 if (!equi &&
    2296             :                     /* DISABLES CODE */ (0) && imprintable(bi.type) &&
    2297             :                     (!bi.transient ||
    2298             :                      (pb != NULL && !pbi.transient)) &&
    2299             :                     BATimprints(b) == GDK_SUCCEED) {
    2300             :                         if (pb != NULL) {
    2301             :                                 MT_lock_set(&pb->batIdxLock);
    2302             :                                 imprints = pb->timprints;
    2303             :                                 if (imprints != NULL)
    2304             :                                         IMPSincref(imprints);
    2305             :                                 MT_lock_unset(&pb->batIdxLock);
    2306             :                         } else {
    2307             :                                 MT_lock_set(&b->batIdxLock);
    2308             :                                 imprints = b->timprints;
    2309             :                                 if (imprints != NULL)
    2310             :                                         IMPSincref(imprints);
    2311     1292955 :                                 MT_lock_unset(&b->batIdxLock);
    2312             :                         }
    2313             :                 }
    2314     1292955 :                 GDKclrerr();
    2315     1292628 :                 bn = scanselect(&bi, &ci, bn, tl, th, li, hi, equi, anti,
    2316             :                                 lval, hval, lnil, maximum, imprints, &algo);
    2317     1292628 :                 if (imprints)
    2318             :                         IMPSdecref(imprints, false);
    2319             :         }
    2320     1357335 :         bat_iterator_end(&bi);
    2321     1358259 :         bat_iterator_end(&pbi);
    2322     1358293 :         BBPreclaim(pb);
    2323             : 
    2324     1358288 :         bn = virtualize(bn);
    2325     1357772 :         MT_thread_setalgorithm(algo);
    2326     1357628 :         TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT",anti=%s -> " ALGOOPTBATFMT
    2327             :                   " %s (" LLFMT " usec)\n",
    2328             :                   ALGOBATPAR(b), ALGOOPTBATPAR(s),
    2329             :                   anti ? "true" : "false",
    2330             :                   ALGOOPTBATPAR(bn), algo,
    2331             :                   GDKusec() - t0);
    2332             : 
    2333             :         return bn;
    2334             : }
    2335             : 
    2336             : /* theta select
    2337             :  *
    2338             :  * Returns a BAT with the OID values of b for qualifying tuples.  The
    2339             :  * return BAT is sorted (i.e. in the same order as the input BAT).
    2340             :  *
    2341             :  * If s is not NULL, it is a list of candidates.  s must be sorted.
    2342             :  *
    2343             :  * Theta select returns all values from b which are less/greater than
    2344             :  * or (not) equal to the provided value depending on the value of op.
    2345             :  * Op is a string with one of the values: "=", "==", "<", "<=", ">",
    2346             :  * ">=", "<>", "!=" (the first two are equivalent and the last two are
    2347             :  * equivalent).  Theta select never returns nils.
    2348             :  *
    2349             :  * If value is nil, the result is empty.
    2350             :  */
    2351             : BAT *
    2352      491198 : BATthetaselect(BAT *b, BAT *s, const void *val, const char *op)
    2353             : {
    2354      491198 :         const void *nil;
    2355             : 
    2356      491198 :         BATcheck(b, NULL);
    2357      491198 :         BATcheck(val, NULL);
    2358      491198 :         BATcheck(op, NULL);
    2359             : 
    2360      491198 :         nil = ATOMnilptr(b->ttype);
    2361      491198 :         if (ATOMcmp(b->ttype, val, nil) == 0)
    2362          29 :                 return BATdense(0, 0, 0);
    2363      491202 :         if (op[0] == '=' && ((op[1] == '=' && op[2] == 0) || op[1] == 0)) {
    2364             :                 /* "=" or "==" */
    2365      406191 :                 return BATselect(b, s, val, NULL, true, true, false);
    2366             :         }
    2367       85011 :         if (op[0] == '!' && op[1] == '=' && op[2] == 0) {
    2368             :                 /* "!=" (equivalent to "<>") */
    2369       78432 :                 return BATselect(b, s, val, NULL, true, true, true);
    2370             :         }
    2371        6579 :         if (op[0] == '<') {
    2372         674 :                 if (op[1] == 0) {
    2373             :                         /* "<" */
    2374         573 :                         return BATselect(b, s, nil, val, false, false, false);
    2375             :                 }
    2376         101 :                 if (op[1] == '=' && op[2] == 0) {
    2377             :                         /* "<=" */
    2378          94 :                         return BATselect(b, s, nil, val, false, true, false);
    2379             :                 }
    2380           7 :                 if (op[1] == '>' && op[2] == 0) {
    2381             :                         /* "<>" (equivalent to "!=") */
    2382           6 :                         return BATselect(b, s, val, NULL, true, true, true);
    2383             :                 }
    2384             :         }
    2385        5906 :         if (op[0] == '>') {
    2386        5906 :                 if (op[1] == 0) {
    2387             :                         /* ">" */
    2388        5297 :                         return BATselect(b, s, val, nil, false, false, false);
    2389             :                 }
    2390         609 :                 if (op[1] == '=' && op[2] == 0) {
    2391             :                         /* ">=" */
    2392         612 :                         return BATselect(b, s, val, nil, true, false, false);
    2393             :                 }
    2394             :         }
    2395           0 :         GDKerror("unknown operator.\n");
    2396           0 :         return NULL;
    2397             : }
    2398             : 
    2399             : #define VALUE(s, x)     (s##vars ?                                      \
    2400             :                          s##vars + VarHeapVal(s##vals, (x), s##width) : \
    2401             :                          s##vals + ((x) * s##width))
    2402             : #define FVALUE(s, x)    (s##vals + ((x) * s##width))
    2403             : 
    2404             : #define LTany(a,b)      ((*cmp)(a, b) < 0)
    2405             : #define EQany(a,b)      ((*cmp)(a, b) == 0)
    2406             : #define is_any_nil(v)   ((v) == NULL || (*cmp)((v), nil) == 0)
    2407             : 
    2408             : #define less3(a,b,i,t)  (is_##t##_nil(a) || is_##t##_nil(b) ? bit_nil : LT##t(a, b) || (i && EQ##t(a, b)))
    2409             : #define grtr3(a,b,i,t)  (is_##t##_nil(a) || is_##t##_nil(b) ? bit_nil : LT##t(b, a) || (i && EQ##t(a, b)))
    2410             : #define or3(a,b)        ((a) == 1 || (b) == 1 ? 1 : is_bit_nil(a) || is_bit_nil(b) ? bit_nil : 0)
    2411             : #define and3(a,b)       ((a) == 0 || (b) == 0 ? 0 : is_bit_nil(a) || is_bit_nil(b) ? bit_nil : 1)
    2412             : #define not3(a)         (is_bit_nil(a) ? bit_nil : !(a))
    2413             : 
    2414             : #define between3(v, lo, linc, hi, hinc, TYPE)                           \
    2415             :         and3(grtr3(v, lo, linc, TYPE), less3(v, hi, hinc, TYPE))
    2416             : 
    2417             : #define BETWEEN(v, lo, linc, hi, hinc, TYPE)                            \
    2418             :         (is_##TYPE##_nil(v)                                             \
    2419             :          ? bit_nil                                                      \
    2420             :          : (bit) (anti                                                  \
    2421             :                   ? (symmetric                                          \
    2422             :                      ? not3(or3(between3(v, lo, linc, hi, hinc, TYPE),  \
    2423             :                                 between3(v, hi, hinc, lo, linc, TYPE))) \
    2424             :                      : not3(between3(v, lo, linc, hi, hinc, TYPE)))     \
    2425             :                   : (symmetric                                          \
    2426             :                      ? or3(between3(v, lo, linc, hi, hinc, TYPE),       \
    2427             :                            between3(v, hi, hinc, lo, linc, TYPE))       \
    2428             :                      : between3(v, lo, linc, hi, hinc, TYPE))))
    2429             : 
    2430             : gdk_return
    2431         126 : rangejoin(BAT *r1, BAT *r2, BAT *l, BAT *rl, BAT *rh,
    2432             :           struct canditer *lci, struct canditer *rci,
    2433             :           bool linc, bool hinc, bool anti, bool symmetric, BUN maxsize)
    2434             : {
    2435         126 :         if (!anti && !symmetric) {
    2436             :                 /* we'll need these */
    2437         115 :                 (void) BATordered(l);
    2438         118 :                 (void) BATordered_rev(l);
    2439             :         }
    2440         128 :         BATiter li = bat_iterator(l);
    2441         129 :         BATiter rli = bat_iterator(rl);
    2442         129 :         BATiter rhi = bat_iterator(rh);
    2443         129 :         const char *rlvals, *rhvals;
    2444         129 :         const char *lvars, *rlvars, *rhvars;
    2445         129 :         int rlwidth, rhwidth;
    2446         129 :         int lwidth;
    2447         129 :         const void *nil = ATOMnilptr(li.type);
    2448         129 :         int (*cmp)(const void *, const void *) = ATOMcompare(li.type);
    2449         129 :         int t;
    2450         129 :         BUN cnt, ncnt, lncand = lci->ncand, rncand = rci->ncand;
    2451         129 :         oid *restrict dst1, *restrict dst2;
    2452         129 :         const void *vrl, *vrh;
    2453         129 :         oid ro;
    2454         129 :         oid rlval = oid_nil, rhval = oid_nil;
    2455         129 :         int sorted = 0;         /* which output column is sorted */
    2456         129 :         BAT *tmp = NULL;
    2457         129 :         const char *algo = NULL;
    2458         129 :         Heap *oidxh = NULL;
    2459             : 
    2460         129 :         QryCtx *qry_ctx = MT_thread_get_qry_ctx();
    2461             : 
    2462         387 :         assert(ATOMtype(li.type) == ATOMtype(rli.type));
    2463         258 :         assert(ATOMtype(li.type) == ATOMtype(rhi.type));
    2464         129 :         assert(BATcount(rl) == BATcount(rh));
    2465         129 :         assert(rl->hseqbase == rh->hseqbase);
    2466         129 :         assert(r1->ttype == TYPE_oid);
    2467         129 :         assert(r2 == NULL || r2->ttype == TYPE_oid);
    2468         110 :         assert(r2 == NULL || BATcount(r1) == BATcount(r2));
    2469         129 :         assert(li.type != TYPE_void || !is_oid_nil(l->tseqbase));
    2470         129 :         assert(rli.type != TYPE_void || !is_oid_nil(rl->tseqbase));
    2471         129 :         assert(rhi.type != TYPE_void || !is_oid_nil(rh->tseqbase));
    2472             : 
    2473         129 :         TRC_DEBUG(ALGO, "l=" ALGOBATFMT ","
    2474             :                   "rl=" ALGOBATFMT ",rh=" ALGOBATFMT ","
    2475             :                   "sl=" ALGOOPTBATFMT ",sr=" ALGOOPTBATFMT ","
    2476             :                   "anti=%s,symmetric=%s\n",
    2477             :                   ALGOBATPAR(l),
    2478             :                   ALGOBATPAR(rl),
    2479             :                   ALGOBATPAR(rh),
    2480             :                   ALGOOPTBATPAR(lci->s),
    2481             :                   ALGOOPTBATPAR(rci->s),
    2482             :                   anti ? "true" : "false",
    2483             :                   symmetric ? "true" : "false");
    2484             : 
    2485         128 :         rlvals = rli.type == TYPE_void ? NULL : (const char *) rli.base;
    2486         128 :         rhvals = rhi.type == TYPE_void ? NULL : (const char *) rhi.base;
    2487         128 :         lwidth = li.width;
    2488         128 :         rlwidth = rli.width;
    2489         128 :         rhwidth = rhi.width;
    2490         128 :         dst1 = (oid *) Tloc(r1, 0);
    2491         128 :         dst2 = r2 ? (oid *) Tloc(r2, 0) : NULL;
    2492             : 
    2493         128 :         t = ATOMtype(li.type);
    2494         128 :         t = ATOMbasetype(t);
    2495             : 
    2496         128 :         if (li.vh && li.type) {
    2497          16 :                 assert(rli.vh && rli.type);
    2498          16 :                 assert(rhi.vh && rhi.type);
    2499          16 :                 lvars = li.vh->base;
    2500          16 :                 rlvars = rli.vh->base;
    2501          16 :                 rhvars = rhi.vh->base;
    2502             :         } else {
    2503         112 :                 assert(rli.vh == NULL);
    2504         112 :                 assert(rhi.vh == NULL);
    2505             :                 lvars = rlvars = rhvars = NULL;
    2506             :         }
    2507             : 
    2508         128 :         if (!anti && !symmetric && !li.sorted && !li.revsorted) {
    2509          13 :                 (void) BATcheckorderidx(l);
    2510          13 :                 MT_lock_set(&l->batIdxLock);
    2511          13 :                 if ((oidxh = l->torderidx) != NULL)
    2512           0 :                         HEAPincref(oidxh);
    2513          13 :                 MT_lock_unset(&l->batIdxLock);
    2514             : #if 0 /* needs checking */
    2515             :                 if (oidxh == NULL && VIEWtparent(l)) {
    2516             : /* if enabled, need to fix/unfix parent bat */
    2517             :                         BAT *pb = BBP_desc(VIEWtparent(l));
    2518             :                         (void) BATcheckorderidx(pb);
    2519             :                         MT_lock_set(&pb->batIdxLock);
    2520             :                         if ((oidxh = pb->torderidx) != NULL) {
    2521             :                                 HEAPincref(oidxh);
    2522             :                                 l = pb;
    2523             :                         }
    2524             :                         MT_lock_unset(&pb->batIdxLock);
    2525             :                 }
    2526             : #endif
    2527             :         }
    2528             : 
    2529         128 :         vrl = &rlval;
    2530         128 :         vrh = &rhval;
    2531         128 :         if (!anti && !symmetric && (li.sorted || li.revsorted || oidxh)) {
    2532             :                 /* left column is sorted, use binary search */
    2533         105 :                 sorted = 2;
    2534         632 :                 TIMEOUT_LOOP(rncand, qry_ctx) {
    2535         422 :                         BUN low, high;
    2536             : 
    2537         422 :                         ro = canditer_next(rci);
    2538         419 :                         if (rlvals) {
    2539         419 :                                 vrl = VALUE(rl, ro - rl->hseqbase);
    2540             :                         } else {
    2541             :                                 /* TYPE_void */
    2542           0 :                                 rlval = ro - rl->hseqbase + rl->tseqbase;
    2543             :                         }
    2544         419 :                         if (rhvals) {
    2545         419 :                                 vrh = VALUE(rh, ro - rh->hseqbase);
    2546             :                         } else {
    2547             :                                 /* TYPE_void */
    2548           0 :                                 rhval = ro - rh->hseqbase + rh->tseqbase;
    2549             :                         }
    2550         419 :                         if (cmp(vrl, nil) == 0 || cmp(vrh, nil) == 0)
    2551           9 :                                 continue;
    2552         403 :                         if (li.sorted) {
    2553         400 :                                 if (linc)
    2554         289 :                                         low = SORTfndfirst(l, vrl);
    2555             :                                 else
    2556         111 :                                         low = SORTfndlast(l, vrl);
    2557         412 :                                 if (hinc)
    2558         350 :                                         high = SORTfndlast(l, vrh);
    2559             :                                 else
    2560          62 :                                         high = SORTfndfirst(l, vrh);
    2561           3 :                         } else  if (li.revsorted) {
    2562           3 :                                 if (hinc)
    2563           3 :                                         low = SORTfndfirst(l, vrh);
    2564             :                                 else
    2565           0 :                                         low = SORTfndlast(l, vrh);
    2566           3 :                                 if (linc)
    2567           3 :                                         high = SORTfndlast(l, vrl);
    2568             :                                 else
    2569           0 :                                         high = SORTfndfirst(l, vrl);
    2570             :                         } else {
    2571           0 :                                 assert(oidxh);
    2572           0 :                                 if (linc)
    2573           0 :                                         low = ORDERfndfirst(l, oidxh, vrl);
    2574             :                                 else
    2575           0 :                                         low = ORDERfndlast(l, oidxh, vrl);
    2576           0 :                                 if (hinc)
    2577           0 :                                         high = ORDERfndlast(l, oidxh, vrh);
    2578             :                                 else
    2579           0 :                                         high = ORDERfndfirst(l, oidxh, vrh);
    2580             :                         }
    2581         416 :                         if (high <= low)
    2582         228 :                                 continue;
    2583         188 :                         if (li.sorted || li.revsorted) {
    2584         188 :                                 low = canditer_search(lci, low + l->hseqbase, true);
    2585         188 :                                 high = canditer_search(lci, high + l->hseqbase, true);
    2586         188 :                                 assert(high >= low);
    2587             : 
    2588         188 :                                 if (BATcapacity(r1) < BATcount(r1) + high - low) {
    2589           0 :                                         cnt = BATcount(r1) + high - low + 1024;
    2590           0 :                                         if (cnt > maxsize)
    2591             :                                                 cnt = maxsize;
    2592           0 :                                         BATsetcount(r1, BATcount(r1));
    2593           0 :                                         if (BATextend(r1, cnt) != GDK_SUCCEED)
    2594           0 :                                                 goto bailout;
    2595           0 :                                         dst1 = (oid *) Tloc(r1, 0);
    2596           0 :                                         if (r2) {
    2597           0 :                                                 BATsetcount(r2, BATcount(r2));
    2598           0 :                                                 if (BATextend(r2, cnt) != GDK_SUCCEED)
    2599           0 :                                                         goto bailout;
    2600           0 :                                                 assert(BATcapacity(r1) == BATcapacity(r2));
    2601           0 :                                                 dst2 = (oid *) Tloc(r2, 0);
    2602             :                                         }
    2603             :                                 }
    2604         188 :                                 canditer_setidx(lci, low);
    2605        1040 :                                 while (low < high) {
    2606         855 :                                         dst1[r1->batCount++] = canditer_next(lci);
    2607         852 :                                         if (r2) {
    2608         840 :                                                 dst2[r2->batCount++] = ro;
    2609             :                                         }
    2610         852 :                                         low++;
    2611             :                                 }
    2612             :                         } else {
    2613           0 :                                 const oid *ord;
    2614             : 
    2615           0 :                                 assert(oidxh);
    2616           0 :                                 ord = (const oid *) oidxh->base + ORDERIDXOFF;
    2617             : 
    2618           0 :                                 if (BATcapacity(r1) < BATcount(r1) + high - low) {
    2619           0 :                                         cnt = BATcount(r1) + high - low + 1024;
    2620           0 :                                         if (cnt > maxsize)
    2621             :                                                 cnt = maxsize;
    2622           0 :                                         BATsetcount(r1, BATcount(r1));
    2623           0 :                                         if (BATextend(r1, cnt) != GDK_SUCCEED)
    2624           0 :                                                 goto bailout;
    2625           0 :                                         dst1 = (oid *) Tloc(r1, 0);
    2626           0 :                                         if (r2) {
    2627           0 :                                                 BATsetcount(r2, BATcount(r2));
    2628           0 :                                                 if (BATextend(r2, cnt) != GDK_SUCCEED)
    2629           0 :                                                         goto bailout;
    2630           0 :                                                 assert(BATcapacity(r1) == BATcapacity(r2));
    2631           0 :                                                 dst2 = (oid *) Tloc(r2, 0);
    2632             :                                         }
    2633             :                                 }
    2634             : 
    2635           0 :                                 while (low < high) {
    2636           0 :                                         if (canditer_contains(lci, ord[low])) {
    2637           0 :                                                 dst1[r1->batCount++] = ord[low];
    2638           0 :                                                 if (r2) {
    2639           0 :                                                         dst2[r2->batCount++] = ro;
    2640             :                                                 }
    2641             :                                         }
    2642           0 :                                         low++;
    2643             :                                 }
    2644             :                         }
    2645             :                 }
    2646         105 :                 if (oidxh)
    2647           0 :                         HEAPdecref(oidxh, false);
    2648         105 :                 TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
    2649         105 :                 cnt = BATcount(r1);
    2650         105 :                 assert(r2 == NULL || BATcount(r1) == BATcount(r2));
    2651          23 :         } else if (/* DISABLES CODE */ (0) &&
    2652             :                    !anti && !symmetric &&
    2653             :                    imprintable(li.type) &&
    2654             :                    (BATcount(rl) > 2 ||
    2655             :                     !li.transient ||
    2656             :                     (VIEWtparent(l) != 0 &&
    2657             : /* if enabled, need to fix/unfix parent bat */
    2658             :                      /* batTransient access needs to be protected */
    2659             :                      !(tmp = BBP_desc(VIEWtparent(l)))->batTransient) ||
    2660             :                     BATcheckimprints(l)) &&
    2661             :                    BATimprints(l) == GDK_SUCCEED) {
    2662             :                 /* implementation using imprints on left column
    2663             :                  *
    2664             :                  * we use imprints if we can (the type is right for
    2665             :                  * imprints) and either the left bat is persistent or
    2666             :                  * already has imprints, or the right bats are long
    2667             :                  * enough (for creating imprints being worth it) */
    2668             :                 Imprints *imprints = NULL;
    2669             : 
    2670             :                 if (tmp) {
    2671             :                         MT_lock_set(&tmp->batIdxLock);
    2672             :                         imprints = tmp->timprints;
    2673             :                         if (imprints != NULL)
    2674             :                                 IMPSincref(imprints);
    2675             :                         MT_lock_unset(&tmp->batIdxLock);
    2676             :                 } else {
    2677             :                         MT_lock_set(&l->batIdxLock);
    2678             :                         imprints = l->timprints;
    2679             :                         if (imprints != NULL)
    2680             :                                 IMPSincref(imprints);
    2681             :                         MT_lock_unset(&l->batIdxLock);
    2682             :                 }
    2683             :                 /* in the unlikely case that the imprints were removed
    2684             :                  * before we could get at them, take the slow, nested
    2685             :                  * loop implementation */
    2686             :                 if (imprints == NULL)
    2687             :                         goto nestedloop;
    2688             : 
    2689             :                 sorted = 2;
    2690             :                 cnt = 0;
    2691             :                 TIMEOUT_LOOP_IDX_DECL(i, rncand, qry_ctx) {
    2692             :                         maxsize = cnt + (rncand - i) * lncand;
    2693             :                         ro = canditer_next(rci);
    2694             :                         if (rlvals) {
    2695             :                                 vrl = FVALUE(rl, ro - rl->hseqbase);
    2696             :                         } else {
    2697             :                                 /* TYPE_void */
    2698             :                                 rlval = ro - rl->hseqbase + rl->tseqbase;
    2699             :                         }
    2700             :                         if (rhvals) {
    2701             :                                 vrh = FVALUE(rh, ro - rh->hseqbase);
    2702             :                         } else {
    2703             :                                 /* TYPE_void */
    2704             :                                 rhval = ro - rl->hseqbase + rl->tseqbase;
    2705             :                         }
    2706             :                         dst1 = (oid *) Tloc(r1, 0);
    2707             :                         canditer_reset(lci);
    2708             :                         switch (t) {
    2709             :                         case TYPE_bte: {
    2710             :                                 bte vl, vh;
    2711             :                                 if (is_bte_nil((vl = *(bte *) vrl)))
    2712             :                                         continue;
    2713             :                                 if (is_bte_nil((vh = *(bte *) vrh)))
    2714             :                                         continue;
    2715             :                                 if (!linc) {
    2716             :                                         if (vl == MAXVALUEbte)
    2717             :                                                 continue;
    2718             :                                         vl = NEXTVALUEbte(vl);
    2719             :                                 }
    2720             :                                 if (!hinc) {
    2721             :                                         if (vh == MINVALUEbte)
    2722             :                                                 continue;
    2723             :                                         vh = PREVVALUEbte(vh);
    2724             :                                 }
    2725             :                                 if (vl > vh)
    2726             :                                         continue;
    2727             :                                 ncnt = fullscan_bte(&li, lci, r1, &vl, &vh,
    2728             :                                                     true, true, false,
    2729             :                                                     false, true, true,
    2730             :                                                     false, cnt,
    2731             :                                                     l->hseqbase, dst1,
    2732             :                                                     maxsize,
    2733             :                                                     imprints, &algo);
    2734             :                                 break;
    2735             :                         }
    2736             :                         case TYPE_sht: {
    2737             :                                 sht vl, vh;
    2738             :                                 if (is_sht_nil((vl = *(sht *) vrl)))
    2739             :                                         continue;
    2740             :                                 if (is_sht_nil((vh = *(sht *) vrh)))
    2741             :                                         continue;
    2742             :                                 if (!linc) {
    2743             :                                         if (vl == MAXVALUEsht)
    2744             :                                                 continue;
    2745             :                                         vl = NEXTVALUEsht(vl);
    2746             :                                 }
    2747             :                                 if (!hinc) {
    2748             :                                         if (vh == MINVALUEsht)
    2749             :                                                 continue;
    2750             :                                         vh = PREVVALUEsht(vh);
    2751             :                                 }
    2752             :                                 if (vl > vh)
    2753             :                                         continue;
    2754             :                                 ncnt = fullscan_sht(&li, lci, r1, &vl, &vh,
    2755             :                                                     true, true, false,
    2756             :                                                     false, true, true,
    2757             :                                                     false, cnt,
    2758             :                                                     l->hseqbase, dst1,
    2759             :                                                     maxsize,
    2760             :                                                     imprints, &algo);
    2761             :                                 break;
    2762             :                         }
    2763             :                         case TYPE_int:
    2764             : #if SIZEOF_OID == SIZEOF_INT
    2765             :                         case TYPE_oid:
    2766             : #endif
    2767             :                         {
    2768             :                                 int vl, vh;
    2769             :                                 if (is_int_nil((vl = *(int *) vrl)))
    2770             :                                         continue;
    2771             :                                 if (is_int_nil((vh = *(int *) vrh)))
    2772             :                                         continue;
    2773             :                                 if (!linc) {
    2774             :                                         if (vl == MAXVALUEint)
    2775             :                                                 continue;
    2776             :                                         vl = NEXTVALUEint(vl);
    2777             :                                 }
    2778             :                                 if (!hinc) {
    2779             : #if SIZEOF_OID == SIZEOF_INT
    2780             :                                         if (t == TYPE_oid) {
    2781             :                                                 if (vh == MINVALUEoid)
    2782             :                                                         continue;
    2783             :                                                 vh = PREVVALUEoid(vh);
    2784             :                                         } else
    2785             : #endif
    2786             :                                         {
    2787             :                                                 if (vh == MINVALUEint)
    2788             :                                                         continue;
    2789             :                                                 vh = PREVVALUEint(vh);
    2790             :                                         }
    2791             :                                 }
    2792             :                                 if (vl > vh)
    2793             :                                         continue;
    2794             :                                 ncnt = fullscan_int(&li, lci, r1, &vl, &vh,
    2795             :                                                     true, true, false,
    2796             :                                                     false, true, true,
    2797             :                                                     false, cnt,
    2798             :                                                     l->hseqbase, dst1,
    2799             :                                                     maxsize,
    2800             :                                                     imprints, &algo);
    2801             :                                 break;
    2802             :                         }
    2803             :                         case TYPE_lng:
    2804             : #if SIZEOF_OID == SIZEOF_LNG
    2805             :                         case TYPE_oid:
    2806             : #endif
    2807             :                         {
    2808             :                                 lng vl, vh;
    2809             :                                 if (is_lng_nil((vl = *(lng *) vrl)))
    2810             :                                         continue;
    2811             :                                 if (is_lng_nil((vh = *(lng *) vrh)))
    2812             :                                         continue;
    2813             :                                 if (!linc) {
    2814             :                                         if (vl == MAXVALUElng)
    2815             :                                                 continue;
    2816             :                                         vl = NEXTVALUElng(vl);
    2817             :                                 }
    2818             :                                 if (!hinc) {
    2819             : #if SIZEOF_OID == SIZEOF_LNG
    2820             :                                         if (t == TYPE_oid) {
    2821             :                                                 if (vh == MINVALUEoid)
    2822             :                                                         continue;
    2823             :                                                 vh = PREVVALUEoid(vh);
    2824             :                                         } else
    2825             : #endif
    2826             :                                         {
    2827             :                                                 if (vh == MINVALUElng)
    2828             :                                                         continue;
    2829             :                                                 vh = PREVVALUElng(vh);
    2830             :                                         }
    2831             :                                 }
    2832             :                                 if (vl > vh)
    2833             :                                         continue;
    2834             :                                 ncnt = fullscan_lng(&li, lci, r1, &vl, &vh,
    2835             :                                                     true, true, false,
    2836             :                                                     false, true, true,
    2837             :                                                     false, cnt,
    2838             :                                                     l->hseqbase, dst1,
    2839             :                                                     maxsize,
    2840             :                                                     imprints, &algo);
    2841             :                                 break;
    2842             :                         }
    2843             : #ifdef HAVE_HGE
    2844             :                         case TYPE_hge: {
    2845             :                                 hge vl, vh;
    2846             :                                 if (is_hge_nil((vl = *(hge *) vrl)))
    2847             :                                         continue;
    2848             :                                 if (is_hge_nil((vh = *(hge *) vrh)))
    2849             :                                         continue;
    2850             :                                 if (!linc) {
    2851             :                                         if (vl == MAXVALUEhge)
    2852             :                                                 continue;
    2853             :                                         vl = NEXTVALUEhge(vl);
    2854             :                                 }
    2855             :                                 if (!hinc) {
    2856             :                                         if (vh == MINVALUEhge)
    2857             :                                                 continue;
    2858             :                                         vh = PREVVALUEhge(vh);
    2859             :                                 }
    2860             :                                 if (vl > vh)
    2861             :                                         continue;
    2862             :                                 ncnt = fullscan_hge(&li, lci, r1, &vl, &vh,
    2863             :                                                     true, true, false,
    2864             :                                                     false, true, true,
    2865             :                                                     false, cnt,
    2866             :                                                     l->hseqbase, dst1,
    2867             :                                                     maxsize,
    2868             :                                                     imprints, &algo);
    2869             :                                 break;
    2870             :                         }
    2871             : #endif
    2872             :                         case TYPE_flt: {
    2873             :                                 flt vl, vh;
    2874             :                                 vl = *(flt *) vrl;
    2875             :                                 if (is_flt_nil(vl))
    2876             :                                         continue;
    2877             :                                 vh = *(flt *) vrh;
    2878             :                                 if (is_flt_nil(vh))
    2879             :                                         continue;
    2880             :                                 if (!linc) {
    2881             :                                         if (vl == MAXVALUEflt)
    2882             :                                                 continue;
    2883             :                                         vl = NEXTVALUEflt(vl);
    2884             :                                 }
    2885             :                                 if (!hinc) {
    2886             :                                         if (vh == MINVALUEflt)
    2887             :                                                 continue;
    2888             :                                         vh = PREVVALUEflt(vh);
    2889             :                                 }
    2890             :                                 if (vl > vh)
    2891             :                                         continue;
    2892             :                                 ncnt = fullscan_flt(&li, lci, r1, &vl, &vh,
    2893             :                                                     true, true, false,
    2894             :                                                     false, true, true,
    2895             :                                                     false, cnt,
    2896             :                                                     l->hseqbase, dst1,
    2897             :                                                     maxsize,
    2898             :                                                     imprints, &algo);
    2899             :                                 break;
    2900             :                         }
    2901             :                         case TYPE_dbl: {
    2902             :                                 dbl vl, vh;
    2903             :                                 vl = *(dbl *) vrl;
    2904             :                                 if (is_dbl_nil(vl))
    2905             :                                         continue;
    2906             :                                 vh = *(dbl *) vrh;
    2907             :                                 if (is_dbl_nil(vh))
    2908             :                                         continue;
    2909             :                                 if (!linc) {
    2910             :                                         if (vl == MAXVALUEdbl)
    2911             :                                                 continue;
    2912             :                                         vl = NEXTVALUEdbl(vl);
    2913             :                                 }
    2914             :                                 if (!hinc) {
    2915             :                                         if (vh == MINVALUEdbl)
    2916             :                                                 continue;
    2917             :                                         vh = PREVVALUEdbl(vh);
    2918             :                                 }
    2919             :                                 if (vl > vh)
    2920             :                                         continue;
    2921             :                                 ncnt = fullscan_dbl(&li, lci, r1, &vl, &vh,
    2922             :                                                     true, true, false,
    2923             :                                                     false, true, true,
    2924             :                                                     false, cnt,
    2925             :                                                     l->hseqbase, dst1,
    2926             :                                                     maxsize,
    2927             :                                                     imprints, &algo);
    2928             :                                 break;
    2929             :                         }
    2930             :                         default:
    2931             :                                 ncnt = BUN_NONE;
    2932             :                                 GDKerror("unsupported type\n");
    2933             :                                 MT_UNREACHABLE();
    2934             :                         }
    2935             :                         if (ncnt == BUN_NONE) {
    2936             :                                 IMPSdecref(imprints, false);
    2937             :                                 goto bailout;
    2938             :                         }
    2939             :                         assert(ncnt >= cnt || ncnt == 0);
    2940             :                         if (ncnt == cnt || ncnt == 0)
    2941             :                                 continue;
    2942             :                         if (r2) {
    2943             :                                 if (BATcapacity(r2) < ncnt) {
    2944             :                                         BATsetcount(r2, cnt);
    2945             :                                         if (BATextend(r2, BATcapacity(r1)) != GDK_SUCCEED) {
    2946             :                                                 IMPSdecref(imprints, false);
    2947             :                                                 goto bailout;
    2948             :                                         }
    2949             :                                         dst2 = (oid *) Tloc(r2, 0);
    2950             :                                 }
    2951             :                                 while (cnt < ncnt)
    2952             :                                         dst2[cnt++] = ro;
    2953             :                         } else {
    2954             :                                 cnt = ncnt;
    2955             :                         }
    2956             :                 }
    2957             :                 IMPSdecref(imprints, false);
    2958             :                 TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
    2959             :         } else {
    2960          23 :           nestedloop:;
    2961             :                 /* nested loop implementation */
    2962          23 :                 const void *vl;
    2963          23 :                 const char *lvals;
    2964          23 :                 oid lval;
    2965             : 
    2966          23 :                 GDKclrerr();    /* not interested in BATimprints errors */
    2967          24 :                 sorted = 1;
    2968          24 :                 lvals = li.type == TYPE_void ? NULL : (const char *) li.base;
    2969          24 :                 vl = &lval;
    2970         280 :                 TIMEOUT_LOOP(lncand, qry_ctx) {
    2971         237 :                         oid lo;
    2972             : 
    2973         237 :                         lo = canditer_next(lci);
    2974         236 :                         if (lvals) {
    2975         236 :                                 vl = VALUE(l, lo - l->hseqbase);
    2976         236 :                                 if (cmp(vl, nil) == 0)
    2977           8 :                                         continue;
    2978             :                         } else {
    2979           0 :                                 lval = lo - l->hseqbase + l->tseqbase;
    2980             :                         }
    2981         228 :                         canditer_reset(rci);
    2982       26021 :                         for (BUN j = 0; j < rncand; j++) {
    2983       25793 :                                 ro = canditer_next(rci);
    2984       19151 :                                 if (rlvals) {
    2985       19151 :                                         vrl = VALUE(rl, ro - rl->hseqbase);
    2986             :                                 } else {
    2987             :                                         /* TYPE_void */
    2988           0 :                                         rlval = ro - rl->hseqbase + rl->tseqbase;
    2989             :                                 }
    2990       19151 :                                 if (rhvals) {
    2991       19151 :                                         vrh = VALUE(rh, ro - rh->hseqbase);
    2992             :                                 } else {
    2993             :                                         /* TYPE_void */
    2994           0 :                                         rhval = ro - rh->hseqbase + rh->tseqbase;
    2995             :                                 }
    2996       19266 :                                 if (BETWEEN(vl, vrl, linc, vrh, hinc, any) != 1)
    2997       15753 :                                         continue;
    2998       10040 :                                 if (BATcount(r1) == BATcapacity(r1)) {
    2999           2 :                                         BUN newcap = BATgrows(r1);
    3000           2 :                                         if (newcap > maxsize)
    3001             :                                                 newcap = maxsize;
    3002           2 :                                         BATsetcount(r1, BATcount(r1));
    3003           2 :                                         if (BATextend(r1, newcap) != GDK_SUCCEED)
    3004           0 :                                                 goto bailout;
    3005           2 :                                         dst1 = (oid *) Tloc(r1, 0);
    3006           2 :                                         if (r2) {
    3007           2 :                                                 BATsetcount(r2, BATcount(r2));
    3008           2 :                                                 if (BATextend(r2, newcap) != GDK_SUCCEED)
    3009           0 :                                                         goto bailout;
    3010           2 :                                                 assert(BATcapacity(r1) == BATcapacity(r2));
    3011           2 :                                                 dst2 = (oid *) Tloc(r2, 0);
    3012             :                                         }
    3013             :                                 }
    3014       10040 :                                 dst1[r1->batCount++] = lo;
    3015       10040 :                                 if (r2) {
    3016       10034 :                                         dst2[r2->batCount++] = ro;
    3017             :                                 }
    3018             :                         }
    3019             :                 }
    3020          21 :                 TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
    3021          22 :                 cnt = BATcount(r1);
    3022          22 :                 assert(r2 == NULL || BATcount(r1) == BATcount(r2));
    3023             :         }
    3024             : 
    3025             :         /* also set other bits of heap to correct value to indicate size */
    3026         127 :         BATsetcount(r1, cnt);
    3027             : 
    3028             :         /* set properties using an extra scan (usually not complete) */
    3029         126 :         dst1 = (oid *) Tloc(r1, 0);
    3030         126 :         r1->tkey = true;
    3031         126 :         r1->tsorted = true;
    3032         126 :         r1->trevsorted = true;
    3033         126 :         r1->tseqbase = 0;
    3034         126 :         r1->tnil = false;
    3035         126 :         r1->tnonil = true;
    3036         604 :         for (ncnt = 1; ncnt < cnt; ncnt++) {
    3037         489 :                 if (dst1[ncnt - 1] == dst1[ncnt]) {
    3038         426 :                         r1->tseqbase = oid_nil;
    3039         426 :                         r1->tkey = false;
    3040          63 :                 } else if (dst1[ncnt - 1] < dst1[ncnt]) {
    3041          60 :                         r1->trevsorted = false;
    3042          60 :                         if (dst1[ncnt - 1] + 1 != dst1[ncnt])
    3043           3 :                                 r1->tseqbase = oid_nil;
    3044             :                 } else {
    3045           3 :                         assert(sorted != 1);
    3046           3 :                         r1->tsorted = false;
    3047           3 :                         r1->tseqbase = oid_nil;
    3048           3 :                         r1->tkey = false;
    3049             :                 }
    3050         538 :                 if (!(r1->trevsorted | BATtdense(r1) | r1->tkey | ((sorted != 1) & r1->tsorted)))
    3051             :                         break;
    3052             :         }
    3053         126 :         if (BATtdense(r1))
    3054         106 :                 r1->tseqbase = cnt > 0 ? dst1[0] : 0;
    3055         126 :         if (r2) {
    3056         109 :                 BATsetcount(r2, cnt);
    3057         108 :                 dst2 = (oid *) Tloc(r2, 0);
    3058         108 :                 r2->tkey = true;
    3059         108 :                 r2->tsorted = true;
    3060         108 :                 r2->trevsorted = true;
    3061         108 :                 r2->tseqbase = 0;
    3062         108 :                 r2->tnil = false;
    3063         108 :                 r2->tnonil = true;
    3064         580 :                 for (ncnt = 1; ncnt < cnt; ncnt++) {
    3065         485 :                         if (dst2[ncnt - 1] == dst2[ncnt]) {
    3066          44 :                                 r2->tseqbase = oid_nil;
    3067          44 :                                 r2->tkey = false;
    3068         441 :                         } else if (dst2[ncnt - 1] < dst2[ncnt]) {
    3069         431 :                                 r2->trevsorted = false;
    3070         431 :                                 if (dst2[ncnt - 1] + 1 != dst2[ncnt])
    3071         127 :                                         r2->tseqbase = oid_nil;
    3072             :                         } else {
    3073          10 :                                 assert(sorted != 2);
    3074          10 :                                 r2->tsorted = false;
    3075          10 :                                 r2->tseqbase = oid_nil;
    3076          10 :                                 r2->tkey = false;
    3077             :                         }
    3078         657 :                         if (!(r2->trevsorted | BATtdense(r2) | r2->tkey | ((sorted != 2) & r2->tsorted)))
    3079             :                                 break;
    3080             :                 }
    3081         108 :                 if (BATtdense(r2))
    3082          80 :                         r2->tseqbase = cnt > 0 ? dst2[0] : 0;
    3083             :         }
    3084         125 :         TRC_DEBUG(ALGO, "l=%s,rl=%s,rh=%s -> "
    3085             :                   "(" ALGOBATFMT "," ALGOOPTBATFMT ")\n",
    3086             :                   BATgetId(l), BATgetId(rl), BATgetId(rh),
    3087             :                   ALGOBATPAR(r1), ALGOOPTBATPAR(r2));
    3088         125 :         bat_iterator_end(&li);
    3089         128 :         bat_iterator_end(&rli);
    3090         129 :         bat_iterator_end(&rhi);
    3091         129 :         return GDK_SUCCEED;
    3092             : 
    3093           0 :   bailout:
    3094           0 :         bat_iterator_end(&li);
    3095           0 :         bat_iterator_end(&rli);
    3096           0 :         bat_iterator_end(&rhi);
    3097           0 :         BBPreclaim(r1);
    3098           0 :         BBPreclaim(r2);
    3099             :         return GDK_FAIL;
    3100             : }

Generated by: LCOV version 1.14