LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 747 973 76.8 %
Date: 2024-11-15 19:37:45 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        2388 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts)
      60             : {
      61        2388 :         BUN j;
      62        2388 :         BATiter gi = bat_iterator(gids);
      63        2388 :         BAT *r = COLnew(0, TYPE_oid, gi.count * 2, TRANSIENT);
      64             : 
      65        2388 :         if (r == NULL) {
      66           0 :                 bat_iterator_end(&gi);
      67           0 :                 return GDK_FAIL;
      68             :         }
      69        2388 :         BATiter ci = bat_iterator(cnts);
      70        2388 :         if (gi.type == TYPE_void) {
      71        1049 :                 oid id = gi.tseq;
      72        1049 :                 lng *cnt = (lng *) ci.base;
      73       96195 :                 for (j = 0; j < gi.count; j++) {
      74       95146 :                         lng i, sz = cnt[j];
      75      190236 :                         for (i = 0; i < sz; i++) {
      76       95090 :                                 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       95146 :                         id ++;
      84             :                 }
      85             :         } else {
      86        1339 :                 oid *id = (oid *) gi.base;
      87        1339 :                 lng *cnt = (lng *) ci.base;
      88      140494 :                 for (j = 0; j < gi.count; j++) {
      89      139155 :                         lng i, sz = cnt[j];
      90      274814 :                         for (i = 0; i < sz; i++) {
      91      135659 :                                 if (BUNappend(r, id, false) != GDK_SUCCEED) {
      92           0 :                                         BBPreclaim(r);
      93           0 :                                         bat_iterator_end(&ci);
      94           0 :                                         bat_iterator_end(&gi);
      95           0 :                                         return GDK_FAIL;
      96             :                                 }
      97             :                         }
      98      139155 :                         id ++;
      99             :                 }
     100             :         }
     101        2388 :         bat_iterator_end(&ci);
     102        2388 :         r->tkey = false;
     103        2388 :         r->tseqbase = oid_nil;
     104        2388 :         r->tsorted = gi.sorted;
     105        2388 :         r->trevsorted = gi.revsorted;
     106        2388 :         r->tnonil = gi.nonil;
     107        2388 :         bat_iterator_end(&gi);
     108        2388 :         *result = r;
     109        2388 :         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         771 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         771 :         BAT *b;
     143         771 :         ptr p;
     144         771 :         str msg = MAL_SUCCEED;
     145             : 
     146         771 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         774 :         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         774 :                 if (ATOMextern(b->ttype)) {
     155          42 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         732 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         732 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         774 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         774 :         BBPunfix(b->batCacheid);
     166         774 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         771 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         771 :         bit skipnil = TRUE;
     173         771 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         545 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         545 :         BAT *b;
     180         545 :         ptr p;
     181         545 :         str msg = MAL_SUCCEED;
     182             : 
     183         545 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         545 :         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         545 :                 if (ATOMextern(b->ttype)) {
     192          68 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         477 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         477 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         545 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         545 :         BBPunfix(b->batCacheid);
     203         545 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         545 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         545 :         bit skipnil = TRUE;
     210         545 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     211             : }
     212             : 
     213             : static str
     214        2388 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     215             : {
     216        2388 :         BAT *bn, *g, *c;
     217             : 
     218        2388 :         g = BATdescriptor(*gids);
     219        2388 :         if (g == NULL) {
     220           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     221             :         }
     222        2388 :         c = BATdescriptor(*cnts);
     223        2388 :         if (c == NULL) {
     224           0 :                 BBPunfix(g->batCacheid);
     225           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     226             :         }
     227        2388 :         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        2388 :         *res = bn->batCacheid;
     233        2388 :         BBPkeepref(bn);
     234        2388 :         BBPunfix(g->batCacheid);
     235        2388 :         BBPunfix(c->batCacheid);
     236        2388 :         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      124628 : 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      124628 :         BAT *b, *s = NULL, *bn;
     265             : 
     266      124628 :         if ((*li != 0 && *li != 1) ||
     267      124628 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270             : 
     271      124769 :         if ((b = BATdescriptor(*bid)) == NULL) {
     272           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     273             :         }
     274      125495 :         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      125516 :         derefStr(b, low);
     279      125516 :         derefStr(b, high);
     280             : 
     281      125516 :         bool nanti = *anti, nli = *li, nhi = *hi;
     282             : 
     283             :         /* here we don't need open ended parts with nil */
     284      125516 :         if (!nanti && *unknown) {
     285        1376 :                 const void *nilptr = ATOMnilptr(b->ttype);
     286        1376 :                 if (nilptr) {
     287        1376 :                         if (nli && ATOMcmp(b->ttype, low, nilptr) == 0) {
     288          22 :                                 low = high;
     289          22 :                                 nli = false;
     290             :                         }
     291        1375 :                         if (nhi && ATOMcmp(b->ttype, high, nilptr) == 0) {
     292          24 :                                 high = low;
     293          24 :                                 nhi = false;
     294             :                         }
     295        1376 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     296          14 :                                 nanti = true;
     297             :                 }
     298      124140 :         } else if (!*unknown) {
     299      118021 :                 const void *nilptr = ATOMnilptr(b->ttype);
     300      235505 :                 if (nli && nhi && nilptr != NULL &&
     301      117976 :                         ATOMcmp(b->ttype, low, nilptr) == 0 &&
     302          24 :                         ATOMcmp(b->ttype, high, nilptr) == 0) {
     303             :                         /* special case: equi-select for NIL */
     304      125050 :                         high = NULL;
     305             :                 }
     306             :         }
     307             : 
     308      125050 :         bn = BATselect(b, s, low, high, nli, nhi, nanti, false);
     309      124303 :         BBPunfix(b->batCacheid);
     310      125368 :         BBPreclaim(s);
     311      125381 :         if (bn == NULL)
     312           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     313      125381 :         *result = bn->batCacheid;
     314      125381 :         BBPkeepref(bn);
     315      125381 :         return MAL_SUCCEED;
     316             : }
     317             : 
     318             : static str
     319       40805 : 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       40805 :         return ALGselect2nil(result, bid, sid, low, high, li, hi, anti, &(bit){0});
     323             : }
     324             : 
     325             : static str
     326       76567 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     327             :                    const bit *li, const bit *hi, const bit *anti)
     328             : {
     329       76567 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, &(bit){0});
     330             : }
     331             : 
     332             : static str
     333         310 : 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         310 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     337             : }
     338             : 
     339             : static str
     340      469693 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     341             :                                 const char **op)
     342             : {
     343      469693 :         BAT *b, *s = NULL, *bn;
     344             : 
     345      469693 :         if ((b = BATdescriptor(*bid)) == NULL) {
     346           0 :                 throw(MAL, "algebra.thetaselect",
     347             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     348             :         }
     349      472209 :         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      472295 :         derefStr(b, val);
     355      472295 :         bn = BATthetaselect(b, s, val, *op);
     356      469747 :         BBPunfix(b->batCacheid);
     357      471913 :         BBPreclaim(s);
     358      471780 :         if (bn == NULL)
     359           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     360      471780 :         *result = bn->batCacheid;
     361      471780 :         BBPkeepref(bn);
     362      471780 :         return MAL_SUCCEED;
     363             : }
     364             : 
     365             : static str
     366         396 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     367             : {
     368         396 :         BAT *g = BATdescriptor(*gid); /* oid */
     369         396 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     370         396 :         BAT *p = BATdescriptor(*pid); /* bit */
     371         396 :         BAT *res1 = NULL, *res2 = NULL;
     372         396 :         bit any = *Any; /* any or normal comparison semantics */
     373             : 
     374         396 :         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         396 :         BUN nr = BATcount(g), q = 0;
     381             : 
     382         396 :         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         396 :         assert(g->tsorted);
     390         396 :         oid *ri1 = Tloc(res1, 0);
     391         396 :         bit *ri2 = Tloc(res2, 0);
     392         396 :         bit *mi = Tloc(m, 0);
     393         396 :         bit *pi = Tloc(p, 0);
     394         396 :         oid cur = oid_nil;
     395             : 
     396         396 :         if (g->ttype == TYPE_void) { /* void case ? */
     397          31 :                 oid c = g->hseqbase;
     398         127 :                 for (BUN n = 0; n < nr; n++, c++) {
     399          96 :                         ri1[q] = c;
     400          96 :                         ri2[q] = FALSE;
     401          96 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     402           7 :                                 ri2[q] = TRUE;
     403          89 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     404           7 :                                 ri2[q] = bit_nil;
     405          96 :                         q++;
     406             :                 }
     407             :         } else {
     408         365 :                 oid *gi = Tloc(g, 0);
     409         365 :                 oid c = g->hseqbase;
     410         365 :                 if (nr)
     411         365 :                         cur = gi[0];
     412             :                 bit m = FALSE;
     413             :                 bool has_nil = false;
     414      332661 :                 for (BUN n = 0; n < nr; n++, c++) {
     415      332296 :                         if (c && cur != gi[n]) {
     416       57735 :                                 ri1[q] = c-1;
     417       57735 :                                 ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     418       57735 :                                 q++;
     419       57735 :                                 cur = gi[n];
     420       57735 :                                 m = FALSE;
     421       57735 :                                 has_nil = false;
     422             :                         }
     423      332296 :                         if (m == TRUE)
     424      191843 :                                 continue;
     425             : 
     426      140453 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     427             :                                 m = TRUE;
     428      133526 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     429      332296 :                                 has_nil = true;
     430             :                 }
     431         365 :                 if (nr) {
     432         365 :                         ri1[q] = c-1;
     433         365 :                         ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     434             :                 }
     435         365 :                 q++;
     436             :         }
     437         396 :         BATsetcount(res1, q);
     438         396 :         BATsetcount(res2, q);
     439         396 :         res1->tsorted = true;
     440         396 :         res1->tkey = true;
     441         396 :         res1->trevsorted = false;
     442         396 :         res2->tsorted = false;
     443         396 :         res2->trevsorted = false;
     444         396 :         res1->tnil = false;
     445         396 :         res1->tnonil = true;
     446         396 :         res2->tnonil = false;
     447         396 :         res2->tkey = false;
     448             : 
     449         396 :         BBPreclaim(g);
     450         396 :         BBPreclaim(m);
     451         396 :         BBPreclaim(p);
     452             : 
     453         396 :         BBPkeepref(res1);
     454         396 :         BBPkeepref(res2);
     455         396 :         *r1 = res1->batCacheid;
     456         396 :         *r2 = res2->batCacheid;
     457         396 :         return MAL_SUCCEED;
     458             : }
     459             : 
     460             : static str
     461          38 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     462             : {
     463          38 :         BAT *g = BATdescriptor(*gid); /* oid */
     464          38 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     465          38 :         BAT *p = BATdescriptor(*pid); /* bit */
     466          38 :         BAT *res1 = NULL, *res2 = NULL;
     467          38 :         bit any = *Any; /* any or normal comparison semantics */
     468             : 
     469          38 :         if (!g || !m || !p) {
     470           0 :                 if (g) BBPreclaim(g);
     471           0 :                 if (m) BBPreclaim(m);
     472           0 :                 if (p) BBPreclaim(p);
     473           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     474             :         }
     475          38 :         BUN nr = BATcount(g), q = 0;
     476             : 
     477          38 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     478             :                 BBPreclaim(g);
     479           0 :                 BBPreclaim(m);
     480           0 :                 BBPreclaim(p);
     481           0 :                 if (res1) BBPreclaim(res1);
     482           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     483             :         }
     484          38 :         assert(g->tsorted);
     485          38 :         oid *ri1 = Tloc(res1, 0);
     486          38 :         bit *ri2 = Tloc(res2, 0);
     487          38 :         bit *mi = Tloc(m, 0);
     488          38 :         bit *pi = Tloc(p, 0);
     489          38 :         oid cur = oid_nil;
     490             : 
     491          38 :         if (g->ttype == TYPE_void) { /* void case ? */
     492          12 :                 oid c = g->hseqbase;
     493         101 :                 for (BUN n = 0; n < nr; n++, c++) {
     494          89 :                         ri1[q] = c;
     495         161 :                         ri2[q] = (any && (mi[n] == bit_nil || pi[n] == bit_nil))?bit_nil:(mi[n] == TRUE && pi[n] == TRUE)?TRUE:FALSE;
     496          89 :                         q++;
     497             :                 }
     498             :         } else {
     499          26 :                 oid *gi = Tloc(g, 0);
     500          26 :                 oid c = g->hseqbase;
     501          26 :                 if (nr)
     502          26 :                         cur = gi[0];
     503             :                 bool used = false;
     504         602 :                 for (BUN n = 0; n < nr; n++, c++) {
     505         576 :                         if (c && cur != gi[n]) {
     506         159 :                                 if (!used) {
     507           3 :                                         ri1[q] = c-1;
     508           3 :                                         ri2[q] = false;
     509           3 :                                         q++;
     510             :                                 }
     511         159 :                                 used = false;
     512         159 :                                 cur = gi[n];
     513             :                         }
     514         576 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     515         322 :                                 ri1[q] = c;
     516         322 :                                 ri2[q] = TRUE;
     517         322 :                                 used = true;
     518         322 :                                 q++;
     519         254 :                         } else if (mi[n] == FALSE) { /* empty */
     520          55 :                                 ri1[q] = c;
     521          55 :                                 ri2[q] = FALSE;
     522          55 :                                 used = true;
     523          55 :                                 q++;
     524         199 :                         } else if (any && (mi[n] == bit_nil /* ie has nil */ || pi[n] == bit_nil)) {
     525           6 :                                 ri1[q] = c;
     526           6 :                                 ri2[q] = bit_nil;
     527           6 :                                 used = true;
     528           6 :                                 q++;
     529             :                         }
     530             :                 }
     531          26 :                 if (nr && !used) {
     532           1 :                         ri1[q] = c-1;
     533           1 :                         ri2[q] = FALSE;
     534           1 :                         q++;
     535             :                 }
     536             :         }
     537          38 :         BATsetcount(res1, q);
     538          38 :         BATsetcount(res2, q);
     539          38 :         res1->tsorted = true;
     540          38 :         res1->tkey = true;
     541          38 :         res1->trevsorted = false;
     542          38 :         res2->tsorted = false;
     543          38 :         res2->trevsorted = false;
     544          38 :         res1->tnil = false;
     545          38 :         res1->tnonil = true;
     546          38 :         res2->tnonil = false;
     547          38 :         res2->tkey = false;
     548             : 
     549          38 :         BBPreclaim(g);
     550          38 :         BBPreclaim(m);
     551          38 :         BBPreclaim(p);
     552             : 
     553          38 :         BBPkeepref(res1);
     554          38 :         BBPkeepref(res2);
     555          38 :         *r1 = res1->batCacheid;
     556          38 :         *r2 = res2->batCacheid;
     557          38 :         return MAL_SUCCEED;
     558             : }
     559             : 
     560             : 
     561             : static str
     562        1583 : ALGselectNotNil(bat *result, const bat *bid)
     563             : {
     564        1583 :         BAT *b;
     565             : 
     566        1583 :         if ((b = BATdescriptor(*bid)) == NULL)
     567           0 :                 throw(MAL, "algebra.selectNotNil",
     568             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     569             : 
     570        1584 :         MT_lock_set(&b->theaplock);
     571        1584 :         bool bnonil = b->tnonil || b->ttype == TYPE_msk;
     572        1584 :         MT_lock_unset(&b->theaplock);
     573        1584 :         if (!bnonil) {
     574         123 :                 BAT *s;
     575         123 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true, false);
     576         123 :                 if (s) {
     577         123 :                         BAT *bn = BATproject(s, b);
     578         123 :                         BBPunfix(s->batCacheid);
     579         123 :                         if (bn) {
     580         123 :                                 BBPunfix(b->batCacheid);
     581         123 :                                 *result = bn->batCacheid;
     582         123 :                                 BBPkeepref(bn);
     583         123 :                                 return MAL_SUCCEED;
     584             :                         }
     585             :                 }
     586           0 :                 BBPunfix(b->batCacheid);
     587           0 :                 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
     588             :         }
     589             :         /* just pass on the result */
     590        1461 :         *result = b->batCacheid;
     591        1461 :         BBPkeepref(b);
     592        1461 :         return MAL_SUCCEED;
     593             : }
     594             : 
     595             : static str
     596      589231 : 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      589231 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     616      589231 :         BAT *candleft = NULL, *candright = NULL;
     617      589231 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     618      589231 :         BUN est;
     619      589231 :         const char *err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     620             : 
     621      589231 :         assert(r2id == NULL || rangefunc != NULL);
     622             : 
     623      589231 :         if ((left = BATdescriptor(*lid)) == NULL)
     624           0 :                 goto fail;
     625      595660 :         if ((right = BATdescriptor(*rid)) == NULL)
     626           0 :                 goto fail;
     627      595684 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     628           0 :                 goto fail;
     629      595690 :         if (srid && !is_bat_nil(*srid)
     630           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     631           0 :                 goto fail;
     632      595690 :         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      595690 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     639             : 
     640      595690 :         if (thetafunc) {
     641       51301 :                 assert(joinfunc == NULL);
     642       51301 :                 assert(semifunc == NULL);
     643       51301 :                 assert(markfunc == NULL);
     644       51301 :                 assert(bandfunc == NULL);
     645       51301 :                 assert(rangefunc == NULL);
     646       51301 :                 assert(difffunc == NULL);
     647       51301 :                 assert(interfunc == NULL);
     648       51301 :                 if ((*thetafunc)
     649             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     650       51301 :                          op, *nil_matches, est) != GDK_SUCCEED)
     651           0 :                         goto fail;
     652      544389 :         } else if (joinfunc) {
     653      367624 :                 assert(semifunc == NULL);
     654      367624 :                 assert(markfunc == NULL);
     655      367624 :                 assert(bandfunc == NULL);
     656      367624 :                 assert(rangefunc == NULL);
     657      367624 :                 assert(difffunc == NULL);
     658      367624 :                 assert(interfunc == NULL);
     659      367624 :                 if ((*joinfunc)
     660             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     661      367624 :                          *nil_matches, est) != GDK_SUCCEED)
     662           1 :                         goto fail;
     663      176765 :         } else if (semifunc) {
     664         332 :                 assert(markfunc == NULL);
     665         332 :                 assert(bandfunc == NULL);
     666         332 :                 assert(rangefunc == NULL);
     667         332 :                 assert(difffunc == NULL);
     668         332 :                 assert(interfunc == NULL);
     669         332 :                 if ((*semifunc)
     670             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     671         332 :                          *nil_matches, *max_one, est) != GDK_SUCCEED)
     672          42 :                         goto fail;
     673      176433 :         } else if (markfunc) {
     674       19127 :                 assert(bandfunc == NULL);
     675       19127 :                 assert(rangefunc == NULL);
     676       19127 :                 assert(difffunc == NULL);
     677       19127 :                 assert(interfunc == NULL);
     678       38248 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     679             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     680           0 :                         goto fail;
     681      157306 :         } 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      157306 :         } 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      157159 :         } else if (difffunc) {
     702      148531 :                 assert(r2 == NULL);
     703      148531 :                 assert(interfunc == NULL);
     704      148081 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     705      148531 :                                                                         *nil_matches, *not_in, est)) == NULL)
     706           0 :                         goto fail;
     707             :         } else {
     708        8628 :                 assert(r2 == NULL);
     709        8606 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     710        8628 :                                                                          *nil_matches, *max_one, est)) == NULL)
     711           1 :                         goto fail;
     712             :         }
     713      591555 :         *r1 = result1->batCacheid;
     714      591555 :         BBPkeepref(result1);
     715      593187 :         if (r2) {
     716      344018 :                 *r2 = result2->batCacheid;
     717      344018 :                 BBPkeepref(result2);
     718             :         }
     719      593617 :         if (r3) {
     720       19061 :                 *r3 = result3->batCacheid;
     721       19061 :                 BBPkeepref(result3);
     722             :         }
     723      593655 :         BBPunfix(left->batCacheid);
     724      595053 :         BBPunfix(right->batCacheid);
     725      595379 :         BBPreclaim(candleft);
     726      595235 :         BBPreclaim(candright);
     727             :         return MAL_SUCCEED;
     728             : 
     729          44 :   fail:
     730          44 :         BBPreclaim(left);
     731          44 :         BBPreclaim(right);
     732          44 :         BBPreclaim(right2);
     733          44 :         BBPreclaim(candleft);
     734          44 :         BBPreclaim(candright);
     735          44 :         if (err == NULL)
     736          44 :                 throw(MAL, funcname, GDK_EXCEPTION);
     737           0 :         throw(MAL, funcname, "%s", err);
     738             : }
     739             : 
     740             : static str
     741      333336 : 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      333336 :         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       30702 : 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       30702 :         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         120 : 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         120 :         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         209 : 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         209 :         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       19025 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     815             :                          const bat *slid, const bat *srid, const lng *estimate)
     816             : {
     817       19025 :         return do_join(r1, NULL, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     818             :                                    false, false, false, false, NULL, NULL, NULL,
     819             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     820             :                                    "algebra.markjoin");
     821             : }
     822             : 
     823             : static str
     824           5 : ALGmark3join(bat *r1, bat *r2, bat *r3, const bat *lid, const bat *rid,
     825             :                          const bat *slid, const bat *srid, const lng *estimate)
     826             : {
     827           5 :         return do_join(r1, r2, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     828             :                                    false, false, false, false, NULL, NULL, NULL,
     829             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     830             :                                    "algebra.markjoin");
     831             : }
     832             : 
     833             : static str
     834        7663 : 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        7663 :         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       41372 : 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       41372 :         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         115 : 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         237 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     883         115 :                                    *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          24 : 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          49 :         return do_join(r1, NULL, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     894          24 :                                    *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      148441 : 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      148441 :         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        8625 : 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        8625 :         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        1611 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     932             : {
     933        1611 :         bat *ret1, *ret2 = NULL;
     934        1611 :         bat bid, sid, gid;
     935        1611 :         BAT *b, *s = NULL, *g = NULL;
     936        1611 :         BAT *bn = NULL, *gn = NULL;
     937        1611 :         lng n;
     938        1611 :         bit asc, nilslast, distinct;
     939        1611 :         gdk_return rc;
     940             : 
     941        1611 :         (void) cntxt;
     942        1611 :         (void) mb;
     943             : 
     944        1611 :         assert(pci->retc == 1 || pci->retc == 2);
     945        1611 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     946             : 
     947        1611 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     948        1611 :         if (n < 0)
     949           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     950        1611 :         if (n > (lng) BUN_MAX)
     951             :                 n = BUN_MAX;
     952        1611 :         ret1 = getArgReference_bat(stk, pci, 0);
     953        1611 :         if (pci->retc == 2)
     954         526 :                 ret2 = getArgReference_bat(stk, pci, 1);
     955        1611 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     956        1611 :         if ((b = BATdescriptor(bid)) == NULL)
     957           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     958        1613 :         if (pci->argc - pci->retc > 5) {
     959        1613 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     960        1613 :                 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        1613 :                 if (pci->argc - pci->retc > 6) {
     966        1613 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     967        1613 :                         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        1613 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     976        1613 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     977        1613 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
     978        2699 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
     979             :                                    distinct);
     980        1610 :         BBPunfix(b->batCacheid);
     981        1612 :         BBPreclaim(s);
     982        1606 :         BBPreclaim(g);
     983        1610 :         if (rc != GDK_SUCCEED)
     984           0 :                 throw(MAL, "algebra.firstn", GDK_EXCEPTION);
     985        1610 :         *ret1 = bn->batCacheid;
     986        1610 :         BBPkeepref(bn);
     987        1616 :         if (ret2) {
     988         527 :                 *ret2 = gn->batCacheid;
     989         527 :                 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       43377 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1047             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1048             : {
    1049       43377 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1050       43377 :         BAT *sl = NULL, *sr = NULL;
    1051       43377 :         gdk_return ret;
    1052             : 
    1053       43377 :         L = BATdescriptor(*left);
    1054       44848 :         R = BATdescriptor(*right);
    1055       44938 :         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       44938 :         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       46691 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1071       44938 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1072       44083 :         BBPunfix(L->batCacheid);
    1073       44802 :         BBPunfix(R->batCacheid);
    1074       44937 :         BBPreclaim(sl);
    1075       44937 :         BBPreclaim(sr);
    1076       44936 :         if (ret != GDK_SUCCEED)
    1077          86 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1078       44850 :         *l = bn1->batCacheid;
    1079       44850 :         BBPkeepref(bn1);
    1080       44788 :         if (r) {
    1081       43049 :                 *r = bn2->batCacheid;
    1082       43049 :                 BBPkeepref(bn2);
    1083             :         }
    1084             :         return MAL_SUCCEED;
    1085             : }
    1086             : 
    1087             : static str
    1088        1686 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1089             : {
    1090        1686 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1091             : }
    1092             : 
    1093             : static str
    1094       41742 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1095             :                                  const bit *max_one)
    1096             : {
    1097       41742 :         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         425 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1116             : {
    1117         425 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1118         425 :         BAT *sl = NULL, *sr = NULL;
    1119         425 :         gdk_return ret;
    1120             : 
    1121         425 :         L = BATdescriptor(*left);
    1122         425 :         R = BATdescriptor(*right);
    1123         425 :         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         425 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1129         425 :                 (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         425 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1137         425 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1138         425 :         BBPunfix(L->batCacheid);
    1139         425 :         BBPunfix(R->batCacheid);
    1140         425 :         BBPreclaim(sl);
    1141         425 :         BBPreclaim(sr);
    1142         425 :         if (ret != GDK_SUCCEED)
    1143           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1144         425 :         *l = bn1->batCacheid;
    1145         425 :         BBPkeepref(bn1);
    1146         425 :         if (r) {
    1147         425 :                 *r = bn2->batCacheid;
    1148         425 :                 BBPkeepref(bn2);
    1149             :         }
    1150             :         return MAL_SUCCEED;
    1151             : }
    1152             : 
    1153             : static str
    1154     1762883 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1155             : {
    1156     1762883 :         BAT *l, *r1, *r2 = NULL, *bn;
    1157             : 
    1158     1762883 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1159           0 :                 throw(MAL, "algebra.projection",
    1160             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1161             :         }
    1162     1775175 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1163           0 :                 BBPunfix(l->batCacheid);
    1164           0 :                 throw(MAL, "algebra.projection",
    1165             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1166             :         }
    1167     1774047 :         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     1774047 :         bn = BATproject2(l, r1, r2);
    1174     1746858 :         BBPunfix(l->batCacheid);
    1175     1772890 :         BBPunfix(r1->batCacheid);
    1176     1773331 :         BBPreclaim(r2);
    1177     1772421 :         if (bn == NULL)
    1178           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1179     1772421 :         *result = bn->batCacheid;
    1180     1772421 :         BBPkeepref(bn);
    1181     1772421 :         return MAL_SUCCEED;
    1182             : }
    1183             : 
    1184             : str
    1185     1764543 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1186             : {
    1187     1764543 :         return ALGprojection2(result, lid, rid, NULL);
    1188             : }
    1189             : 
    1190             : static str
    1191       19230 : 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       19230 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1196       19230 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1197             : 
    1198       19230 :         if ((b = BATdescriptor(*bid)) == NULL)
    1199           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1200       19230 :         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       19230 :         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       22728 :         if (BATsort(result ? &bn : NULL,
    1210             :                                 norder ? &on : NULL,
    1211             :                                 ngroup ? &gn : NULL,
    1212       19230 :                                 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       19231 :         BBPunfix(b->batCacheid);
    1219       19231 :         BBPreclaim(o);
    1220       19231 :         BBPreclaim(g);
    1221       19231 :         if (result) {
    1222       19231 :                 *result = bn->batCacheid;
    1223       19231 :                 BBPkeepref(bn);
    1224             :         }
    1225       19231 :         if (norder) {
    1226       15733 :                 *norder = on->batCacheid;
    1227       15733 :                 BBPkeepref(on);
    1228             :         }
    1229       19231 :         if (ngroup) {
    1230       10852 :                 *ngroup = gn->batCacheid;
    1231       10852 :                 BBPkeepref(gn);
    1232             :         }
    1233             :         return MAL_SUCCEED;
    1234             : }
    1235             : 
    1236             : static str
    1237        2836 : 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        2836 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast,
    1242             :                                          stable);
    1243             : }
    1244             : 
    1245             : static str
    1246        1916 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group,
    1247             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1248             : {
    1249        1916 :         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        5008 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1280             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1281             : {
    1282        5008 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1283             :                                          stable);
    1284             : }
    1285             : 
    1286             : static str
    1287        2044 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1288             :                   const bit *nilslast, const bit *stable)
    1289             : {
    1290        2044 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast,
    1291             :                                          stable);
    1292             : }
    1293             : 
    1294             : static str
    1295        1582 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast,
    1296             :                   const bit *stable)
    1297             : {
    1298        1582 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast,
    1299             :                                          stable);
    1300             : }
    1301             : 
    1302             : static str
    1303       69869 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1304             :                                 const bit *ignore_nils)
    1305             : {
    1306       69869 :         BAT *b, *s = NULL;
    1307             : 
    1308       69869 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1309           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1310             :         }
    1311       70070 :         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       70070 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1316          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1317       70040 :         } else if (*ignore_nils) {
    1318        1770 :                 *result = (lng) BATcount_no_nil(b, s);
    1319             :         } else {
    1320       68270 :                 struct canditer ci;
    1321       68270 :                 canditer_init(&ci, b, s);
    1322       68266 :                 *result = (lng) ci.ncand;
    1323             :         }
    1324       70066 :         BBPreclaim(s);
    1325       70066 :         BBPunfix(b->batCacheid);
    1326       70066 :         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       68104 : ALGcount_bat(lng *result, const bat *bid)
    1343             : {
    1344       68104 :         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       17233 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1408             : {
    1409       17233 :         BAT *b, *bn;
    1410       17233 :         BUN s, e;
    1411             : 
    1412       17233 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1413           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1414       17233 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1415           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1416       17233 :         s = (BUN) *start;
    1417       17233 :         if (s > BATcount(b))
    1418             :                 s = BATcount(b);
    1419       17233 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1420       17233 :         if (e > BATcount(b))
    1421             :                 e = BATcount(b);
    1422       17233 :         if (e < s)
    1423             :                 e = s;
    1424       17233 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1425       17231 :         if (bn == NULL)
    1426           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1427       17231 :         *ret = bn->batCacheid;
    1428       17231 :         BBPkeepref(bn);
    1429       17231 :         return MAL_SUCCEED;
    1430             : }
    1431             : 
    1432             : /*
    1433             :  * BUN Get/Fetch
    1434             :  */
    1435             : 
    1436             : static str
    1437      185168 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1438             : {
    1439      185168 :         assert(pos <= BUN_MAX);
    1440      185168 :         BATiter bi = bat_iterator(b);
    1441      185168 :         if (ATOMextern(b->ttype)) {
    1442         176 :                 ptr _src = BUNtail(bi, pos);
    1443         176 :                 size_t _len = ATOMlen(b->ttype, _src);
    1444         176 :                 ptr _dst = GDKmalloc(_len);
    1445         176 :                 if (_dst == NULL) {
    1446           0 :                         bat_iterator_end(&bi);
    1447           0 :                         throw(MAL, "doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1448             :                 }
    1449         176 :                 memcpy(_dst, _src, _len);
    1450         176 :                 *(ptr *) ret = _dst;
    1451             :         } else {
    1452      184992 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1453      184992 :                 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      184992 :                 } else if (_s == 4) {
    1458      184905 :                         *(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      185168 :         bat_iterator_end(&bi);
    1474      185168 :         return MAL_SUCCEED;
    1475             : }
    1476             : 
    1477             : static str
    1478      185170 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1479             : {
    1480      185170 :         BAT *b;
    1481      185170 :         str msg;
    1482             : 
    1483      185170 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1484           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1485             :         }
    1486      185170 :         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      185170 :         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      185168 :         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      185168 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1503      185168 :         BBPunfix(b->batCacheid);
    1504      185168 :         return msg;
    1505             : }
    1506             : 
    1507             : str
    1508      185170 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1509             : {
    1510      185170 :         lng o = *pos;
    1511             : 
    1512      185170 :         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      270588 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1555             : {
    1556      270588 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1557      270588 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1558      270588 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1559      270588 :         BAT *b, *bn;
    1560             : 
    1561      270588 :         (void) cntxt;
    1562      270588 :         (void) mb;
    1563      270588 :         if (isaBatType(getArgType(mb, pci, 2)))
    1564           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1565      270588 :         if ((b = BBPquickdesc(bid)) == NULL)
    1566           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1567      270492 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1568      270717 :         if (bn == NULL) {
    1569           0 :                 *ret = bat_nil;
    1570           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1571             :         }
    1572      270717 :         *ret = bn->batCacheid;
    1573      270717 :         BBPkeepref(bn);
    1574      270717 :         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           5 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1701           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1702           5 :         *res = covariance;
    1703           5 :         return MAL_SUCCEED;
    1704             : }
    1705             : 
    1706             : static str
    1707           8 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1708             : {
    1709           8 :         BAT *b1, *b2;
    1710           8 :         dbl covariance;
    1711             : 
    1712           8 :         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           8 :         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         308 : LIB_STARTUP_FUNC(init_algebra_mal)
    1838         308 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14