LCOV - code coverage report
Current view: top level - gdk - gdk_analytic_func.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 369 591 62.4 %
Date: 2025-03-25 20:06:35 Functions: 13 13 100.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, 2025 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_analytic.h"
      16             : #include "gdk_calc_private.h"
      17             : 
      18             : BAT *
      19         220 : GDKinitialize_segment_tree(void)
      20             : {
      21             :         /* The tree is allocated using raw bytes, so use a GDK type of size 1 */
      22         220 :         BAT *st = COLnew(0, TYPE_bte, 0, TRANSIENT);
      23             : 
      24         220 :         if (!st)
      25             :                 return NULL;
      26         220 :         assert(st->tshift == 0);
      27         220 :         BATsetcount(st, 0);
      28         220 :         st->tsorted = st->trevsorted = st->tkey = st->tnonil = st->tnil = false;
      29         220 :         st->tnosorted = st->tnorevsorted = 0;
      30         220 :         return st;
      31             : }
      32             : 
      33             : gdk_return
      34       41516 : GDKrebuild_segment_tree(oid ncount, oid data_size, BAT *st, void **segment_tree, oid **levels_offset, oid *nlevels)
      35             : {
      36       41516 :         oid total_size, next_tree_size = ncount, counter = ncount, next_levels = 1; /* there will be at least one level */
      37             : 
      38       41516 :         assert(ncount > 0);
      39       71735 :         do { /* compute the next number of levels */
      40       71735 :                 counter = (counter+(SEGMENT_TREE_FANOUT-1)) / SEGMENT_TREE_FANOUT;
      41       71735 :                 next_tree_size += counter;
      42       71735 :                 next_levels++;
      43       71735 :         } while (counter > 1);
      44             : 
      45       41516 :         *nlevels = next_levels; /* set the logical size of levels before the physical one */
      46       41516 :         next_tree_size *= data_size;
      47             :         /* round up to multiple of sizeof(oid) */
      48       41516 :         next_tree_size = ((next_tree_size + SIZEOF_OID - 1) / SIZEOF_OID) * SIZEOF_OID;
      49       41516 :         total_size = next_tree_size + next_levels * sizeof(oid);
      50             : 
      51       41516 :         if (total_size > BATcount(st)) {
      52         221 :                 total_size = (((total_size) + 1023) & ~1023); /* align to a multiple of 1024 bytes */
      53         221 :                 if (BATextend(st, total_size) != GDK_SUCCEED)
      54             :                         return GDK_FAIL;
      55         221 :                 BATsetcount(st, total_size);
      56         221 :                 *segment_tree = (void*)Tloc(st, 0);
      57         221 :                 *levels_offset = (oid*)((bte*)Tloc(st, 0) + next_tree_size); /* levels offset will be next to the segment tree */
      58             :         } else {
      59       41295 :                 *levels_offset = (oid*)(*(bte**)segment_tree + next_tree_size); /* no reallocation, just update location of levels offset */
      60             :         }
      61             :         return GDK_SUCCEED;
      62             : }
      63             : 
      64             : #define NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION)        \
      65             :         do {                                                            \
      66             :                 UPCAST j = 0, ncnt = (UPCAST) (i - k);                  \
      67             :                 for (; k < i; k++, j++) {                            \
      68             :                         TPE val = NEXT_VALUE;                           \
      69             :                         if (is_##TPE##_nil(val)) {                      \
      70             :                                 has_nils = true;                        \
      71             :                                 rb[k] = TPE##_nil;                      \
      72             :                         } else {                                        \
      73             :                                 UPCAST nval = (UPCAST) (LNG_HGE);       \
      74             :                                 VALIDATION /* validation must come after null check */ \
      75             :                                 if (nval >= ncnt) {                  \
      76             :                                         rb[k] = (TPE)(j + 1);           \
      77             :                                 } else {                                \
      78             :                                         UPCAST bsize = ncnt / nval;     \
      79             :                                         UPCAST top = ncnt - nval * bsize; \
      80             :                                         UPCAST small = top * (bsize + 1); \
      81             :                                         if ((UPCAST) j < small)              \
      82             :                                                 rb[k] = (TPE)(1 + j / (bsize + 1)); \
      83             :                                         else                            \
      84             :                                                 rb[k] = (TPE)(1 + top + (j - small) / bsize); \
      85             :                                 }                                       \
      86             :                         }                                               \
      87             :                 }                                                       \
      88             :         } while (0)
      89             : 
      90             : #define ANALYTICAL_NTILE(IMP, TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION) \
      91             :         do {                                                            \
      92             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
      93             :                 if (p) {                                                \
      94             :                         while (i < cnt) {                            \
      95             :                                 if (np[i]) {                            \
      96             : ntile##IMP##TPE:                                                        \
      97             :                                         NTILE_CALC(TPE, NEXT_VALUE, LNG_HGE, UPCAST, VALIDATION); \
      98             :                                 }                                       \
      99             :                                 if (!last)                              \
     100             :                                         i++;                            \
     101             :                         }                                               \
     102             :                 }                                                       \
     103             :                 if (!last) {                                            \
     104             :                         last = true;                                    \
     105             :                         i = cnt;                                        \
     106             :                         goto ntile##IMP##TPE;                           \
     107             :                 }                                                       \
     108             :         } while (0)
     109             : 
     110             : #define ANALYTICAL_NTILE_SINGLE_IMP(TPE, LNG_HGE, UPCAST)               \
     111             :         do {                                                            \
     112             :                 TPE ntl = *(TPE*) ntile;                                \
     113             :                 if (!is_##TPE##_nil(ntl) && ntl <= 0) goto invalidntile; \
     114             :                 ANALYTICAL_NTILE(SINGLE, TPE, ntl, LNG_HGE, UPCAST, ;); \
     115             :         } while (0)
     116             : 
     117             : #define ANALYTICAL_NTILE_MULTI_IMP(TPE, LNG_HGE, UPCAST)                \
     118             :         do {                                                            \
     119             :                 const TPE *restrict nn = (TPE*)ni.base;                 \
     120             :                 ANALYTICAL_NTILE(MULTI, TPE, nn[k], LNG_HGE, UPCAST, if (val <= 0) goto invalidntile;); \
     121             :         } while (0)
     122             : 
     123             : BAT *
     124          62 : GDKanalyticalntile(BAT *b, BAT *p, BAT *n, int tpe, const void *restrict ntile)
     125             : {
     126          62 :         BATiter bi = bat_iterator(b);
     127          62 :         BATiter pi = bat_iterator(p);
     128          62 :         BATiter ni = bat_iterator(n);
     129          62 :         lng i = 0, k = 0, cnt = (lng) BATcount(b);
     130          62 :         const bit *restrict np = pi.base;
     131          62 :         bool has_nils = false, last = false;
     132          62 :         BAT *r = COLnew(b->hseqbase, tpe, BATcount(b), TRANSIENT);
     133          62 :         if (r == NULL)
     134             :                 return NULL;
     135             : 
     136          62 :         assert((n && !ntile) || (!n && ntile));
     137             : 
     138          62 :         if (ntile) {
     139          35 :                 switch (tpe) {
     140          33 :                 case TYPE_bte:
     141         674 :                         ANALYTICAL_NTILE_SINGLE_IMP(bte, val, BUN);
     142             :                         break;
     143           0 :                 case TYPE_sht:
     144           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(sht, val, BUN);
     145             :                         break;
     146           0 :                 case TYPE_int:
     147           0 :                         ANALYTICAL_NTILE_SINGLE_IMP(int, val, BUN);
     148             :                         break;
     149           1 :                 case TYPE_lng:
     150             : #if SIZEOF_OID == SIZEOF_INT
     151             :                         ANALYTICAL_NTILE_SINGLE_IMP(lng, val, lng);
     152             : #else
     153         162 :                         ANALYTICAL_NTILE_SINGLE_IMP(lng, val, BUN);
     154             : #endif
     155             :                         break;
     156             : #ifdef HAVE_HGE
     157           1 :                 case TYPE_hge:
     158             : #if SIZEOF_OID == SIZEOF_INT
     159             :                         ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_int_max) ? GDK_int_max : (lng) val, lng);
     160             : #else
     161           4 :                         ANALYTICAL_NTILE_SINGLE_IMP(hge, (val > (hge) GDK_lng_max) ? GDK_lng_max : (lng) val, BUN);
     162             : #endif
     163             :                         break;
     164             : #endif
     165           0 :                 default:
     166           0 :                         goto nosupport;
     167             :                 }
     168             :         } else {
     169          27 :                 switch (tpe) {
     170           1 :                 case TYPE_bte:
     171          12 :                         ANALYTICAL_NTILE_MULTI_IMP(bte, val, BUN);
     172             :                         break;
     173           0 :                 case TYPE_sht:
     174           0 :                         ANALYTICAL_NTILE_MULTI_IMP(sht, val, BUN);
     175             :                         break;
     176          26 :                 case TYPE_int:
     177         420 :                         ANALYTICAL_NTILE_MULTI_IMP(int, val, BUN);
     178             :                         break;
     179           0 :                 case TYPE_lng:
     180             : #if SIZEOF_OID == SIZEOF_INT
     181             :                         ANALYTICAL_NTILE_MULTI_IMP(lng, val, lng);
     182             : #else
     183           0 :                         ANALYTICAL_NTILE_MULTI_IMP(lng, val, BUN);
     184             : #endif
     185             :                         break;
     186             : #ifdef HAVE_HGE
     187           0 :                 case TYPE_hge:
     188             : #if SIZEOF_OID == SIZEOF_INT
     189             :                         ANALYTICAL_NTILE_MULTI_IMP(hge, val > (hge) GDK_int_max ? GDK_int_max : (lng) val, lng);
     190             : #else
     191           0 :                         ANALYTICAL_NTILE_MULTI_IMP(hge, val > (hge) GDK_lng_max ? GDK_lng_max : (lng) val, BUN);
     192             : #endif
     193             :                         break;
     194             : #endif
     195           0 :                 default:
     196           0 :                         goto nosupport;
     197             :                 }
     198             :         }
     199          62 :         bat_iterator_end(&bi);
     200          62 :         bat_iterator_end(&pi);
     201          62 :         bat_iterator_end(&ni);
     202          62 :         BATsetcount(r, BATcount(b));
     203          62 :         r->tnonil = !has_nils;
     204          62 :         r->tnil = has_nils;
     205          62 :         return r;
     206           0 : nosupport:
     207           0 :         BBPreclaim(r);
     208           0 :         bat_iterator_end(&bi);
     209           0 :         bat_iterator_end(&pi);
     210           0 :         bat_iterator_end(&ni);
     211           0 :         GDKerror("42000!type %s not supported for the ntile type.\n", ATOMname(tpe));
     212           0 :         return NULL;
     213           0 : invalidntile:
     214           0 :         BBPreclaim(r);
     215           0 :         bat_iterator_end(&bi);
     216           0 :         bat_iterator_end(&pi);
     217           0 :         bat_iterator_end(&ni);
     218           0 :         GDKerror("42000!ntile must be greater than zero.\n");
     219           0 :         return NULL;
     220             : }
     221             : 
     222             : #define ANALYTICAL_FIRST_FIXED(TPE)                                     \
     223             :         do {                                                            \
     224             :                 const TPE *bp = (TPE*)bi.base;                          \
     225             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     226             :                 for (; k < cnt; k++) {                                       \
     227             :                         const TPE *bs = bp + start[k], *be = bp + end[k]; \
     228             :                         TPE curval = (be > bs) ? *bs : TPE##_nil;    \
     229             :                         rb[k] = curval;                                 \
     230             :                         has_nils |= is_##TPE##_nil(curval);             \
     231             :                 }                                                       \
     232             :         } while (0)
     233             : 
     234             : BAT *
     235          36 : GDKanalyticalfirst(BAT *b, BAT *s, BAT *e, int tpe)
     236             : {
     237          36 :         BAT *r = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
     238          36 :         if (r == NULL)
     239             :                 return NULL;
     240          36 :         BATiter bi = bat_iterator(b);
     241          36 :         BATiter si = bat_iterator(s);
     242          36 :         BATiter ei = bat_iterator(e);
     243          36 :         bool has_nils = false;
     244          36 :         oid k = 0, cnt = BATcount(b);
     245          36 :         const oid *restrict start = si.base, *restrict end = ei.base;
     246          36 :         const void *nil = ATOMnilptr(tpe);
     247          36 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     248             : 
     249          72 :         switch (ATOMbasetype(tpe)) {
     250           1 :         case TYPE_bte:
     251          11 :                 ANALYTICAL_FIRST_FIXED(bte);
     252             :                 break;
     253           0 :         case TYPE_sht:
     254           0 :                 ANALYTICAL_FIRST_FIXED(sht);
     255             :                 break;
     256          25 :         case TYPE_int:
     257      845627 :                 ANALYTICAL_FIRST_FIXED(int);
     258             :                 break;
     259           1 :         case TYPE_lng:
     260          12 :                 ANALYTICAL_FIRST_FIXED(lng);
     261             :                 break;
     262             : #ifdef HAVE_HGE
     263           0 :         case TYPE_hge:
     264           0 :                 ANALYTICAL_FIRST_FIXED(hge);
     265             :                 break;
     266             : #endif
     267           0 :         case TYPE_flt:
     268           0 :                 ANALYTICAL_FIRST_FIXED(flt);
     269             :                 break;
     270           2 :         case TYPE_dbl:
     271          14 :                 ANALYTICAL_FIRST_FIXED(dbl);
     272             :                 break;
     273           7 :         default:{
     274           7 :                 if (ATOMvarsized(tpe)) {
     275      245752 :                         for (; k < cnt; k++) {
     276      245745 :                                 const void *curval = (end[k] > start[k]) ? BUNtvar(bi, start[k]) : nil;
     277      245745 :                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     278           0 :                                         BBPreclaim(r);
     279           0 :                                         bat_iterator_end(&bi);
     280           0 :                                         bat_iterator_end(&si);
     281           0 :                                         bat_iterator_end(&ei);
     282           0 :                                         return NULL;
     283             :                                 }
     284      245745 :                                 has_nils |= atomcmp(curval, nil) == 0;
     285             :                         }
     286             :                 } else {
     287           0 :                         uint16_t width = r->twidth;
     288           0 :                         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     289           0 :                         for (; k < cnt; k++) {
     290           0 :                                 const void *curval = (end[k] > start[k]) ? BUNtloc(bi, start[k]) : nil;
     291           0 :                                 memcpy(rcast, curval, width);
     292           0 :                                 rcast += width;
     293           0 :                                 has_nils |= atomcmp(curval, nil) == 0;
     294             :                         }
     295             :                 }
     296             :         }
     297             :         }
     298          36 :         bat_iterator_end(&bi);
     299          36 :         bat_iterator_end(&si);
     300          36 :         bat_iterator_end(&ei);
     301             : 
     302          36 :         BATsetcount(r, cnt);
     303          36 :         r->tnonil = !has_nils;
     304          36 :         r->tnil = has_nils;
     305          36 :         return r;
     306             : }
     307             : 
     308             : #define ANALYTICAL_LAST_FIXED(TPE)                                      \
     309             :         do {                                                            \
     310             :                 const TPE *bp = (TPE*)bi.base;                          \
     311             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     312             :                 for (; k < cnt; k++) {                                       \
     313             :                         const TPE *bs = bp + start[k], *be = bp + end[k]; \
     314             :                         TPE curval = (be > bs) ? be[-1] : TPE##_nil; \
     315             :                         rb[k] = curval;                                 \
     316             :                         has_nils |= is_##TPE##_nil(curval);             \
     317             :                 }                                                       \
     318             :         } while (0)
     319             : 
     320             : BAT *
     321          31 : GDKanalyticallast(BAT *b, BAT *s, BAT *e, int tpe)
     322             : {
     323          31 :         BAT *r = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
     324          31 :         if (r == NULL)
     325             :                 return NULL;
     326          31 :         BATiter bi = bat_iterator(b);
     327          31 :         BATiter si = bat_iterator(s);
     328          31 :         BATiter ei = bat_iterator(e);
     329          31 :         bool has_nils = false;
     330          31 :         oid k = 0, cnt = BATcount(b);
     331          31 :         const oid *restrict start = si.base, *restrict end = ei.base;
     332          31 :         const void *nil = ATOMnilptr(tpe);
     333          31 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     334             : 
     335          62 :         switch (ATOMbasetype(tpe)) {
     336           1 :         case TYPE_bte:
     337          11 :                 ANALYTICAL_LAST_FIXED(bte);
     338             :                 break;
     339           0 :         case TYPE_sht:
     340           0 :                 ANALYTICAL_LAST_FIXED(sht);
     341             :                 break;
     342          22 :         case TYPE_int:
     343         339 :                 ANALYTICAL_LAST_FIXED(int);
     344             :                 break;
     345           1 :         case TYPE_lng:
     346          12 :                 ANALYTICAL_LAST_FIXED(lng);
     347             :                 break;
     348             : #ifdef HAVE_HGE
     349           0 :         case TYPE_hge:
     350           0 :                 ANALYTICAL_LAST_FIXED(hge);
     351             :                 break;
     352             : #endif
     353           0 :         case TYPE_flt:
     354           0 :                 ANALYTICAL_LAST_FIXED(flt);
     355             :                 break;
     356           2 :         case TYPE_dbl:
     357          14 :                 ANALYTICAL_LAST_FIXED(dbl);
     358             :                 break;
     359           5 :         default:{
     360           5 :                 if (ATOMvarsized(tpe)) {
     361          50 :                         for (; k < cnt; k++) {
     362          45 :                                 const void *curval = (end[k] > start[k]) ? BUNtvar(bi, end[k] - 1) : nil;
     363          45 :                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     364           0 :                                         BBPreclaim(r);
     365           0 :                                         bat_iterator_end(&bi);
     366           0 :                                         bat_iterator_end(&si);
     367           0 :                                         bat_iterator_end(&ei);
     368           0 :                                         return NULL;
     369             :                                 }
     370          45 :                                 has_nils |= atomcmp(curval, nil) == 0;
     371             :                         }
     372             :                 } else {
     373           0 :                         uint16_t width = r->twidth;
     374           0 :                         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     375           0 :                         for (; k < cnt; k++) {
     376           0 :                                 const void *curval = (end[k] > start[k]) ? BUNtloc(bi, end[k] - 1) : nil;
     377           0 :                                 memcpy(rcast, curval, width);
     378           0 :                                 rcast += width;
     379           0 :                                 has_nils |= atomcmp(curval, nil) == 0;
     380             :                         }
     381             :                 }
     382             :         }
     383             :         }
     384          31 :         bat_iterator_end(&bi);
     385          31 :         bat_iterator_end(&si);
     386          31 :         bat_iterator_end(&ei);
     387          31 :         BATsetcount(r, cnt);
     388          31 :         r->tnonil = !has_nils;
     389          31 :         r->tnil = has_nils;
     390          31 :         return r;
     391             : }
     392             : 
     393             : #define ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(TPE)                       \
     394             :         do {                                                            \
     395             :                 const TPE *bp = (TPE*)bi.base;                          \
     396             :                 TPE *rb = (TPE*)Tloc(r, 0);                             \
     397             :                 if (is_lng_nil(nth)) {                                  \
     398             :                         has_nils = true;                                \
     399             :                         for (; k < cnt; k++)                         \
     400             :                                 rb[k] = TPE##_nil;                      \
     401             :                 } else {                                                \
     402             :                         nth--;                                          \
     403             :                         for (; k < cnt; k++) {                               \
     404             :                                 const TPE *bs = bp + start[k];          \
     405             :                                 const TPE *be = bp + end[k];            \
     406             :                                 TPE curval = (be > bs && nth < (lng)(end[k] - start[k])) ? bs[nth] : TPE##_nil; \
     407             :                                 rb[k] = curval;                         \
     408             :                                 has_nils |= is_##TPE##_nil(curval);     \
     409             :                         }                                               \
     410             :                 }                                                       \
     411             :         } while (0)
     412             : 
     413             : #define ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(TPE)                        \
     414             :         do {                                                            \
     415             :                 const TPE *bp = (TPE*)bi.base;                          \
     416             :                 TPE curval, *rb = (TPE*)Tloc(r, 0);                     \
     417             :                 for (; k < cnt; k++) {                                       \
     418             :                         lng lnth = tp[k];                               \
     419             :                         const TPE *bs = bp + start[k];                  \
     420             :                         const TPE *be = bp + end[k];                    \
     421             :                         if (!is_lng_nil(lnth) && lnth <= 0) goto invalidnth; \
     422             :                         if (is_lng_nil(lnth) || be <= bs || lnth - 1 > (lng)(end[k] - start[k])) { \
     423             :                                 curval = TPE##_nil;                     \
     424             :                                 has_nils = true;                        \
     425             :                         } else {                                        \
     426             :                                 curval = bs[lnth - 1];                  \
     427             :                                 has_nils |= is_##TPE##_nil(curval);     \
     428             :                         }                                               \
     429             :                         rb[k] = curval;                                 \
     430             :                 }                                                       \
     431             :         } while (0)
     432             : 
     433             : BAT *
     434          40 : GDKanalyticalnthvalue(BAT *b, BAT *s, BAT *e, BAT *t, lng nth, int tpe)
     435             : {
     436          40 :         BAT *r = COLnew(b->hseqbase, tpe, BATcount(b), TRANSIENT);
     437          40 :         if (r == NULL)
     438             :                 return NULL;
     439          40 :         BATiter bi = bat_iterator(b);
     440          40 :         BATiter si = bat_iterator(s);
     441          40 :         BATiter ei = bat_iterator(e);
     442          40 :         BATiter ti = bat_iterator(t);
     443          40 :         bool has_nils = false;
     444          40 :         oid k = 0, cnt = bi.count;
     445          40 :         const oid *restrict start = si.base, *restrict end = ei.base;
     446          40 :         const lng *restrict tp = ti.base;
     447          40 :         const void *nil = ATOMnilptr(tpe);
     448          40 :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);
     449             : 
     450          40 :         if (t && t->ttype != TYPE_lng)
     451           0 :                 goto nosupport;
     452             : 
     453          40 :         if (t) {
     454          10 :                 switch (ATOMbasetype(tpe)) {
     455           3 :                 case TYPE_bte:
     456          33 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(bte);
     457             :                         break;
     458           0 :                 case TYPE_sht:
     459           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(sht);
     460             :                         break;
     461           2 :                 case TYPE_int:
     462          22 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(int);
     463             :                         break;
     464           0 :                 case TYPE_lng:
     465           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(lng);
     466             :                         break;
     467             : #ifdef HAVE_HGE
     468           0 :                 case TYPE_hge:
     469           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(hge);
     470             :                         break;
     471             : #endif
     472           0 :                 case TYPE_flt:
     473           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(flt);
     474             :                         break;
     475           0 :                 case TYPE_dbl:
     476           0 :                         ANALYTICAL_NTHVALUE_IMP_MULTI_FIXED(dbl);
     477             :                         break;
     478           0 :                 default:{
     479           0 :                         const void *curval = nil;
     480           0 :                         if (ATOMvarsized(tpe)) {
     481           0 :                                 for (; k < cnt; k++) {
     482           0 :                                         lng lnth = tp[k];
     483           0 :                                         if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
     484           0 :                                         if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
     485             :                                                 curval = (void *) nil;
     486             :                                                 has_nils = true;
     487             :                                         } else {
     488           0 :                                                 curval = BUNtvar(bi, start[k] + (oid)(lnth - 1));
     489           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     490             :                                         }
     491           0 :                                         if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     492           0 :                                                 bat_iterator_end(&bi);
     493           0 :                                                 bat_iterator_end(&si);
     494           0 :                                                 bat_iterator_end(&ei);
     495           0 :                                                 bat_iterator_end(&ti);
     496           0 :                                                 BBPreclaim(r);
     497           0 :                                                 return NULL;
     498             :                                         }
     499             :                                 }
     500             :                         } else {
     501           0 :                                 uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     502           0 :                                 uint16_t width = r->twidth;
     503           0 :                                 for (; k < cnt; k++) {
     504           0 :                                         lng lnth = tp[k];
     505           0 :                                         if (!is_lng_nil(nth) && nth <= 0) goto invalidnth;
     506           0 :                                         if (is_lng_nil(lnth) || end[k] <= start[k] || lnth - 1 > (lng)(end[k] - start[k])) {
     507             :                                                 curval = (void *) nil;
     508             :                                                 has_nils = true;
     509             :                                         } else {
     510           0 :                                                 curval = BUNtloc(bi, start[k] + (oid)(lnth - 1));
     511           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     512             :                                         }
     513           0 :                                         memcpy(rcast, curval, width);
     514           0 :                                         rcast += width;
     515             :                                 }
     516             :                         }
     517             :                 }
     518             :                 }
     519             :         } else {
     520          35 :                 if (!is_lng_nil(nth) && nth <= 0) {
     521           0 :                         goto invalidnth;
     522             :                 }
     523          70 :                 switch (ATOMbasetype(tpe)) {
     524           1 :                 case TYPE_bte:
     525          11 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(bte);
     526             :                         break;
     527           0 :                 case TYPE_sht:
     528           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(sht);
     529             :                         break;
     530          23 :                 case TYPE_int:
     531         243 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(int);
     532             :                         break;
     533           0 :                 case TYPE_lng:
     534           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(lng);
     535             :                         break;
     536             : #ifdef HAVE_HGE
     537           0 :                 case TYPE_hge:
     538           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(hge);
     539             :                         break;
     540             : #endif
     541           0 :                 case TYPE_flt:
     542           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(flt);
     543             :                         break;
     544           0 :                 case TYPE_dbl:
     545           0 :                         ANALYTICAL_NTHVALUE_IMP_SINGLE_FIXED(dbl);
     546             :                         break;
     547          11 :                 default:{
     548          11 :                         if (ATOMvarsized(tpe)) {
     549          11 :                                 if (is_lng_nil(nth)) {
     550           0 :                                         has_nils = true;
     551           0 :                                         for (; k < cnt; k++)
     552           0 :                                                 if (tfastins_nocheckVAR(r, k, nil) != GDK_SUCCEED) {
     553           0 :                                                         bat_iterator_end(&bi);
     554           0 :                                                         bat_iterator_end(&si);
     555           0 :                                                         bat_iterator_end(&ei);
     556           0 :                                                         bat_iterator_end(&ti);
     557           0 :                                                         BBPreclaim(r);
     558           0 :                                                         return NULL;
     559             :                                                 }
     560             :                                 } else {
     561          11 :                                         nth--;
     562         112 :                                         for (; k < cnt; k++) {
     563         101 :                                                 const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtvar(bi, start[k] + (oid) nth) : nil;
     564         101 :                                                 if (tfastins_nocheckVAR(r, k, curval) != GDK_SUCCEED) {
     565           0 :                                                         bat_iterator_end(&bi);
     566           0 :                                                         bat_iterator_end(&si);
     567           0 :                                                         bat_iterator_end(&ei);
     568           0 :                                                         bat_iterator_end(&ti);
     569           0 :                                                         BBPreclaim(r);
     570           0 :                                                         return NULL;
     571             :                                                 }
     572         101 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     573             :                                         }
     574             :                                 }
     575             :                         } else {
     576           0 :                                 uint16_t width = r->twidth;
     577           0 :                                 uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);
     578           0 :                                 if (is_lng_nil(nth)) {
     579           0 :                                         has_nils = true;
     580           0 :                                         for (; k < cnt; k++) {
     581           0 :                                                 memcpy(rcast, nil, width);
     582           0 :                                                 rcast += width;
     583             :                                         }
     584             :                                 } else {
     585           0 :                                         nth--;
     586           0 :                                         for (; k < cnt; k++) {
     587           0 :                                                 const void *curval = (end[k] > start[k] && nth < (lng)(end[k] - start[k])) ? BUNtloc(bi, start[k] + (oid) nth) : nil;
     588           0 :                                                 memcpy(rcast, curval, width);
     589           0 :                                                 rcast += width;
     590           0 :                                                 has_nils |= atomcmp(curval, nil) == 0;
     591             :                                         }
     592             :                                 }
     593             :                         }
     594             :                 }
     595             :                 }
     596             :         }
     597          40 :         bat_iterator_end(&bi);
     598          40 :         bat_iterator_end(&si);
     599          40 :         bat_iterator_end(&ei);
     600          40 :         bat_iterator_end(&ti);
     601             : 
     602          40 :         BATsetcount(r, cnt);
     603          40 :         r->tnonil = !has_nils;
     604          40 :         r->tnil = has_nils;
     605          40 :         return r;
     606           0 : nosupport:
     607           0 :         bat_iterator_end(&bi);
     608           0 :         bat_iterator_end(&si);
     609           0 :         bat_iterator_end(&ei);
     610           0 :         bat_iterator_end(&ti);
     611           0 :         BBPreclaim(r);
     612           0 :         GDKerror("42000!type %s not supported for the nth_value.\n", ATOMname(t->ttype));
     613           0 :         return NULL;
     614           0 : invalidnth:
     615           0 :         bat_iterator_end(&bi);
     616           0 :         bat_iterator_end(&si);
     617           0 :         bat_iterator_end(&ei);
     618           0 :         bat_iterator_end(&ti);
     619           0 :         BBPreclaim(r);
     620           0 :         GDKerror("42000!nth_value must be greater than zero.\n");
     621           0 :         return NULL;
     622             : }
     623             : 
     624             : #define ANALYTICAL_LAG_CALC(TPE)                                \
     625             :         do {                                                    \
     626             :                 for (i = 0; i < lag && rb < rp; i++, rb++)        \
     627             :                         *rb = def;                              \
     628             :                 has_nils |= (lag > 0 && is_##TPE##_nil(def));        \
     629             :                 for (; rb < rp; rb++, bp++) {                        \
     630             :                         next = *bp;                             \
     631             :                         *rb = next;                             \
     632             :                         has_nils |= is_##TPE##_nil(next);       \
     633             :                 }                                               \
     634             :         } while (0)
     635             : 
     636             : #define ANALYTICAL_LAG_IMP(TPE)                                         \
     637             :         do {                                                            \
     638             :                 TPE *rp, *rb, *rend,                                    \
     639             :                         def = *((TPE *) default_value), next;           \
     640             :                 const TPE *bp, *nbp;                                    \
     641             :                 bp = (TPE*)bi.base;                                     \
     642             :                 rb = rp = (TPE*)Tloc(r, 0);                             \
     643             :                 rend = rb + cnt;                                        \
     644             :                 if (lag == BUN_NONE) {                                  \
     645             :                         has_nils = true;                                \
     646             :                         for (; rb < rend; rb++)                              \
     647             :                                 *rb = TPE##_nil;                        \
     648             :                 } else if (p) {                                         \
     649             :                         pnp = np = (bit*)pi.base;                       \
     650             :                         end = np + cnt;                                 \
     651             :                         for (; np < end; np++) {                     \
     652             :                                 if (*np) {                              \
     653             :                                         ncnt = (np - pnp);              \
     654             :                                         rp += ncnt;                     \
     655             :                                         nbp = bp + ncnt;                \
     656             :                                         ANALYTICAL_LAG_CALC(TPE);       \
     657             :                                         bp = nbp;                       \
     658             :                                         pnp = np;                       \
     659             :                                 }                                       \
     660             :                         }                                               \
     661             :                         rp += (np - pnp);                               \
     662             :                         ANALYTICAL_LAG_CALC(TPE);                       \
     663             :                 } else {                                                \
     664             :                         rp += cnt;                                      \
     665             :                         ANALYTICAL_LAG_CALC(TPE);                       \
     666             :                 }                                                       \
     667             :         } while (0)
     668             : 
     669             : #define ANALYTICAL_LAG_OTHERS                                           \
     670             :         do {                                                            \
     671             :                 for (i = 0; i < lag && k < j; i++, k++) {         \
     672             :                         if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
     673             :                                 bat_iterator_end(&bi);                      \
     674             :                                 bat_iterator_end(&pi);                      \
     675             :                                 BBPreclaim(r);                          \
     676             :                                 return NULL;                            \
     677             :                         }                                               \
     678             :                 }                                                       \
     679             :                 has_nils |= (lag > 0 && atomcmp(default_value, nil) == 0); \
     680             :                 for (l = k - lag; k < j; k++, l++) {                 \
     681             :                         curval = BUNtail(bi, l);                        \
     682             :                         if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
     683             :                                 bat_iterator_end(&bi);                      \
     684             :                                 bat_iterator_end(&pi);                      \
     685             :                                 BBPreclaim(r);                          \
     686             :                                 return NULL;                            \
     687             :                         }                                               \
     688             :                         has_nils |= atomcmp(curval, nil) == 0;          \
     689             :                 }                                                       \
     690             :         } while (0)
     691             : 
     692             : BAT *
     693          30 : GDKanalyticallag(BAT *b, BAT *p, BUN lag, const void *restrict default_value, int tpe)
     694             : {
     695          30 :         BATiter bi = bat_iterator(b);
     696          30 :         BATiter pi = bat_iterator(p);
     697          30 :         int (*atomcmp) (const void *, const void *);
     698          30 :         const void *restrict nil;
     699          30 :         BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
     700          30 :         bit *np, *pnp, *end;
     701          30 :         bool has_nils = false;
     702          30 :         BAT *r = COLnew(b->hseqbase, tpe, BATcount(b), TRANSIENT);
     703          30 :         if (r == NULL)
     704             :                 return NULL;
     705             : 
     706          30 :         assert(default_value);
     707             : 
     708          60 :         switch (ATOMbasetype(tpe)) {
     709           3 :         case TYPE_bte:
     710          33 :                 ANALYTICAL_LAG_IMP(bte);
     711             :                 break;
     712           0 :         case TYPE_sht:
     713           0 :                 ANALYTICAL_LAG_IMP(sht);
     714             :                 break;
     715          21 :         case TYPE_int:
     716         337 :                 ANALYTICAL_LAG_IMP(int);
     717             :                 break;
     718           1 :         case TYPE_lng:
     719          23 :                 ANALYTICAL_LAG_IMP(lng);
     720             :                 break;
     721             : #ifdef HAVE_HGE
     722           0 :         case TYPE_hge:
     723           0 :                 ANALYTICAL_LAG_IMP(hge);
     724             :                 break;
     725             : #endif
     726           0 :         case TYPE_flt:
     727           0 :                 ANALYTICAL_LAG_IMP(flt);
     728             :                 break;
     729           0 :         case TYPE_dbl:
     730           0 :                 ANALYTICAL_LAG_IMP(dbl);
     731             :                 break;
     732           5 :         default:{
     733           5 :                 const void *restrict curval;
     734           5 :                 nil = ATOMnilptr(tpe);
     735           5 :                 atomcmp = ATOMcompare(tpe);
     736           5 :                 if (lag == BUN_NONE) {
     737           0 :                         has_nils = true;
     738           0 :                         for (j = 0; j < cnt; j++) {
     739           0 :                                 if (BUNappend(r, nil, false) != GDK_SUCCEED) {
     740           0 :                                         bat_iterator_end(&bi);
     741           0 :                                         bat_iterator_end(&pi);
     742           0 :                                         BBPreclaim(r);
     743           0 :                                         return NULL;
     744             :                                 }
     745             :                         }
     746           5 :                 } else if (p) {
     747           3 :                         pnp = np = (bit *) pi.base;
     748           3 :                         end = np + cnt;
     749          30 :                         for (; np < end; np++) {
     750          27 :                                 if (*np) {
     751           9 :                                         j += (np - pnp);
     752          33 :                                         ANALYTICAL_LAG_OTHERS;
     753             :                                         pnp = np;
     754             :                                 }
     755             :                         }
     756           3 :                         j += (np - pnp);
     757           6 :                         ANALYTICAL_LAG_OTHERS;
     758             :                 } else {
     759           4 :                         j += cnt;
     760          20 :                         ANALYTICAL_LAG_OTHERS;
     761             :                 }
     762             :         }
     763             :         }
     764          30 :         bat_iterator_end(&bi);
     765          30 :         bat_iterator_end(&pi);
     766          30 :         BATsetcount(r, cnt);
     767          30 :         r->tnonil = !has_nils;
     768          30 :         r->tnil = has_nils;
     769          30 :         return r;
     770             : }
     771             : 
     772             : #define LEAD_CALC(TPE)                                                  \
     773             :         do {                                                            \
     774             :                 if (lead < ncnt) {                                   \
     775             :                         bp += lead;                                     \
     776             :                         l = ncnt - lead;                                \
     777             :                         for (i = 0; i < l; i++, rb++, bp++) {                \
     778             :                                 next = *bp;                             \
     779             :                                 *rb = next;                             \
     780             :                                 has_nils |= is_##TPE##_nil(next);       \
     781             :                         }                                               \
     782             :                 } else {                                                \
     783             :                         bp += ncnt;                                     \
     784             :                 }                                                       \
     785             :                 for (;rb < rp; rb++)                                 \
     786             :                         *rb = def;                                      \
     787             :                 has_nils |= (lead > 0 && is_##TPE##_nil(def));               \
     788             :         } while (0)
     789             : 
     790             : #define ANALYTICAL_LEAD_IMP(TPE)                                \
     791             :         do {                                                    \
     792             :                 TPE *rp, *rb, *bp, *rend,                       \
     793             :                         def = *((TPE *) default_value), next;   \
     794             :                 bp = (TPE*)bi.base;                             \
     795             :                 rb = rp = (TPE*)Tloc(r, 0);                     \
     796             :                 rend = rb + cnt;                                \
     797             :                 if (lead == BUN_NONE) {                         \
     798             :                         has_nils = true;                        \
     799             :                         for (; rb < rend; rb++)                      \
     800             :                                 *rb = TPE##_nil;                \
     801             :                 } else if (p) {                                 \
     802             :                         pnp = np = (bit*)pi.base;               \
     803             :                         end = np + cnt;                         \
     804             :                         for (; np < end; np++) {             \
     805             :                                 if (*np) {                      \
     806             :                                         ncnt = (np - pnp);      \
     807             :                                         rp += ncnt;             \
     808             :                                         LEAD_CALC(TPE);         \
     809             :                                         pnp = np;               \
     810             :                                 }                               \
     811             :                         }                                       \
     812             :                         ncnt = (np - pnp);                      \
     813             :                         rp += ncnt;                             \
     814             :                         LEAD_CALC(TPE);                         \
     815             :                 } else {                                        \
     816             :                         ncnt = cnt;                             \
     817             :                         rp += ncnt;                             \
     818             :                         LEAD_CALC(TPE);                         \
     819             :                 }                                               \
     820             :         } while (0)
     821             : 
     822             : #define ANALYTICAL_LEAD_OTHERS                                          \
     823             :         do {                                                            \
     824             :                 j += ncnt;                                              \
     825             :                 if (lead < ncnt) {                                   \
     826             :                         m = ncnt - lead;                                \
     827             :                         for (i = 0,n = k + lead; i < m; i++, n++) {  \
     828             :                                 curval = BUNtail(bi, n);                \
     829             :                                 if (BUNappend(r, curval, false) != GDK_SUCCEED) { \
     830             :                                         bat_iterator_end(&bi);              \
     831             :                                         bat_iterator_end(&pi);              \
     832             :                                         BBPreclaim(r);                  \
     833             :                                         return NULL;                    \
     834             :                                 }                                       \
     835             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
     836             :                         }                                               \
     837             :                         k += i;                                         \
     838             :                 }                                                       \
     839             :                 for (; k < j; k++) {                                 \
     840             :                         if (BUNappend(r, default_value, false) != GDK_SUCCEED) { \
     841             :                                 bat_iterator_end(&bi);                      \
     842             :                                 bat_iterator_end(&pi);                      \
     843             :                                 BBPreclaim(r);                          \
     844             :                                 return NULL;                            \
     845             :                         }                                               \
     846             :                 }                                                       \
     847             :                 has_nils |= (lead > 0 && atomcmp(default_value, nil) == 0); \
     848             :         } while (0)
     849             : 
     850             : BAT *
     851          29 : GDKanalyticallead(BAT *b, BAT *p, BUN lead, const void *restrict default_value, int tpe)
     852             : {
     853          29 :         BATiter bi = bat_iterator(b);
     854          29 :         BATiter pi = bat_iterator(p);
     855          29 :         int (*atomcmp) (const void *, const void *);
     856          29 :         const void *restrict nil;
     857          29 :         BUN i = 0, j = 0, k = 0, l = 0, ncnt, cnt = BATcount(b);
     858          29 :         bit *np, *pnp, *end;
     859          29 :         bool has_nils = false;
     860          29 :         BAT *r = COLnew(b->hseqbase, tpe, BATcount(b), TRANSIENT);
     861          29 :         if (r == NULL)
     862             :                 return NULL;
     863             : 
     864          29 :         assert(default_value);
     865             : 
     866          58 :         switch (ATOMbasetype(tpe)) {
     867           4 :         case TYPE_bte:
     868          35 :                 ANALYTICAL_LEAD_IMP(bte);
     869             :                 break;
     870           0 :         case TYPE_sht:
     871           0 :                 ANALYTICAL_LEAD_IMP(sht);
     872             :                 break;
     873          18 :         case TYPE_int:
     874         296 :                 ANALYTICAL_LEAD_IMP(int);
     875             :                 break;
     876           1 :         case TYPE_lng:
     877          23 :                 ANALYTICAL_LEAD_IMP(lng);
     878             :                 break;
     879             : #ifdef HAVE_HGE
     880           0 :         case TYPE_hge:
     881           0 :                 ANALYTICAL_LEAD_IMP(hge);
     882             :                 break;
     883             : #endif
     884           0 :         case TYPE_flt:
     885           0 :                 ANALYTICAL_LEAD_IMP(flt);
     886             :                 break;
     887           0 :         case TYPE_dbl:
     888           0 :                 ANALYTICAL_LEAD_IMP(dbl);
     889             :                 break;
     890           6 :         default:{
     891           6 :                 BUN m = 0, n = 0;
     892           6 :                 const void *restrict curval;
     893           6 :                 nil = ATOMnilptr(tpe);
     894           6 :                 atomcmp = ATOMcompare(tpe);
     895           6 :                 if (lead == BUN_NONE) {
     896           0 :                         has_nils = true;
     897           0 :                         for (j = 0; j < cnt; j++) {
     898           0 :                                 if (BUNappend(r, nil, false) != GDK_SUCCEED) {
     899           0 :                                         bat_iterator_end(&bi);
     900           0 :                                         bat_iterator_end(&pi);
     901           0 :                                         BBPreclaim(r);
     902           0 :                                         return NULL;
     903             :                                 }
     904             :                         }
     905           6 :                 } else if (p) {
     906           4 :                         pnp = np = (bit *) pi.base;
     907           4 :                         end = np + cnt;
     908          42 :                         for (; np < end; np++) {
     909          38 :                                 if (*np) {
     910          12 :                                         ncnt = (np - pnp);
     911          58 :                                         ANALYTICAL_LEAD_OTHERS;
     912          12 :                                         pnp = np;
     913             :                                 }
     914             :                         }
     915           4 :                         ncnt = (np - pnp);
     916          12 :                         ANALYTICAL_LEAD_OTHERS;
     917             :                 } else {
     918           2 :                         ncnt = cnt;
     919          20 :                         ANALYTICAL_LEAD_OTHERS;
     920             :                 }
     921             :         }
     922             :         }
     923          29 :         bat_iterator_end(&bi);
     924          29 :         bat_iterator_end(&pi);
     925          29 :         BATsetcount(r, cnt);
     926          29 :         r->tnonil = !has_nils;
     927          29 :         r->tnil = has_nils;
     928          29 :         return r;
     929             : }
     930             : 
     931             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE, MIN_MAX) \
     932             :         do {                                                            \
     933             :                 TPE curval = TPE##_nil;                                 \
     934             :                 for (; k < i;) {                                     \
     935             :                         j = k;                                          \
     936             :                         do {                                            \
     937             :                                 if (!is_##TPE##_nil(bp[k])) {           \
     938             :                                         if (is_##TPE##_nil(curval))     \
     939             :                                                 curval = bp[k];         \
     940             :                                         else                            \
     941             :                                                 curval = MIN_MAX(bp[k], curval); \
     942             :                                 }                                       \
     943             :                                 k++;                                    \
     944             :                         } while (k < i && !op[k]);                   \
     945             :                         for (; j < k; j++)                           \
     946             :                                 rb[j] = curval;                         \
     947             :                         has_nils |= is_##TPE##_nil(curval);             \
     948             :                 }                                                       \
     949             :         } while (0)
     950             : 
     951             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE, MIN_MAX) \
     952             :         do {                                                            \
     953             :                 TPE curval = TPE##_nil;                                 \
     954             :                 l = i - 1;                                              \
     955             :                 for (j = l; ; j--) {                                    \
     956             :                         if (!is_##TPE##_nil(bp[j])) {                   \
     957             :                                 if (is_##TPE##_nil(curval))             \
     958             :                                         curval = bp[j];                 \
     959             :                                 else                                    \
     960             :                                         curval = MIN_MAX(bp[j], curval); \
     961             :                         }                                               \
     962             :                         if (op[j] || j == k) {                          \
     963             :                                 for (; ; l--) {                         \
     964             :                                         rb[l] = curval;                 \
     965             :                                         if (l == j)                     \
     966             :                                                 break;                  \
     967             :                                 }                                       \
     968             :                                 has_nils |= is_##TPE##_nil(curval);     \
     969             :                                 if (j == k)                             \
     970             :                                         break;                          \
     971             :                                 l = j - 1;                              \
     972             :                         }                                               \
     973             :                 }                                                       \
     974             :                 k = i;                                                  \
     975             :         } while (0)
     976             : 
     977             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_ALL_ROWS(TPE, MIN_MAX)            \
     978             :         do {                                                            \
     979             :                 TPE curval = TPE##_nil;                                 \
     980             :                 for (j = k; j < i; j++) {                            \
     981             :                         TPE v = bp[j];                                  \
     982             :                         if (!is_##TPE##_nil(v)) {                       \
     983             :                                 if (is_##TPE##_nil(curval))             \
     984             :                                         curval = v;                     \
     985             :                                 else                                    \
     986             :                                         curval = MIN_MAX(v, curval);    \
     987             :                         }                                               \
     988             :                 }                                                       \
     989             :                 for (; k < i; k++)                                   \
     990             :                         rb[k] = curval;                                 \
     991             :                 has_nils |= is_##TPE##_nil(curval);                     \
     992             :         } while (0)
     993             : 
     994             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_CURRENT_ROW(TPE, MIN_MAX) \
     995             :         do {                                                    \
     996             :                 for (; k < i; k++) {                         \
     997             :                         TPE v = bp[k];                          \
     998             :                         rb[k] = v;                              \
     999             :                         has_nils |= is_##TPE##_nil(v);          \
    1000             :                 }                                               \
    1001             :         } while (0)
    1002             : 
    1003             : #define INIT_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING)     \
    1004             :         do {                                                    \
    1005             :                 computed = TPE##_nil;                           \
    1006             :         } while (0)
    1007             : #define COMPUTE_LEVEL0_MIN_MAX_FIXED(X, TPE, MIN_MAX, NOTHING)  \
    1008             :         do {                                                    \
    1009             :                 computed = bp[j + X];                           \
    1010             :         } while (0)
    1011             : #define COMPUTE_LEVELN_MIN_MAX_FIXED(VAL, TPE, MIN_MAX, NOTHING)        \
    1012             :         do {                                                            \
    1013             :                 if (!is_##TPE##_nil(VAL)) {                             \
    1014             :                         if (is_##TPE##_nil(computed))                   \
    1015             :                                 computed = VAL;                         \
    1016             :                         else                                            \
    1017             :                                 computed = MIN_MAX(computed, VAL);      \
    1018             :                 }                                                       \
    1019             :         } while (0)
    1020             : #define FINALIZE_AGGREGATE_MIN_MAX_FIXED(TPE, MIN_MAX, NOTHING) \
    1021             :         do {                                                    \
    1022             :                 rb[k] = computed;                               \
    1023             :                 has_nils |= is_##TPE##_nil(computed);           \
    1024             :         } while (0)
    1025             : #define ANALYTICAL_MIN_MAX_CALC_FIXED_OTHERS(TPE, MIN_MAX)              \
    1026             :         do {                                                            \
    1027             :                 oid ncount = i - k;                                     \
    1028             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1029             :                         goto cleanup;                                   \
    1030             :                 populate_segment_tree(TPE, ncount, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVEL0_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
    1031             :                 for (; k < i; k++)                                   \
    1032             :                         compute_on_segment_tree(TPE, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_FIXED, COMPUTE_LEVELN_MIN_MAX_FIXED, FINALIZE_AGGREGATE_MIN_MAX_FIXED, TPE, MIN_MAX, NOTHING); \
    1033             :                 j = k;                                                  \
    1034             :         } while (0)
    1035             : 
    1036             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_UNBOUNDED_TILL_CURRENT_ROW(GT_LT) \
    1037             :         do {                                                            \
    1038             :                 const void *curval = nil;                               \
    1039             :                 if (ATOMvarsized(tpe)) {                                \
    1040             :                         for (; k < i;) {                             \
    1041             :                                 j = k;                                  \
    1042             :                                 do {                                    \
    1043             :                                         const void *next = BUNtvar(bi, k); \
    1044             :                                         if (atomcmp(next, nil) != 0) {  \
    1045             :                                                 if (atomcmp(curval, nil) == 0) \
    1046             :                                                         curval = next;  \
    1047             :                                                 else                    \
    1048             :                                                         curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1049             :                                         }                               \
    1050             :                                         k++;                            \
    1051             :                                 } while (k < i && !op[k]);           \
    1052             :                                 for (; j < k; j++)                   \
    1053             :                                         if ((res = tfastins_nocheckVAR(r, j, curval)) != GDK_SUCCEED) \
    1054             :                                                 goto cleanup;           \
    1055             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
    1056             :                         }                                               \
    1057             :                 } else {                                                \
    1058             :                         for (; k < i;) {                             \
    1059             :                                 j = k;                                  \
    1060             :                                 do {                                    \
    1061             :                                         const void *next = BUNtloc(bi, k); \
    1062             :                                         if (atomcmp(next, nil) != 0) {  \
    1063             :                                                 if (atomcmp(curval, nil) == 0) \
    1064             :                                                         curval = next;  \
    1065             :                                                 else                    \
    1066             :                                                         curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1067             :                                         }                               \
    1068             :                                         k++;                            \
    1069             :                                 } while (k < i && !op[k]);           \
    1070             :                                 for (; j < k; j++) {                 \
    1071             :                                         memcpy(rcast, curval, width);   \
    1072             :                                         rcast += width;                 \
    1073             :                                 }                                       \
    1074             :                                 has_nils |= atomcmp(curval, nil) == 0;  \
    1075             :                         }                                               \
    1076             :                 }                                                       \
    1077             :         } while (0)
    1078             : 
    1079             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW_TILL_UNBOUNDED(GT_LT) \
    1080             :         do {                                                            \
    1081             :                 const void *curval = nil;                               \
    1082             :                 l = i - 1;                                              \
    1083             :                 if (ATOMvarsized(tpe)) {                                \
    1084             :                         for (j = l; ; j--) {                            \
    1085             :                                 const void *next = BUNtvar(bi, j);      \
    1086             :                                 if (atomcmp(next, nil) != 0) {          \
    1087             :                                         if (atomcmp(curval, nil) == 0)  \
    1088             :                                                 curval = next;          \
    1089             :                                         else                            \
    1090             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1091             :                                 }                                       \
    1092             :                                 if (op[j] || j == k) {                  \
    1093             :                                         for (; ; l--) {                 \
    1094             :                                                 if ((res = tfastins_nocheckVAR(r, l, curval)) != GDK_SUCCEED) \
    1095             :                                                         goto cleanup;   \
    1096             :                                                 if (l == j)             \
    1097             :                                                         break;          \
    1098             :                                         }                               \
    1099             :                                         has_nils |= atomcmp(curval, nil) == 0; \
    1100             :                                         if (j == k)                     \
    1101             :                                                 break;                  \
    1102             :                                         l = j - 1;                      \
    1103             :                                 }                                       \
    1104             :                         }                                               \
    1105             :                 } else {                                                \
    1106             :                         for (j = l; ; j--) {                            \
    1107             :                                 const void *next = BUNtloc(bi, j);      \
    1108             :                                 if (atomcmp(next, nil) != 0) {          \
    1109             :                                         if (atomcmp(curval, nil) == 0)  \
    1110             :                                                 curval = next;          \
    1111             :                                         else                            \
    1112             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1113             :                                 }                                       \
    1114             :                                 if (op[j] || j == k) {                  \
    1115             :                                         BUN x = l * width;              \
    1116             :                                         for (; ; l--) {                 \
    1117             :                                                 memcpy(rcast + x, curval, width); \
    1118             :                                                 x -= width;             \
    1119             :                                                 if (l == j)             \
    1120             :                                                         break;          \
    1121             :                                         }                               \
    1122             :                                         has_nils |= atomcmp(curval, nil) == 0; \
    1123             :                                         if (j == k)                     \
    1124             :                                                 break;                  \
    1125             :                                         l = j - 1;                      \
    1126             :                                 }                                       \
    1127             :                         }                                               \
    1128             :                 }                                                       \
    1129             :                 k = i;                                                  \
    1130             :         } while (0)
    1131             : 
    1132             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_ALL_ROWS(GT_LT)                  \
    1133             :         do {                                                            \
    1134             :                 const void *curval = (void*) nil;                       \
    1135             :                 if (ATOMvarsized(tpe)) {                                \
    1136             :                         for (j = k; j < i; j++) {                    \
    1137             :                                 const void *next = BUNtvar(bi, j);      \
    1138             :                                 if (atomcmp(next, nil) != 0) {          \
    1139             :                                         if (atomcmp(curval, nil) == 0)  \
    1140             :                                                 curval = next;          \
    1141             :                                         else                            \
    1142             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1143             :                                 }                                       \
    1144             :                         }                                               \
    1145             :                         for (; k < i; k++)                           \
    1146             :                                 if ((res = tfastins_nocheckVAR(r, k, curval)) != GDK_SUCCEED) \
    1147             :                                         goto cleanup;                   \
    1148             :                 } else {                                                \
    1149             :                         for (j = k; j < i; j++) {                    \
    1150             :                                 const void *next = BUNtloc(bi, j);      \
    1151             :                                 if (atomcmp(next, nil) != 0) {          \
    1152             :                                         if (atomcmp(curval, nil) == 0)  \
    1153             :                                                 curval = next;          \
    1154             :                                         else                            \
    1155             :                                                 curval = atomcmp(next, curval) GT_LT 0 ? curval : next; \
    1156             :                                 }                                       \
    1157             :                         }                                               \
    1158             :                         for (; k < i; k++) {                         \
    1159             :                                 memcpy(rcast, curval, width);           \
    1160             :                                 rcast += width;                         \
    1161             :                         }                                               \
    1162             :                 }                                                       \
    1163             :                 has_nils |= atomcmp(curval, nil) == 0;                  \
    1164             :         } while (0)
    1165             : 
    1166             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_CURRENT_ROW(GT_LT)               \
    1167             :         do {                                                            \
    1168             :                 if (ATOMvarsized(tpe)) {                                \
    1169             :                         for (; k < i; k++) {                         \
    1170             :                                 const void *next = BUNtvar(bi, k);      \
    1171             :                                 if ((res = tfastins_nocheckVAR(r, k, next)) != GDK_SUCCEED) \
    1172             :                                         goto cleanup;                   \
    1173             :                                 has_nils |= atomcmp(next, nil) == 0;    \
    1174             :                         }                                               \
    1175             :                 } else {                                                \
    1176             :                         for (; k < i; k++) {                         \
    1177             :                                 const void *next = BUNtloc(bi, k);      \
    1178             :                                 memcpy(rcast, next, width);             \
    1179             :                                 rcast += width;                         \
    1180             :                                 has_nils |= atomcmp(next, nil) == 0;    \
    1181             :                         }                                               \
    1182             :                 }                                                       \
    1183             :         } while (0)
    1184             : 
    1185             : #define INIT_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2)        \
    1186             :         do {                                                            \
    1187             :                 computed = (void*) nil;                                 \
    1188             :         } while (0)
    1189             : #define COMPUTE_LEVEL0_MIN_MAX_OTHERS(X, GT_LT, NOTHING1, NOTHING2)     \
    1190             :         do {                                                            \
    1191             :                 computed = BUNtail(bi, j + X);                          \
    1192             :         } while (0)
    1193             : #define COMPUTE_LEVELN_MIN_MAX_OTHERS(VAL, GT_LT, NOTHING1, NOTHING2)   \
    1194             :         do {                                                            \
    1195             :                 if (atomcmp(VAL, nil) != 0) {                           \
    1196             :                         if (atomcmp(computed, nil) == 0)                \
    1197             :                                 computed = VAL;                         \
    1198             :                         else                                            \
    1199             :                                 computed = atomcmp(VAL, computed) GT_LT 0 ? computed : VAL; \
    1200             :                 }                                                       \
    1201             :         } while (0)
    1202             : #define FINALIZE_AGGREGATE_MIN_MAX_OTHERS(GT_LT, NOTHING1, NOTHING2)    \
    1203             :         do {                                                            \
    1204             :                 if (ATOMvarsized(tpe)) {                                \
    1205             :                         if ((res = tfastins_nocheckVAR(r, k, computed)) != GDK_SUCCEED) \
    1206             :                                 goto cleanup;                           \
    1207             :                 } else {                                                \
    1208             :                         memcpy(rcast, computed, width);                 \
    1209             :                         rcast += width;                                 \
    1210             :                 }                                                       \
    1211             :                 has_nils |= atomcmp(computed, nil) == 0;                \
    1212             :         } while (0)
    1213             : #define ANALYTICAL_MIN_MAX_CALC_OTHERS_OTHERS(GT_LT)                    \
    1214             :         do {                                                            \
    1215             :                 oid ncount = i - k;                                     \
    1216             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(void*), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1217             :                         goto cleanup;                                   \
    1218             :                 populate_segment_tree(void*, ncount, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVEL0_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
    1219             :                 for (; k < i; k++)                                   \
    1220             :                         compute_on_segment_tree(void*, start[k] - j, end[k] - j, INIT_AGGREGATE_MIN_MAX_OTHERS, COMPUTE_LEVELN_MIN_MAX_OTHERS, FINALIZE_AGGREGATE_MIN_MAX_OTHERS, GT_LT, NOTHING, NOTHING); \
    1221             :                 j = k;                                                  \
    1222             :         } while (0)
    1223             : 
    1224             : #define ANALYTICAL_MIN_MAX_PARTITIONS(TPE, MIN_MAX, IMP)                \
    1225             :         do {                                                            \
    1226             :                 TPE *restrict bp = (TPE*)bi.base, *rb = (TPE*)Tloc(r, 0); \
    1227             :                 if (p) {                                                \
    1228             :                         while (i < cnt) {                            \
    1229             :                                 if (np[i]) {                            \
    1230             : minmaxfixed##TPE##IMP:                                                  \
    1231             :                                         ANALYTICAL_MIN_MAX_CALC_FIXED_##IMP(TPE, MIN_MAX); \
    1232             :                                 }                                       \
    1233             :                                 if (!last)                              \
    1234             :                                         i++;                            \
    1235             :                         }                                               \
    1236             :                 }                                                       \
    1237             :                 if (!last) { /* hack to reduce code explosion, there's no need to duplicate the code to iterate each partition */ \
    1238             :                         last = true;                                    \
    1239             :                         i = cnt;                                        \
    1240             :                         goto minmaxfixed##TPE##IMP;                     \
    1241             :                 }                                                       \
    1242             :         } while (0)
    1243             : 
    1244             : #ifdef HAVE_HGE
    1245             : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)                          \
    1246             :         case TYPE_hge:                                                  \
    1247             :                 ANALYTICAL_MIN_MAX_PARTITIONS(hge, MIN_MAX, IMP);       \
    1248             :         break;
    1249             : #else
    1250             : #define ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)
    1251             : #endif
    1252             : 
    1253             : #define ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, IMP)                \
    1254             :         do {                                                            \
    1255             :                 switch (ATOMbasetype(tpe)) {                            \
    1256             :                 case TYPE_bte:                                          \
    1257             :                         ANALYTICAL_MIN_MAX_PARTITIONS(bte, MIN_MAX, IMP); \
    1258             :                         break;                                          \
    1259             :                 case TYPE_sht:                                          \
    1260             :                         ANALYTICAL_MIN_MAX_PARTITIONS(sht, MIN_MAX, IMP); \
    1261             :                         break;                                          \
    1262             :                 case TYPE_int:                                          \
    1263             :                         ANALYTICAL_MIN_MAX_PARTITIONS(int, MIN_MAX, IMP); \
    1264             :                         break;                                          \
    1265             :                 case TYPE_lng:                                          \
    1266             :                         ANALYTICAL_MIN_MAX_PARTITIONS(lng, MIN_MAX, IMP); \
    1267             :                         break;                                          \
    1268             :                         ANALYTICAL_MIN_MAX_LIMIT(MIN_MAX, IMP)          \
    1269             :                 case TYPE_flt:                                          \
    1270             :                         ANALYTICAL_MIN_MAX_PARTITIONS(flt, MIN_MAX, IMP); \
    1271             :                         break;                                          \
    1272             :                 case TYPE_dbl:                                          \
    1273             :                         ANALYTICAL_MIN_MAX_PARTITIONS(dbl, MIN_MAX, IMP); \
    1274             :                         break;                                          \
    1275             :                 default: {                                              \
    1276             :                         if (p) {                                        \
    1277             :                                 while (i < cnt) {                    \
    1278             :                                         if (np[i]) {                    \
    1279             : minmaxvarsized##IMP:                                                    \
    1280             :                                                 ANALYTICAL_MIN_MAX_CALC_OTHERS_##IMP(GT_LT); \
    1281             :                                         }                               \
    1282             :                                         if (!last)                      \
    1283             :                                                 i++;                    \
    1284             :                                 }                                       \
    1285             :                         }                                               \
    1286             :                         if (!last) {                                    \
    1287             :                                 last = true;                            \
    1288             :                                 i = cnt;                                \
    1289             :                                 goto minmaxvarsized##IMP;               \
    1290             :                         }                                               \
    1291             :                 }                                                       \
    1292             :                 }                                                       \
    1293             :         } while (0)
    1294             : 
    1295             : #define ANALYTICAL_MIN_MAX(OP, MIN_MAX, GT_LT)                          \
    1296             : BAT *                                                                   \
    1297             : GDKanalytical##OP(BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tpe, int frame_type) \
    1298             : {                                                                       \
    1299             :         BAT *r = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT); \
    1300             :         if (r == NULL)                                                  \
    1301             :                 return NULL;                                            \
    1302             :         BATiter pi = bat_iterator(p);                                   \
    1303             :         BATiter oi = bat_iterator(o);                                   \
    1304             :         BATiter bi = bat_iterator(b);                                   \
    1305             :         BATiter si = bat_iterator(s);                                   \
    1306             :         BATiter ei = bat_iterator(e);                                   \
    1307             :         bool has_nils = false, last = false;                            \
    1308             :         oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base, \
    1309             :                 *levels_offset = NULL, nlevels = 0;                     \
    1310             :         bit *np = pi.base, *op = oi.base;                               \
    1311             :         const void *nil = ATOMnilptr(tpe);                              \
    1312             :         int (*atomcmp)(const void *, const void *) = ATOMcompare(tpe);  \
    1313             :         void *segment_tree = NULL;                                      \
    1314             :         gdk_return res = GDK_SUCCEED;                                   \
    1315             :         uint16_t width = r->twidth;                                  \
    1316             :         uint8_t *restrict rcast = (uint8_t *) Tloc(r, 0);               \
    1317             :         BAT *st = NULL;                                                 \
    1318             :                                                                         \
    1319             :         assert(np == NULL || cnt == 0 || np[0] == 0);                   \
    1320             :         if (cnt > 0) {                                                       \
    1321             :                 switch (frame_type) {                                   \
    1322             :                 case 3: /* unbounded until current row */               \
    1323             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, UNBOUNDED_TILL_CURRENT_ROW); \
    1324             :                         break;                                          \
    1325             :                 case 4: /* current row until unbounded */               \
    1326             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW_TILL_UNBOUNDED); \
    1327             :                         break;                                          \
    1328             :                 case 5: /* all rows */                                  \
    1329             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, ALL_ROWS); \
    1330             :                         break;                                          \
    1331             :                 case 6: /* current row */                               \
    1332             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, CURRENT_ROW); \
    1333             :                         break;                                          \
    1334             :                 default:                                                \
    1335             :                         if ((st = GDKinitialize_segment_tree()) == NULL) { \
    1336             :                                 res = GDK_FAIL;                         \
    1337             :                                 goto cleanup;                           \
    1338             :                         }                                               \
    1339             :                         ANALYTICAL_MIN_MAX_BRANCHES(MIN_MAX, GT_LT, OTHERS); \
    1340             :                         break;                                          \
    1341             :                 }                                                       \
    1342             :         }                                                               \
    1343             :                                                                         \
    1344             :         BATsetcount(r, cnt);                                            \
    1345             :         r->tnonil = !has_nils;                                               \
    1346             :         r->tnil = has_nils;                                          \
    1347             : cleanup:                                                                \
    1348             :         bat_iterator_end(&pi);                                              \
    1349             :         bat_iterator_end(&oi);                                              \
    1350             :         bat_iterator_end(&bi);                                              \
    1351             :         bat_iterator_end(&si);                                              \
    1352             :         bat_iterator_end(&ei);                                              \
    1353             :         BBPreclaim(st);                                                 \
    1354             :         if (res != GDK_SUCCEED) {                                       \
    1355             :                 BBPreclaim(r);                                          \
    1356             :                 r = NULL;                                               \
    1357             :         }                                                               \
    1358             :         return r;                                                       \
    1359             : }
    1360             : 
    1361        3369 : ANALYTICAL_MIN_MAX(min, MIN, >)
    1362    14275787 : ANALYTICAL_MIN_MAX(max, MAX, <)
    1363             : 
    1364             : /* Counting no nils for fixed sizes */
    1365             : #define ANALYTICAL_COUNT_FIXED_UNBOUNDED_TILL_CURRENT_ROW(TPE)          \
    1366             :         do {                                                            \
    1367             :                 curval = 0;                                             \
    1368             :                 if (count_all) {                                        \
    1369             :                         for (; k < i;) {                             \
    1370             :                                 j = k;                                  \
    1371             :                                 do {                                    \
    1372             :                                         k++;                            \
    1373             :                                 } while (k < i && !op[k]);           \
    1374             :                                 curval += k - j;                        \
    1375             :                                 for (; j < k; j++)                   \
    1376             :                                         rb[j] = curval;                 \
    1377             :                         }                                               \
    1378             :                 } else {                                                \
    1379             :                         for (; k < i;) {                             \
    1380             :                                 j = k;                                  \
    1381             :                                 do {                                    \
    1382             :                                         curval += !is_##TPE##_nil(bp[k]); \
    1383             :                                         k++;                            \
    1384             :                                 } while (k < i && !op[k]);           \
    1385             :                                 for (; j < k; j++)                   \
    1386             :                                         rb[j] = curval;                 \
    1387             :                         }                                               \
    1388             :                 }                                                       \
    1389             :         } while (0)
    1390             : 
    1391             : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW_TILL_UNBOUNDED(TPE)          \
    1392             :         do {                                                            \
    1393             :                 curval = 0;                                             \
    1394             :                 l = i - 1;                                              \
    1395             :                 if (count_all) {                                        \
    1396             :                         for (j = l; ; j--) {                            \
    1397             :                                 if (op[j] || j == k) {                  \
    1398             :                                         curval += l - j + 1;            \
    1399             :                                         for (; ; l--) {                 \
    1400             :                                                 rb[l] = curval;         \
    1401             :                                                 if (l == j)             \
    1402             :                                                         break;          \
    1403             :                                         }                               \
    1404             :                                         if (j == k)                     \
    1405             :                                                 break;                  \
    1406             :                                         l = j - 1;                      \
    1407             :                                 }                                       \
    1408             :                         }                                               \
    1409             :                 } else {                                                \
    1410             :                         for (j = l; ; j--) {                            \
    1411             :                                 curval += !is_##TPE##_nil(bp[j]);       \
    1412             :                                 if (op[j] || j == k) {                  \
    1413             :                                         for (; ; l--) {                 \
    1414             :                                                 rb[l] = curval;         \
    1415             :                                                 if (l == j)             \
    1416             :                                                         break;          \
    1417             :                                         }                               \
    1418             :                                         if (j == k)                     \
    1419             :                                                 break;                  \
    1420             :                                         l = j - 1;                      \
    1421             :                                 }                                       \
    1422             :                         }                                               \
    1423             :                 }                                                       \
    1424             :                 k = i;                                                  \
    1425             :         } while (0)
    1426             : 
    1427             : #define ANALYTICAL_COUNT_FIXED_ALL_ROWS(TPE)                            \
    1428             :         do {                                                            \
    1429             :                 if (count_all) {                                        \
    1430             :                         curval = (lng)(i - k);                          \
    1431             :                         for (; k < i; k++)                           \
    1432             :                                 rb[k] = curval;                         \
    1433             :                 } else {                                                \
    1434             :                         curval = 0;                                     \
    1435             :                         for (; j < i; j++)                           \
    1436             :                                 curval += !is_##TPE##_nil(bp[j]);       \
    1437             :                         for (; k < i; k++)                           \
    1438             :                                 rb[k] = curval;                         \
    1439             :                 }                                                       \
    1440             :         } while (0)
    1441             : 
    1442             : #define ANALYTICAL_COUNT_FIXED_CURRENT_ROW(TPE)                 \
    1443             :         do {                                                    \
    1444             :                 if (count_all) {                                \
    1445             :                         for (; k < i; k++)                   \
    1446             :                                 rb[k] = 1;                      \
    1447             :                 } else {                                        \
    1448             :                         for (; k < i; k++)                   \
    1449             :                                 rb[k] = !is_##TPE##_nil(bp[k]); \
    1450             :                 }                                               \
    1451             :         } while (0)
    1452             : 
    1453             : #define INIT_AGGREGATE_COUNT(TPE, NOTHING1, NOTHING2)   \
    1454             :         do {                                            \
    1455             :                 computed = 0;                           \
    1456             :         } while (0)
    1457             : #define COMPUTE_LEVEL0_COUNT_FIXED(X, TPE, NOTHING1, NOTHING2)  \
    1458             :         do {                                                    \
    1459             :                 computed = !is_##TPE##_nil(bp[j + X]);          \
    1460             :         } while (0)
    1461             : #define COMPUTE_LEVELN_COUNT(VAL, NOTHING1, NOTHING2, NOTHING3) \
    1462             :         do {                                                    \
    1463             :                 computed += VAL;                                \
    1464             :         } while (0)
    1465             : #define FINALIZE_AGGREGATE_COUNT(NOTHING1, NOTHING2, NOTHING3)  \
    1466             :         do {                                                    \
    1467             :                 rb[k] = computed;                               \
    1468             :         } while (0)
    1469             : #define ANALYTICAL_COUNT_FIXED_OTHERS(TPE)                              \
    1470             :         do {                                                            \
    1471             :                 if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
    1472             :                         for (; k < i; k++)                           \
    1473             :                                 rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
    1474             :                 } else {                                                \
    1475             :                         oid ncount = i - k;                             \
    1476             :                         if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1477             :                                 goto cleanup;                           \
    1478             :                         populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_FIXED, COMPUTE_LEVELN_COUNT, TPE, NOTHING, NOTHING); \
    1479             :                         for (; k < i; k++)                           \
    1480             :                                 compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, TPE, NOTHING, NOTHING); \
    1481             :                         j = k;                                          \
    1482             :                 }                                                       \
    1483             :         } while (0)
    1484             : 
    1485             : /* Counting no nils for other types */
    1486             : #define ANALYTICAL_COUNT_OTHERS_UNBOUNDED_TILL_CURRENT_ROW              \
    1487             :         do {                                                            \
    1488             :                 curval = 0;                                             \
    1489             :                 if (count_all) {                                        \
    1490             :                         for (; k < i;) {                             \
    1491             :                                 j = k;                                  \
    1492             :                                 do {                                    \
    1493             :                                         k++;                            \
    1494             :                                 } while (k < i && !op[k]);           \
    1495             :                                 curval += k - j;                        \
    1496             :                                 for (; j < k; j++)                   \
    1497             :                                         rb[j] = curval;                 \
    1498             :                         }                                               \
    1499             :                 } else {                                                \
    1500             :                         for (; k < i; ) {                            \
    1501             :                                 j = k;                                  \
    1502             :                                 do {                                    \
    1503             :                                         curval += cmp(BUNtail(bi, k), nil) != 0; \
    1504             :                                         k++;                            \
    1505             :                                 } while (k < i && !op[k]);           \
    1506             :                                 for (; j < k; j++)                   \
    1507             :                                         rb[j] = curval;                 \
    1508             :                         }                                               \
    1509             :                 }                                                       \
    1510             :         } while (0)
    1511             : 
    1512             : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW_TILL_UNBOUNDED              \
    1513             :         do {                                                            \
    1514             :                 curval = 0;                                             \
    1515             :                 l = i - 1;                                              \
    1516             :                 if (count_all) {                                        \
    1517             :                         for (j = l; ; j--) {                            \
    1518             :                                 if (op[j] || j == k) {                  \
    1519             :                                         curval += l - j + 1;            \
    1520             :                                         for (; ; l--) {                 \
    1521             :                                                 rb[l] = curval;         \
    1522             :                                                 if (l == j)             \
    1523             :                                                         break;          \
    1524             :                                         }                               \
    1525             :                                         if (j == k)                     \
    1526             :                                                 break;                  \
    1527             :                                         l = j - 1;                      \
    1528             :                                 }                                       \
    1529             :                         }                                               \
    1530             :                 } else {                                                \
    1531             :                         for (j = l; ; j--) {                            \
    1532             :                                 curval += cmp(BUNtail(bi, j), nil) != 0; \
    1533             :                                 if (op[j] || j == k) {                  \
    1534             :                                         for (; ; l--) {                 \
    1535             :                                                 rb[l] = curval;         \
    1536             :                                                 if (l == j)             \
    1537             :                                                         break;          \
    1538             :                                         }                               \
    1539             :                                         if (j == k)                     \
    1540             :                                                 break;                  \
    1541             :                                         l = j - 1;                      \
    1542             :                                 }                                       \
    1543             :                         }                                               \
    1544             :                 }                                                       \
    1545             :                 k = i;                                                  \
    1546             :         } while (0)
    1547             : 
    1548             : #define ANALYTICAL_COUNT_OTHERS_ALL_ROWS                                \
    1549             :         do {                                                            \
    1550             :                 curval = 0;                                             \
    1551             :                 if (count_all) {                                        \
    1552             :                         curval = (lng)(i - k);                          \
    1553             :                 } else {                                                \
    1554             :                         for (; j < i; j++)                           \
    1555             :                                 curval += cmp(BUNtail(bi, j), nil) != 0; \
    1556             :                 }                                                       \
    1557             :                 for (; k < i; k++)                                   \
    1558             :                         rb[k] = curval;                                 \
    1559             :         } while (0)
    1560             : 
    1561             : #define ANALYTICAL_COUNT_OTHERS_CURRENT_ROW                             \
    1562             :         do {                                                            \
    1563             :                 if (count_all) {                                        \
    1564             :                         for (; k < i; k++)                           \
    1565             :                                 rb[k] = 1;                              \
    1566             :                 } else {                                                \
    1567             :                         for (; k < i; k++)                           \
    1568             :                                 rb[k] = cmp(BUNtail(bi, k), nil) != 0;  \
    1569             :                 }                                                       \
    1570             :         } while (0)
    1571             : 
    1572             : #define COMPUTE_LEVEL0_COUNT_OTHERS(X, NOTHING1, NOTHING2, NOTHING3)    \
    1573             :         do {                                                            \
    1574             :                 computed = cmp(BUNtail(bi, j + X), nil) != 0;           \
    1575             :         } while (0)
    1576             : #define ANALYTICAL_COUNT_OTHERS_OTHERS                                  \
    1577             :         do {                                                            \
    1578             :                 if (count_all) { /* no segment tree required for the global case (it scales in O(n)) */ \
    1579             :                         for (; k < i; k++)                           \
    1580             :                                 rb[k] = (end[k] > start[k]) ? (lng)(end[k] - start[k]) : 0; \
    1581             :                 } else {                                                \
    1582             :                         oid ncount = i - k;                             \
    1583             :                         if ((res = GDKrebuild_segment_tree(ncount, sizeof(lng), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1584             :                                 goto cleanup;                           \
    1585             :                         populate_segment_tree(lng, ncount, INIT_AGGREGATE_COUNT, COMPUTE_LEVEL0_COUNT_OTHERS, COMPUTE_LEVELN_COUNT, NOTHING, NOTHING, NOTHING); \
    1586             :                         for (; k < i; k++)                           \
    1587             :                                 compute_on_segment_tree(lng, start[k] - j, end[k] - j, INIT_AGGREGATE_COUNT, COMPUTE_LEVELN_COUNT, FINALIZE_AGGREGATE_COUNT, NOTHING, NOTHING, NOTHING); \
    1588             :                         j = k;                                          \
    1589             :                 }                                                       \
    1590             :         } while (0)
    1591             : 
    1592             : /* Now do the count analytic function branches */
    1593             : #define ANALYTICAL_COUNT_FIXED_PARTITIONS(TPE, IMP)                     \
    1594             :         do {                                                            \
    1595             :                 TPE *restrict bp = (TPE*) bheap;                        \
    1596             :                 if (p) {                                                \
    1597             :                         while (i < cnt) {                            \
    1598             :                                 if (np[i]) {                            \
    1599             : count##TPE##IMP:                                                        \
    1600             :                                         ANALYTICAL_COUNT_FIXED_##IMP(TPE); \
    1601             :                                 }                                       \
    1602             :                                 if (!last)                              \
    1603             :                                         i++;                            \
    1604             :                         }                                               \
    1605             :                 }                                                       \
    1606             :                 if (!last) {                                            \
    1607             :                         last = true;                                    \
    1608             :                         i = cnt;                                        \
    1609             :                         goto count##TPE##IMP;                           \
    1610             :                 }                                                       \
    1611             :         } while (0)
    1612             : 
    1613             : #ifdef HAVE_HGE
    1614             : #define ANALYTICAL_COUNT_LIMIT(IMP)                             \
    1615             :         case TYPE_hge:                                          \
    1616             :                 ANALYTICAL_COUNT_FIXED_PARTITIONS(hge, IMP);    \
    1617             :         break;
    1618             : #else
    1619             : #define ANALYTICAL_COUNT_LIMIT(IMP)
    1620             : #endif
    1621             : 
    1622             : #define ANALYTICAL_COUNT_BRANCHES(IMP)                                  \
    1623             :         do {                                                            \
    1624             :                 switch (ATOMbasetype(tpe)) {                            \
    1625             :                 case TYPE_bte:                                          \
    1626             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(bte, IMP);    \
    1627             :                         break;                                          \
    1628             :                 case TYPE_sht:                                          \
    1629             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(sht, IMP);    \
    1630             :                         break;                                          \
    1631             :                 case TYPE_int:                                          \
    1632             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(int, IMP);    \
    1633             :                         break;                                          \
    1634             :                 case TYPE_lng:                                          \
    1635             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(lng, IMP);    \
    1636             :                         break;                                          \
    1637             :                         ANALYTICAL_COUNT_LIMIT(IMP)                     \
    1638             :                 case TYPE_flt:                                          \
    1639             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(flt, IMP);    \
    1640             :                         break;                                          \
    1641             :                 case TYPE_dbl:                                          \
    1642             :                         ANALYTICAL_COUNT_FIXED_PARTITIONS(dbl, IMP);    \
    1643             :                         break;                                          \
    1644             :                 default: {                                              \
    1645             :                         if (p) {                                        \
    1646             :                                 while (i < cnt) {                    \
    1647             :                                         if (np[i]) {                    \
    1648             : countothers##IMP:                                                       \
    1649             :                                                 ANALYTICAL_COUNT_OTHERS_##IMP; \
    1650             :                                         }                               \
    1651             :                                         if (!last)                      \
    1652             :                                                 i++;                    \
    1653             :                                 }                                       \
    1654             :                         }                                               \
    1655             :                         if (!last) {                                    \
    1656             :                                 last = true;                            \
    1657             :                                 i = cnt;                                \
    1658             :                                 goto countothers##IMP;                  \
    1659             :                         }                                               \
    1660             :                 }                                                       \
    1661             :                 }                                                       \
    1662             :         } while (0)
    1663             : 
    1664             : BAT *
    1665         159 : GDKanalyticalcount(BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, bit ignore_nils, int tpe, int frame_type)
    1666             : {
    1667         159 :         BAT *r = COLnew(b->hseqbase, TYPE_lng, BATcount(b), TRANSIENT);
    1668         159 :         if (r == NULL)
    1669             :                 return NULL;
    1670         159 :         BATiter pi = bat_iterator(p);
    1671         159 :         BATiter oi = bat_iterator(o);
    1672         159 :         BATiter bi = bat_iterator(b);
    1673         159 :         BATiter si = bat_iterator(s);
    1674         159 :         BATiter ei = bat_iterator(e);
    1675         159 :         oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    1676         159 :                 *levels_offset = NULL, nlevels = 0;
    1677         159 :         lng curval = 0, *rb = (lng *) Tloc(r, 0);
    1678         159 :         bit *np = pi.base, *op = oi.base;
    1679         159 :         const void *restrict nil = ATOMnilptr(tpe);
    1680         159 :         int (*cmp) (const void *, const void *) = ATOMcompare(tpe);
    1681         159 :         const void *restrict bheap = bi.base;
    1682         159 :         bool count_all = !ignore_nils || bi.nonil, last = false;
    1683         159 :         void *segment_tree = NULL;
    1684         159 :         gdk_return res = GDK_SUCCEED;
    1685         159 :         BAT *st = NULL;
    1686             : 
    1687         159 :         assert(np == NULL || cnt == 0 || np[0] == 0);
    1688         159 :         if (cnt > 0) {
    1689         159 :                 switch (frame_type) {
    1690          38 :                 case 3: /* unbounded until current row */
    1691         968 :                         ANALYTICAL_COUNT_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    1692             :                         break;
    1693           3 :                 case 4: /* current row until unbounded */
    1694          43 :                         ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    1695             :                         break;
    1696          32 :                 case 5: /* all rows */
    1697         631 :                         ANALYTICAL_COUNT_BRANCHES(ALL_ROWS);
    1698             :                         break;
    1699           8 :                 case 6: /* current row */
    1700          95 :                         ANALYTICAL_COUNT_BRANCHES(CURRENT_ROW);
    1701             :                         break;
    1702          78 :                 default:
    1703          78 :                         if (!count_all && (st = GDKinitialize_segment_tree()) == NULL) {
    1704           0 :                                 res = GDK_FAIL;
    1705           0 :                                 goto cleanup;
    1706             :                         }
    1707        2615 :                         ANALYTICAL_COUNT_BRANCHES(OTHERS);
    1708             :                         break;
    1709             :                 }
    1710             :         }
    1711             : 
    1712         159 :         BATsetcount(r, cnt);
    1713         159 :         r->tnonil = true;
    1714         159 :         r->tnil = false;
    1715         159 : cleanup:
    1716         159 :         bat_iterator_end(&pi);
    1717         159 :         bat_iterator_end(&oi);
    1718         159 :         bat_iterator_end(&bi);
    1719         159 :         bat_iterator_end(&si);
    1720         159 :         bat_iterator_end(&ei);
    1721         159 :         BBPreclaim(st);
    1722         159 :         if (res != GDK_SUCCEED) {
    1723           0 :                 BBPreclaim(r);
    1724           0 :                 r = NULL;
    1725             :         }
    1726             :         return r;
    1727             : }
    1728             : 
    1729             : /* sum on fixed size integers */
    1730             : #define ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2)   \
    1731             :         do {                                                            \
    1732             :                 TPE2 curval = TPE2##_nil;                               \
    1733             :                 for (; k < i;) {                                     \
    1734             :                         j = k;                                          \
    1735             :                         do {                                            \
    1736             :                                 if (!is_##TPE1##_nil(bp[k])) {          \
    1737             :                                         if (is_##TPE2##_nil(curval))    \
    1738             :                                                 curval = (TPE2) bp[k];  \
    1739             :                                         else                            \
    1740             :                                                 ADD_WITH_CHECK(bp[k], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1741             :                                 }                                       \
    1742             :                                 k++;                                    \
    1743             :                         } while (k < i && !op[k]);                   \
    1744             :                         for (; j < k; j++)                           \
    1745             :                                 rb[j] = curval;                         \
    1746             :                         has_nils |= is_##TPE2##_nil(curval);            \
    1747             :                 }                                                       \
    1748             :         } while (0)
    1749             : 
    1750             : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2)   \
    1751             :         do {                                                            \
    1752             :                 TPE2 curval = TPE2##_nil;                               \
    1753             :                 l = i - 1;                                              \
    1754             :                 for (j = l; ; j--) {                                    \
    1755             :                         if (!is_##TPE1##_nil(bp[j])) {                  \
    1756             :                                 if (is_##TPE2##_nil(curval))            \
    1757             :                                         curval = (TPE2) bp[j];          \
    1758             :                                 else                                    \
    1759             :                                         ADD_WITH_CHECK(bp[j], curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1760             :                         }                                               \
    1761             :                         if (op[j] || j == k) {                          \
    1762             :                                 for (; ; l--) {                         \
    1763             :                                         rb[l] = curval;                 \
    1764             :                                         if (l == j)                     \
    1765             :                                                 break;                  \
    1766             :                                 }                                       \
    1767             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    1768             :                                 if (j == k)                             \
    1769             :                                         break;                          \
    1770             :                                 l = j - 1;                              \
    1771             :                         }                                               \
    1772             :                 }                                                       \
    1773             :                 k = i;                                                  \
    1774             :         } while (0)
    1775             : 
    1776             : #define ANALYTICAL_SUM_IMP_NUM_ALL_ROWS(TPE1, TPE2)                     \
    1777             :         do {                                                            \
    1778             :                 TPE2 curval = TPE2##_nil;                               \
    1779             :                 for (; j < i; j++) {                                 \
    1780             :                         TPE1 v = bp[j];                                 \
    1781             :                         if (!is_##TPE1##_nil(v)) {                      \
    1782             :                                 if (is_##TPE2##_nil(curval))            \
    1783             :                                         curval = (TPE2) v;              \
    1784             :                                 else                                    \
    1785             :                                         ADDI_WITH_CHECK(v, curval, TPE2, curval, GDK_##TPE2##_max, goto calc_overflow); \
    1786             :                         }                                               \
    1787             :                 }                                                       \
    1788             :                 for (; k < i; k++)                                   \
    1789             :                         rb[k] = curval;                                 \
    1790             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    1791             :         } while (0)
    1792             : 
    1793             : #define ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2)  \
    1794             :         do {                                            \
    1795             :                 for (; k < i; k++) {                 \
    1796             :                         TPE1 v = bp[k];                 \
    1797             :                         if (is_##TPE1##_nil(v)) {       \
    1798             :                                 rb[k] = TPE2##_nil;     \
    1799             :                                 has_nils = true;        \
    1800             :                         } else  {                       \
    1801             :                                 rb[k] = (TPE2) v;       \
    1802             :                         }                               \
    1803             :                 }                                       \
    1804             :         } while (0)
    1805             : 
    1806             : #define INIT_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2)    \
    1807             :         do {                                            \
    1808             :                 computed = TPE2##_nil;                  \
    1809             :         } while (0)
    1810             : #define COMPUTE_LEVEL0_SUM(X, TPE1, TPE2, NOTHING)                      \
    1811             :         do {                                                            \
    1812             :                 TPE1 v = bp[j + X];                                     \
    1813             :                 computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v;  \
    1814             :         } while (0)
    1815             : #define COMPUTE_LEVELN_SUM_NUM(VAL, NOTHING1, TPE2, NOTHING2)           \
    1816             :         do {                                                            \
    1817             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    1818             :                         if (is_##TPE2##_nil(computed))                  \
    1819             :                                 computed = VAL;                         \
    1820             :                         else                                            \
    1821             :                                 ADD_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, goto calc_overflow); \
    1822             :                 }                                                       \
    1823             :         } while (0)
    1824             : #define FINALIZE_AGGREGATE_SUM(NOTHING1, TPE2, NOTHING2)        \
    1825             :         do {                                                    \
    1826             :                 rb[k] = computed;                               \
    1827             :                 has_nils |= is_##TPE2##_nil(computed);          \
    1828             :         } while (0)
    1829             : #define ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2)                       \
    1830             :         do {                                                            \
    1831             :                 oid ncount = i - k;                                     \
    1832             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    1833             :                         goto cleanup;                                   \
    1834             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_SUM, COMPUTE_LEVEL0_SUM, COMPUTE_LEVELN_SUM_NUM, TPE1, TPE2, NOTHING); \
    1835             :                 for (; k < i; k++)                                   \
    1836             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_SUM, COMPUTE_LEVELN_SUM_NUM, FINALIZE_AGGREGATE_SUM, TPE1, TPE2, NOTHING); \
    1837             :                 j = k;                                                  \
    1838             :         } while (0)
    1839             : 
    1840             : /* sum on floating-points */
    1841             : /* TODO go through a version of dofsum which returns the current partials for all the cases */
    1842             : #define ANALYTICAL_SUM_IMP_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2)
    1843             : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2)
    1844             : 
    1845             : #define ANALYTICAL_SUM_IMP_FP_ALL_ROWS(TPE1, TPE2)                      \
    1846             :         do {                                                            \
    1847             :                 TPE1 *bs = bp + k;                                      \
    1848             :                 BUN parcel = i - k;                                     \
    1849             :                 TPE2 curval = TPE2##_nil;                               \
    1850             :                 if (dofsum(bs, 0,                                       \
    1851             :                            &(struct canditer){.tpe = cand_dense, .ncand = parcel,}, \
    1852             :                            &curval, 1, TYPE_##TPE1,                 \
    1853             :                            TYPE_##TPE2, NULL, 0, 0, true,               \
    1854             :                            true) == BUN_NONE) {                         \
    1855             :                         goto bailout;                                   \
    1856             :                 }                                                       \
    1857             :                 for (; k < i; k++)                                   \
    1858             :                         rb[k] = curval;                                 \
    1859             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    1860             :         } while (0)
    1861             : 
    1862             : #define ANALYTICAL_SUM_IMP_FP_CURRENT_ROW(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_CURRENT_ROW(TPE1, TPE2)
    1863             : #define ANALYTICAL_SUM_IMP_FP_OTHERS(TPE1, TPE2) ANALYTICAL_SUM_IMP_NUM_OTHERS(TPE1, TPE2)
    1864             : 
    1865             : #define ANALYTICAL_SUM_CALC(TPE1, TPE2, IMP)                    \
    1866             :         do {                                                    \
    1867             :                 TPE1 *restrict bp = (TPE1*)bi.base;             \
    1868             :                 TPE2 *rb = (TPE2*)Tloc(r, 0);                   \
    1869             :                 if (p) {                                        \
    1870             :                         while (i < cnt) {                    \
    1871             :                                 if (np[i]) {                    \
    1872             : sum##TPE1##TPE2##IMP:                                           \
    1873             :                                         IMP(TPE1, TPE2);        \
    1874             :                                 }                               \
    1875             :                                 if (!last)                      \
    1876             :                                         i++;                    \
    1877             :                         }                                       \
    1878             :                 }                                               \
    1879             :                 if (!last) {                                    \
    1880             :                         last = true;                            \
    1881             :                         i = cnt;                                \
    1882             :                         goto sum##TPE1##TPE2##IMP;              \
    1883             :                 }                                               \
    1884             :         } while (0)
    1885             : 
    1886             : #ifdef HAVE_HGE
    1887             : #define ANALYTICAL_SUM_LIMIT(IMP)                                       \
    1888             :         case TYPE_hge:{                                                 \
    1889             :                 switch (tp1) {                                          \
    1890             :                 case TYPE_bte:                                          \
    1891             :                         ANALYTICAL_SUM_CALC(bte, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1892             :                         break;                                          \
    1893             :                 case TYPE_sht:                                          \
    1894             :                         ANALYTICAL_SUM_CALC(sht, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1895             :                         break;                                          \
    1896             :                 case TYPE_int:                                          \
    1897             :                         ANALYTICAL_SUM_CALC(int, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1898             :                         break;                                          \
    1899             :                 case TYPE_lng:                                          \
    1900             :                         ANALYTICAL_SUM_CALC(lng, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1901             :                         break;                                          \
    1902             :                 case TYPE_hge:                                          \
    1903             :                         ANALYTICAL_SUM_CALC(hge, hge, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1904             :                         break;                                          \
    1905             :                 default:                                                \
    1906             :                         goto nosupport;                                 \
    1907             :                 }                                                       \
    1908             :                 break;                                                  \
    1909             :         }
    1910             : #else
    1911             : #define ANALYTICAL_SUM_LIMIT(IMP)
    1912             : #endif
    1913             : 
    1914             : #define ANALYTICAL_SUM_BRANCHES(IMP)                                    \
    1915             :         do {                                                            \
    1916             :                 switch (tp2) {                                          \
    1917             :                 case TYPE_bte:{                                         \
    1918             :                         switch (tp1) {                                  \
    1919             :                         case TYPE_bte:                                  \
    1920             :                                 ANALYTICAL_SUM_CALC(bte, bte, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1921             :                                 break;                                  \
    1922             :                         default:                                        \
    1923             :                                 goto nosupport;                         \
    1924             :                         }                                               \
    1925             :                         break;                                          \
    1926             :                 }                                                       \
    1927             :                 case TYPE_sht:{                                         \
    1928             :                         switch (tp1) {                                  \
    1929             :                         case TYPE_bte:                                  \
    1930             :                                 ANALYTICAL_SUM_CALC(bte, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1931             :                                 break;                                  \
    1932             :                         case TYPE_sht:                                  \
    1933             :                                 ANALYTICAL_SUM_CALC(sht, sht, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1934             :                                 break;                                  \
    1935             :                         default:                                        \
    1936             :                                 goto nosupport;                         \
    1937             :                         }                                               \
    1938             :                         break;                                          \
    1939             :                 }                                                       \
    1940             :                 case TYPE_int:{                                         \
    1941             :                         switch (tp1) {                                  \
    1942             :                         case TYPE_bte:                                  \
    1943             :                                 ANALYTICAL_SUM_CALC(bte, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1944             :                                 break;                                  \
    1945             :                         case TYPE_sht:                                  \
    1946             :                                 ANALYTICAL_SUM_CALC(sht, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1947             :                                 break;                                  \
    1948             :                         case TYPE_int:                                  \
    1949             :                                 ANALYTICAL_SUM_CALC(int, int, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1950             :                                 break;                                  \
    1951             :                         default:                                        \
    1952             :                                 goto nosupport;                         \
    1953             :                         }                                               \
    1954             :                         break;                                          \
    1955             :                 }                                                       \
    1956             :                 case TYPE_lng:{                                         \
    1957             :                         switch (tp1) {                                  \
    1958             :                         case TYPE_bte:                                  \
    1959             :                                 ANALYTICAL_SUM_CALC(bte, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1960             :                                 break;                                  \
    1961             :                         case TYPE_sht:                                  \
    1962             :                                 ANALYTICAL_SUM_CALC(sht, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1963             :                                 break;                                  \
    1964             :                         case TYPE_int:                                  \
    1965             :                                 ANALYTICAL_SUM_CALC(int, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1966             :                                 break;                                  \
    1967             :                         case TYPE_lng:                                  \
    1968             :                                 ANALYTICAL_SUM_CALC(lng, lng, ANALYTICAL_SUM_IMP_NUM_##IMP); \
    1969             :                                 break;                                  \
    1970             :                         default:                                        \
    1971             :                                 goto nosupport;                         \
    1972             :                         }                                               \
    1973             :                         break;                                          \
    1974             :                 }                                                       \
    1975             :                 ANALYTICAL_SUM_LIMIT(IMP)                               \
    1976             :                 case TYPE_flt:{                                         \
    1977             :                         switch (tp1) {                                  \
    1978             :                         case TYPE_flt:                                  \
    1979             :                                 ANALYTICAL_SUM_CALC(flt, flt, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1980             :                                 break;                                  \
    1981             :                         default:                                        \
    1982             :                                 goto nosupport;                         \
    1983             :                         }                                               \
    1984             :                         break;                                          \
    1985             :                 }                                                       \
    1986             :                 case TYPE_dbl:{                                         \
    1987             :                         switch (tp1) {                                  \
    1988             :                         case TYPE_flt:                                  \
    1989             :                                 ANALYTICAL_SUM_CALC(flt, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1990             :                                 break;                                  \
    1991             :                         case TYPE_dbl:                                  \
    1992             :                                 ANALYTICAL_SUM_CALC(dbl, dbl, ANALYTICAL_SUM_IMP_FP_##IMP); \
    1993             :                                 break;                                  \
    1994             :                         default:                                        \
    1995             :                                 goto nosupport;                         \
    1996             :                         }                                               \
    1997             :                         break;                                          \
    1998             :                 }                                                       \
    1999             :                 default:                                                \
    2000             :                         goto nosupport;                                 \
    2001             :                 }                                                       \
    2002             :         } while (0)
    2003             : 
    2004             : BAT *
    2005         130 : GDKanalyticalsum(BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
    2006             : {
    2007         130 :         BAT *r = COLnew(b->hseqbase, tp2, BATcount(b), TRANSIENT);
    2008         130 :         if (r == NULL)
    2009             :                 return NULL;
    2010         130 :         BATiter pi = bat_iterator(p);
    2011         130 :         BATiter oi = bat_iterator(o);
    2012         130 :         BATiter bi = bat_iterator(b);
    2013         130 :         BATiter si = bat_iterator(s);
    2014         130 :         BATiter ei = bat_iterator(e);
    2015         130 :         bool has_nils = false, last = false;
    2016         130 :         oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    2017         130 :                 *levels_offset = NULL, nlevels = 0;
    2018         130 :         bit *np = pi.base, *op = oi.base;
    2019         130 :         void *segment_tree = NULL;
    2020         130 :         gdk_return res = GDK_SUCCEED;
    2021         130 :         BAT *st = NULL;
    2022             : 
    2023         130 :         assert(np == NULL || cnt == 0 || np[0] == 0);
    2024         130 :         if (cnt > 0) {
    2025         128 :                 switch (frame_type) {
    2026          48 :                 case 3: /* unbounded until current row */
    2027        1072 :                         ANALYTICAL_SUM_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    2028             :                         break;
    2029           0 :                 case 4: /* current row until unbounded */
    2030           0 :                         ANALYTICAL_SUM_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    2031             :                         break;
    2032          32 :                 case 5: /* all rows */
    2033       19602 :                         ANALYTICAL_SUM_BRANCHES(ALL_ROWS);
    2034             :                         break;
    2035           2 :                 case 6: /* current row */
    2036          33 :                         ANALYTICAL_SUM_BRANCHES(CURRENT_ROW);
    2037             :                         break;
    2038          46 :                 default:
    2039          46 :                         if ((st = GDKinitialize_segment_tree()) == NULL) {
    2040           0 :                                 res = GDK_FAIL;
    2041           0 :                                 goto cleanup;
    2042             :                         }
    2043     8354882 :                         ANALYTICAL_SUM_BRANCHES(OTHERS);
    2044             :                         break;
    2045             :                 }
    2046             :         }
    2047             : 
    2048         130 :         BATsetcount(r, cnt);
    2049         130 :         r->tnonil = !has_nils;
    2050         130 :         r->tnil = has_nils;
    2051         130 :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
    2052           0 : bailout:
    2053           0 :         GDKerror("42000!error while calculating floating-point sum\n");
    2054           0 :         res = GDK_FAIL;
    2055           0 :         goto cleanup;
    2056           0 : calc_overflow:
    2057           0 :         GDKerror("22003!overflow in calculation.\n");
    2058           0 :         res = GDK_FAIL;
    2059         130 : cleanup:
    2060         130 :         bat_iterator_end(&pi);
    2061         130 :         bat_iterator_end(&oi);
    2062         130 :         bat_iterator_end(&bi);
    2063         130 :         bat_iterator_end(&si);
    2064         130 :         bat_iterator_end(&ei);
    2065         130 :         BBPreclaim(st);
    2066         130 :         if (res != GDK_SUCCEED) {
    2067           0 :                 BBPreclaim(r);
    2068           0 :                 r = NULL;
    2069             :         }
    2070             :         return r;
    2071           0 : nosupport:
    2072           0 :         GDKerror("42000!type combination (sum(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
    2073           0 :         res = GDK_FAIL;
    2074           0 :         goto cleanup;
    2075             : }
    2076             : 
    2077             : /* product on integers */
    2078             : #define PROD_NUM(TPE1, TPE2, TPE3, ARG)                                 \
    2079             :         do {                                                            \
    2080             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2081             :                         if (is_##TPE2##_nil(curval))                    \
    2082             :                                 curval = (TPE2) ARG;                    \
    2083             :                         else                                            \
    2084             :                                 MULI4_WITH_CHECK(ARG, curval, TPE2, curval, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
    2085             :                 }                                                       \
    2086             :         } while(0)
    2087             : 
    2088             : #define ANALYTICAL_PROD_CALC_NUM_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, TPE3) \
    2089             :         do {                                                            \
    2090             :                 TPE2 curval = TPE2##_nil;                               \
    2091             :                 for (; k < i;) {                                     \
    2092             :                         j = k;                                          \
    2093             :                         do {                                            \
    2094             :                                 PROD_NUM(TPE1, TPE2, TPE3, bp[k]);      \
    2095             :                                 k++;                                    \
    2096             :                         } while (k < i && !op[k]);                   \
    2097             :                         for (; j < k; j++)                           \
    2098             :                                 rb[j] = curval;                         \
    2099             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2100             :                 }                                                       \
    2101             :         } while (0)
    2102             : 
    2103             : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, TPE3) \
    2104             :         do {                                                            \
    2105             :                 TPE2 curval = TPE2##_nil;                               \
    2106             :                 l = i - 1;                                              \
    2107             :                 for (j = l; ; j--) {                                    \
    2108             :                         PROD_NUM(TPE1, TPE2, TPE3, bp[j]);              \
    2109             :                         if (op[j] || j == k) {                          \
    2110             :                                 for (; ; l--) {                         \
    2111             :                                         rb[l] = curval;                 \
    2112             :                                         if (l == j)                     \
    2113             :                                                 break;                  \
    2114             :                                 }                                       \
    2115             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2116             :                                 if (j == k)                             \
    2117             :                                         break;                          \
    2118             :                                 l = j - 1;                              \
    2119             :                         }                                               \
    2120             :                 }                                                       \
    2121             :                 k = i;                                                  \
    2122             :         } while (0)
    2123             : 
    2124             : #define ANALYTICAL_PROD_CALC_NUM_ALL_ROWS(TPE1, TPE2, TPE3)     \
    2125             :         do {                                                    \
    2126             :                 TPE2 curval = TPE2##_nil;                       \
    2127             :                 for (; j < i; j++) {                         \
    2128             :                         TPE1 v = bp[j];                         \
    2129             :                         PROD_NUM(TPE1, TPE2, TPE3, v);          \
    2130             :                 }                                               \
    2131             :                 for (; k < i; k++)                           \
    2132             :                         rb[k] = curval;                         \
    2133             :                 has_nils |= is_##TPE2##_nil(curval);            \
    2134             :         } while (0)
    2135             : 
    2136             : #define ANALYTICAL_PROD_CALC_NUM_CURRENT_ROW(TPE1, TPE2, TPE3)  \
    2137             :         do {                                                    \
    2138             :                 for (; k < i; k++) {                         \
    2139             :                         TPE1 v = bp[k];                         \
    2140             :                         if (is_##TPE1##_nil(v)) {               \
    2141             :                                 rb[k] = TPE2##_nil;             \
    2142             :                                 has_nils = true;                \
    2143             :                         } else  {                               \
    2144             :                                 rb[k] = (TPE2) v;               \
    2145             :                         }                                       \
    2146             :                 }                                               \
    2147             :         } while (0)
    2148             : 
    2149             : #define INIT_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2)   \
    2150             :         do {                                            \
    2151             :                 computed = TPE2##_nil;                  \
    2152             :         } while (0)
    2153             : #define COMPUTE_LEVEL0_PROD(X, TPE1, TPE2, NOTHING)                     \
    2154             :         do {                                                            \
    2155             :                 TPE1 v = bp[j + X];                                     \
    2156             :                 computed = is_##TPE1##_nil(v) ? TPE2##_nil : (TPE2) v;  \
    2157             :         } while (0)
    2158             : #define COMPUTE_LEVELN_PROD_NUM(VAL, NOTHING, TPE2, TPE3)               \
    2159             :         do {                                                            \
    2160             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2161             :                         if (is_##TPE2##_nil(computed))                  \
    2162             :                                 computed = VAL;                         \
    2163             :                         else                                            \
    2164             :                                 MULI4_WITH_CHECK(VAL, computed, TPE2, computed, GDK_##TPE2##_max, TPE3, goto calc_overflow); \
    2165             :                 }                                                       \
    2166             :         } while (0)
    2167             : #define FINALIZE_AGGREGATE_PROD(NOTHING1, TPE2, NOTHING2)       \
    2168             :         do {                                                    \
    2169             :                 rb[k] = computed;                               \
    2170             :                 has_nils |= is_##TPE2##_nil(computed);          \
    2171             :         } while (0)
    2172             : #define ANALYTICAL_PROD_CALC_NUM_OTHERS(TPE1, TPE2, TPE3)               \
    2173             :         do {                                                            \
    2174             :                 oid ncount = i - k;                                     \
    2175             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2176             :                         goto cleanup;                                   \
    2177             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM, TPE1, TPE2, TPE3); \
    2178             :                 for (; k < i; k++)                                   \
    2179             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, TPE3); \
    2180             :                 j = k;                                                  \
    2181             :         } while (0)
    2182             : 
    2183             : /* product on integers while checking for overflows on the output  */
    2184             : #define PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, ARG)                       \
    2185             :         do {                                                            \
    2186             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2187             :                         if (is_##TPE2##_nil(curval))                    \
    2188             :                                 curval = (TPE2) ARG;                    \
    2189             :                         else                                            \
    2190             :                                 REAL_IMP(ARG, curval, curval, GDK_##TPE2##_max, goto calc_overflow); \
    2191             :                 }                                                       \
    2192             :         } while(0)
    2193             : 
    2194             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
    2195             :         do {                                                            \
    2196             :                 TPE2 curval = TPE2##_nil;                               \
    2197             :                 for (; k < i;) {                                     \
    2198             :                         j = k;                                          \
    2199             :                         do {                                            \
    2200             :                                 PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[k]); \
    2201             :                                 k++;                                    \
    2202             :                         } while (k < i && !op[k]);                   \
    2203             :                         for (; j < k; j++)                           \
    2204             :                                 rb[j] = curval;                         \
    2205             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2206             :                 }                                                       \
    2207             :         } while (0)
    2208             : 
    2209             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, REAL_IMP) \
    2210             :         do {                                                            \
    2211             :                 TPE2 curval = TPE2##_nil;                               \
    2212             :                 l = i - 1;                                              \
    2213             :                 for (j = l; ; j--) {                                    \
    2214             :                         PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, bp[j]);    \
    2215             :                         if (op[j] || j == k) {                          \
    2216             :                                 for (; ; l--) {                         \
    2217             :                                         rb[l] = curval;                 \
    2218             :                                         if (l == j)                     \
    2219             :                                                 break;                  \
    2220             :                                 }                                       \
    2221             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2222             :                                 if (j == k)                             \
    2223             :                                         break;                          \
    2224             :                                 l = j - 1;                              \
    2225             :                         }                                               \
    2226             :                 }                                                       \
    2227             :                 k = i;                                                  \
    2228             :         } while (0)
    2229             : 
    2230             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_ALL_ROWS(TPE1, TPE2, REAL_IMP)   \
    2231             :         do {                                                            \
    2232             :                 TPE2 curval = TPE2##_nil;                               \
    2233             :                 for (; j < i; j++) {                                 \
    2234             :                         TPE1 v = bp[j];                                 \
    2235             :                         PROD_NUM_LIMIT(TPE1, TPE2, REAL_IMP, v);        \
    2236             :                 }                                                       \
    2237             :                 for (; k < i; k++)                                   \
    2238             :                         rb[k] = curval;                                 \
    2239             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    2240             :         } while (0)
    2241             : 
    2242             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_CURRENT_ROW(TPE1, TPE2, REAL_IMP) \
    2243             :         do {                                                            \
    2244             :                 for (; k < i; k++) {                                 \
    2245             :                         TPE1 v = bp[k];                                 \
    2246             :                         if (is_##TPE1##_nil(v)) {                       \
    2247             :                                 rb[k] = TPE2##_nil;                     \
    2248             :                                 has_nils = true;                        \
    2249             :                         } else  {                                       \
    2250             :                                 rb[k] = (TPE2) v;                       \
    2251             :                         }                                               \
    2252             :                 }                                                       \
    2253             :         } while (0)
    2254             : 
    2255             : #define COMPUTE_LEVELN_PROD_NUM_LIMIT(VAL, NOTHING, TPE2, REAL_IMP)     \
    2256             :         do {                                                            \
    2257             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2258             :                         if (is_##TPE2##_nil(computed))                  \
    2259             :                                 computed = VAL;                         \
    2260             :                         else                                            \
    2261             :                                 REAL_IMP(VAL, computed, computed, GDK_##TPE2##_max, goto calc_overflow); \
    2262             :                 }                                                       \
    2263             :         } while (0)
    2264             : #define ANALYTICAL_PROD_CALC_NUM_LIMIT_OTHERS(TPE1, TPE2, REAL_IMP)     \
    2265             :         do {                                                            \
    2266             :                 oid ncount = i - k;                                     \
    2267             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2268             :                         goto cleanup;                                   \
    2269             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, TPE1, TPE2, REAL_IMP); \
    2270             :                 for (; k < i; k++)                                   \
    2271             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_NUM_LIMIT, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, REAL_IMP); \
    2272             :                 j = k;                                                  \
    2273             :         } while (0)
    2274             : 
    2275             : /* product on floating-points */
    2276             : #define PROD_FP(TPE1, TPE2, ARG)                                        \
    2277             :         do {                                                            \
    2278             :                 if (!is_##TPE1##_nil(ARG)) {                            \
    2279             :                         if (is_##TPE2##_nil(curval)) {                  \
    2280             :                                 curval = (TPE2) ARG;                    \
    2281             :                         } else if (ABSOLUTE(curval) > 1 && GDK_##TPE2##_max / ABSOLUTE(ARG) < ABSOLUTE(curval)) { \
    2282             :                                 goto calc_overflow;                     \
    2283             :                         } else {                                        \
    2284             :                                 curval *= ARG;                          \
    2285             :                         }                                               \
    2286             :                 }                                                       \
    2287             :         } while(0)
    2288             : 
    2289             : #define ANALYTICAL_PROD_CALC_FP_UNBOUNDED_TILL_CURRENT_ROW(TPE1, TPE2, ARG3)    /* ARG3 is ignored here */ \
    2290             :         do {                                                            \
    2291             :                 TPE2 curval = TPE2##_nil;                               \
    2292             :                 for (; k < i;) {                                     \
    2293             :                         j = k;                                          \
    2294             :                         do {                                            \
    2295             :                                 PROD_FP(TPE1, TPE2, bp[k]);             \
    2296             :                                 k++;                                    \
    2297             :                         } while (k < i && !op[k]);                   \
    2298             :                         for (; j < k; j++)                           \
    2299             :                                 rb[j] = curval;                         \
    2300             :                         has_nils |= is_##TPE2##_nil(curval);            \
    2301             :                 }                                                       \
    2302             :         } while (0)
    2303             : 
    2304             : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW_TILL_UNBOUNDED(TPE1, TPE2, ARG3)    /* ARG3 is ignored here */ \
    2305             :         do {                                                            \
    2306             :                 TPE2 curval = TPE2##_nil;                               \
    2307             :                 l = i - 1;                                              \
    2308             :                 for (j = l; ; j--) {                                    \
    2309             :                         PROD_FP(TPE1, TPE2, bp[j]);                     \
    2310             :                         if (op[j] || j == k) {                          \
    2311             :                                 for (; ; l--) {                         \
    2312             :                                         rb[l] = curval;                 \
    2313             :                                         if (l == j)                     \
    2314             :                                                 break;                  \
    2315             :                                 }                                       \
    2316             :                                 has_nils |= is_##TPE2##_nil(curval);    \
    2317             :                                 if (j == k)                             \
    2318             :                                         break;                          \
    2319             :                                 l = j - 1;                              \
    2320             :                         }                                               \
    2321             :                 }                                                       \
    2322             :                 k = i;                                                  \
    2323             :         } while (0)
    2324             : 
    2325             : #define ANALYTICAL_PROD_CALC_FP_ALL_ROWS(TPE1, TPE2, ARG3)      /* ARG3 is ignored here */ \
    2326             :         do {                                                            \
    2327             :                 TPE2 curval = TPE2##_nil;                               \
    2328             :                 for (; j < i; j++) {                                 \
    2329             :                         TPE1 v = bp[j];                                 \
    2330             :                         PROD_FP(TPE1, TPE2, v);                         \
    2331             :                 }                                                       \
    2332             :                 for (; k < i; k++)                                   \
    2333             :                         rb[k] = curval;                                 \
    2334             :                 has_nils |= is_##TPE2##_nil(curval);                    \
    2335             :         } while (0)
    2336             : 
    2337             : #define ANALYTICAL_PROD_CALC_FP_CURRENT_ROW(TPE1, TPE2, ARG3)   /* ARG3 is ignored here */ \
    2338             :         do {                                                            \
    2339             :                 for (; k < i; k++) {                                 \
    2340             :                         TPE1 v = bp[k];                                 \
    2341             :                         if (is_##TPE1##_nil(v)) {                       \
    2342             :                                 rb[k] = TPE2##_nil;                     \
    2343             :                                 has_nils = true;                        \
    2344             :                         } else  {                                       \
    2345             :                                 rb[k] = (TPE2) v;                       \
    2346             :                         }                                               \
    2347             :                 }                                                       \
    2348             :         } while (0)
    2349             : 
    2350             : #define COMPUTE_LEVELN_PROD_FP(VAL, NOTHING1, TPE2, NOTHING2)           \
    2351             :         do {                                                            \
    2352             :                 if (!is_##TPE2##_nil(VAL)) {                            \
    2353             :                         if (is_##TPE2##_nil(computed)) {                \
    2354             :                                 computed = VAL;                         \
    2355             :                         } else if (ABSOLUTE(computed) > 1 && GDK_##TPE2##_max / ABSOLUTE(VAL) < ABSOLUTE(computed)) { \
    2356             :                                 goto calc_overflow;                     \
    2357             :                         } else {                                        \
    2358             :                                 computed *= VAL;                        \
    2359             :                         }                                               \
    2360             :                 }                                                       \
    2361             :         } while (0)
    2362             : #define ANALYTICAL_PROD_CALC_FP_OTHERS(TPE1, TPE2, ARG3) /* ARG3 is ignored here */ \
    2363             :         do {                                                            \
    2364             :                 oid ncount = i - k;                                     \
    2365             :                 if ((res = GDKrebuild_segment_tree(ncount, sizeof(TPE2), st, &segment_tree, &levels_offset, &nlevels)) != GDK_SUCCEED) \
    2366             :                         goto cleanup;                                   \
    2367             :                 populate_segment_tree(TPE2, ncount, INIT_AGGREGATE_PROD, COMPUTE_LEVEL0_PROD, COMPUTE_LEVELN_PROD_FP, TPE1, TPE2, ARG3); \
    2368             :                 for (; k < i; k++)                                   \
    2369             :                         compute_on_segment_tree(TPE2, start[k] - j, end[k] - j, INIT_AGGREGATE_PROD, COMPUTE_LEVELN_PROD_FP, FINALIZE_AGGREGATE_PROD, TPE1, TPE2, ARG3); \
    2370             :                 j = k;                                                  \
    2371             :         } while (0)
    2372             : 
    2373             : #define ANALYTICAL_PROD_CALC_NUM_PARTITIONS(TPE1, TPE2, TPE3_OR_REAL_IMP, IMP) \
    2374             :         do {                                                            \
    2375             :                 TPE1 *restrict bp = (TPE1*)bi.base;                     \
    2376             :                 TPE2 *rb = (TPE2*)Tloc(r, 0);                           \
    2377             :                 if (p) {                                                \
    2378             :                         while (i < cnt) {                            \
    2379             :                                 if (np[i]) {                            \
    2380             : prod##TPE1##TPE2##IMP:                                                  \
    2381             :                                         IMP(TPE1, TPE2, TPE3_OR_REAL_IMP); \
    2382             :                                 }                                       \
    2383             :                                 if (!last)                              \
    2384             :                                         i++;                            \
    2385             :                         }                                               \
    2386             :                 }                                                       \
    2387             :                 if (!last) {                                            \
    2388             :                         last = true;                                    \
    2389             :                         i = cnt;                                        \
    2390             :                         goto prod##TPE1##TPE2##IMP;                     \
    2391             :                 }                                                       \
    2392             :         } while (0)
    2393             : 
    2394             : #ifdef HAVE_HGE
    2395             : #define ANALYTICAL_PROD_LIMIT(IMP)                                      \
    2396             :         case TYPE_lng:{                                                 \
    2397             :                 switch (tp1) {                                          \
    2398             :                 case TYPE_bte:                                          \
    2399             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2400             :                         break;                                          \
    2401             :                 case TYPE_sht:                                          \
    2402             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2403             :                         break;                                          \
    2404             :                 case TYPE_int:                                          \
    2405             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2406             :                         break;                                          \
    2407             :                 case TYPE_lng:                                          \
    2408             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, hge, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2409             :                         break;                                          \
    2410             :                 default:                                                \
    2411             :                         goto nosupport;                                 \
    2412             :                 }                                                       \
    2413             :                 break;                                                  \
    2414             :         }                                                               \
    2415             :         case TYPE_hge:{                                                 \
    2416             :                 switch (tp1) {                                          \
    2417             :                 case TYPE_bte:                                          \
    2418             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2419             :                         break;                                          \
    2420             :                 case TYPE_sht:                                          \
    2421             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2422             :                         break;                                          \
    2423             :                 case TYPE_int:                                          \
    2424             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2425             :                         break;                                          \
    2426             :                 case TYPE_lng:                                          \
    2427             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2428             :                         break;                                          \
    2429             :                 case TYPE_hge:                                          \
    2430             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(hge, hge, HGEMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2431             :                         break;                                          \
    2432             :                 default:                                                \
    2433             :                         goto nosupport;                                 \
    2434             :                 }                                                       \
    2435             :                 break;                                                  \
    2436             :         }
    2437             : #else
    2438             : #define ANALYTICAL_PROD_LIMIT(IMP)                                      \
    2439             :         case TYPE_lng:{                                                 \
    2440             :                 switch (tp1) {                                          \
    2441             :                 case TYPE_bte:                                          \
    2442             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2443             :                         break;                                          \
    2444             :                 case TYPE_sht:                                          \
    2445             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2446             :                         break;                                          \
    2447             :                 case TYPE_int:                                          \
    2448             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2449             :                         break;                                          \
    2450             :                 case TYPE_lng:                                          \
    2451             :                         ANALYTICAL_PROD_CALC_NUM_PARTITIONS(lng, lng, LNGMUL_CHECK, ANALYTICAL_PROD_CALC_NUM_LIMIT_##IMP); \
    2452             :                         break;                                          \
    2453             :                 default:                                                \
    2454             :                         goto nosupport;                                 \
    2455             :                 }                                                       \
    2456             :                 break;                                                  \
    2457             :         }
    2458             : #endif
    2459             : 
    2460             : #define ANALYTICAL_PROD_BRANCHES(IMP)                                   \
    2461             :         do {                                                            \
    2462             :                 switch (tp2) {                                          \
    2463             :                 case TYPE_bte:{                                         \
    2464             :                         switch (tp1) {                                  \
    2465             :                         case TYPE_bte:                                  \
    2466             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, bte, sht, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2467             :                                 break;                                  \
    2468             :                         default:                                        \
    2469             :                                 goto nosupport;                         \
    2470             :                         }                                               \
    2471             :                         break;                                          \
    2472             :                 }                                                       \
    2473             :                 case TYPE_sht:{                                         \
    2474             :                         switch (tp1) {                                  \
    2475             :                         case TYPE_bte:                                  \
    2476             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2477             :                                 break;                                  \
    2478             :                         case TYPE_sht:                                  \
    2479             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, sht, int, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2480             :                                 break;                                  \
    2481             :                         default:                                        \
    2482             :                                 goto nosupport;                         \
    2483             :                         }                                               \
    2484             :                         break;                                          \
    2485             :                 }                                                       \
    2486             :                 case TYPE_int:{                                         \
    2487             :                         switch (tp1) {                                  \
    2488             :                         case TYPE_bte:                                  \
    2489             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(bte, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2490             :                                 break;                                  \
    2491             :                         case TYPE_sht:                                  \
    2492             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(sht, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2493             :                                 break;                                  \
    2494             :                         case TYPE_int:                                  \
    2495             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(int, int, lng, ANALYTICAL_PROD_CALC_NUM_##IMP); \
    2496             :                                 break;                                  \
    2497             :                         default:                                        \
    2498             :                                 goto nosupport;                         \
    2499             :                         }                                               \
    2500             :                         break;                                          \
    2501             :                 }                                                       \
    2502             :                 ANALYTICAL_PROD_LIMIT(IMP)                              \
    2503             :                 case TYPE_flt:{                                         \
    2504             :                         switch (tp1) {                                  \
    2505             :                         case TYPE_flt:                                  \
    2506             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, flt, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2507             :                                 break;                                  \
    2508             :                         default:                                        \
    2509             :                                 goto nosupport;                         \
    2510             :                         }                                               \
    2511             :                         break;                                          \
    2512             :                 }                                                       \
    2513             :                 case TYPE_dbl:{                                         \
    2514             :                         switch (tp1) {                                  \
    2515             :                         case TYPE_flt:                                  \
    2516             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(flt, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2517             :                                 break;                                  \
    2518             :                         case TYPE_dbl:                                  \
    2519             :                                 ANALYTICAL_PROD_CALC_NUM_PARTITIONS(dbl, dbl, ;, ANALYTICAL_PROD_CALC_FP_##IMP); \
    2520             :                                 break;                                  \
    2521             :                         default:                                        \
    2522             :                                 goto nosupport;                         \
    2523             :                         }                                               \
    2524             :                         break;                                          \
    2525             :                 }                                                       \
    2526             :                 default:                                                \
    2527             :                         goto nosupport;                                 \
    2528             :                 }                                                       \
    2529             :         } while (0)
    2530             : 
    2531             : BAT *
    2532          31 : GDKanalyticalprod(BAT *p, BAT *o, BAT *b, BAT *s, BAT *e, int tp1, int tp2, int frame_type)
    2533             : {
    2534          31 :         BAT *r = COLnew(b->hseqbase, tp2, BATcount(b), TRANSIENT);
    2535          31 :         if (r == NULL)
    2536             :                 return NULL;
    2537          31 :         BATiter pi = bat_iterator(p);
    2538          31 :         BATiter oi = bat_iterator(o);
    2539          31 :         BATiter bi = bat_iterator(b);
    2540          31 :         BATiter si = bat_iterator(s);
    2541          31 :         BATiter ei = bat_iterator(e);
    2542          31 :         bool has_nils = false, last = false;
    2543          31 :         oid i = 1, j = 0, k = 0, l = 0, cnt = BATcount(b), *restrict start = si.base, *restrict end = ei.base,
    2544          31 :                 *levels_offset = NULL, nlevels = 0;
    2545          31 :         bit *np = pi.base, *op = oi.base;
    2546          31 :         void *segment_tree = NULL;
    2547          31 :         gdk_return res = GDK_SUCCEED;
    2548          31 :         BAT *st = NULL;
    2549             : 
    2550          31 :         assert(np == NULL || cnt == 0 || np[0] == 0);
    2551          31 :         if (cnt > 0) {
    2552          31 :                 switch (frame_type) {
    2553          12 :                 case 3: /* unbounded until current row */
    2554         334 :                         ANALYTICAL_PROD_BRANCHES(UNBOUNDED_TILL_CURRENT_ROW);
    2555             :                         break;
    2556           0 :                 case 4: /* current row until unbounded */
    2557           0 :                         ANALYTICAL_PROD_BRANCHES(CURRENT_ROW_TILL_UNBOUNDED);
    2558             :                         break;
    2559           7 :                 case 5: /* all rows */
    2560         187 :                         ANALYTICAL_PROD_BRANCHES(ALL_ROWS);
    2561             :                         break;
    2562           0 :                 case 6: /* current row */
    2563           0 :                         ANALYTICAL_PROD_BRANCHES(CURRENT_ROW);
    2564             :                         break;
    2565          12 :                 default:
    2566          12 :                         if ((st = GDKinitialize_segment_tree()) == NULL) {
    2567           0 :                                 res = GDK_FAIL;
    2568           0 :                                 goto cleanup;
    2569             :                         }
    2570         938 :                         ANALYTICAL_PROD_BRANCHES(OTHERS);
    2571             :                         break;
    2572             :                 }
    2573             :         }
    2574             : 
    2575          31 :         BATsetcount(r, cnt);
    2576          31 :         r->tnonil = !has_nils;
    2577          31 :         r->tnil = has_nils;
    2578          31 :         goto cleanup; /* all these gotos seem confusing but it cleans up the ending of the operator */
    2579           0 : calc_overflow:
    2580           0 :         GDKerror("22003!overflow in calculation.\n");
    2581           0 :         res = GDK_FAIL;
    2582          31 : cleanup:
    2583          31 :         bat_iterator_end(&pi);
    2584          31 :         bat_iterator_end(&oi);
    2585          31 :         bat_iterator_end(&bi);
    2586          31 :         bat_iterator_end(&si);
    2587          31 :         bat_iterator_end(&ei);
    2588          31 :         BBPreclaim(st);
    2589          31 :         if (res != GDK_SUCCEED) {
    2590           0 :                 BBPreclaim(r);
    2591           0 :                 r = NULL;
    2592             :         }
    2593             :         return r;
    2594           0 : nosupport:
    2595           0 :         GDKerror("42000!type combination (prod(%s)->%s) not supported.\n", ATOMname(tp1), ATOMname(tp2));
    2596           0 :         res = GDK_FAIL;
    2597           0 :         goto cleanup;
    2598             : }

Generated by: LCOV version 1.14