LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 788 1036 76.1 %
Date: 2025-03-26 20:06:40 Functions: 68 83 81.9 %

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

Generated by: LCOV version 1.14