LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 787 1036 76.0 %
Date: 2024-12-20 21:24:02 Functions: 68 83 81.9 %

          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             : /*
      14             :  * (c) Peter Boncz, Martin Kersten, Niels Nes, Sjoerd Mullender
      15             :  * BAT Algebra
      16             :  * This modules contains the most common algebraic BAT manipulation
      17             :  * commands. We call them algebra, because all operations take
      18             :  * values as parameters, and produce new result values, but
      19             :  * do not modify their parameters.
      20             :  *
      21             :  * Unlike the previous Monet versions, we reduce the number
      22             :  * of functions returning a BAT reference. This was previously needed
      23             :  * to simplify recursive bat-expression and manage reference counts.
      24             :  * In the current version we return only a BAT identifier when a new
      25             :  * bat is being created.
      26             :  *
      27             :  * All parameters to the modules are passed by reference.
      28             :  * In particular, this means that
      29             :  * string values are passed to the module layer as (str *)
      30             :  * and we have to de-reference them before entering the gdk library.
      31             :  * This calls for knowledge on the underlying BAT typs`s
      32             :  */
      33             : #define derefStr(b, v)                                                  \
      34             :         do {                                                                            \
      35             :                 int _tpe= ATOMstorage((b)->ttype);           \
      36             :                 if (_tpe >= TYPE_str) {                                      \
      37             :                         if ((v) == 0 || *(str*) (v) == 0)       \
      38             :                                 (v) = (str) str_nil;                    \
      39             :                         else                                                            \
      40             :                                 (v) = *(str *) (v);                             \
      41             :                 }                                                                               \
      42             :         } while (0)
      43             : 
      44             : #include "monetdb_config.h"
      45             : #include "algebra.h"
      46             : 
      47             : /*
      48             :  * Command Implementations in C
      49             :  * This module contains just a wrapper implementations; since all described
      50             :  * operations are part of the GDK kernel.
      51             :  *
      52             :  * BAT sum operation
      53             :  * The sum aggregate only works for int and float fields.
      54             :  * The routines below assumes that the caller knows what type
      55             :  * is large enough to prevent overflow.
      56             :  */
      57             : 
      58             : static gdk_return
      59        2392 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts)
      60             : {
      61        2392 :         BUN j;
      62        2392 :         BATiter gi = bat_iterator(gids);
      63        2392 :         BAT *r = COLnew(0, TYPE_oid, gi.count * 2, TRANSIENT);
      64             : 
      65        2393 :         if (r == NULL) {
      66           0 :                 bat_iterator_end(&gi);
      67           0 :                 return GDK_FAIL;
      68             :         }
      69        2393 :         BATiter ci = bat_iterator(cnts);
      70        2393 :         if (gi.type == TYPE_void) {
      71        1054 :                 oid id = gi.tseq;
      72        1054 :                 lng *cnt = (lng *) ci.base;
      73       96216 :                 for (j = 0; j < gi.count; j++) {
      74       95163 :                         lng i, sz = cnt[j];
      75      190262 :                         for (i = 0; i < sz; i++) {
      76       95100 :                                 if (BUNappend(r, &id, false) != GDK_SUCCEED) {
      77           0 :                                         BBPreclaim(r);
      78           0 :                                         bat_iterator_end(&ci);
      79           0 :                                         bat_iterator_end(&gi);
      80           0 :                                         return GDK_FAIL;
      81             :                                 }
      82             :                         }
      83       95162 :                         id ++;
      84             :                 }
      85             :         } else {
      86        1339 :                 oid *id = (oid *) gi.base;
      87        1339 :                 lng *cnt = (lng *) ci.base;
      88      140494 :                 for (j = 0; j < gi.count; j++) {
      89      139155 :                         lng i, sz = cnt[j];
      90      274814 :                         for (i = 0; i < sz; i++) {
      91      135659 :                                 if (BUNappend(r, id, false) != GDK_SUCCEED) {
      92           0 :                                         BBPreclaim(r);
      93           0 :                                         bat_iterator_end(&ci);
      94           0 :                                         bat_iterator_end(&gi);
      95           0 :                                         return GDK_FAIL;
      96             :                                 }
      97             :                         }
      98      139155 :                         id ++;
      99             :                 }
     100             :         }
     101        2392 :         bat_iterator_end(&ci);
     102        2392 :         r->tkey = false;
     103        2392 :         r->tseqbase = oid_nil;
     104        2392 :         r->tsorted = gi.sorted;
     105        2392 :         r->trevsorted = gi.revsorted;
     106        2392 :         r->tnonil = gi.nonil;
     107        2392 :         bat_iterator_end(&gi);
     108        2393 :         *result = r;
     109        2393 :         return GDK_SUCCEED;
     110             : }
     111             : 
     112             : 
     113             : static gdk_return
     114           6 : slice(BAT **retval, BAT *b, lng start, lng end)
     115             : {
     116             :         /* the internal BATslice requires exclusive end */
     117           6 :         if (start < 0) {
     118           0 :                 GDKerror("start position of slice should >= 0\n");
     119           0 :                 return GDK_FAIL;
     120             :         }
     121           6 :         if (is_lng_nil(end))
     122           3 :                 end = BATcount(b);
     123             : 
     124           6 :         return (*retval = BATslice(b, (BUN) start, (BUN) end + 1)) ? GDK_SUCCEED : GDK_FAIL;
     125             : }
     126             : 
     127             : /*
     128             :  *
     129             :  * The remainder of this file contains the wrapper around the V4 code base
     130             :  * The BAT identifiers passed through this module may indicate
     131             :  * that the 'reverse' view applies. This should be taken into
     132             :  * account while resolving them.
     133             :  *
     134             :  * The sum aggregate only works for int and float fields.
     135             :  * The routines below assumes that the caller knows what type
     136             :  * is large enough to prevent overflow.
     137             :  */
     138             : 
     139             : static str
     140         781 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         781 :         BAT *b;
     143         781 :         ptr p;
     144         781 :         str msg = MAL_SUCCEED;
     145             : 
     146         781 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         782 :         if (!ATOMlinear(b->ttype)) {
     150           0 :                 msg = createException(MAL, "algebra.min",
     151             :                                                           "atom '%s' cannot be ordered linearly",
     152             :                                                           ATOMname(b->ttype));
     153             :         } else {
     154         782 :                 if (ATOMextern(b->ttype)) {
     155          42 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         740 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         739 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         780 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         780 :         BBPunfix(b->batCacheid);
     166         780 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         781 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         781 :         bit skipnil = TRUE;
     173         781 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         548 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         548 :         BAT *b;
     180         548 :         ptr p;
     181         548 :         str msg = MAL_SUCCEED;
     182             : 
     183         548 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         551 :         if (!ATOMlinear(b->ttype)) {
     187           0 :                 msg = createException(MAL, "algebra.max",
     188             :                                                           "atom '%s' cannot be ordered linearly",
     189             :                                                           ATOMname(b->ttype));
     190             :         } else {
     191         551 :                 if (ATOMextern(b->ttype)) {
     192          68 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         483 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         484 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         551 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         551 :         BBPunfix(b->batCacheid);
     203         551 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         549 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         549 :         bit skipnil = TRUE;
     210         549 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     211             : }
     212             : 
     213             : static str
     214        2392 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     215             : {
     216        2392 :         BAT *bn, *g, *c;
     217             : 
     218        2392 :         g = BATdescriptor(*gids);
     219        2393 :         if (g == NULL) {
     220           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     221             :         }
     222        2393 :         c = BATdescriptor(*cnts);
     223        2393 :         if (c == NULL) {
     224           0 :                 BBPunfix(g->batCacheid);
     225           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     226             :         }
     227        2393 :         if (CMDgen_group(&bn, g, c) != GDK_SUCCEED) {
     228           0 :                 BBPunfix(g->batCacheid);
     229           0 :                 BBPunfix(c->batCacheid);
     230           0 :                 throw(MAL, "algebra.groupby", GDK_EXCEPTION);
     231             :         }
     232        2392 :         *res = bn->batCacheid;
     233        2392 :         BBPkeepref(bn);
     234        2393 :         BBPunfix(g->batCacheid);
     235        2393 :         BBPunfix(c->batCacheid);
     236        2393 :         return MAL_SUCCEED;
     237             : }
     238             : 
     239             : static str
     240           1 : ALGcard(lng *result, const bat *bid)
     241             : {
     242           1 :         BAT *b, *en;
     243             : 
     244           1 :         if ((b = BATdescriptor(*bid)) == NULL) {
     245           0 :                 throw(MAL, "algebra.card", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     246             :         }
     247           1 :         en = BATunique(b, NULL);
     248           1 :         BBPunfix(b->batCacheid);
     249           1 :         if (en == NULL) {
     250           0 :                 throw(MAL, "algebra.card", GDK_EXCEPTION);
     251             :         }
     252           1 :         struct canditer ci;
     253           1 :         canditer_init(&ci, NULL, en);
     254           1 :         *result = (lng) ci.ncand;
     255           1 :         BBPunfix(en->batCacheid);
     256           1 :         return MAL_SUCCEED;
     257             : }
     258             : 
     259             : static str
     260      137401 : ALGselect2nil(bat *result, const bat *bid, const bat *sid, const void *low,
     261             :                           const void *high, const bit *li, const bit *hi, const bit *anti,
     262             :                           const bit *unknown)
     263             : {
     264      137401 :         BAT *b, *s = NULL, *bn;
     265             : 
     266      137401 :         if ((*li != 0 && *li != 1) ||
     267      137401 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270             : 
     271      137563 :         if ((b = BATdescriptor(*bid)) == NULL) {
     272           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     273             :         }
     274      138237 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     275           0 :                 BBPunfix(b->batCacheid);
     276           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     277             :         }
     278      138260 :         derefStr(b, low);
     279      138260 :         derefStr(b, high);
     280             : 
     281      138260 :         bool nanti = *anti, nli = *li, nhi = *hi;
     282             : 
     283             :         /* here we don't need open ended parts with nil */
     284      138260 :         if (!nanti && *unknown) {
     285        1584 :                 const void *nilptr = ATOMnilptr(b->ttype);
     286        1584 :                 if (nilptr) {
     287        1584 :                         if (nli && ATOMcmp(b->ttype, low, nilptr) == 0) {
     288          22 :                                 low = high;
     289          22 :                                 nli = false;
     290             :                         }
     291        1581 :                         if (nhi && ATOMcmp(b->ttype, high, nilptr) == 0) {
     292          24 :                                 high = low;
     293          24 :                                 nhi = false;
     294             :                         }
     295        1580 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     296          14 :                                 nanti = true;
     297             :                 }
     298      136676 :         } else if (!*unknown) {
     299      130425 :                 const void *nilptr = ATOMnilptr(b->ttype);
     300      260517 :                 if (nli && nhi && nilptr != NULL &&
     301      130463 :                         ATOMcmp(b->ttype, low, nilptr) == 0 &&
     302          24 :                         ATOMcmp(b->ttype, high, nilptr) == 0) {
     303             :                         /* special case: equi-select for NIL */
     304      137913 :                         high = NULL;
     305             :                 }
     306             :         }
     307             : 
     308      137913 :         bn = BATselect(b, s, low, high, nli, nhi, nanti, false);
     309      136929 :         BBPunfix(b->batCacheid);
     310      138186 :         BBPreclaim(s);
     311      138087 :         if (bn == NULL)
     312           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     313      138087 :         *result = bn->batCacheid;
     314      138087 :         BBPkeepref(bn);
     315      138087 :         return MAL_SUCCEED;
     316             : }
     317             : 
     318             : static str
     319       40862 : ALGselect2(bat *result, const bat *bid, const bat *sid, const void *low,
     320             :                    const void *high, const bit *li, const bit *hi, const bit *anti)
     321             : {
     322       40862 :         return ALGselect2nil(result, bid, sid, low, high, li, hi, anti, &(bit){0});
     323             : }
     324             : 
     325             : static str
     326       89089 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     327             :                    const bit *li, const bit *hi, const bit *anti)
     328             : {
     329       89089 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, &(bit){0});
     330             : }
     331             : 
     332             : static str
     333         308 : ALGselect1nil(bat *result, const bat *bid, const void *low, const void *high,
     334             :                           const bit *li, const bit *hi, const bit *anti, const bit *unknown)
     335             : {
     336         308 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     337             : }
     338             : 
     339             : static str
     340      526247 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     341             :                                 const char **op)
     342             : {
     343      526247 :         BAT *b, *s = NULL, *bn;
     344             : 
     345      526247 :         if ((b = BATdescriptor(*bid)) == NULL) {
     346           0 :                 throw(MAL, "algebra.thetaselect",
     347             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     348             :         }
     349      528644 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     350           0 :                 BBPunfix(b->batCacheid);
     351           0 :                 throw(MAL, "algebra.thetaselect",
     352             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     353             :         }
     354      528897 :         derefStr(b, val);
     355      528897 :         bn = BATthetaselect(b, s, val, *op);
     356      526197 :         BBPunfix(b->batCacheid);
     357      528523 :         BBPreclaim(s);
     358      528528 :         if (bn == NULL)
     359           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     360      528528 :         *result = bn->batCacheid;
     361      528528 :         BBPkeepref(bn);
     362      528528 :         return MAL_SUCCEED;
     363             : }
     364             : 
     365             : static str
     366         398 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     367             : {
     368         398 :         BAT *g = BATdescriptor(*gid); /* oid */
     369         398 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     370         398 :         BAT *p = BATdescriptor(*pid); /* bit */
     371         398 :         BAT *res1 = NULL, *res2 = NULL;
     372         398 :         bit any = *Any; /* any or normal comparison semantics */
     373             : 
     374         398 :         if (!g || !m || !p) {
     375           0 :                 if (g) BBPreclaim(g);
     376           0 :                 if (m) BBPreclaim(m);
     377           0 :                 if (p) BBPreclaim(p);
     378           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     379             :         }
     380         398 :         BUN nr = BATcount(g), q = 0;
     381             : 
     382         398 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     383             :                 BBPreclaim(g);
     384           0 :                 BBPreclaim(m);
     385           0 :                 BBPreclaim(p);
     386           0 :                 if (res1) BBPreclaim(res1);
     387           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     388             :         }
     389         398 :         assert(g->tsorted);
     390         398 :         oid *ri1 = Tloc(res1, 0);
     391         398 :         bit *ri2 = Tloc(res2, 0);
     392         398 :         bit *mi = Tloc(m, 0);
     393         398 :         bit *pi = Tloc(p, 0);
     394         398 :         oid cur = oid_nil;
     395             : 
     396         398 :         if (g->ttype == TYPE_void) { /* void case ? */
     397          33 :                 oid c = g->hseqbase;
     398         131 :                 for (BUN n = 0; n < nr; n++, c++) {
     399          98 :                         ri1[q] = c;
     400          98 :                         ri2[q] = FALSE;
     401          98 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     402           7 :                                 ri2[q] = TRUE;
     403          91 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     404           7 :                                 ri2[q] = bit_nil;
     405          98 :                         q++;
     406             :                 }
     407             :         } else {
     408         365 :                 oid *gi = Tloc(g, 0);
     409         365 :                 oid c = g->hseqbase;
     410         365 :                 if (nr)
     411         365 :                         cur = gi[0];
     412             :                 bit m = FALSE;
     413             :                 bool has_nil = false;
     414      332661 :                 for (BUN n = 0; n < nr; n++, c++) {
     415      332296 :                         if (c && cur != gi[n]) {
     416       57735 :                                 ri1[q] = c-1;
     417       57735 :                                 ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     418       57735 :                                 q++;
     419       57735 :                                 cur = gi[n];
     420       57735 :                                 m = FALSE;
     421       57735 :                                 has_nil = false;
     422             :                         }
     423      332296 :                         if (m == TRUE)
     424      191843 :                                 continue;
     425             : 
     426      140453 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     427             :                                 m = TRUE;
     428      133526 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     429      332296 :                                 has_nil = true;
     430             :                 }
     431         365 :                 if (nr) {
     432         365 :                         ri1[q] = c-1;
     433         365 :                         ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     434             :                 }
     435         365 :                 q++;
     436             :         }
     437         398 :         BATsetcount(res1, q);
     438         398 :         BATsetcount(res2, q);
     439         398 :         res1->tsorted = true;
     440         398 :         res1->tkey = true;
     441         398 :         res1->trevsorted = false;
     442         398 :         res2->tsorted = false;
     443         398 :         res2->trevsorted = false;
     444         398 :         res1->tnil = false;
     445         398 :         res1->tnonil = true;
     446         398 :         res2->tnonil = false;
     447         398 :         res2->tkey = false;
     448             : 
     449         398 :         BBPreclaim(g);
     450         398 :         BBPreclaim(m);
     451         398 :         BBPreclaim(p);
     452             : 
     453         398 :         BBPkeepref(res1);
     454         398 :         BBPkeepref(res2);
     455         398 :         *r1 = res1->batCacheid;
     456         398 :         *r2 = res2->batCacheid;
     457         398 :         return MAL_SUCCEED;
     458             : }
     459             : 
     460             : static str
     461          38 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     462             : {
     463          38 :         BAT *g = BATdescriptor(*gid); /* oid */
     464          38 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     465          38 :         BAT *p = BATdescriptor(*pid); /* bit */
     466          38 :         BAT *res1 = NULL, *res2 = NULL;
     467          38 :         bit any = *Any; /* any or normal comparison semantics */
     468             : 
     469          38 :         if (!g || !m || !p) {
     470           0 :                 if (g) BBPreclaim(g);
     471           0 :                 if (m) BBPreclaim(m);
     472           0 :                 if (p) BBPreclaim(p);
     473           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     474             :         }
     475          38 :         BUN nr = BATcount(g), q = 0;
     476             : 
     477          38 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     478             :                 BBPreclaim(g);
     479           0 :                 BBPreclaim(m);
     480           0 :                 BBPreclaim(p);
     481           0 :                 if (res1) BBPreclaim(res1);
     482           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     483             :         }
     484          38 :         assert(g->tsorted);
     485          38 :         oid *ri1 = Tloc(res1, 0);
     486          38 :         bit *ri2 = Tloc(res2, 0);
     487          38 :         bit *mi = Tloc(m, 0);
     488          38 :         bit *pi = Tloc(p, 0);
     489          38 :         oid cur = oid_nil;
     490             : 
     491          38 :         if (g->ttype == TYPE_void) { /* void case ? */
     492          12 :                 oid c = g->hseqbase;
     493         101 :                 for (BUN n = 0; n < nr; n++, c++) {
     494          89 :                         ri1[q] = c;
     495         161 :                         ri2[q] = (any && (mi[n] == bit_nil || pi[n] == bit_nil))?bit_nil:(mi[n] == TRUE && pi[n] == TRUE)?TRUE:FALSE;
     496          89 :                         q++;
     497             :                 }
     498             :         } else {
     499          26 :                 oid *gi = Tloc(g, 0);
     500          26 :                 oid c = g->hseqbase;
     501          26 :                 if (nr)
     502          26 :                         cur = gi[0];
     503             :                 bool used = false;
     504         602 :                 for (BUN n = 0; n < nr; n++, c++) {
     505         576 :                         if (c && cur != gi[n]) {
     506         159 :                                 if (!used) {
     507           3 :                                         ri1[q] = c-1;
     508           3 :                                         ri2[q] = false;
     509           3 :                                         q++;
     510             :                                 }
     511         159 :                                 used = false;
     512         159 :                                 cur = gi[n];
     513             :                         }
     514         576 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     515         322 :                                 ri1[q] = c;
     516         322 :                                 ri2[q] = TRUE;
     517         322 :                                 used = true;
     518         322 :                                 q++;
     519         254 :                         } else if (mi[n] == FALSE) { /* empty */
     520          55 :                                 ri1[q] = c;
     521          55 :                                 ri2[q] = FALSE;
     522          55 :                                 used = true;
     523          55 :                                 q++;
     524         199 :                         } else if (any && (mi[n] == bit_nil /* ie has nil */ || pi[n] == bit_nil)) {
     525           6 :                                 ri1[q] = c;
     526           6 :                                 ri2[q] = bit_nil;
     527           6 :                                 used = true;
     528           6 :                                 q++;
     529             :                         }
     530             :                 }
     531          26 :                 if (nr && !used) {
     532           1 :                         ri1[q] = c-1;
     533           1 :                         ri2[q] = FALSE;
     534           1 :                         q++;
     535             :                 }
     536             :         }
     537          38 :         BATsetcount(res1, q);
     538          38 :         BATsetcount(res2, q);
     539          38 :         res1->tsorted = true;
     540          38 :         res1->tkey = true;
     541          38 :         res1->trevsorted = false;
     542          38 :         res2->tsorted = false;
     543          38 :         res2->trevsorted = false;
     544          38 :         res1->tnil = false;
     545          38 :         res1->tnonil = true;
     546          38 :         res2->tnonil = false;
     547          38 :         res2->tkey = false;
     548             : 
     549          38 :         BBPreclaim(g);
     550          38 :         BBPreclaim(m);
     551          38 :         BBPreclaim(p);
     552             : 
     553          38 :         BBPkeepref(res1);
     554          38 :         BBPkeepref(res2);
     555          38 :         *r1 = res1->batCacheid;
     556          38 :         *r2 = res2->batCacheid;
     557          38 :         return MAL_SUCCEED;
     558             : }
     559             : 
     560             : 
     561             : static str
     562        1583 : ALGselectNotNil(bat *result, const bat *bid)
     563             : {
     564        1583 :         BAT *b;
     565             : 
     566        1583 :         if ((b = BATdescriptor(*bid)) == NULL)
     567           0 :                 throw(MAL, "algebra.selectNotNil",
     568             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     569             : 
     570        1585 :         MT_lock_set(&b->theaplock);
     571        1585 :         bool bnonil = b->tnonil || b->ttype == TYPE_msk;
     572        1585 :         MT_lock_unset(&b->theaplock);
     573        1586 :         if (!bnonil) {
     574         125 :                 BAT *s;
     575         125 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true, false);
     576         124 :                 if (s) {
     577         124 :                         BAT *bn = BATproject(s, b);
     578         125 :                         BBPunfix(s->batCacheid);
     579         125 :                         if (bn) {
     580         125 :                                 BBPunfix(b->batCacheid);
     581         125 :                                 *result = bn->batCacheid;
     582         125 :                                 BBPkeepref(bn);
     583         125 :                                 return MAL_SUCCEED;
     584             :                         }
     585             :                 }
     586           0 :                 BBPunfix(b->batCacheid);
     587           0 :                 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
     588             :         }
     589             :         /* just pass on the result */
     590        1461 :         *result = b->batCacheid;
     591        1461 :         BBPkeepref(b);
     592        1461 :         return MAL_SUCCEED;
     593             : }
     594             : 
     595             : static str
     596      647780 : do_join(bat *r1, bat *r2, bat *r3, const bat *lid, const bat *rid, const bat *r2id, const bat *slid, const bat *srid, int op, const void *c1, const void *c2, bool li, bool hi, bool anti, bool symmetric,      /* these two only for rangejoin */
     597             :                 const bit *nil_matches, const bit *not_in, const bit *max_one,
     598             :                 const lng *estimate,
     599             :                 gdk_return (*joinfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     600             :                                                            bool, BUN),
     601             :                 gdk_return (*semifunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     602             :                                                           bool, bool, BUN),
     603             :                 gdk_return (*markfunc)(BAT **, BAT **, BAT **,
     604             :                                                            BAT *, BAT *, BAT *, BAT *, BUN),
     605             :                 gdk_return (*thetafunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     606             :                                                            int, bool, BUN),
     607             :                 gdk_return (*bandfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     608             :                                                           const void *, const void *, bool, bool, BUN),
     609             :                 gdk_return (*rangefunc)(BAT **, BAT **, BAT *, BAT *, BAT *,
     610             :                                                            BAT *, BAT *, bool, bool, bool, bool, BUN),
     611             :                 BAT * (*difffunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     612             :                 BAT * (*interfunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     613             :                 const char *funcname)
     614             : {
     615      647780 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     616      647780 :         BAT *candleft = NULL, *candright = NULL;
     617      647780 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     618      647780 :         BUN est;
     619      647780 :         const char *err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     620             : 
     621      647780 :         assert(r2id == NULL || rangefunc != NULL);
     622             : 
     623      647780 :         if ((left = BATdescriptor(*lid)) == NULL)
     624           0 :                 goto fail;
     625      654521 :         if ((right = BATdescriptor(*rid)) == NULL)
     626           0 :                 goto fail;
     627      654519 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     628           0 :                 goto fail;
     629      654522 :         if (srid && !is_bat_nil(*srid)
     630           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     631           0 :                 goto fail;
     632      654522 :         if (estimate == NULL || *estimate < 0 || is_lng_nil(*estimate)
     633           0 :                 || *estimate > (lng) BUN_MAX)
     634             :                 est = BUN_NONE;
     635             :         else
     636           0 :                 est = (BUN) *estimate;
     637             : 
     638      654522 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     639             : 
     640      654522 :         if (thetafunc) {
     641       51398 :                 assert(joinfunc == NULL);
     642       51398 :                 assert(semifunc == NULL);
     643       51398 :                 assert(markfunc == NULL);
     644       51398 :                 assert(bandfunc == NULL);
     645       51398 :                 assert(rangefunc == NULL);
     646       51398 :                 assert(difffunc == NULL);
     647       51398 :                 assert(interfunc == NULL);
     648       51398 :                 if ((*thetafunc)
     649             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     650       51398 :                          op, *nil_matches, est) != GDK_SUCCEED)
     651           0 :                         goto fail;
     652      603124 :         } else if (joinfunc) {
     653      413129 :                 assert(semifunc == NULL);
     654      413129 :                 assert(markfunc == NULL);
     655      413129 :                 assert(bandfunc == NULL);
     656      413129 :                 assert(rangefunc == NULL);
     657      413129 :                 assert(difffunc == NULL);
     658      413129 :                 assert(interfunc == NULL);
     659      413129 :                 if ((*joinfunc)
     660             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     661      413129 :                          *nil_matches, est) != GDK_SUCCEED)
     662           1 :                         goto fail;
     663      189995 :         } else if (semifunc) {
     664         334 :                 assert(markfunc == NULL);
     665         334 :                 assert(bandfunc == NULL);
     666         334 :                 assert(rangefunc == NULL);
     667         334 :                 assert(difffunc == NULL);
     668         334 :                 assert(interfunc == NULL);
     669         334 :                 if ((*semifunc)
     670             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     671         334 :                          *nil_matches, *max_one, est) != GDK_SUCCEED)
     672          44 :                         goto fail;
     673      189661 :         } else if (markfunc) {
     674       19347 :                 assert(bandfunc == NULL);
     675       19347 :                 assert(rangefunc == NULL);
     676       19347 :                 assert(difffunc == NULL);
     677       19347 :                 assert(interfunc == NULL);
     678       38688 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     679             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     680           0 :                         goto fail;
     681      170314 :         } else if (bandfunc) {
     682           0 :                 assert(rangefunc == NULL);
     683           0 :                 assert(difffunc == NULL);
     684           0 :                 assert(interfunc == NULL);
     685           0 :                 if ((*bandfunc)
     686             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     687             :                          c1, c2, li, hi, est) != GDK_SUCCEED)
     688           0 :                         goto fail;
     689      170314 :         } else if (rangefunc) {
     690         147 :                 assert(difffunc == NULL);
     691         147 :                 assert(interfunc == NULL);
     692         147 :                 if ((right2 = BATdescriptor(*r2id)) == NULL) {
     693           0 :                         err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     694           0 :                         goto fail;
     695             :                 }
     696         172 :                 if ((*rangefunc)
     697             :                         (&result1, r2 ? &result2 : NULL, left, right, right2, candleft,
     698             :                          candright, li, hi, anti, symmetric, est) != GDK_SUCCEED)
     699           0 :                         goto fail;
     700         144 :                 BBPunfix(right2->batCacheid);
     701      170167 :         } else if (difffunc) {
     702      160510 :                 assert(r2 == NULL);
     703      160510 :                 assert(interfunc == NULL);
     704      160226 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     705      160510 :                                                                         *nil_matches, *not_in, est)) == NULL)
     706           0 :                         goto fail;
     707             :         } else {
     708        9657 :                 assert(r2 == NULL);
     709        9615 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     710        9657 :                                                                          *nil_matches, *max_one, est)) == NULL)
     711           1 :                         goto fail;
     712             :         }
     713      649825 :         *r1 = result1->batCacheid;
     714      649825 :         BBPkeepref(result1);
     715      652460 :         if (r2) {
     716      376929 :                 *r2 = result2->batCacheid;
     717      376929 :                 BBPkeepref(result2);
     718             :         }
     719      653282 :         if (r3) {
     720       19284 :                 *r3 = result3->batCacheid;
     721       19284 :                 BBPkeepref(result3);
     722             :         }
     723      653313 :         BBPunfix(left->batCacheid);
     724      653915 :         BBPunfix(right->batCacheid);
     725      654389 :         BBPreclaim(candleft);
     726      654414 :         BBPreclaim(candright);
     727             :         return MAL_SUCCEED;
     728             : 
     729          46 :   fail:
     730          46 :         BBPreclaim(left);
     731          46 :         BBPreclaim(right);
     732          46 :         BBPreclaim(right2);
     733          46 :         BBPreclaim(candleft);
     734          46 :         BBPreclaim(candright);
     735          46 :         if (err == NULL)
     736          46 :                 throw(MAL, funcname, GDK_EXCEPTION);
     737           0 :         throw(MAL, funcname, "%s", err);
     738             : }
     739             : 
     740             : static str
     741      366208 : ALGjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     742             :                 const bat *srid, const bit *nil_matches, const lng *estimate)
     743             : {
     744      366208 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     745             :                                    false, false, false, false, nil_matches, NULL, NULL,
     746             :                                    estimate, BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     747             :                                    "algebra.join");
     748             : }
     749             : 
     750             : static str
     751       43365 : ALGjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     752             :                  const bat *srid, const bit *nil_matches, const lng *estimate)
     753             : {
     754       43365 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     755             :                                    false, false, false, false, nil_matches, NULL, NULL,
     756             :                                    estimate, BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     757             :                                    "algebra.join");
     758             : }
     759             : 
     760             : static str
     761         645 : ALGleftjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     762             :                         const bat *srid, const bit *nil_matches, const lng *estimate)
     763             : {
     764         645 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     765             :                                    false, false, false, false, nil_matches, NULL, NULL,
     766             :                                    estimate, BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     767             :                                    "algebra.leftjoin");
     768             : }
     769             : 
     770             : static str
     771           0 : ALGleftjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     772             :                          const bat *srid, const bit *nil_matches, const lng *estimate)
     773             : {
     774           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     775             :                                    false, false, false, false, nil_matches, NULL, NULL,
     776             :                                    estimate, BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     777             :                                    "algebra.leftjoin");
     778             : }
     779             : 
     780             : static str
     781         119 : ALGouterjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     782             :                          const bat *srid, const bit *nil_matches, const bit *match_one,
     783             :                          const lng *estimate)
     784             : {
     785         119 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     786             :                                    false, false, false, false, nil_matches, NULL, match_one,
     787             :                                    estimate, NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, NULL,
     788             :                                    "algebra.outerjoin");
     789             : }
     790             : 
     791             : static str
     792           0 : ALGouterjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     793             :                           const bat *srid, const bit *nil_matches, const bit *match_one,
     794             :                           const lng *estimate)
     795             : {
     796           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     797             :                                    false, false, false, false, nil_matches, NULL, match_one,
     798             :                                    estimate, NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, NULL,
     799             :                                    "algebra.outerjoin");
     800             : }
     801             : 
     802             : static str
     803         211 : ALGsemijoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     804             :                         const bat *srid, const bit *nil_matches, const bit *max_one,
     805             :                         const lng *estimate)
     806             : {
     807         211 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     808             :                                    false, false, false, false, nil_matches, NULL, max_one,
     809             :                                    estimate, NULL, BATsemijoin, NULL, NULL, NULL, NULL, NULL, NULL,
     810             :                                    "algebra.semijoin");
     811             : }
     812             : 
     813             : static str
     814       19265 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     815             :                          const bat *slid, const bat *srid, const lng *estimate)
     816             : {
     817       19265 :         return do_join(r1, NULL, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     818             :                                    false, false, false, false, NULL, NULL, NULL,
     819             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     820             :                                    "algebra.markjoin");
     821             : }
     822             : 
     823             : static str
     824           5 : ALGmark3join(bat *r1, bat *r2, bat *r3, const bat *lid, const bat *rid,
     825             :                          const bat *slid, const bat *srid, const lng *estimate)
     826             : {
     827           5 :         return do_join(r1, r2, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     828             :                                    false, false, false, false, NULL, NULL, NULL,
     829             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     830             :                                    "algebra.markjoin");
     831             : }
     832             : 
     833             : static str
     834        7685 : ALGthetajoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     835             :                          const bat *srid, const int *op, const bit *nil_matches,
     836             :                          const lng *estimate)
     837             : {
     838        7685 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     839             :                                    false, false, false, false, nil_matches, NULL, NULL,
     840             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     841             :                                    "algebra.thetajoin");
     842             : }
     843             : 
     844             : static str
     845       41396 : ALGthetajoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     846             :                           const bat *srid, const int *op, const bit *nil_matches,
     847             :                           const lng *estimate)
     848             : {
     849       41396 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     850             :                                    false, false, false, false, nil_matches, NULL, NULL,
     851             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     852             :                                    "algebra.thetajoin");
     853             : }
     854             : 
     855             : static str
     856           0 : ALGbandjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     857             :                         const bat *srid, const void *c1, const void *c2, const bit *li,
     858             :                         const bit *hi, const lng *estimate)
     859             : {
     860           0 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     861           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     862             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     863             :                                    "algebra.bandjoin");
     864             : }
     865             : 
     866             : static str
     867           0 : ALGbandjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     868             :                          const bat *srid, const void *c1, const void *c2, const bit *li,
     869             :                          const bit *hi, const lng *estimate)
     870             : {
     871           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     872           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     873             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     874             :                                    "algebra.bandjoin");
     875             : }
     876             : 
     877             : static str
     878         117 : ALGrangejoin(bat *r1, bat *r2, const bat *lid, const bat *rlid, const bat *rhid,
     879             :                          const bat *slid, const bat *srid, const bit *li, const bit *hi,
     880             :                          const bit *anti, const bit *symmetric, const lng *estimate)
     881             : {
     882         239 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     883         117 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     884             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     885             :                                    "algebra.rangejoin");
     886             : }
     887             : 
     888             : static str
     889          23 : ALGrangejoin1(bat *r1, const bat *lid, const bat *rlid, const bat *rhid,
     890             :                           const bat *slid, const bat *srid, const bit *li, const bit *hi,
     891             :                           const bit *anti, const bit *symmetric, const lng *estimate)
     892             : {
     893          48 :         return do_join(r1, NULL, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     894          23 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     895             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     896             :                                    "algebra.rangejoin");
     897             : }
     898             : 
     899             : static str
     900      160447 : ALGdifference(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     901             :                           const bat *srid, const bit *nil_matches, const bit *not_in,
     902             :                           const lng *estimate)
     903             : {
     904      160447 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     905             :                                    false, false, false, false, nil_matches, not_in, NULL,
     906             :                                    estimate, NULL, NULL, NULL, NULL, NULL, NULL, BATdiff, NULL,
     907             :                                    "algebra.difference");
     908             : }
     909             : 
     910             : static str
     911        9645 : ALGintersect(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     912             :                          const bat *srid, const bit *nil_matches, const bit *max_one,
     913             :                          const lng *estimate)
     914             : {
     915        9645 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     916             :                                    false, false, false, false, nil_matches, NULL, max_one,
     917             :                                    estimate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, BATintersect,
     918             :                                    "algebra.intersect");
     919             : }
     920             : 
     921             : /* algebra.firstn(b:bat[:any],
     922             :  *                [ s:bat[:oid],
     923             :  *                [ g:bat[:oid], ] ]
     924             :  *                n:lng,
     925             :  *                asc:bit,
     926             :  *                nilslast:bit,
     927             :  *                distinct:bit)
     928             :  * returns :bat[:oid] [ , :bat[:oid] ]
     929             :  */
     930             : static str
     931        1717 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     932             : {
     933        1717 :         bat *ret1, *ret2 = NULL;
     934        1717 :         bat bid, sid, gid;
     935        1717 :         BAT *b, *s = NULL, *g = NULL;
     936        1717 :         BAT *bn = NULL, *gn = NULL;
     937        1717 :         lng n;
     938        1717 :         bit asc, nilslast, distinct;
     939        1717 :         gdk_return rc;
     940             : 
     941        1717 :         (void) cntxt;
     942        1717 :         (void) mb;
     943             : 
     944        1717 :         assert(pci->retc == 1 || pci->retc == 2);
     945        1717 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     946             : 
     947        1717 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     948        1717 :         if (n < 0)
     949           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     950        1717 :         if (n > (lng) BUN_MAX)
     951             :                 n = BUN_MAX;
     952        1717 :         ret1 = getArgReference_bat(stk, pci, 0);
     953        1717 :         if (pci->retc == 2)
     954         621 :                 ret2 = getArgReference_bat(stk, pci, 1);
     955        1717 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     956        1717 :         if ((b = BATdescriptor(bid)) == NULL)
     957           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     958        1718 :         if (pci->argc - pci->retc > 5) {
     959        1718 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     960        1718 :                 if (!is_bat_nil(sid) && (s = BATdescriptor(sid)) == NULL) {
     961           0 :                         BBPunfix(bid);
     962           0 :                         throw(MAL, "algebra.firstn",
     963             :                                   SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     964             :                 }
     965        1719 :                 if (pci->argc - pci->retc > 6) {
     966        1719 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     967        1719 :                         if (!is_bat_nil(gid) && (g = BATdescriptor(gid)) == NULL) {
     968           0 :                                 BBPunfix(bid);
     969           0 :                                 BBPunfix(sid);
     970           0 :                                 throw(MAL, "algebra.firstn",
     971             :                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     972             :                         }
     973             :                 }
     974             :         }
     975        1719 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     976        1719 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     977        1719 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
     978        2818 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
     979             :                                    distinct);
     980        1719 :         BBPunfix(b->batCacheid);
     981        1723 :         BBPreclaim(s);
     982        1720 :         BBPreclaim(g);
     983        1722 :         if (rc != GDK_SUCCEED)
     984           0 :                 throw(MAL, "algebra.firstn", GDK_EXCEPTION);
     985        1722 :         *ret1 = bn->batCacheid;
     986        1722 :         BBPkeepref(bn);
     987        1717 :         if (ret2) {
     988         622 :                 *ret2 = gn->batCacheid;
     989         622 :                 BBPkeepref(gn);
     990             :         }
     991             :         return MAL_SUCCEED;
     992             : }
     993             : 
     994             : static str
     995           6 : ALGgroupedfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     996             : {
     997           6 :         bat *ret;
     998           6 :         bat sid, gid;
     999           6 :         BAT *s = NULL, *g = NULL;
    1000           6 :         BAT *bn = NULL;
    1001           6 :         lng n;
    1002             : 
    1003           6 :         (void) cntxt;
    1004           6 :         (void) mb;
    1005             : 
    1006           6 :         n = *getArgReference_lng(stk, pci, 1);
    1007           6 :         if (n < 0)
    1008           0 :                 throw(MAL, "algebra.groupedfirstn", ILLEGAL_ARGUMENT);
    1009           6 :         ret = getArgReference_bat(stk, pci, 0);
    1010           6 :         sid = *getArgReference_bat(stk, pci, 2);
    1011           6 :         gid = *getArgReference_bat(stk, pci, 3);
    1012           6 :         int nbats = pci->argc - 4;
    1013           6 :         if (nbats % 3 != 0)
    1014           0 :                 throw(MAL, "algebra.groupedfirstn", ILLEGAL_ARGUMENT);
    1015           6 :         nbats /= 3;
    1016           6 :         BAT **bats = GDKmalloc(nbats * sizeof(BAT *));
    1017           6 :         bool *ascs = GDKmalloc(nbats * sizeof(bool));
    1018           6 :         bool *nlss = GDKmalloc(nbats * sizeof(bool));
    1019           6 :         if (bats == NULL || ascs == NULL || nlss == NULL) {
    1020           0 :                 GDKfree(bats);
    1021           0 :                 GDKfree(ascs);
    1022           0 :                 GDKfree(nlss);
    1023           0 :                 throw(MAL, "algebra.groupedfirstn", MAL_MALLOC_FAIL);
    1024             :         }
    1025           6 :         if (!is_bat_nil(sid) && (s = BATdescriptor(sid)) == NULL) {
    1026           0 :                 GDKfree(bats);
    1027           0 :                 GDKfree(ascs);
    1028           0 :                 GDKfree(nlss);
    1029           0 :                 throw(MAL, "algebra.groupedfirstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1030             :         }
    1031           6 :         if (!is_bat_nil(gid) && (g = BATdescriptor(gid)) == NULL) {
    1032           0 :                 BBPreclaim(s);
    1033           0 :                 GDKfree(bats);
    1034           0 :                 GDKfree(ascs);
    1035           0 :                 GDKfree(nlss);
    1036           0 :                 throw(MAL, "algebra.groupedfirstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1037             :         }
    1038          12 :         for (int i = 0; i < nbats; i++) {
    1039           6 :                 bats[i] = BATdescriptor(*getArgReference_bat(stk, pci, i * 3 + 4));
    1040           6 :                 if (bats[i] == NULL) {
    1041           0 :                         while (i > 0)
    1042           0 :                                 BBPreclaim(bats[--i]);
    1043           0 :                         BBPreclaim(g);
    1044           0 :                         BBPreclaim(s);
    1045           0 :                         GDKfree(bats);
    1046           0 :                         GDKfree(ascs);
    1047           0 :                         GDKfree(nlss);
    1048           0 :                         throw(MAL, "algebra.groupedfirstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1049             :                 }
    1050           6 :                 ascs[i] = *getArgReference_bit(stk, pci, i * 3 + 5);
    1051           6 :                 nlss[i] = *getArgReference_bit(stk, pci, i * 3 + 6);
    1052             :         }
    1053           6 :         bn = BATgroupedfirstn((BUN) n, s, g, nbats, bats, ascs, nlss);
    1054           6 :         BBPreclaim(s);
    1055           6 :         BBPreclaim(g);
    1056          12 :         for (int i = 0; i < nbats; i++)
    1057          12 :                 BBPreclaim(bats[i]);
    1058           6 :         GDKfree(bats);
    1059           6 :         GDKfree(ascs);
    1060           6 :         GDKfree(nlss);
    1061           6 :         if (bn == NULL)
    1062           0 :                 throw(MAL, "algebra.groupedfirstn", GDK_EXCEPTION);
    1063           6 :         *ret = bn->batCacheid;
    1064           6 :         BBPkeepref(bn);
    1065           6 :         return MAL_SUCCEED;
    1066             : }
    1067             : 
    1068             : static str
    1069           9 : ALGunary(bat *result, const bat *bid, BAT *(*func)(BAT *), const char *name)
    1070             : {
    1071           9 :         BAT *b, *bn;
    1072             : 
    1073           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1074           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1075             :         }
    1076           9 :         bn = (*func) (b);
    1077           9 :         BBPunfix(b->batCacheid);
    1078           9 :         if (bn == NULL)
    1079           0 :                 throw(MAL, name, GDK_EXCEPTION);
    1080           9 :         *result = bn->batCacheid;
    1081           9 :         BBPkeepref(bn);
    1082           9 :         return MAL_SUCCEED;
    1083             : }
    1084             : 
    1085             : static inline BAT *
    1086           9 : BATwcopy(BAT *b)
    1087             : {
    1088           9 :         return COLcopy(b, b->ttype, true, TRANSIENT);
    1089             : }
    1090             : 
    1091             : static str
    1092           9 : ALGcopy(bat *result, const bat *bid)
    1093             : {
    1094           9 :         return ALGunary(result, bid, BATwcopy, "algebra.copy");
    1095             : }
    1096             : 
    1097             : static str
    1098          74 : ALGunique(bat *result, const bat *bid, const bat *sid)
    1099             : {
    1100          74 :         BAT *b, *s = NULL, *bn = NULL;
    1101             : 
    1102          74 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1103           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1104             :         }
    1105          74 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
    1106           0 :                 BBPunfix(b->batCacheid);
    1107           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1108             :         }
    1109          74 :         bn = BATunique(b, s);
    1110          74 :         BBPunfix(b->batCacheid);
    1111          74 :         BBPreclaim(s);
    1112          74 :         if (bn == NULL)
    1113           0 :                 throw(MAL, "algebra.unique", GDK_EXCEPTION);
    1114          74 :         *result = bn->batCacheid;
    1115          74 :         BBPkeepref(bn);
    1116          74 :         return MAL_SUCCEED;
    1117             : }
    1118             : 
    1119             : static str
    1120       45503 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1121             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1122             : {
    1123       45503 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1124       45503 :         BAT *sl = NULL, *sr = NULL;
    1125       45503 :         gdk_return ret;
    1126             : 
    1127       45503 :         L = BATdescriptor(*left);
    1128       46918 :         R = BATdescriptor(*right);
    1129       46991 :         if (L == NULL || R == NULL) {
    1130           0 :                 BBPreclaim(L);
    1131           0 :                 BBPreclaim(R);
    1132           0 :                 throw(MAL, "algebra.crossproduct",
    1133             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1134             :         }
    1135       46991 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1136           0 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1137           0 :                 BBPunfix(L->batCacheid);
    1138           0 :                 BBPunfix(R->batCacheid);
    1139           0 :                 BBPreclaim(sl);
    1140             :                 /* sr == NULL, so no need to unfix */
    1141           0 :                 throw(MAL, "algebra.crossproduct",
    1142             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1143             :         }
    1144       48802 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1145       46991 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1146       46412 :         BBPunfix(L->batCacheid);
    1147       46925 :         BBPunfix(R->batCacheid);
    1148       46999 :         BBPreclaim(sl);
    1149       46999 :         BBPreclaim(sr);
    1150       46995 :         if (ret != GDK_SUCCEED)
    1151          88 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1152       46907 :         *l = bn1->batCacheid;
    1153       46907 :         BBPkeepref(bn1);
    1154       46862 :         if (r) {
    1155       45066 :                 *r = bn2->batCacheid;
    1156       45066 :                 BBPkeepref(bn2);
    1157             :         }
    1158             :         return MAL_SUCCEED;
    1159             : }
    1160             : 
    1161             : static str
    1162        1767 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1163             : {
    1164        1767 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1165             : }
    1166             : 
    1167             : static str
    1168       43797 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1169             :                                  const bit *max_one)
    1170             : {
    1171       43797 :         return ALGcrossproduct(l, r, left, right, NULL, NULL, max_one);
    1172             : }
    1173             : 
    1174             : static str
    1175           0 : ALGcrossproduct3(bat *l, bat *r, const bat *left, const bat *right,
    1176             :                                  const bat *sl, const bat *sr, const bit *max_one)
    1177             : {
    1178           0 :         return ALGcrossproduct(l, r, left, right, sl, sr, max_one);
    1179             : }
    1180             : 
    1181             : static str
    1182           0 : ALGcrossproduct4(bat *l, const bat *left, const bat *right, const bat *sl,
    1183             :                                  const bat *sr, const bit *max_one)
    1184             : {
    1185           0 :         return ALGcrossproduct(l, NULL, left, right, sl, sr, max_one);
    1186             : }
    1187             : 
    1188             : static str
    1189         427 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1190             : {
    1191         427 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1192         427 :         BAT *sl = NULL, *sr = NULL;
    1193         427 :         gdk_return ret;
    1194             : 
    1195         427 :         L = BATdescriptor(*left);
    1196         427 :         R = BATdescriptor(*right);
    1197         427 :         if (L == NULL || R == NULL) {
    1198           0 :                 BBPreclaim(L);
    1199           0 :                 BBPreclaim(R);
    1200           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1201             :         }
    1202         427 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1203         427 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1204           0 :                 BBPunfix(L->batCacheid);
    1205           0 :                 BBPunfix(R->batCacheid);
    1206           0 :                 BBPreclaim(sl);
    1207             :                 /* sr == NULL, so no need to unfix */
    1208           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1209             :         }
    1210         427 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1211         427 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1212         427 :         BBPunfix(L->batCacheid);
    1213         427 :         BBPunfix(R->batCacheid);
    1214         427 :         BBPreclaim(sl);
    1215         427 :         BBPreclaim(sr);
    1216         427 :         if (ret != GDK_SUCCEED)
    1217           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1218         427 :         *l = bn1->batCacheid;
    1219         427 :         BBPkeepref(bn1);
    1220         427 :         if (r) {
    1221         427 :                 *r = bn2->batCacheid;
    1222         427 :                 BBPkeepref(bn2);
    1223             :         }
    1224             :         return MAL_SUCCEED;
    1225             : }
    1226             : 
    1227             : static str
    1228     1991435 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1229             : {
    1230     1991435 :         BAT *l, *r1, *r2 = NULL, *bn;
    1231             : 
    1232     1991435 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1233           0 :                 throw(MAL, "algebra.projection",
    1234             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1235             :         }
    1236     2003602 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1237           0 :                 BBPunfix(l->batCacheid);
    1238           0 :                 throw(MAL, "algebra.projection",
    1239             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1240             :         }
    1241     2002673 :         if (r2id && !is_bat_nil(*r2id) && (r2 = BATdescriptor(*r2id)) == NULL) {
    1242           0 :                 BBPunfix(l->batCacheid);
    1243           0 :                 BBPunfix(r1->batCacheid);
    1244           0 :                 throw(MAL, "algebra.projection",
    1245             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1246             :         }
    1247     2002673 :         bn = BATproject2(l, r1, r2);
    1248     1976181 :         BBPunfix(l->batCacheid);
    1249     1999932 :         BBPunfix(r1->batCacheid);
    1250     2002541 :         BBPreclaim(r2);
    1251     2002737 :         if (bn == NULL)
    1252           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1253     2002737 :         *result = bn->batCacheid;
    1254     2002737 :         BBPkeepref(bn);
    1255     2002737 :         return MAL_SUCCEED;
    1256             : }
    1257             : 
    1258             : str
    1259     1993312 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1260             : {
    1261     1993312 :         return ALGprojection2(result, lid, rid, NULL);
    1262             : }
    1263             : 
    1264             : static str
    1265       24717 : ALGsort33(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1266             :                   const bat *order, const bat *group, const bit *reverse,
    1267             :                   const bit *nilslast, const bit *stable)
    1268             : {
    1269       24717 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1270       24717 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1271             : 
    1272       24717 :         if ((b = BATdescriptor(*bid)) == NULL)
    1273           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1274       24717 :         if (order && !is_bat_nil(*order) && (o = BATdescriptor(*order)) == NULL) {
    1275           0 :                 BBPunfix(b->batCacheid);
    1276           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1277             :         }
    1278       24717 :         if (group &&!is_bat_nil(*group) && (g = BATdescriptor(*group)) == NULL) {
    1279           0 :                 BBPreclaim(o);
    1280           0 :                 BBPunfix(b->batCacheid);
    1281           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1282             :         }
    1283       28460 :         if (BATsort(result ? &bn : NULL,
    1284             :                                 norder ? &on : NULL,
    1285             :                                 ngroup ? &gn : NULL,
    1286       24717 :                                 b, o, g, *reverse, *nilslast, *stable) != GDK_SUCCEED) {
    1287           0 :                 BBPreclaim(o);
    1288           0 :                 BBPreclaim(g);
    1289           0 :                 BBPunfix(b->batCacheid);
    1290           0 :                 throw(MAL, "algebra.sort", GDK_EXCEPTION);
    1291             :         }
    1292       24717 :         BBPunfix(b->batCacheid);
    1293       24717 :         BBPreclaim(o);
    1294       24717 :         BBPreclaim(g);
    1295       24717 :         if (result) {
    1296       24717 :                 *result = bn->batCacheid;
    1297       24717 :                 BBPkeepref(bn);
    1298             :         }
    1299       24717 :         if (norder) {
    1300       20974 :                 *norder = on->batCacheid;
    1301       20974 :                 BBPkeepref(on);
    1302             :         }
    1303       24717 :         if (ngroup) {
    1304       14087 :                 *ngroup = gn->batCacheid;
    1305       14087 :                 BBPkeepref(gn);
    1306             :         }
    1307             :         return MAL_SUCCEED;
    1308             : }
    1309             : 
    1310             : static str
    1311        4284 : ALGsort32(bat *result, bat *norder, const bat *bid, const bat *order,
    1312             :                   const bat *group, const bit *reverse, const bit *nilslast,
    1313             :                   const bit *stable)
    1314             : {
    1315        4284 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast,
    1316             :                                          stable);
    1317             : }
    1318             : 
    1319             : static str
    1320        2078 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group,
    1321             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1322             : {
    1323        2078 :         return ALGsort33(result, NULL, NULL, bid, order, group, reverse, nilslast,
    1324             :                                          stable);
    1325             : }
    1326             : 
    1327             : static str
    1328           0 : ALGsort23(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1329             :                   const bat *order, const bit *reverse, const bit *nilslast,
    1330             :                   const bit *stable)
    1331             : {
    1332           0 :         return ALGsort33(result, norder, ngroup, bid, order, NULL, reverse,
    1333             :                                          nilslast, stable);
    1334             : }
    1335             : 
    1336             : static str
    1337           0 : ALGsort22(bat *result, bat *norder, const bat *bid, const bat *order,
    1338             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1339             : {
    1340           0 :         return ALGsort33(result, norder, NULL, bid, order, NULL, reverse, nilslast,
    1341             :                                          stable);
    1342             : }
    1343             : 
    1344             : static str
    1345           0 : ALGsort21(bat *result, const bat *bid, const bat *order, const bit *reverse,
    1346             :                   const bit *nilslast, const bit *stable)
    1347             : {
    1348           0 :         return ALGsort33(result, NULL, NULL, bid, order, NULL, reverse, nilslast,
    1349             :                                          stable);
    1350             : }
    1351             : 
    1352             : static str
    1353        6617 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1354             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1355             : {
    1356        6617 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1357             :                                          stable);
    1358             : }
    1359             : 
    1360             : static str
    1361        2603 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1362             :                   const bit *nilslast, const bit *stable)
    1363             : {
    1364        2603 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast,
    1365             :                                          stable);
    1366             : }
    1367             : 
    1368             : static str
    1369        1665 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast,
    1370             :                   const bit *stable)
    1371             : {
    1372        1665 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast,
    1373             :                                          stable);
    1374             : }
    1375             : 
    1376             : static str
    1377       70955 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1378             :                                 const bit *ignore_nils)
    1379             : {
    1380       70955 :         BAT *b, *s = NULL;
    1381             : 
    1382       70955 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1383           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1384             :         }
    1385       71242 :         if (cnd && !is_bat_nil(*cnd) && (s = BATdescriptor(*cnd)) == NULL) {
    1386           0 :                 BBPunfix(b->batCacheid);
    1387           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1388             :         }
    1389       71242 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1390          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1391       71212 :         } else if (*ignore_nils) {
    1392        1770 :                 *result = (lng) BATcount_no_nil(b, s);
    1393             :         } else {
    1394       69442 :                 struct canditer ci;
    1395       69442 :                 canditer_init(&ci, b, s);
    1396       69421 :                 *result = (lng) ci.ncand;
    1397             :         }
    1398       71219 :         BBPreclaim(s);
    1399       71219 :         BBPunfix(b->batCacheid);
    1400       71219 :         return MAL_SUCCEED;
    1401             : }
    1402             : 
    1403             : static str
    1404        1768 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1405             : {
    1406        1768 :         return ALGcountCND_nil(result, bid, NULL, ignore_nils);
    1407             : }
    1408             : 
    1409             : static str
    1410           0 : ALGcountCND_bat(lng *result, const bat *bid, const bat *cnd)
    1411             : {
    1412           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 0 });
    1413             : }
    1414             : 
    1415             : static str
    1416       69194 : ALGcount_bat(lng *result, const bat *bid)
    1417             : {
    1418       69194 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 0 });
    1419             : }
    1420             : 
    1421             : static str
    1422           0 : ALGcountCND_no_nil(lng *result, const bat *bid, const bat *cnd)
    1423             : {
    1424           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 1 });
    1425             : }
    1426             : 
    1427             : static str
    1428           0 : ALGcount_no_nil(lng *result, const bat *bid)
    1429             : {
    1430           0 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 1 });
    1431             : }
    1432             : 
    1433             : static str
    1434           6 : ALGslice(bat *ret, const bat *bid, const lng *start, const lng *end)
    1435             : {
    1436           6 :         BAT *b, *bn = NULL;
    1437             : 
    1438           6 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1439           0 :                 throw(MAL, "algebra.slice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1440             :         }
    1441           6 :         if (slice(&bn, b, *start, *end) == GDK_SUCCEED) {
    1442           6 :                 *ret = bn->batCacheid;
    1443           6 :                 BBPkeepref(bn);
    1444           6 :                 BBPunfix(b->batCacheid);
    1445           6 :                 return MAL_SUCCEED;
    1446             :         }
    1447           0 :         BBPunfix(b->batCacheid);
    1448           0 :         throw(MAL, "algebra.slice", GDK_EXCEPTION);
    1449             : }
    1450             : 
    1451             : static str
    1452           1 : ALGslice_int(bat *ret, const bat *bid, const int *start, const int *end)
    1453             : {
    1454           1 :         lng s = *start;
    1455           1 :         lng e = (is_int_nil(*end) ? lng_nil : *end);
    1456             : 
    1457           1 :         return ALGslice(ret, bid, &s, &e);
    1458             : }
    1459             : 
    1460             : static str
    1461           0 : ALGslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1462             : {
    1463           0 :         lng s = *start;
    1464           0 :         lng e = *end;
    1465             : 
    1466           0 :         return ALGslice(ret, bid, &s, &e);
    1467             : }
    1468             : 
    1469             : /* carve out a slice based on the OIDs */
    1470             : /* beware that BATs may have different OID bases */
    1471             : static str
    1472           5 : ALGslice_oid(bat *ret, const bat *bid, const oid *start, const oid *end)
    1473             : {
    1474           5 :         lng s = (lng) (is_oid_nil(*start) ? 0 : (lng) *start);
    1475           5 :         lng e = (is_oid_nil(*end) ? lng_nil : (lng) *end);
    1476             : 
    1477           5 :         return ALGslice(ret, bid, &s, &e);
    1478             : }
    1479             : 
    1480             : static str
    1481       17460 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1482             : {
    1483       17460 :         BAT *b, *bn;
    1484       17460 :         BUN s, e;
    1485             : 
    1486       17460 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1487           2 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1488       17458 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1489           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1490       17459 :         s = (BUN) *start;
    1491       17459 :         if (s > BATcount(b))
    1492             :                 s = BATcount(b);
    1493       17459 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1494       17459 :         if (e > BATcount(b))
    1495             :                 e = BATcount(b);
    1496       17459 :         if (e < s)
    1497             :                 e = s;
    1498       17459 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1499       17460 :         if (bn == NULL)
    1500           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1501       17460 :         *ret = bn->batCacheid;
    1502       17460 :         BBPkeepref(bn);
    1503       17460 :         return MAL_SUCCEED;
    1504             : }
    1505             : 
    1506             : /*
    1507             :  * BUN Get/Fetch
    1508             :  */
    1509             : 
    1510             : static str
    1511      185286 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1512             : {
    1513      185286 :         assert(pos <= BUN_MAX);
    1514      185286 :         BATiter bi = bat_iterator(b);
    1515      185286 :         if (ATOMextern(b->ttype)) {
    1516         190 :                 ptr _src = BUNtail(bi, pos);
    1517         190 :                 size_t _len = ATOMlen(b->ttype, _src);
    1518         190 :                 ptr _dst = GDKmalloc(_len);
    1519         190 :                 if (_dst == NULL) {
    1520           0 :                         bat_iterator_end(&bi);
    1521           0 :                         throw(MAL, "doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1522             :                 }
    1523         190 :                 memcpy(_dst, _src, _len);
    1524         190 :                 *(ptr *) ret = _dst;
    1525             :         } else {
    1526      185096 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1527      185096 :                 if (b->ttype == TYPE_void) {
    1528           0 :                         *(oid *) ret = b->tseqbase;
    1529           0 :                         if (!is_oid_nil(b->tseqbase))
    1530           0 :                                 *(oid *) ret += pos;
    1531      185096 :                 } else if (_s == 4) {
    1532      185009 :                         *(int *) ret = ((int *) bi.base)[pos];
    1533             :                 } else if (_s == 1) {
    1534          11 :                         *(bte *) ret = ((bte *) bi.base)[pos];
    1535             :                 } else if (_s == 2) {
    1536           1 :                         *(sht *) ret = ((sht *) bi.base)[pos];
    1537             :                 } else if (_s == 8) {
    1538          75 :                         *(lng *) ret = ((lng *) bi.base)[pos];
    1539             : #ifdef HAVE_HGE
    1540             :                 } else if (_s == 16) {
    1541           0 :                         *(hge *) ret = ((hge *) bi.base)[pos];
    1542             : #endif
    1543             :                 } else {
    1544           0 :                         memcpy(ret, (const char *) bi.base + (pos << bi.shift), _s);
    1545             :                 }
    1546             :         }
    1547      185286 :         bat_iterator_end(&bi);
    1548      185286 :         return MAL_SUCCEED;
    1549             : }
    1550             : 
    1551             : static str
    1552      185288 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1553             : {
    1554      185288 :         BAT *b;
    1555      185288 :         str msg;
    1556             : 
    1557      185288 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1558           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1559             :         }
    1560      185288 :         if (*pos < (lng) 0) {
    1561           0 :                 BBPunfix(b->batCacheid);
    1562           0 :                 throw(MAL, "algebra.fetch",
    1563             :                           ILLEGAL_ARGUMENT ": row index to fetch must be non negative\n");
    1564             :         }
    1565      185288 :         if (BATcount(b) == 0) {
    1566           2 :                 BBPunfix(b->batCacheid);
    1567           2 :                 throw(MAL, "algebra.fetch",
    1568             :                           ILLEGAL_ARGUMENT
    1569             :                           ": cannot fetch a single row from an empty input\n");
    1570             :         }
    1571      185286 :         if (*pos >= (lng) BATcount(b)) {
    1572           0 :                 BBPunfix(b->batCacheid);
    1573           0 :                 throw(MAL, "algebra.fetch",
    1574             :                           ILLEGAL_ARGUMENT ": row index to fetch is out of range\n");
    1575             :         }
    1576      185286 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1577      185286 :         BBPunfix(b->batCacheid);
    1578      185286 :         return msg;
    1579             : }
    1580             : 
    1581             : str
    1582      185288 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1583             : {
    1584      185288 :         lng o = *pos;
    1585             : 
    1586      185288 :         return ALGfetch(ret, bid, &o);
    1587             : }
    1588             : 
    1589             : static str
    1590           0 : ALGexist(bit *ret, const bat *bid, const void *val)
    1591             : {
    1592           0 :         BAT *b;
    1593           0 :         BUN q;
    1594             : 
    1595           0 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1596           0 :                 throw(MAL, "algebra.exist", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1597             :         }
    1598           0 :         derefStr(b, val);
    1599           0 :         q = BUNfnd(b, val);
    1600           0 :         *ret = (q != BUN_NONE);
    1601           0 :         BBPunfix(b->batCacheid);
    1602           0 :         return MAL_SUCCEED;
    1603             : }
    1604             : 
    1605             : static str
    1606           9 : ALGfind(oid *ret, const bat *bid, ptr val)
    1607             : {
    1608           9 :         BAT *b;
    1609           9 :         BUN q;
    1610           9 :         str msg = MAL_SUCCEED;
    1611             : 
    1612           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1613           0 :                 throw(MAL, "algebra.find", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1614             :         }
    1615           9 :         derefStr(b, val);
    1616           9 :         q = BUNfnd(b, val);
    1617             : 
    1618           9 :         if (q == BUN_NONE) {
    1619           3 :                 *ret = oid_nil;
    1620             :         } else
    1621           6 :                 *ret = (oid) q;
    1622           9 :         BBPunfix(b->batCacheid);
    1623           9 :         return msg;
    1624             : }
    1625             : 
    1626             : 
    1627             : static str
    1628      293210 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1629             : {
    1630      293210 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1631      293210 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1632      293210 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1633      293210 :         BAT *b, *bn;
    1634             : 
    1635      293210 :         (void) cntxt;
    1636      293210 :         (void) mb;
    1637      293210 :         if (isaBatType(getArgType(mb, pci, 2)))
    1638           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1639      293210 :         if ((b = BBPquickdesc(bid)) == NULL)
    1640           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1641      293186 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1642      293270 :         if (bn == NULL) {
    1643           0 :                 *ret = bat_nil;
    1644           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1645             :         }
    1646      293270 :         *ret = bn->batCacheid;
    1647      293270 :         BBPkeepref(bn);
    1648      293270 :         return MAL_SUCCEED;
    1649             : }
    1650             : 
    1651             : 
    1652             : static str
    1653           0 : ALGreuse(bat *ret, const bat *bid)
    1654             : {
    1655           0 :         BAT *b, *bn;
    1656           0 :         if ((b = BATdescriptor(*bid)) == NULL)
    1657           0 :                 throw(MAL, "algebra.reuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1658             : 
    1659           0 :         if (!b->batTransient || b->batRestricted != BAT_WRITE) {
    1660           0 :                 if (ATOMvarsized(b->ttype)) {
    1661           0 :                         bn = BATwcopy(b);
    1662           0 :                         if (bn == NULL) {
    1663           0 :                                 BBPunfix(b->batCacheid);
    1664           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1665             :                         }
    1666             :                 } else {
    1667           0 :                         bn = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
    1668           0 :                         if (bn == NULL) {
    1669           0 :                                 BBPunfix(b->batCacheid);
    1670           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1671             :                         }
    1672           0 :                         BATsetcount(bn, BATcount(b));
    1673           0 :                         bn->tsorted = false;
    1674           0 :                         bn->trevsorted = false;
    1675           0 :                         BATkey(bn, false);
    1676             :                 }
    1677           0 :                 *ret = bn->batCacheid;
    1678           0 :                 BBPkeepref(bn);
    1679           0 :                 BBPunfix(b->batCacheid);
    1680             :         } else
    1681           0 :                 BBPkeepref(b);
    1682             :         return MAL_SUCCEED;
    1683             : }
    1684             : 
    1685             : /*
    1686             :  * BAT standard deviation
    1687             :  */
    1688             : static str
    1689           7 : ALGstdev(dbl *res, const bat *bid)
    1690             : {
    1691           7 :         BAT *b;
    1692           7 :         dbl stdev;
    1693             : 
    1694           7 :         if ((b = BATdescriptor(*bid)) == NULL)
    1695           0 :                 throw(MAL, "aggr.stdev", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1696           7 :         stdev = BATcalcstdev_sample(NULL, b);
    1697           7 :         BBPunfix(b->batCacheid);
    1698           7 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1699           0 :                 throw(MAL, "aggr.stdev", GDK_EXCEPTION);
    1700           7 :         *res = stdev;
    1701           7 :         return MAL_SUCCEED;
    1702             : }
    1703             : 
    1704             : static str
    1705          13 : ALGstdevp(dbl *res, const bat *bid)
    1706             : {
    1707          13 :         BAT *b;
    1708          13 :         dbl stdev;
    1709             : 
    1710          13 :         if ((b = BATdescriptor(*bid)) == NULL)
    1711           0 :                 throw(MAL, "aggr.stdevp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1712          13 :         stdev = BATcalcstdev_population(NULL, b);
    1713          13 :         BBPunfix(b->batCacheid);
    1714          13 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1715           1 :                 throw(MAL, "aggr.stdevp", GDK_EXCEPTION);
    1716          12 :         *res = stdev;
    1717          12 :         return MAL_SUCCEED;
    1718             : }
    1719             : 
    1720             : /*
    1721             :  * BAT variance
    1722             :  */
    1723             : static str
    1724           2 : ALGvariance(dbl *res, const bat *bid)
    1725             : {
    1726           2 :         BAT *b;
    1727           2 :         dbl variance;
    1728             : 
    1729           2 :         if ((b = BATdescriptor(*bid)) == NULL)
    1730           0 :                 throw(MAL, "aggr.variance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1731           2 :         variance = BATcalcvariance_sample(NULL, b);
    1732           2 :         BBPunfix(b->batCacheid);
    1733           2 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1734           0 :                 throw(MAL, "aggr.variance", GDK_EXCEPTION);
    1735           2 :         *res = variance;
    1736           2 :         return MAL_SUCCEED;
    1737             : }
    1738             : 
    1739             : static str
    1740           5 : ALGvariancep(dbl *res, const bat *bid)
    1741             : {
    1742           5 :         BAT *b;
    1743           5 :         dbl variance;
    1744             : 
    1745           5 :         if ((b = BATdescriptor(*bid)) == NULL)
    1746           0 :                 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1747           5 :         variance = BATcalcvariance_population(NULL, b);
    1748           5 :         BBPunfix(b->batCacheid);
    1749           5 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1750           1 :                 throw(MAL, "aggr.variancep", GDK_EXCEPTION);
    1751           4 :         *res = variance;
    1752           4 :         return MAL_SUCCEED;
    1753             : }
    1754             : 
    1755             : /*
    1756             :  * BAT covariance
    1757             :  */
    1758             : static str
    1759           5 : ALGcovariance(dbl *res, const bat *bid1, const bat *bid2)
    1760             : {
    1761           5 :         BAT *b1, *b2;
    1762           5 :         dbl covariance;
    1763             : 
    1764           5 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1765           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1766           5 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1767           0 :                 BBPunfix(b1->batCacheid);
    1768           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1769             :         }
    1770             : 
    1771           5 :         covariance = BATcalccovariance_sample(b1, b2);
    1772           5 :         BBPunfix(b1->batCacheid);
    1773           5 :         BBPunfix(b2->batCacheid);
    1774           5 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1775           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1776           5 :         *res = covariance;
    1777           5 :         return MAL_SUCCEED;
    1778             : }
    1779             : 
    1780             : static str
    1781           9 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1782             : {
    1783           9 :         BAT *b1, *b2;
    1784           9 :         dbl covariance;
    1785             : 
    1786           9 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1787           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1788           9 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1789           0 :                 BBPunfix(b1->batCacheid);
    1790           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1791             :         }
    1792             : 
    1793           9 :         covariance = BATcalccovariance_population(b1, b2);
    1794           9 :         BBPunfix(b1->batCacheid);
    1795           9 :         BBPunfix(b2->batCacheid);
    1796           9 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1797           1 :                 throw(MAL, "aggr.covariancep", GDK_EXCEPTION);
    1798           8 :         *res = covariance;
    1799           8 :         return MAL_SUCCEED;
    1800             : }
    1801             : 
    1802             : /*
    1803             :  * BAT correlation
    1804             :  */
    1805             : static str
    1806          19 : ALGcorr(dbl *res, const bat *bid1, const bat *bid2)
    1807             : {
    1808          19 :         BAT *b1, *b2;
    1809          19 :         dbl covariance;
    1810             : 
    1811          19 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1812           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1813          19 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1814           0 :                 BBPunfix(b1->batCacheid);
    1815           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1816             :         }
    1817             : 
    1818          19 :         covariance = BATcalccorrelation(b1, b2);
    1819          19 :         BBPunfix(b1->batCacheid);
    1820          19 :         BBPunfix(b2->batCacheid);
    1821          19 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1822           1 :                 throw(MAL, "aggr.corr", GDK_EXCEPTION);
    1823          18 :         *res = covariance;
    1824          18 :         return MAL_SUCCEED;
    1825             : }
    1826             : 
    1827             : #include "mel.h"
    1828             : mel_func algebra_init_funcs[] = {
    1829             :  command("algebra", "groupby", ALGgroupby, false, "Produces a new BAT with groups identified by the head column. The result contains tail times the head value, ie the tail contains the result group sizes.", args(1,3, batarg("",oid),batarg("gids",oid),batarg("cnts",lng))),
    1830             :  command("algebra", "find", ALGfind, false, "Returns the index position of a value.  If no such BUN exists return OID-nil.", args(1,3, arg("",oid),batargany("b",1),argany("t",1))),
    1831             :  command("algebra", "fetch", ALGfetchoid, false, "Returns the value of the BUN at x-th position with 0 <= x < b.count", args(1,3, argany("",1),batargany("b",1),arg("x",oid))),
    1832             :  pattern("algebra", "project", ALGprojecttail, false, "Fill the tail with a constant", args(1,3, batargany("",2),batargany("b",1),argany("v",2))),
    1833             :  command("algebra", "projection", ALGprojection, false, "Project left input onto right input.", args(1,3, batargany("",1),batarg("left",oid),batargany("right",1))),
    1834             :  command("algebra", "projection", ALGprojection2, false, "Project left input onto right inputs which should be consecutive.", args(1,4, batargany("",1),batarg("left",oid),batargany("right1",1),batargany("right2",1))),
    1835             :  command("algebra", "copy", ALGcopy, false, "Returns physical copy of a BAT.", args(1,2, batargany("",1),batargany("b",1))),
    1836             :  command("algebra", "exist", ALGexist, false, "Returns whether 'val' occurs in b.", args(1,3, arg("",bit),batargany("b",1),argany("val",1))),
    1837             :  command("algebra", "select", ALGselect1, false, "Select all head values for which the tail value is in range.\nInput is a dense-headed BAT, output is a dense-headed BAT with in\nthe tail the head value of the input BAT for which the tail value\nis between the values low and high (inclusive if li respectively\nhi is set).  The output BAT is sorted on the tail value.  If low\nor high is nil, the boundary is not considered (effectively - and\n+ infinity).  If anti is set, the result is the complement.  Nil\nvalues in the tail are never matched, unless low=nil, high=nil,\nli=1, hi=1, anti=0.  All non-nil values are returned if low=nil,\nhigh=nil, and li, hi are not both 1, or anti=1.\nNote that the output is suitable as second input for the other\nversion of this function.", args(1,7, batarg("",oid),batargany("b",1),argany("low",1),argany("high",1),arg("li",bit),arg("hi",bit),arg("anti",bit))),
    1838             :  command("algebra", "select", ALGselect2, false, "Select all head values of the first input BAT for which the tail value\nis in range and for which the head value occurs in the tail of the\nsecond input BAT.\nThe first input is a dense-headed BAT, the second input is a\ndense-headed BAT with sorted tail, output is a dense-headed BAT\nwith in the tail the head value of the input BAT for which the\ntail value is between the values low and high (inclusive if li\nrespectively hi is set).  The output BAT is sorted on the tail\nvalue.  If low or high is nil, the boundary is not considered\n(effectively - and + infinity).  If anti is set, the result is the\ncomplement.  Nil values in the tail are never matched, unless\nlow=nil, high=nil, li=1, hi=1, anti=0.  All non-nil values are\nreturned if low=nil, high=nil, and li, hi are not both 1, or anti=1.\nNote that the output is suitable as second input for this\nfunction.", args(1,8, batarg("",oid),batargany("b",1),batarg("s",oid),argany("low",1),argany("high",1),arg("li",bit),arg("hi",bit),arg("anti",bit))),
    1839             :  command("algebra", "select", ALGselect1nil, false, "With unknown set, each nil != nil", args(1,8, batarg("",oid),batargany("b",1),argany("low",1),argany("high",1),arg("li",bit),arg("hi",bit),arg("anti",bit),arg("unknown",bit))),
    1840             :  command("algebra", "select", ALGselect2nil, false, "With unknown set, each nil != nil", args(1,9, batarg("",oid),batargany("b",1),batarg("s",oid),argany("low",1),argany("high",1),arg("li",bit),arg("hi",bit),arg("anti",bit),arg("unknown",bit))),
    1841             :  command("algebra", "thetaselect", ALGthetaselect2, false, "Select all head values of the first input BAT for which the tail value\nobeys the relation value OP VAL and for which the head value occurs in\nthe tail of the second input BAT.\nInput is a dense-headed BAT, output is a dense-headed BAT with in\nthe tail the head value of the input BAT for which the\nrelationship holds.  The output BAT is sorted on the tail value.", args(1,5, batarg("",oid),batargany("b",1),batarg("s",oid),argany("val",1),arg("op",str))),
    1842             :  command("algebra", "markselect", ALGmarkselect, false, "Group on group-ids, return aggregated anyequal or allnotequal", args(2,6, batarg("",oid), batarg("", bit), batarg("gid",oid), batarg("m", bit), batarg("p", bit), arg("any", bit))),
    1843             :  command("algebra", "outerselect", ALGouterselect, false, "Per input lid return at least one row, if none of the predicates (p) hold, return a nil, else 'all' true cases.", args(2,6, batarg("",oid), batarg("", bit), batarg("lid", oid), batarg("rid", bit), batarg("predicate", bit), arg("any", bit))),
    1844             :  command("algebra", "selectNotNil", ALGselectNotNil, false, "Select all not-nil values", args(1,2, batargany("",1),batargany("b",1))),
    1845             :  command("algebra", "sort", ALGsort11, false, "Returns a copy of the BAT sorted on tail values.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(1,5, batargany("",1),batargany("b",1),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1846             :  command("algebra", "sort", ALGsort12, false, "Returns a copy of the BAT sorted on tail values and a BAT that\nspecifies how the input was reordered.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(2,6, batargany("",1),batarg("",oid),batargany("b",1),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1847             :  command("algebra", "sort", ALGsort13, false, "Returns a copy of the BAT sorted on tail values, a BAT that specifies\nhow the input was reordered, and a BAT with group information.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(3,7, batargany("",1),batarg("",oid),batarg("",oid),batargany("b",1),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1848             :  command("algebra", "sort", ALGsort21, false, "Returns a copy of the BAT sorted on tail values.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(1,6, batargany("",1),batargany("b",1),batarg("o",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1849             :  command("algebra", "sort", ALGsort22, false, "Returns a copy of the BAT sorted on tail values and a BAT that\nspecifies how the input was reordered.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(2,7, batargany("",1),batarg("",oid),batargany("b",1),batarg("o",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1850             :  command("algebra", "sort", ALGsort23, false, "Returns a copy of the BAT sorted on tail values, a BAT that specifies\nhow the input was reordered, and a BAT with group information.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(3,8, batargany("",1),batarg("",oid),batarg("",oid),batargany("b",1),batarg("o",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1851             :  command("algebra", "sort", ALGsort31, false, "Returns a copy of the BAT sorted on tail values.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(1,7, batargany("",1),batargany("b",1),batarg("o",oid),batarg("g",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1852             :  command("algebra", "sort", ALGsort32, false, "Returns a copy of the BAT sorted on tail values and a BAT that\nspecifies how the input was reordered.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(2,8, batargany("",1),batarg("",oid),batargany("b",1),batarg("o",oid),batarg("g",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1853             :  command("algebra", "sort", ALGsort33, false, "Returns a copy of the BAT sorted on tail values, a BAT that specifies\nhow the input was reordered, and a BAT with group information.\nThe order is descending if the reverse bit is set.\nThis is a stable sort if the stable bit is set.", args(3,9, batargany("",1),batarg("",oid),batarg("",oid),batargany("b",1),batarg("o",oid),batarg("g",oid),arg("reverse",bit),arg("nilslast",bit),arg("stable",bit))),
    1854             :  command("algebra", "unique", ALGunique, false, "Select all unique values from the tail of the first input.\nInput is a dense-headed BAT, the second input is a\ndense-headed BAT with sorted tail, output is a dense-headed\nBAT with in the tail the head value of the input BAT that was\nselected.  The output BAT is sorted on the tail value.  The\nsecond input BAT is a list of candidates.", args(1,3, batarg("",oid),batargany("b",1),batarg("s",oid))),
    1855             :  command("algebra", "crossproduct", ALGcrossproduct2, false, "Returns 2 columns with all BUNs, consisting of the head-oids\nfrom 'left' and 'right' for which there are BUNs in 'left'\nand 'right' with equal tails", args(2,5, batarg("l",oid),batarg("r",oid),batargany("left",1),batargany("right",2),arg("max_one",bit))),
    1856             :  command("algebra", "crossproduct", ALGcrossproduct1, false, "Compute the cross product of both input bats; but only produce left output", args(1,4, batarg("",oid),batargany("left",1),batargany("right",2),arg("max_one",bit))),
    1857             :  command("algebra", "crossproduct", ALGcrossproduct3, false, "Compute the cross product of both input bats", args(2,7, batarg("l",oid),batarg("r",oid),batargany("left",1),batargany("right",2),batarg("sl",oid),batarg("sr",oid),arg("max_one",bit))),
    1858             :  command("algebra", "crossproduct", ALGcrossproduct4, false, "Compute the cross product of both input bats; but only produce left output", args(1,6, batarg("",oid),batargany("left",1),batargany("right",2),batarg("sl",oid),batarg("sr",oid),arg("max_one",bit))),
    1859             :  command("algebra", "outercrossproduct", ALGoutercrossproduct3, false, "Compute the outer cross product of both input bats", args(2,7, batarg("l",oid),batarg("r",oid),batargany("left",1),batargany("right",2),batarg("sl",oid),batarg("sr",oid),arg("max_one",bit))),
    1860             :  command("algebra", "join", ALGjoin, false, "Join", args(2,8, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng))),
    1861             :  command("algebra", "join", ALGjoin1, false, "Join; only produce left output", args(1,7, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng))),
    1862             :  command("algebra", "leftjoin", ALGleftjoin, false, "Left join with candidate lists", args(2,8, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng))),
    1863             :  command("algebra", "leftjoin", ALGleftjoin1, false, "Left join with candidate lists; only produce left output", args(1,7, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("estimate",lng))),
    1864             :  command("algebra", "outerjoin", ALGouterjoin, false, "Left outer join with candidate lists", args(2,9, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("match_one",bit),arg("estimate",lng))),
    1865             :  command("algebra", "outerjoin", ALGouterjoin1, false, "Left outer join with candidate lists; only produce left output", args(1,8,batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("match_one",bit),arg("estimate",lng))),
    1866             :  command("algebra", "semijoin", ALGsemijoin, false, "Semi join with candidate lists", args(2,9, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("max_one",bit),arg("estimate",lng))),
    1867             :  command("algebra", "markjoin", ALGmark2join, false, "Mark join with candidate lists", args(2,7, batarg("",oid),batarg("",bit),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("estimate",lng))),
    1868             :  command("algebra", "markjoin", ALGmark3join, false, "Mark join with candidate lists", args(3,8, batarg("",oid),batarg("",oid),batarg("",bit),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("estimate",lng))),
    1869             :  command("algebra", "thetajoin", ALGthetajoin, false, "Theta join with candidate lists", args(2,9, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("op",int),arg("nil_matches",bit),arg("estimate",lng))),
    1870             :  command("algebra", "thetajoin", ALGthetajoin1, false, "Theta join with candidate lists; only produce left output", args(1,8, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("op",int),arg("nil_matches",bit),arg("estimate",lng))),
    1871             :  command("algebra", "bandjoin", ALGbandjoin, false, "Band join: values in l and r match if r - c1 <[=] l <[=] r + c2", args(2,11, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),argany("c1",1),argany("c2",1),arg("li",bit),arg("hi",bit),arg("estimate",lng))),
    1872             :  command("algebra", "bandjoin", ALGbandjoin1, false, "Band join: values in l and r match if r - c1 <[=] l <[=] r + c2; only produce left output", args(1,10, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),argany("c1",1),argany("c2",1),arg("li",bit),arg("hi",bit),arg("estimate",lng))),
    1873             :  command("algebra", "rangejoin", ALGrangejoin, false, "Range join: values in l and r1/r2 match if r1 <[=] l <[=] r2", args(2,12, batarg("",oid),batarg("",oid),batargany("l",1),batargany("r1",1),batargany("r2",1),batarg("sl",oid),batarg("sr",oid),arg("li",bit),arg("hi",bit),arg("anti",bit),arg("symmetric",bit),arg("estimate",lng))),
    1874             :  command("algebra", "rangejoin", ALGrangejoin1, false, "Range join: values in l and r1/r2 match if r1 <[=] l <[=] r2; only produce left output", args(1,11,batarg("",oid),batargany("l",1),batargany("r1",1),batargany("r2",1),batarg("sl",oid),batarg("sr",oid),arg("li",bit),arg("hi",bit),arg("anti",bit),arg("symmetric",bit),arg("estimate",lng))),
    1875             :  command("algebra", "difference", ALGdifference, false, "Difference of l and r with candidate lists", args(1,8, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("nil_clears",bit),arg("estimate",lng))),
    1876             :  command("algebra", "intersect", ALGintersect, false, "Intersection of l and r with candidate lists (i.e. half of semi-join)", args(1,8, batarg("",oid),batargany("l",1),batargany("r",1),batarg("sl",oid),batarg("sr",oid),arg("nil_matches",bit),arg("max_one",bit),arg("estimate",lng))),
    1877             :  pattern("algebra", "firstn", ALGfirstn, false, "Calculate first N values of B with candidate list S", args(1,8, batarg("",oid),batargany("b",0),batarg("s",oid),batarg("g",oid),arg("n",lng),arg("asc",bit),arg("nilslast",bit),arg("distinct",bit))),
    1878             :  pattern("algebra", "firstn", ALGfirstn, false, "Calculate first N values of B with candidate list S", args(2,9, batarg("",oid),batarg("",oid),batargany("b",0),batarg("s",oid),batarg("g",oid),arg("n",lng),arg("asc",bit),arg("nilslast",bit),arg("distinct",bit))),
    1879             :  pattern("algebra", "groupedfirstn", ALGgroupedfirstn, false, "Grouped firstn", args(1,5, batarg("",oid),arg("n",lng),batarg("s",oid),batarg("g",oid),varargany("arg",0))),
    1880             :  command("algebra", "reuse", ALGreuse, false, "Reuse a temporary BAT if you can. Otherwise,\nallocate enough storage to accept result of an\noperation (not involving the heap)", args(1,2, batargany("",1),batargany("b",1))),
    1881             :  command("algebra", "slice", ALGslice_oid, false, "Return the slice based on head oid x till y (exclusive).", args(1,4, batargany("",1),batargany("b",1),arg("x",oid),arg("y",oid))),
    1882             :  command("algebra", "slice", ALGslice_int, false, "Return the slice with the BUNs at position x till y.", args(1,4, batargany("",1),batargany("b",1),arg("x",int),arg("y",int))),
    1883             :  command("algebra", "slice", ALGslice_lng, false, "Return the slice with the BUNs at position x till y.", args(1,4, batargany("",1),batargany("b",1),arg("x",lng),arg("y",lng))),
    1884             :  command("algebra", "subslice", ALGsubslice_lng, false, "Return the oids of the slice with the BUNs at position x till y.", args(1,4, batarg("",oid),batargany("b",1),arg("x",lng),arg("y",lng))),
    1885             :  command("aggr", "count", ALGcount_bat, false, "Return the current size (in number of elements) in a BAT.", args(1,2, arg("",lng),batargany("b",0))),
    1886             :  command("aggr", "count", ALGcount_nil, false, "Return the number of elements currently in a BAT ignores\nBUNs with nil-tail iff ignore_nils==TRUE.", args(1,3, arg("",lng),batargany("b",0),arg("ignore_nils",bit))),
    1887             :  command("aggr", "count_no_nil", ALGcount_no_nil, false, "Return the number of elements currently\nin a BAT ignoring BUNs with nil-tail", args(1,2, arg("",lng),batargany("b",2))),
    1888             :  command("aggr", "count", ALGcountCND_bat, false, "Return the current size (in number of elements) in a BAT.", args(1,3, arg("",lng),batargany("b",0),batarg("cnd",oid))),
    1889             :  command("aggr", "count", ALGcountCND_nil, false, "Return the number of elements currently in a BAT ignores\nBUNs with nil-tail iff ignore_nils==TRUE.", args(1,4, arg("",lng),batargany("b",0),batarg("cnd",oid),arg("ignore_nils",bit))),
    1890             :  command("aggr", "count_no_nil", ALGcountCND_no_nil, false, "Return the number of elements currently\nin a BAT ignoring BUNs with nil-tail", args(1,3, arg("",lng),batargany("b",2),batarg("cnd",oid))),
    1891             :  command("aggr", "cardinality", ALGcard, false, "Return the cardinality of the BAT tail values.", args(1,2, arg("",lng),batargany("b",2))),
    1892             :  command("aggr", "min", ALGminany, false, "Return the lowest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1893             :  command("aggr", "min", ALGminany_skipnil, false, "Return the lowest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1894             :  command("aggr", "max", ALGmaxany, false, "Return the highest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1895             :  command("aggr", "max", ALGmaxany_skipnil, false, "Return the highest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1896             :  command("aggr", "stdev", ALGstdev, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1897             :  command("aggr", "stdevp", ALGstdevp, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1898             :  command("aggr", "variance", ALGvariance, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1899             :  command("aggr", "variancep", ALGvariancep, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1900             :  command("aggr", "covariance", ALGcovariance, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1901             :  command("aggr", "covariancep", ALGcovariancep, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1902             :  command("aggr", "corr", ALGcorr, false, "Gives the correlation of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1903             :  // sql
    1904             :  command("aggr", "exist", ALGexist, false, "", args(1,3, arg("",bit),batargany("b",2),argany("h",1))),
    1905             :  { .imp=NULL }
    1906             : };
    1907             : #include "mal_import.h"
    1908             : #ifdef _MSC_VER
    1909             : #undef read
    1910             : #pragma section(".CRT$XCU",read)
    1911             : #endif
    1912         345 : LIB_STARTUP_FUNC(init_algebra_mal)
    1913         345 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14