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

Generated by: LCOV version 1.14