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

Generated by: LCOV version 1.14