LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 737 973 75.7 %
Date: 2024-10-07 21:21:43 Functions: 67 82 81.7 %

          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        2377 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts)
      60             : {
      61        2377 :         BUN j;
      62        2377 :         BATiter gi = bat_iterator(gids);
      63        2377 :         BAT *r = COLnew(0, TYPE_oid, gi.count * 2, TRANSIENT);
      64             : 
      65        2377 :         if (r == NULL) {
      66           0 :                 bat_iterator_end(&gi);
      67           0 :                 return GDK_FAIL;
      68             :         }
      69        2377 :         BATiter ci = bat_iterator(cnts);
      70        2377 :         if (gi.type == TYPE_void) {
      71        1041 :                 oid id = gi.tseq;
      72        1041 :                 lng *cnt = (lng *) ci.base;
      73       96149 :                 for (j = 0; j < gi.count; j++) {
      74       95108 :                         lng i, sz = cnt[j];
      75      190162 :                         for (i = 0; i < sz; i++) {
      76       95054 :                                 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       95108 :                         id ++;
      84             :                 }
      85             :         } else {
      86        1336 :                 oid *id = (oid *) gi.base;
      87        1336 :                 lng *cnt = (lng *) ci.base;
      88      140457 :                 for (j = 0; j < gi.count; j++) {
      89      139121 :                         lng i, sz = cnt[j];
      90      274767 :                         for (i = 0; i < sz; i++) {
      91      135646 :                                 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      139121 :                         id ++;
      99             :                 }
     100             :         }
     101        2377 :         bat_iterator_end(&ci);
     102        2377 :         r->tkey = false;
     103        2377 :         r->tseqbase = oid_nil;
     104        2377 :         r->tsorted = gi.sorted;
     105        2377 :         r->trevsorted = gi.revsorted;
     106        2377 :         r->tnonil = gi.nonil;
     107        2377 :         bat_iterator_end(&gi);
     108        2377 :         *result = r;
     109        2377 :         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         655 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         655 :         BAT *b;
     143         655 :         ptr p;
     144         655 :         str msg = MAL_SUCCEED;
     145             : 
     146         655 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         659 :         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         659 :                 if (ATOMextern(b->ttype)) {
     155          42 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         617 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         617 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         659 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         659 :         BBPunfix(b->batCacheid);
     166         659 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         656 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         656 :         bit skipnil = TRUE;
     173         656 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         554 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         554 :         BAT *b;
     180         554 :         ptr p;
     181         554 :         str msg = MAL_SUCCEED;
     182             : 
     183         554 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         554 :         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         554 :                 if (ATOMextern(b->ttype)) {
     192          68 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         486 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         490 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         558 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         558 :         BBPunfix(b->batCacheid);
     203         558 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         554 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         554 :         bit skipnil = TRUE;
     210         554 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     211             : }
     212             : 
     213             : static str
     214        2377 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     215             : {
     216        2377 :         BAT *bn, *g, *c;
     217             : 
     218        2377 :         g = BATdescriptor(*gids);
     219        2377 :         if (g == NULL) {
     220           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     221             :         }
     222        2377 :         c = BATdescriptor(*cnts);
     223        2377 :         if (c == NULL) {
     224           0 :                 BBPunfix(g->batCacheid);
     225           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     226             :         }
     227        2377 :         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        2377 :         *res = bn->batCacheid;
     233        2377 :         BBPkeepref(bn);
     234        2377 :         BBPunfix(g->batCacheid);
     235        2377 :         BBPunfix(c->batCacheid);
     236        2377 :         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      128051 : 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      128051 :         BAT *b, *s = NULL, *bn;
     265             : 
     266      128051 :         if ((*li != 0 && *li != 1) ||
     267      128051 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270             : 
     271      128122 :         if ((b = BATdescriptor(*bid)) == NULL) {
     272           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     273             :         }
     274      128816 :         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      128858 :         derefStr(b, low);
     279      128858 :         derefStr(b, high);
     280             : 
     281      128858 :         bool nanti = *anti, nli = *li, nhi = *hi;
     282             : 
     283             :         /* here we don't need open ended parts with nil */
     284      128858 :         if (!nanti && *unknown) {
     285        1375 :                 const void *nilptr = ATOMnilptr(b->ttype);
     286        1375 :                 if (nilptr) {
     287        1375 :                         if (nli && ATOMcmp(b->ttype, low, nilptr) == 0) {
     288          21 :                                 low = high;
     289          21 :                                 nli = false;
     290             :                         }
     291        1369 :                         if (nhi && ATOMcmp(b->ttype, high, nilptr) == 0) {
     292          23 :                                 high = low;
     293          23 :                                 nhi = false;
     294             :                         }
     295        1370 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     296          13 :                                 nanti = true;
     297             :                 }
     298      127483 :         } else if (!*unknown) {
     299      121232 :                 const void *nilptr = ATOMnilptr(b->ttype);
     300      242233 :                 if (nli && nhi && nilptr != NULL &&
     301      121258 :                         ATOMcmp(b->ttype, low, nilptr) == 0 &&
     302          24 :                         ATOMcmp(b->ttype, high, nilptr) == 0) {
     303             :                         /* special case: equi-select for NIL */
     304      128625 :                         high = NULL;
     305             :                 }
     306             :         }
     307             : 
     308      128625 :         bn = BATselect(b, s, low, high, nli, nhi, nanti, false);
     309      127705 :         BBPunfix(b->batCacheid);
     310      128803 :         BBPreclaim(s);
     311      128655 :         if (bn == NULL)
     312           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     313      128655 :         *result = bn->batCacheid;
     314      128655 :         BBPkeepref(bn);
     315      128655 :         return MAL_SUCCEED;
     316             : }
     317             : 
     318             : static str
     319       40835 : 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       40835 :         return ALGselect2nil(result, bid, sid, low, high, li, hi, anti, &(bit){0});
     323             : }
     324             : 
     325             : static str
     326       79947 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     327             :                    const bit *li, const bit *hi, const bit *anti)
     328             : {
     329       79947 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, &(bit){0});
     330             : }
     331             : 
     332             : static str
     333         311 : 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         311 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     337             : }
     338             : 
     339             : static str
     340      431539 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     341             :                                 const char **op)
     342             : {
     343      431539 :         BAT *b, *s = NULL, *bn;
     344             : 
     345      431539 :         if ((b = BATdescriptor(*bid)) == NULL) {
     346           0 :                 throw(MAL, "algebra.thetaselect",
     347             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     348             :         }
     349      433620 :         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      433787 :         derefStr(b, val);
     355      433787 :         bn = BATthetaselect(b, s, val, *op);
     356      431361 :         BBPunfix(b->batCacheid);
     357      433530 :         BBPreclaim(s);
     358      433559 :         if (bn == NULL)
     359           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     360      433559 :         *result = bn->batCacheid;
     361      433559 :         BBPkeepref(bn);
     362      433559 :         return MAL_SUCCEED;
     363             : }
     364             : 
     365             : static str
     366         337 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     367             : {
     368         337 :         BAT *g = BATdescriptor(*gid); /* oid */
     369         337 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     370         337 :         BAT *p = BATdescriptor(*pid); /* bit */
     371         337 :         BAT *res1 = NULL, *res2 = NULL;
     372         337 :         bit any = *Any; /* any or normal comparison semantics */
     373             : 
     374         337 :         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         337 :         BUN nr = BATcount(g), q = 0;
     381             : 
     382         337 :         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         337 :         assert(g->tsorted);
     390         337 :         oid *ri1 = Tloc(res1, 0);
     391         337 :         bit *ri2 = Tloc(res2, 0);
     392         337 :         bit *mi = Tloc(m, 0);
     393         337 :         bit *pi = Tloc(p, 0);
     394         337 :         oid cur = oid_nil;
     395             : 
     396         337 :         if (g->ttype == TYPE_void) { /* void case ? */
     397          25 :                 oid c = g->hseqbase;
     398         100 :                 for (BUN n = 0; n < nr; n++, c++) {
     399          75 :                         ri1[q] = c;
     400          75 :                         ri2[q] = FALSE;
     401          75 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     402           7 :                                 ri2[q] = TRUE;
     403          68 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     404           3 :                                 ri2[q] = bit_nil;
     405          75 :                         q++;
     406             :                 }
     407             :         } else {
     408         312 :                 oid *gi = Tloc(g, 0);
     409         312 :                 oid c = g->hseqbase;
     410         312 :                 if (nr)
     411         312 :                         cur = gi[0];
     412             :                 bit m = FALSE;
     413             :                 bool has_nil = false;
     414      332251 :                 for (BUN n = 0; n < nr; n++, c++) {
     415      331939 :                         if (c && cur != gi[n]) {
     416       57618 :                                 ri1[q] = c-1;
     417       57618 :                                 ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     418       57618 :                                 q++;
     419       57618 :                                 cur = gi[n];
     420       57618 :                                 m = FALSE;
     421       57618 :                                 has_nil = false;
     422             :                         }
     423      331939 :                         if (m == TRUE)
     424      191802 :                                 continue;
     425             : 
     426      140137 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     427             :                                 m = TRUE;
     428      133264 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     429      331939 :                                 has_nil = true;
     430             :                 }
     431         312 :                 if (nr) {
     432         312 :                         ri1[q] = c-1;
     433         312 :                         ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     434             :                 }
     435         312 :                 q++;
     436             :         }
     437         337 :         BATsetcount(res1, q);
     438         337 :         BATsetcount(res2, q);
     439         337 :         res1->tsorted = true;
     440         337 :         res1->tkey = true;
     441         337 :         res1->trevsorted = false;
     442         337 :         res2->tsorted = false;
     443         337 :         res2->trevsorted = false;
     444         337 :         res1->tnil = false;
     445         337 :         res1->tnonil = true;
     446         337 :         res2->tnonil = false;
     447         337 :         res2->tkey = false;
     448             : 
     449         337 :         BBPreclaim(g);
     450         337 :         BBPreclaim(m);
     451         337 :         BBPreclaim(p);
     452             : 
     453         337 :         BBPkeepref(res1);
     454         337 :         BBPkeepref(res2);
     455         337 :         *r1 = res1->batCacheid;
     456         337 :         *r2 = res2->batCacheid;
     457         337 :         return MAL_SUCCEED;
     458             : }
     459             : 
     460             : static str
     461          19 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     462             : {
     463          19 :         BAT *g = BATdescriptor(*gid); /* oid */
     464          19 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     465          19 :         BAT *p = BATdescriptor(*pid); /* bit */
     466          19 :         BAT *res1 = NULL, *res2 = NULL;
     467          19 :         bit any = *Any; /* any or normal comparison semantics */
     468             : 
     469          19 :         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          19 :         BUN nr = BATcount(g), q = 0;
     476             : 
     477          19 :         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          19 :         assert(g->tsorted);
     485          19 :         oid *ri1 = Tloc(res1, 0);
     486          19 :         bit *ri2 = Tloc(res2, 0);
     487          19 :         bit *mi = Tloc(m, 0);
     488          19 :         bit *pi = Tloc(p, 0);
     489          19 :         oid cur = oid_nil;
     490             : 
     491          19 :         if (g->ttype == TYPE_void) { /* void case ? */
     492           6 :                 oid c = g->hseqbase;
     493          71 :                 for (BUN n = 0; n < nr; n++, c++) {
     494          65 :                         ri1[q] = c;
     495         127 :                         ri2[q] = (any && (mi[n] == bit_nil || pi[n] == bit_nil))?bit_nil:(mi[n] == TRUE && pi[n] == TRUE)?TRUE:FALSE;
     496          65 :                         q++;
     497             :                 }
     498             :         } else {
     499          13 :                 oid *gi = Tloc(g, 0);
     500          13 :                 oid c = g->hseqbase;
     501          13 :                 if (nr)
     502          13 :                         cur = gi[0];
     503             :                 bool used = false;
     504         493 :                 for (BUN n = 0; n < nr; n++, c++) {
     505         480 :                         if (c && cur != gi[n]) {
     506         122 :                                 if (!used) {
     507           0 :                                         ri1[q] = c-1;
     508           0 :                                         ri2[q] = false;
     509           0 :                                         q++;
     510             :                                 }
     511         122 :                                 used = false;
     512         122 :                                 cur = gi[n];
     513             :                         }
     514         480 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     515         278 :                                 ri1[q] = c;
     516         278 :                                 ri2[q] = TRUE;
     517         278 :                                 used = true;
     518         278 :                                 q++;
     519         202 :                         } else if (mi[n] == FALSE) { /* empty */
     520          40 :                                 ri1[q] = c;
     521          40 :                                 ri2[q] = FALSE;
     522          40 :                                 used = true;
     523          40 :                                 q++;
     524         162 :                         } else if (any && (mi[n] == bit_nil /* ie has nil */ || pi[n] == bit_nil)) {
     525           0 :                                 ri1[q] = c;
     526           0 :                                 ri2[q] = bit_nil;
     527           0 :                                 used = true;
     528           0 :                                 q++;
     529             :                         }
     530             :                 }
     531          13 :                 if (nr && !used) {
     532           0 :                         ri1[q] = c-1;
     533           0 :                         ri2[q] = FALSE;
     534           0 :                         q++;
     535             :                 }
     536             :         }
     537          19 :         BATsetcount(res1, q);
     538          19 :         BATsetcount(res2, q);
     539          19 :         res1->tsorted = true;
     540          19 :         res1->tkey = true;
     541          19 :         res1->trevsorted = false;
     542          19 :         res2->tsorted = false;
     543          19 :         res2->trevsorted = false;
     544          19 :         res1->tnil = false;
     545          19 :         res1->tnonil = true;
     546          19 :         res2->tnonil = false;
     547          19 :         res2->tkey = false;
     548             : 
     549          19 :         BBPreclaim(g);
     550          19 :         BBPreclaim(m);
     551          19 :         BBPreclaim(p);
     552             : 
     553          19 :         BBPkeepref(res1);
     554          19 :         BBPkeepref(res2);
     555          19 :         *r1 = res1->batCacheid;
     556          19 :         *r2 = res2->batCacheid;
     557          19 :         return MAL_SUCCEED;
     558             : }
     559             : 
     560             : 
     561             : static str
     562        1469 : ALGselectNotNil(bat *result, const bat *bid)
     563             : {
     564        1469 :         BAT *b;
     565             : 
     566        1469 :         if ((b = BATdescriptor(*bid)) == NULL)
     567           0 :                 throw(MAL, "algebra.selectNotNil",
     568             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     569             : 
     570        1470 :         MT_lock_set(&b->theaplock);
     571        1470 :         bool bnonil = b->tnonil || b->ttype == TYPE_msk;
     572        1470 :         MT_lock_unset(&b->theaplock);
     573        1470 :         if (!bnonil) {
     574          71 :                 BAT *s;
     575          71 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true, false);
     576          71 :                 if (s) {
     577          71 :                         BAT *bn = BATproject(s, b);
     578          71 :                         BBPunfix(s->batCacheid);
     579          71 :                         if (bn) {
     580          71 :                                 BBPunfix(b->batCacheid);
     581          71 :                                 *result = bn->batCacheid;
     582          71 :                                 BBPkeepref(bn);
     583          71 :                                 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        1399 :         *result = b->batCacheid;
     591        1399 :         BBPkeepref(b);
     592        1399 :         return MAL_SUCCEED;
     593             : }
     594             : 
     595             : static str
     596      522761 : 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      522761 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     616      522761 :         BAT *candleft = NULL, *candright = NULL;
     617      522761 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     618      522761 :         BUN est;
     619      522761 :         const char *err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     620             : 
     621      522761 :         assert(r2id == NULL || rangefunc != NULL);
     622             : 
     623      522761 :         if ((left = BATdescriptor(*lid)) == NULL)
     624           0 :                 goto fail;
     625      528544 :         if ((right = BATdescriptor(*rid)) == NULL)
     626           0 :                 goto fail;
     627      528622 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     628           0 :                 goto fail;
     629      528625 :         if (srid && !is_bat_nil(*srid)
     630           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     631           0 :                 goto fail;
     632      528625 :         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      528625 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     639             : 
     640      528625 :         if (thetafunc) {
     641       51160 :                 assert(joinfunc == NULL);
     642       51160 :                 assert(semifunc == NULL);
     643       51160 :                 assert(markfunc == NULL);
     644       51160 :                 assert(bandfunc == NULL);
     645       51160 :                 assert(rangefunc == NULL);
     646       51160 :                 assert(difffunc == NULL);
     647       51160 :                 assert(interfunc == NULL);
     648       51160 :                 if ((*thetafunc)
     649             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     650       51160 :                          op, *nil_matches, est) != GDK_SUCCEED)
     651           0 :                         goto fail;
     652      477465 :         } else if (joinfunc) {
     653      353779 :                 assert(semifunc == NULL);
     654      353779 :                 assert(markfunc == NULL);
     655      353779 :                 assert(bandfunc == NULL);
     656      353779 :                 assert(rangefunc == NULL);
     657      353779 :                 assert(difffunc == NULL);
     658      353779 :                 assert(interfunc == NULL);
     659      353779 :                 if ((*joinfunc)
     660             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     661      353779 :                          *nil_matches, est) != GDK_SUCCEED)
     662           1 :                         goto fail;
     663      123686 :         } else if (semifunc) {
     664         206 :                 assert(markfunc == NULL);
     665         206 :                 assert(bandfunc == NULL);
     666         206 :                 assert(rangefunc == NULL);
     667         206 :                 assert(difffunc == NULL);
     668         206 :                 assert(interfunc == NULL);
     669         206 :                 if ((*semifunc)
     670             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     671         206 :                          *nil_matches, *max_one, est) != GDK_SUCCEED)
     672          25 :                         goto fail;
     673      123480 :         } else if (markfunc) {
     674        4283 :                 assert(bandfunc == NULL);
     675        4283 :                 assert(rangefunc == NULL);
     676        4283 :                 assert(difffunc == NULL);
     677        4283 :                 assert(interfunc == NULL);
     678        8564 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     679             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     680           0 :                         goto fail;
     681      119197 :         } 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      119197 :         } 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         145 :                 BBPunfix(right2->batCacheid);
     701      119050 :         } else if (difffunc) {
     702      110376 :                 assert(r2 == NULL);
     703      110376 :                 assert(interfunc == NULL);
     704      110277 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     705      110376 :                                                                         *nil_matches, *not_in, est)) == NULL)
     706           0 :                         goto fail;
     707             :         } else {
     708        8674 :                 assert(r2 == NULL);
     709        8671 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     710        8674 :                                                                          *nil_matches, *max_one, est)) == NULL)
     711           1 :                         goto fail;
     712             :         }
     713      525571 :         *r1 = result1->batCacheid;
     714      525571 :         BBPkeepref(result1);
     715      526401 :         if (r2) {
     716      324191 :                 *r2 = result2->batCacheid;
     717      324191 :                 BBPkeepref(result2);
     718             :         }
     719      527524 :         if (r3) {
     720        4274 :                 *r3 = result3->batCacheid;
     721        4274 :                 BBPkeepref(result3);
     722             :         }
     723      527530 :         BBPunfix(left->batCacheid);
     724      528165 :         BBPunfix(right->batCacheid);
     725      528524 :         BBPreclaim(candleft);
     726      528543 :         BBPreclaim(candright);
     727             :         return MAL_SUCCEED;
     728             : 
     729          27 :   fail:
     730          27 :         BBPreclaim(left);
     731          27 :         BBPreclaim(right);
     732          27 :         BBPreclaim(right2);
     733          27 :         BBPreclaim(candleft);
     734          27 :         BBPreclaim(candright);
     735          27 :         if (err == NULL)
     736          27 :                 throw(MAL, funcname, GDK_EXCEPTION);
     737           0 :         throw(MAL, funcname, "%s", err);
     738             : }
     739             : 
     740             : static str
     741      314021 : 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      314021 :         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       36431 : 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       36431 :         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          53 : 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          53 :         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         151 : 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         151 :         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        4262 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     815             :                          const bat *slid, const bat *srid, const lng *estimate)
     816             : {
     817        4262 :         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           2 : 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           2 :         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        7613 : 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        7613 :         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       41384 : 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       41384 :         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         118 : 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         240 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     883         118 :                                    *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          22 : 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          47 :         return do_join(r1, NULL, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     894          22 :                                    *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      110257 : 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      110257 :         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        8669 : 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        8669 :         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        1568 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     932             : {
     933        1568 :         bat *ret1, *ret2 = NULL;
     934        1568 :         bat bid, sid, gid;
     935        1568 :         BAT *b, *s = NULL, *g = NULL;
     936        1568 :         BAT *bn = NULL, *gn = NULL;
     937        1568 :         lng n;
     938        1568 :         bit asc, nilslast, distinct;
     939        1568 :         gdk_return rc;
     940             : 
     941        1568 :         (void) cntxt;
     942        1568 :         (void) mb;
     943             : 
     944        1568 :         assert(pci->retc == 1 || pci->retc == 2);
     945        1568 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     946             : 
     947        1568 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     948        1568 :         if (n < 0)
     949           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     950        1568 :         if (n > (lng) BUN_MAX)
     951             :                 n = BUN_MAX;
     952        1568 :         ret1 = getArgReference_bat(stk, pci, 0);
     953        1568 :         if (pci->retc == 2)
     954         517 :                 ret2 = getArgReference_bat(stk, pci, 1);
     955        1568 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     956        1568 :         if ((b = BATdescriptor(bid)) == NULL)
     957           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     958        1569 :         if (pci->argc - pci->retc > 5) {
     959        1570 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     960        1570 :                 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        1570 :                 if (pci->argc - pci->retc > 6) {
     966        1570 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     967        1570 :                         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        1569 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     976        1569 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     977        1569 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
     978        2621 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
     979             :                                    distinct);
     980        1566 :         BBPunfix(b->batCacheid);
     981        1568 :         BBPreclaim(s);
     982        1568 :         BBPreclaim(g);
     983        1571 :         if (rc != GDK_SUCCEED)
     984           0 :                 throw(MAL, "algebra.firstn", GDK_EXCEPTION);
     985        1571 :         *ret1 = bn->batCacheid;
     986        1571 :         BBPkeepref(bn);
     987        1563 :         if (ret2) {
     988         515 :                 *ret2 = gn->batCacheid;
     989         515 :                 BBPkeepref(gn);
     990             :         }
     991             :         return MAL_SUCCEED;
     992             : }
     993             : 
     994             : static str
     995           9 : ALGunary(bat *result, const bat *bid, BAT *(*func)(BAT *), const char *name)
     996             : {
     997           9 :         BAT *b, *bn;
     998             : 
     999           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1000           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1001             :         }
    1002           9 :         bn = (*func) (b);
    1003           9 :         BBPunfix(b->batCacheid);
    1004           9 :         if (bn == NULL)
    1005           0 :                 throw(MAL, name, GDK_EXCEPTION);
    1006           9 :         *result = bn->batCacheid;
    1007           9 :         BBPkeepref(bn);
    1008           9 :         return MAL_SUCCEED;
    1009             : }
    1010             : 
    1011             : static inline BAT *
    1012           9 : BATwcopy(BAT *b)
    1013             : {
    1014           9 :         return COLcopy(b, b->ttype, true, TRANSIENT);
    1015             : }
    1016             : 
    1017             : static str
    1018           9 : ALGcopy(bat *result, const bat *bid)
    1019             : {
    1020           9 :         return ALGunary(result, bid, BATwcopy, "algebra.copy");
    1021             : }
    1022             : 
    1023             : static str
    1024          74 : ALGunique(bat *result, const bat *bid, const bat *sid)
    1025             : {
    1026          74 :         BAT *b, *s = NULL, *bn = NULL;
    1027             : 
    1028          74 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1029           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1030             :         }
    1031          74 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
    1032           0 :                 BBPunfix(b->batCacheid);
    1033           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1034             :         }
    1035          74 :         bn = BATunique(b, s);
    1036          74 :         BBPunfix(b->batCacheid);
    1037          74 :         BBPreclaim(s);
    1038          74 :         if (bn == NULL)
    1039           0 :                 throw(MAL, "algebra.unique", GDK_EXCEPTION);
    1040          74 :         *result = bn->batCacheid;
    1041          74 :         BBPkeepref(bn);
    1042          74 :         return MAL_SUCCEED;
    1043             : }
    1044             : 
    1045             : static str
    1046       43526 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1047             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1048             : {
    1049       43526 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1050       43526 :         BAT *sl = NULL, *sr = NULL;
    1051       43526 :         gdk_return ret;
    1052             : 
    1053       43526 :         L = BATdescriptor(*left);
    1054       45014 :         R = BATdescriptor(*right);
    1055       45092 :         if (L == NULL || R == NULL) {
    1056           0 :                 BBPreclaim(L);
    1057           0 :                 BBPreclaim(R);
    1058           0 :                 throw(MAL, "algebra.crossproduct",
    1059             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1060             :         }
    1061       45092 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1062           0 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1063           0 :                 BBPunfix(L->batCacheid);
    1064           0 :                 BBPunfix(R->batCacheid);
    1065           0 :                 BBPreclaim(sl);
    1066             :                 /* sr == NULL, so no need to unfix */
    1067           0 :                 throw(MAL, "algebra.crossproduct",
    1068             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1069             :         }
    1070       46622 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1071       45092 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1072       44412 :         BBPunfix(L->batCacheid);
    1073       44996 :         BBPunfix(R->batCacheid);
    1074       45084 :         BBPreclaim(sl);
    1075       45088 :         BBPreclaim(sr);
    1076       45086 :         if (ret != GDK_SUCCEED)
    1077          62 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1078       45024 :         *l = bn1->batCacheid;
    1079       45024 :         BBPkeepref(bn1);
    1080       44974 :         if (r) {
    1081       43461 :                 *r = bn2->batCacheid;
    1082       43461 :                 BBPkeepref(bn2);
    1083             :         }
    1084             :         return MAL_SUCCEED;
    1085             : }
    1086             : 
    1087             : static str
    1088        1479 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1089             : {
    1090        1479 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1091             : }
    1092             : 
    1093             : static str
    1094       42162 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1095             :                                  const bit *max_one)
    1096             : {
    1097       42162 :         return ALGcrossproduct(l, r, left, right, NULL, NULL, max_one);
    1098             : }
    1099             : 
    1100             : static str
    1101           0 : ALGcrossproduct3(bat *l, bat *r, const bat *left, const bat *right,
    1102             :                                  const bat *sl, const bat *sr, const bit *max_one)
    1103             : {
    1104           0 :         return ALGcrossproduct(l, r, left, right, sl, sr, max_one);
    1105             : }
    1106             : 
    1107             : static str
    1108           0 : ALGcrossproduct4(bat *l, const bat *left, const bat *right, const bat *sl,
    1109             :                                  const bat *sr, const bit *max_one)
    1110             : {
    1111           0 :         return ALGcrossproduct(l, NULL, left, right, sl, sr, max_one);
    1112             : }
    1113             : 
    1114             : static str
    1115         366 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1116             : {
    1117         366 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1118         366 :         BAT *sl = NULL, *sr = NULL;
    1119         366 :         gdk_return ret;
    1120             : 
    1121         366 :         L = BATdescriptor(*left);
    1122         366 :         R = BATdescriptor(*right);
    1123         366 :         if (L == NULL || R == NULL) {
    1124           0 :                 BBPreclaim(L);
    1125           0 :                 BBPreclaim(R);
    1126           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1127             :         }
    1128         366 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1129         366 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1130           0 :                 BBPunfix(L->batCacheid);
    1131           0 :                 BBPunfix(R->batCacheid);
    1132           0 :                 BBPreclaim(sl);
    1133             :                 /* sr == NULL, so no need to unfix */
    1134           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1135             :         }
    1136         366 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1137         366 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1138         366 :         BBPunfix(L->batCacheid);
    1139         366 :         BBPunfix(R->batCacheid);
    1140         366 :         BBPreclaim(sl);
    1141         366 :         BBPreclaim(sr);
    1142         366 :         if (ret != GDK_SUCCEED)
    1143           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1144         366 :         *l = bn1->batCacheid;
    1145         366 :         BBPkeepref(bn1);
    1146         366 :         if (r) {
    1147         366 :                 *r = bn2->batCacheid;
    1148         366 :                 BBPkeepref(bn2);
    1149             :         }
    1150             :         return MAL_SUCCEED;
    1151             : }
    1152             : 
    1153             : static str
    1154     1726371 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1155             : {
    1156     1726371 :         BAT *l, *r1, *r2 = NULL, *bn;
    1157             : 
    1158     1726371 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1159           0 :                 throw(MAL, "algebra.projection",
    1160             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1161             :         }
    1162     1738326 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1163           0 :                 BBPunfix(l->batCacheid);
    1164           0 :                 throw(MAL, "algebra.projection",
    1165             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1166             :         }
    1167     1737605 :         if (r2id && !is_bat_nil(*r2id) && (r2 = BATdescriptor(*r2id)) == NULL) {
    1168           0 :                 BBPunfix(l->batCacheid);
    1169           0 :                 BBPunfix(r1->batCacheid);
    1170           0 :                 throw(MAL, "algebra.projection",
    1171             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1172             :         }
    1173     1737605 :         bn = BATproject2(l, r1, r2);
    1174     1718373 :         BBPunfix(l->batCacheid);
    1175     1734854 :         BBPunfix(r1->batCacheid);
    1176     1737562 :         BBPreclaim(r2);
    1177     1737727 :         if (bn == NULL)
    1178           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1179     1737727 :         *result = bn->batCacheid;
    1180     1737727 :         BBPkeepref(bn);
    1181     1737727 :         return MAL_SUCCEED;
    1182             : }
    1183             : 
    1184             : str
    1185     1728821 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1186             : {
    1187     1728821 :         return ALGprojection2(result, lid, rid, NULL);
    1188             : }
    1189             : 
    1190             : static str
    1191       23566 : ALGsort33(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1192             :                   const bat *order, const bat *group, const bit *reverse,
    1193             :                   const bit *nilslast, const bit *stable)
    1194             : {
    1195       23566 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1196       23566 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1197             : 
    1198       23566 :         if ((b = BATdescriptor(*bid)) == NULL)
    1199           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1200       23567 :         if (order && !is_bat_nil(*order) && (o = BATdescriptor(*order)) == NULL) {
    1201           0 :                 BBPunfix(b->batCacheid);
    1202           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1203             :         }
    1204       23567 :         if (group &&!is_bat_nil(*group) && (g = BATdescriptor(*group)) == NULL) {
    1205           0 :                 BBPreclaim(o);
    1206           0 :                 BBPunfix(b->batCacheid);
    1207           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1208             :         }
    1209       27122 :         if (BATsort(result ? &bn : NULL,
    1210             :                                 norder ? &on : NULL,
    1211             :                                 ngroup ? &gn : NULL,
    1212       23567 :                                 b, o, g, *reverse, *nilslast, *stable) != GDK_SUCCEED) {
    1213           0 :                 BBPreclaim(o);
    1214           0 :                 BBPreclaim(g);
    1215           0 :                 BBPunfix(b->batCacheid);
    1216           0 :                 throw(MAL, "algebra.sort", GDK_EXCEPTION);
    1217             :         }
    1218       23567 :         BBPunfix(b->batCacheid);
    1219       23567 :         BBPreclaim(o);
    1220       23567 :         BBPreclaim(g);
    1221       23567 :         if (result) {
    1222       23567 :                 *result = bn->batCacheid;
    1223       23567 :                 BBPkeepref(bn);
    1224             :         }
    1225       23567 :         if (norder) {
    1226       20012 :                 *norder = on->batCacheid;
    1227       20012 :                 BBPkeepref(on);
    1228             :         }
    1229       23567 :         if (ngroup) {
    1230       13491 :                 *ngroup = gn->batCacheid;
    1231       13491 :                 BBPkeepref(gn);
    1232             :         }
    1233             :         return MAL_SUCCEED;
    1234             : }
    1235             : 
    1236             : static str
    1237        4024 : ALGsort32(bat *result, bat *norder, const bat *bid, const bat *order,
    1238             :                   const bat *group, const bit *reverse, const bit *nilslast,
    1239             :                   const bit *stable)
    1240             : {
    1241        4024 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast,
    1242             :                                          stable);
    1243             : }
    1244             : 
    1245             : static str
    1246        1952 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group,
    1247             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1248             : {
    1249        1952 :         return ALGsort33(result, NULL, NULL, bid, order, group, reverse, nilslast,
    1250             :                                          stable);
    1251             : }
    1252             : 
    1253             : static str
    1254           0 : ALGsort23(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1255             :                   const bat *order, const bit *reverse, const bit *nilslast,
    1256             :                   const bit *stable)
    1257             : {
    1258           0 :         return ALGsort33(result, norder, ngroup, bid, order, NULL, reverse,
    1259             :                                          nilslast, stable);
    1260             : }
    1261             : 
    1262             : static str
    1263           0 : ALGsort22(bat *result, bat *norder, const bat *bid, const bat *order,
    1264             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1265             : {
    1266           0 :         return ALGsort33(result, norder, NULL, bid, order, NULL, reverse, nilslast,
    1267             :                                          stable);
    1268             : }
    1269             : 
    1270             : static str
    1271           0 : ALGsort21(bat *result, const bat *bid, const bat *order, const bit *reverse,
    1272             :                   const bit *nilslast, const bit *stable)
    1273             : {
    1274           0 :         return ALGsort33(result, NULL, NULL, bid, order, NULL, reverse, nilslast,
    1275             :                                          stable);
    1276             : }
    1277             : 
    1278             : static str
    1279        6231 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1280             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1281             : {
    1282        6231 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1283             :                                          stable);
    1284             : }
    1285             : 
    1286             : static str
    1287        2497 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1288             :                   const bit *nilslast, const bit *stable)
    1289             : {
    1290        2497 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast,
    1291             :                                          stable);
    1292             : }
    1293             : 
    1294             : static str
    1295        1603 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast,
    1296             :                   const bit *stable)
    1297             : {
    1298        1603 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast,
    1299             :                                          stable);
    1300             : }
    1301             : 
    1302             : static str
    1303       69745 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1304             :                                 const bit *ignore_nils)
    1305             : {
    1306       69745 :         BAT *b, *s = NULL;
    1307             : 
    1308       69745 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1309           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1310             :         }
    1311       69974 :         if (cnd && !is_bat_nil(*cnd) && (s = BATdescriptor(*cnd)) == NULL) {
    1312           0 :                 BBPunfix(b->batCacheid);
    1313           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1314             :         }
    1315       69974 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1316          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1317       69944 :         } else if (*ignore_nils) {
    1318        1769 :                 *result = (lng) BATcount_no_nil(b, s);
    1319             :         } else {
    1320       68175 :                 struct canditer ci;
    1321       68175 :                 canditer_init(&ci, b, s);
    1322       68191 :                 *result = (lng) ci.ncand;
    1323             :         }
    1324       69990 :         BBPreclaim(s);
    1325       69990 :         BBPunfix(b->batCacheid);
    1326       69990 :         return MAL_SUCCEED;
    1327             : }
    1328             : 
    1329             : static str
    1330        1769 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1331             : {
    1332        1769 :         return ALGcountCND_nil(result, bid, NULL, ignore_nils);
    1333             : }
    1334             : 
    1335             : static str
    1336           0 : ALGcountCND_bat(lng *result, const bat *bid, const bat *cnd)
    1337             : {
    1338           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 0 });
    1339             : }
    1340             : 
    1341             : static str
    1342       67978 : ALGcount_bat(lng *result, const bat *bid)
    1343             : {
    1344       67978 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 0 });
    1345             : }
    1346             : 
    1347             : static str
    1348           0 : ALGcountCND_no_nil(lng *result, const bat *bid, const bat *cnd)
    1349             : {
    1350           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 1 });
    1351             : }
    1352             : 
    1353             : static str
    1354           0 : ALGcount_no_nil(lng *result, const bat *bid)
    1355             : {
    1356           0 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 1 });
    1357             : }
    1358             : 
    1359             : static str
    1360           6 : ALGslice(bat *ret, const bat *bid, const lng *start, const lng *end)
    1361             : {
    1362           6 :         BAT *b, *bn = NULL;
    1363             : 
    1364           6 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1365           0 :                 throw(MAL, "algebra.slice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1366             :         }
    1367           6 :         if (slice(&bn, b, *start, *end) == GDK_SUCCEED) {
    1368           6 :                 *ret = bn->batCacheid;
    1369           6 :                 BBPkeepref(bn);
    1370           6 :                 BBPunfix(b->batCacheid);
    1371           6 :                 return MAL_SUCCEED;
    1372             :         }
    1373           0 :         BBPunfix(b->batCacheid);
    1374           0 :         throw(MAL, "algebra.slice", GDK_EXCEPTION);
    1375             : }
    1376             : 
    1377             : static str
    1378           1 : ALGslice_int(bat *ret, const bat *bid, const int *start, const int *end)
    1379             : {
    1380           1 :         lng s = *start;
    1381           1 :         lng e = (is_int_nil(*end) ? lng_nil : *end);
    1382             : 
    1383           1 :         return ALGslice(ret, bid, &s, &e);
    1384             : }
    1385             : 
    1386             : static str
    1387           0 : ALGslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1388             : {
    1389           0 :         lng s = *start;
    1390           0 :         lng e = *end;
    1391             : 
    1392           0 :         return ALGslice(ret, bid, &s, &e);
    1393             : }
    1394             : 
    1395             : /* carve out a slice based on the OIDs */
    1396             : /* beware that BATs may have different OID bases */
    1397             : static str
    1398           5 : ALGslice_oid(bat *ret, const bat *bid, const oid *start, const oid *end)
    1399             : {
    1400           5 :         lng s = (lng) (is_oid_nil(*start) ? 0 : (lng) *start);
    1401           5 :         lng e = (is_oid_nil(*end) ? lng_nil : (lng) *end);
    1402             : 
    1403           5 :         return ALGslice(ret, bid, &s, &e);
    1404             : }
    1405             : 
    1406             : static str
    1407       17086 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1408             : {
    1409       17086 :         BAT *b, *bn;
    1410       17086 :         BUN s, e;
    1411             : 
    1412       17086 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1413           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1414       17086 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1415           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1416       17087 :         s = (BUN) *start;
    1417       17087 :         if (s > BATcount(b))
    1418             :                 s = BATcount(b);
    1419       17087 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1420       17087 :         if (e > BATcount(b))
    1421             :                 e = BATcount(b);
    1422       17087 :         if (e < s)
    1423             :                 e = s;
    1424       17087 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1425       17088 :         if (bn == NULL)
    1426           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1427       17088 :         *ret = bn->batCacheid;
    1428       17088 :         BBPkeepref(bn);
    1429       17088 :         return MAL_SUCCEED;
    1430             : }
    1431             : 
    1432             : /*
    1433             :  * BUN Get/Fetch
    1434             :  */
    1435             : 
    1436             : static str
    1437       88858 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1438             : {
    1439       88858 :         assert(pos <= BUN_MAX);
    1440       88858 :         BATiter bi = bat_iterator(b);
    1441       88858 :         if (ATOMextern(b->ttype)) {
    1442         190 :                 ptr _src = BUNtail(bi, pos);
    1443         190 :                 size_t _len = ATOMlen(b->ttype, _src);
    1444         190 :                 ptr _dst = GDKmalloc(_len);
    1445         190 :                 if (_dst == NULL) {
    1446           0 :                         bat_iterator_end(&bi);
    1447           0 :                         throw(MAL, "doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1448             :                 }
    1449         190 :                 memcpy(_dst, _src, _len);
    1450         190 :                 *(ptr *) ret = _dst;
    1451             :         } else {
    1452       88668 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1453       88668 :                 if (b->ttype == TYPE_void) {
    1454           0 :                         *(oid *) ret = b->tseqbase;
    1455           0 :                         if (!is_oid_nil(b->tseqbase))
    1456           0 :                                 *(oid *) ret += pos;
    1457       88668 :                 } else if (_s == 4) {
    1458       88581 :                         *(int *) ret = ((int *) bi.base)[pos];
    1459             :                 } else if (_s == 1) {
    1460          11 :                         *(bte *) ret = ((bte *) bi.base)[pos];
    1461             :                 } else if (_s == 2) {
    1462           1 :                         *(sht *) ret = ((sht *) bi.base)[pos];
    1463             :                 } else if (_s == 8) {
    1464          75 :                         *(lng *) ret = ((lng *) bi.base)[pos];
    1465             : #ifdef HAVE_HGE
    1466             :                 } else if (_s == 16) {
    1467           0 :                         *(hge *) ret = ((hge *) bi.base)[pos];
    1468             : #endif
    1469             :                 } else {
    1470           0 :                         memcpy(ret, (const char *) bi.base + (pos << bi.shift), _s);
    1471             :                 }
    1472             :         }
    1473       88858 :         bat_iterator_end(&bi);
    1474       88858 :         return MAL_SUCCEED;
    1475             : }
    1476             : 
    1477             : static str
    1478       88860 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1479             : {
    1480       88860 :         BAT *b;
    1481       88860 :         str msg;
    1482             : 
    1483       88860 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1484           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1485             :         }
    1486       88860 :         if (*pos < (lng) 0) {
    1487           0 :                 BBPunfix(b->batCacheid);
    1488           0 :                 throw(MAL, "algebra.fetch",
    1489             :                           ILLEGAL_ARGUMENT ": row index to fetch must be non negative\n");
    1490             :         }
    1491       88860 :         if (BATcount(b) == 0) {
    1492           2 :                 BBPunfix(b->batCacheid);
    1493           2 :                 throw(MAL, "algebra.fetch",
    1494             :                           ILLEGAL_ARGUMENT
    1495             :                           ": cannot fetch a single row from an empty input\n");
    1496             :         }
    1497       88858 :         if (*pos >= (lng) BATcount(b)) {
    1498           0 :                 BBPunfix(b->batCacheid);
    1499           0 :                 throw(MAL, "algebra.fetch",
    1500             :                           ILLEGAL_ARGUMENT ": row index to fetch is out of range\n");
    1501             :         }
    1502       88858 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1503       88858 :         BBPunfix(b->batCacheid);
    1504       88858 :         return msg;
    1505             : }
    1506             : 
    1507             : str
    1508       88860 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1509             : {
    1510       88860 :         lng o = *pos;
    1511             : 
    1512       88860 :         return ALGfetch(ret, bid, &o);
    1513             : }
    1514             : 
    1515             : static str
    1516           0 : ALGexist(bit *ret, const bat *bid, const void *val)
    1517             : {
    1518           0 :         BAT *b;
    1519           0 :         BUN q;
    1520             : 
    1521           0 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1522           0 :                 throw(MAL, "algebra.exist", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1523             :         }
    1524           0 :         derefStr(b, val);
    1525           0 :         q = BUNfnd(b, val);
    1526           0 :         *ret = (q != BUN_NONE);
    1527           0 :         BBPunfix(b->batCacheid);
    1528           0 :         return MAL_SUCCEED;
    1529             : }
    1530             : 
    1531             : static str
    1532           9 : ALGfind(oid *ret, const bat *bid, ptr val)
    1533             : {
    1534           9 :         BAT *b;
    1535           9 :         BUN q;
    1536           9 :         str msg = MAL_SUCCEED;
    1537             : 
    1538           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1539           0 :                 throw(MAL, "algebra.find", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1540             :         }
    1541           9 :         derefStr(b, val);
    1542           9 :         q = BUNfnd(b, val);
    1543             : 
    1544           9 :         if (q == BUN_NONE) {
    1545           3 :                 *ret = oid_nil;
    1546             :         } else
    1547           6 :                 *ret = (oid) q;
    1548           9 :         BBPunfix(b->batCacheid);
    1549           9 :         return msg;
    1550             : }
    1551             : 
    1552             : 
    1553             : static str
    1554      205351 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1555             : {
    1556      205351 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1557      205351 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1558      205351 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1559      205351 :         BAT *b, *bn;
    1560             : 
    1561      205351 :         (void) cntxt;
    1562      205351 :         (void) mb;
    1563      205351 :         if (isaBatType(getArgType(mb, pci, 2)))
    1564           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1565      205351 :         if ((b = BBPquickdesc(bid)) == NULL)
    1566           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1567      205337 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1568      205471 :         if (bn == NULL) {
    1569           0 :                 *ret = bat_nil;
    1570           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1571             :         }
    1572      205471 :         *ret = bn->batCacheid;
    1573      205471 :         BBPkeepref(bn);
    1574      205471 :         return MAL_SUCCEED;
    1575             : }
    1576             : 
    1577             : 
    1578             : static str
    1579           0 : ALGreuse(bat *ret, const bat *bid)
    1580             : {
    1581           0 :         BAT *b, *bn;
    1582           0 :         if ((b = BATdescriptor(*bid)) == NULL)
    1583           0 :                 throw(MAL, "algebra.reuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1584             : 
    1585           0 :         if (!b->batTransient || b->batRestricted != BAT_WRITE) {
    1586           0 :                 if (ATOMvarsized(b->ttype)) {
    1587           0 :                         bn = BATwcopy(b);
    1588           0 :                         if (bn == NULL) {
    1589           0 :                                 BBPunfix(b->batCacheid);
    1590           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1591             :                         }
    1592             :                 } else {
    1593           0 :                         bn = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
    1594           0 :                         if (bn == NULL) {
    1595           0 :                                 BBPunfix(b->batCacheid);
    1596           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1597             :                         }
    1598           0 :                         BATsetcount(bn, BATcount(b));
    1599           0 :                         bn->tsorted = false;
    1600           0 :                         bn->trevsorted = false;
    1601           0 :                         BATkey(bn, false);
    1602             :                 }
    1603           0 :                 *ret = bn->batCacheid;
    1604           0 :                 BBPkeepref(bn);
    1605           0 :                 BBPunfix(b->batCacheid);
    1606             :         } else
    1607           0 :                 BBPkeepref(b);
    1608             :         return MAL_SUCCEED;
    1609             : }
    1610             : 
    1611             : /*
    1612             :  * BAT standard deviation
    1613             :  */
    1614             : static str
    1615           7 : ALGstdev(dbl *res, const bat *bid)
    1616             : {
    1617           7 :         BAT *b;
    1618           7 :         dbl stdev;
    1619             : 
    1620           7 :         if ((b = BATdescriptor(*bid)) == NULL)
    1621           0 :                 throw(MAL, "aggr.stdev", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1622           7 :         stdev = BATcalcstdev_sample(NULL, b);
    1623           7 :         BBPunfix(b->batCacheid);
    1624           7 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1625           0 :                 throw(MAL, "aggr.stdev", GDK_EXCEPTION);
    1626           7 :         *res = stdev;
    1627           7 :         return MAL_SUCCEED;
    1628             : }
    1629             : 
    1630             : static str
    1631          13 : ALGstdevp(dbl *res, const bat *bid)
    1632             : {
    1633          13 :         BAT *b;
    1634          13 :         dbl stdev;
    1635             : 
    1636          13 :         if ((b = BATdescriptor(*bid)) == NULL)
    1637           0 :                 throw(MAL, "aggr.stdevp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1638          13 :         stdev = BATcalcstdev_population(NULL, b);
    1639          13 :         BBPunfix(b->batCacheid);
    1640          13 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1641           1 :                 throw(MAL, "aggr.stdevp", GDK_EXCEPTION);
    1642          12 :         *res = stdev;
    1643          12 :         return MAL_SUCCEED;
    1644             : }
    1645             : 
    1646             : /*
    1647             :  * BAT variance
    1648             :  */
    1649             : static str
    1650           2 : ALGvariance(dbl *res, const bat *bid)
    1651             : {
    1652           2 :         BAT *b;
    1653           2 :         dbl variance;
    1654             : 
    1655           2 :         if ((b = BATdescriptor(*bid)) == NULL)
    1656           0 :                 throw(MAL, "aggr.variance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1657           2 :         variance = BATcalcvariance_sample(NULL, b);
    1658           2 :         BBPunfix(b->batCacheid);
    1659           2 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1660           0 :                 throw(MAL, "aggr.variance", GDK_EXCEPTION);
    1661           2 :         *res = variance;
    1662           2 :         return MAL_SUCCEED;
    1663             : }
    1664             : 
    1665             : static str
    1666           5 : ALGvariancep(dbl *res, const bat *bid)
    1667             : {
    1668           5 :         BAT *b;
    1669           5 :         dbl variance;
    1670             : 
    1671           5 :         if ((b = BATdescriptor(*bid)) == NULL)
    1672           0 :                 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1673           5 :         variance = BATcalcvariance_population(NULL, b);
    1674           5 :         BBPunfix(b->batCacheid);
    1675           5 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1676           1 :                 throw(MAL, "aggr.variancep", GDK_EXCEPTION);
    1677           4 :         *res = variance;
    1678           4 :         return MAL_SUCCEED;
    1679             : }
    1680             : 
    1681             : /*
    1682             :  * BAT covariance
    1683             :  */
    1684             : static str
    1685           5 : ALGcovariance(dbl *res, const bat *bid1, const bat *bid2)
    1686             : {
    1687           5 :         BAT *b1, *b2;
    1688           5 :         dbl covariance;
    1689             : 
    1690           5 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1691           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1692           5 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1693           0 :                 BBPunfix(b1->batCacheid);
    1694           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1695             :         }
    1696             : 
    1697           5 :         covariance = BATcalccovariance_sample(b1, b2);
    1698           5 :         BBPunfix(b1->batCacheid);
    1699           5 :         BBPunfix(b2->batCacheid);
    1700           4 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1701           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1702           4 :         *res = covariance;
    1703           4 :         return MAL_SUCCEED;
    1704             : }
    1705             : 
    1706             : static str
    1707           9 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1708             : {
    1709           9 :         BAT *b1, *b2;
    1710           9 :         dbl covariance;
    1711             : 
    1712           9 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1713           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1714           9 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1715           0 :                 BBPunfix(b1->batCacheid);
    1716           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1717             :         }
    1718             : 
    1719           9 :         covariance = BATcalccovariance_population(b1, b2);
    1720           9 :         BBPunfix(b1->batCacheid);
    1721           9 :         BBPunfix(b2->batCacheid);
    1722           9 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1723           1 :                 throw(MAL, "aggr.covariancep", GDK_EXCEPTION);
    1724           8 :         *res = covariance;
    1725           8 :         return MAL_SUCCEED;
    1726             : }
    1727             : 
    1728             : /*
    1729             :  * BAT correlation
    1730             :  */
    1731             : static str
    1732          19 : ALGcorr(dbl *res, const bat *bid1, const bat *bid2)
    1733             : {
    1734          19 :         BAT *b1, *b2;
    1735          19 :         dbl covariance;
    1736             : 
    1737          19 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1738           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1739          19 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1740           0 :                 BBPunfix(b1->batCacheid);
    1741           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1742             :         }
    1743             : 
    1744          19 :         covariance = BATcalccorrelation(b1, b2);
    1745          19 :         BBPunfix(b1->batCacheid);
    1746          19 :         BBPunfix(b2->batCacheid);
    1747          19 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1748           1 :                 throw(MAL, "aggr.corr", GDK_EXCEPTION);
    1749          18 :         *res = covariance;
    1750          18 :         return MAL_SUCCEED;
    1751             : }
    1752             : 
    1753             : #include "mel.h"
    1754             : mel_func algebra_init_funcs[] = {
    1755             :  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))),
    1756             :  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))),
    1757             :  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))),
    1758             :  pattern("algebra", "project", ALGprojecttail, false, "Fill the tail with a constant", args(1,3, batargany("",2),batargany("b",1),argany("v",2))),
    1759             :  command("algebra", "projection", ALGprojection, false, "Project left input onto right input.", args(1,3, batargany("",1),batarg("left",oid),batargany("right",1))),
    1760             :  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))),
    1761             :  command("algebra", "copy", ALGcopy, false, "Returns physical copy of a BAT.", args(1,2, batargany("",1),batargany("b",1))),
    1762             :  command("algebra", "exist", ALGexist, false, "Returns whether 'val' occurs in b.", args(1,3, arg("",bit),batargany("b",1),argany("val",1))),
    1763             :  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))),
    1764             :  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))),
    1765             :  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))),
    1766             :  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))),
    1767             :  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))),
    1768             :  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))),
    1769             :  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))),
    1770             :  command("algebra", "selectNotNil", ALGselectNotNil, false, "Select all not-nil values", args(1,2, batargany("",1),batargany("b",1))),
    1771             :  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))),
    1772             :  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))),
    1773             :  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))),
    1774             :  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))),
    1775             :  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))),
    1776             :  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))),
    1777             :  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))),
    1778             :  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))),
    1779             :  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))),
    1780             :  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))),
    1781             :  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))),
    1782             :  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))),
    1783             :  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))),
    1784             :  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))),
    1785             :  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))),
    1786             :  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))),
    1787             :  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))),
    1788             :  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))),
    1789             :  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))),
    1790             :  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))),
    1791             :  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))),
    1792             :  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))),
    1793             :  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))),
    1794             :  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))),
    1795             :  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))),
    1796             :  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))),
    1797             :  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))),
    1798             :  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))),
    1799             :  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))),
    1800             :  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))),
    1801             :  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))),
    1802             :  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))),
    1803             :  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))),
    1804             :  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))),
    1805             :  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))),
    1806             :  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))),
    1807             :  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))),
    1808             :  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))),
    1809             :  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))),
    1810             :  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))),
    1811             :  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))),
    1812             :  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))),
    1813             :  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))),
    1814             :  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))),
    1815             :  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))),
    1816             :  command("aggr", "cardinality", ALGcard, false, "Return the cardinality of the BAT tail values.", args(1,2, arg("",lng),batargany("b",2))),
    1817             :  command("aggr", "min", ALGminany, false, "Return the lowest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1818             :  command("aggr", "min", ALGminany_skipnil, false, "Return the lowest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1819             :  command("aggr", "max", ALGmaxany, false, "Return the highest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1820             :  command("aggr", "max", ALGmaxany_skipnil, false, "Return the highest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1821             :  command("aggr", "stdev", ALGstdev, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1822             :  command("aggr", "stdevp", ALGstdevp, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1823             :  command("aggr", "variance", ALGvariance, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1824             :  command("aggr", "variancep", ALGvariancep, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1825             :  command("aggr", "covariance", ALGcovariance, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1826             :  command("aggr", "covariancep", ALGcovariancep, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1827             :  command("aggr", "corr", ALGcorr, false, "Gives the correlation of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1828             :  // sql
    1829             :  command("aggr", "exist", ALGexist, false, "", args(1,3, arg("",bit),batargany("b",2),argany("h",1))),
    1830             :  { .imp=NULL }
    1831             : };
    1832             : #include "mal_import.h"
    1833             : #ifdef _MSC_VER
    1834             : #undef read
    1835             : #pragma section(".CRT$XCU",read)
    1836             : #endif
    1837         323 : LIB_STARTUP_FUNC(init_algebra_mal)
    1838         323 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14