LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 786 1036 75.9 %
Date: 2025-03-24 21:28:01 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         777 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         777 :         BAT *b;
     143         777 :         ptr p;
     144         777 :         str msg = MAL_SUCCEED;
     145             : 
     146         777 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         778 :         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         778 :                 if (ATOMextern(b->ttype)) {
     155          42 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         736 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         737 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         779 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         779 :         BBPunfix(b->batCacheid);
     166         779 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         777 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         777 :         bit skipnil = TRUE;
     173         777 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         544 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         544 :         BAT *b;
     180         544 :         ptr p;
     181         544 :         str msg = MAL_SUCCEED;
     182             : 
     183         544 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         543 :         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         543 :                 if (ATOMextern(b->ttype)) {
     192          64 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         479 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         484 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         547 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         547 :         BBPunfix(b->batCacheid);
     203         547 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         544 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         544 :         bit skipnil = TRUE;
     210         544 :         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      137556 : 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      137556 :         BAT *b, *s = NULL, *bn;
     265             : 
     266      137556 :         if ((*li != 0 && *li != 1) ||
     267      137556 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270             : 
     271      137700 :         if ((b = BATdescriptor(*bid)) == NULL) {
     272           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     273             :         }
     274      138382 :         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      138406 :         derefStr(b, low);
     279      138406 :         derefStr(b, high);
     280             : 
     281      138406 :         bool nanti = *anti, nli = *li, nhi = *hi;
     282             : 
     283             :         /* here we don't need open ended parts with nil */
     284      138406 :         if (!nanti && *unknown) {
     285        1574 :                 const void *nilptr = ATOMnilptr(b->ttype);
     286        1574 :                 if (nilptr) {
     287        1574 :                         if (nli && ATOMcmp(b->ttype, low, nilptr) == 0) {
     288          17 :                                 low = high;
     289          17 :                                 nli = false;
     290             :                         }
     291        1570 :                         if (nhi && ATOMcmp(b->ttype, high, nilptr) == 0) {
     292          17 :                                 high = low;
     293          17 :                                 nhi = false;
     294             :                         }
     295        1571 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     296          10 :                                 nanti = true;
     297             :                 }
     298      136832 :         } else if (!*unknown) {
     299      130607 :                 const void *nilptr = ATOMnilptr(b->ttype);
     300      260867 :                 if (nli && nhi && nilptr != NULL &&
     301      130661 :                         ATOMcmp(b->ttype, low, nilptr) == 0 &&
     302          24 :                         ATOMcmp(b->ttype, high, nilptr) == 0) {
     303             :                         /* special case: equi-select for NIL */
     304      138030 :                         high = NULL;
     305             :                 }
     306             :         }
     307             : 
     308      138030 :         bn = BATselect(b, s, low, high, nli, nhi, nanti, false);
     309      137311 :         BBPunfix(b->batCacheid);
     310      138302 :         BBPreclaim(s);
     311      138340 :         if (bn == NULL)
     312           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     313      138340 :         *result = bn->batCacheid;
     314      138340 :         BBPkeepref(bn);
     315      138340 :         return MAL_SUCCEED;
     316             : }
     317             : 
     318             : static str
     319       40836 : 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       40836 :         return ALGselect2nil(result, bid, sid, low, high, li, hi, anti, &(bit){0});
     323             : }
     324             : 
     325             : static str
     326       89253 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     327             :                    const bit *li, const bit *hi, const bit *anti)
     328             : {
     329       89253 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, &(bit){0});
     330             : }
     331             : 
     332             : static str
     333         310 : ALGselect1nil(bat *result, const bat *bid, const void *low, const void *high,
     334             :                           const bit *li, const bit *hi, const bit *anti, const bit *unknown)
     335             : {
     336         310 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     337             : }
     338             : 
     339             : static str
     340      518504 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     341             :                                 const char **op)
     342             : {
     343      518504 :         BAT *b, *s = NULL, *bn;
     344             : 
     345      518504 :         if ((b = BATdescriptor(*bid)) == NULL) {
     346           0 :                 throw(MAL, "algebra.thetaselect",
     347             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     348             :         }
     349      520808 :         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      520909 :         derefStr(b, val);
     355      520909 :         bn = BATthetaselect(b, s, val, *op);
     356      518532 :         BBPunfix(b->batCacheid);
     357      520621 :         BBPreclaim(s);
     358      520505 :         if (bn == NULL)
     359           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     360      520505 :         *result = bn->batCacheid;
     361      520505 :         BBPkeepref(bn);
     362      520505 :         return MAL_SUCCEED;
     363             : }
     364             : 
     365             : static str
     366         396 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     367             : {
     368         396 :         BAT *g = BATdescriptor(*gid); /* oid */
     369         396 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     370         396 :         BAT *p = BATdescriptor(*pid); /* bit */
     371         396 :         BAT *res1 = NULL, *res2 = NULL;
     372         396 :         bit any = *Any; /* any or normal comparison semantics */
     373             : 
     374         396 :         if (!g || !m || !p) {
     375           0 :                 if (g) BBPreclaim(g);
     376           0 :                 if (m) BBPreclaim(m);
     377           0 :                 if (p) BBPreclaim(p);
     378           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     379             :         }
     380         396 :         BUN nr = BATcount(g), q = 0;
     381             : 
     382         396 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     383             :                 BBPreclaim(g);
     384           0 :                 BBPreclaim(m);
     385           0 :                 BBPreclaim(p);
     386           0 :                 if (res1) BBPreclaim(res1);
     387           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     388             :         }
     389         396 :         assert(g->tsorted);
     390         396 :         oid *ri1 = Tloc(res1, 0);
     391         396 :         bit *ri2 = Tloc(res2, 0);
     392         396 :         bit *mi = Tloc(m, 0);
     393         396 :         bit *pi = Tloc(p, 0);
     394         396 :         oid cur = oid_nil;
     395             : 
     396         396 :         if (g->ttype == TYPE_void) { /* void case ? */
     397          32 :                 oid c = g->hseqbase;
     398         132 :                 for (BUN n = 0; n < nr; n++, c++) {
     399         100 :                         ri1[q] = c;
     400         100 :                         ri2[q] = FALSE;
     401         100 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     402           7 :                                 ri2[q] = TRUE;
     403          93 :                         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         100 :                         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         396 :         BATsetcount(res1, q);
     438         396 :         BATsetcount(res2, q);
     439         396 :         res1->tsorted = true;
     440         396 :         res1->tkey = true;
     441         396 :         res1->trevsorted = false;
     442         396 :         res2->tsorted = false;
     443         396 :         res2->trevsorted = false;
     444         396 :         res1->tnil = false;
     445         396 :         res1->tnonil = true;
     446         396 :         res2->tnonil = false;
     447         396 :         res2->tkey = false;
     448             : 
     449         396 :         BBPreclaim(g);
     450         396 :         BBPreclaim(m);
     451         396 :         BBPreclaim(p);
     452             : 
     453         396 :         BBPkeepref(res1);
     454         396 :         BBPkeepref(res2);
     455         396 :         *r1 = res1->batCacheid;
     456         396 :         *r2 = res2->batCacheid;
     457         396 :         return MAL_SUCCEED;
     458             : }
     459             : 
     460             : static str
     461          38 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     462             : {
     463          38 :         BAT *g = BATdescriptor(*gid); /* oid */
     464          38 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     465          38 :         BAT *p = BATdescriptor(*pid); /* bit */
     466          38 :         BAT *res1 = NULL, *res2 = NULL;
     467          38 :         bit any = *Any; /* any or normal comparison semantics */
     468             : 
     469          38 :         if (!g || !m || !p) {
     470           0 :                 if (g) BBPreclaim(g);
     471           0 :                 if (m) BBPreclaim(m);
     472           0 :                 if (p) BBPreclaim(p);
     473           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     474             :         }
     475          38 :         BUN nr = BATcount(g), q = 0;
     476             : 
     477          38 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     478             :                 BBPreclaim(g);
     479           0 :                 BBPreclaim(m);
     480           0 :                 BBPreclaim(p);
     481           0 :                 if (res1) BBPreclaim(res1);
     482           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     483             :         }
     484          38 :         assert(g->tsorted);
     485          38 :         oid *ri1 = Tloc(res1, 0);
     486          38 :         bit *ri2 = Tloc(res2, 0);
     487          38 :         bit *mi = Tloc(m, 0);
     488          38 :         bit *pi = Tloc(p, 0);
     489          38 :         oid cur = oid_nil;
     490             : 
     491          38 :         if (g->ttype == TYPE_void) { /* void case ? */
     492          12 :                 oid c = g->hseqbase;
     493         101 :                 for (BUN n = 0; n < nr; n++, c++) {
     494          89 :                         ri1[q] = c;
     495         161 :                         ri2[q] = (any && (mi[n] == bit_nil || pi[n] == bit_nil))?bit_nil:(mi[n] == TRUE && pi[n] == TRUE)?TRUE:FALSE;
     496          89 :                         q++;
     497             :                 }
     498             :         } else {
     499          26 :                 oid *gi = Tloc(g, 0);
     500          26 :                 oid c = g->hseqbase;
     501          26 :                 if (nr)
     502          26 :                         cur = gi[0];
     503             :                 bool used = false;
     504         602 :                 for (BUN n = 0; n < nr; n++, c++) {
     505         576 :                         if (c && cur != gi[n]) {
     506         159 :                                 if (!used) {
     507           3 :                                         ri1[q] = c-1;
     508           3 :                                         ri2[q] = false;
     509           3 :                                         q++;
     510             :                                 }
     511         159 :                                 used = false;
     512         159 :                                 cur = gi[n];
     513             :                         }
     514         576 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     515         322 :                                 ri1[q] = c;
     516         322 :                                 ri2[q] = TRUE;
     517         322 :                                 used = true;
     518         322 :                                 q++;
     519         254 :                         } else if (mi[n] == FALSE) { /* empty */
     520          55 :                                 ri1[q] = c;
     521          55 :                                 ri2[q] = FALSE;
     522          55 :                                 used = true;
     523          55 :                                 q++;
     524         199 :                         } else if (any && (mi[n] == bit_nil /* ie has nil */ || pi[n] == bit_nil)) {
     525           6 :                                 ri1[q] = c;
     526           6 :                                 ri2[q] = bit_nil;
     527           6 :                                 used = true;
     528           6 :                                 q++;
     529             :                         }
     530             :                 }
     531          26 :                 if (nr && !used) {
     532           1 :                         ri1[q] = c-1;
     533           1 :                         ri2[q] = FALSE;
     534           1 :                         q++;
     535             :                 }
     536             :         }
     537          38 :         BATsetcount(res1, q);
     538          38 :         BATsetcount(res2, q);
     539          38 :         res1->tsorted = true;
     540          38 :         res1->tkey = true;
     541          38 :         res1->trevsorted = false;
     542          38 :         res2->tsorted = false;
     543          38 :         res2->trevsorted = false;
     544          38 :         res1->tnil = false;
     545          38 :         res1->tnonil = true;
     546          38 :         res2->tnonil = false;
     547          38 :         res2->tkey = false;
     548             : 
     549          38 :         BBPreclaim(g);
     550          38 :         BBPreclaim(m);
     551          38 :         BBPreclaim(p);
     552             : 
     553          38 :         BBPkeepref(res1);
     554          38 :         BBPkeepref(res2);
     555          38 :         *r1 = res1->batCacheid;
     556          38 :         *r2 = res2->batCacheid;
     557          38 :         return MAL_SUCCEED;
     558             : }
     559             : 
     560             : 
     561             : static str
     562        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         125 :                 BAT *s;
     575         125 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true, false);
     576         125 :                 if (s) {
     577         125 :                         BAT *bn = BATproject(s, b);
     578         125 :                         BBPunfix(s->batCacheid);
     579         125 :                         if (bn) {
     580         125 :                                 BBPunfix(b->batCacheid);
     581         125 :                                 *result = bn->batCacheid;
     582         125 :                                 BBPkeepref(bn);
     583         125 :                                 return MAL_SUCCEED;
     584             :                         }
     585             :                 }
     586           0 :                 BBPunfix(b->batCacheid);
     587           0 :                 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
     588             :         }
     589             :         /* just pass on the result */
     590        1462 :         *result = b->batCacheid;
     591        1462 :         BBPkeepref(b);
     592        1462 :         return MAL_SUCCEED;
     593             : }
     594             : 
     595             : static str
     596      652123 : 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      652123 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     616      652123 :         BAT *candleft = NULL, *candright = NULL;
     617      652123 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     618      652123 :         BUN est;
     619      652123 :         const char *err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     620             : 
     621      652123 :         assert(r2id == NULL || rangefunc != NULL);
     622             : 
     623      652123 :         if ((left = BATdescriptor(*lid)) == NULL)
     624           0 :                 goto fail;
     625      659218 :         if ((right = BATdescriptor(*rid)) == NULL)
     626           0 :                 goto fail;
     627      659240 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     628           0 :                 goto fail;
     629      659241 :         if (srid && !is_bat_nil(*srid)
     630           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     631           0 :                 goto fail;
     632      659241 :         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      659241 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     639             : 
     640      659241 :         if (thetafunc) {
     641       51259 :                 assert(joinfunc == NULL);
     642       51259 :                 assert(semifunc == NULL);
     643       51259 :                 assert(markfunc == NULL);
     644       51259 :                 assert(bandfunc == NULL);
     645       51259 :                 assert(rangefunc == NULL);
     646       51259 :                 assert(difffunc == NULL);
     647       51259 :                 assert(interfunc == NULL);
     648       51259 :                 if ((*thetafunc)
     649             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     650       51259 :                          op, *nil_matches, est) != GDK_SUCCEED)
     651           0 :                         goto fail;
     652      607982 :         } else if (joinfunc) {
     653      417337 :                 assert(semifunc == NULL);
     654      417337 :                 assert(markfunc == NULL);
     655      417337 :                 assert(bandfunc == NULL);
     656      417337 :                 assert(rangefunc == NULL);
     657      417337 :                 assert(difffunc == NULL);
     658      417337 :                 assert(interfunc == NULL);
     659      417337 :                 if ((*joinfunc)
     660             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     661      417337 :                          *nil_matches, est) != GDK_SUCCEED)
     662           1 :                         goto fail;
     663      190645 :         } 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      190310 :         } else if (markfunc) {
     674       19519 :                 assert(bandfunc == NULL);
     675       19519 :                 assert(rangefunc == NULL);
     676       19519 :                 assert(difffunc == NULL);
     677       19519 :                 assert(interfunc == NULL);
     678       39033 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     679             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     680           0 :                         goto fail;
     681      170791 :         } 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      170791 :         } else if (rangefunc) {
     690         147 :                 assert(difffunc == NULL);
     691         147 :                 assert(interfunc == NULL);
     692         147 :                 if ((right2 = BATdescriptor(*r2id)) == NULL) {
     693           0 :                         err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     694           0 :                         goto fail;
     695             :                 }
     696         172 :                 if ((*rangefunc)
     697             :                         (&result1, r2 ? &result2 : NULL, left, right, right2, candleft,
     698             :                          candright, li, hi, anti, symmetric, est) != GDK_SUCCEED)
     699           0 :                         goto fail;
     700         143 :                 BBPunfix(right2->batCacheid);
     701      170644 :         } else if (difffunc) {
     702      160926 :                 assert(r2 == NULL);
     703      160926 :                 assert(interfunc == NULL);
     704      160678 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     705      160926 :                                                                         *nil_matches, *not_in, est)) == NULL)
     706           0 :                         goto fail;
     707             :         } else {
     708        9718 :                 assert(r2 == NULL);
     709        9689 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     710        9718 :                                                                          *nil_matches, *max_one, est)) == NULL)
     711           1 :                         goto fail;
     712             :         }
     713      655161 :         *r1 = result1->batCacheid;
     714      655161 :         BBPkeepref(result1);
     715      656703 :         if (r2) {
     716      380928 :                 *r2 = result2->batCacheid;
     717      380928 :                 BBPkeepref(result2);
     718             :         }
     719      656960 :         if (r3) {
     720       19446 :                 *r3 = result3->batCacheid;
     721       19446 :                 BBPkeepref(result3);
     722             :         }
     723      657014 :         BBPunfix(left->batCacheid);
     724      658660 :         BBPunfix(right->batCacheid);
     725      659003 :         BBPreclaim(candleft);
     726      658851 :         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      370130 : 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      370130 :         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       43216 : 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       43216 :         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         123 : 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         123 :         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       19427 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     815             :                          const bat *slid, const bat *srid, const lng *estimate)
     816             : {
     817       19427 :         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        7613 : ALGthetajoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     835             :                          const bat *srid, const int *op, const bit *nil_matches,
     836             :                          const lng *estimate)
     837             : {
     838        7613 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     839             :                                    false, false, false, false, nil_matches, NULL, NULL,
     840             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     841             :                                    "algebra.thetajoin");
     842             : }
     843             : 
     844             : static str
     845       41380 : 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       41380 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     850             :                                    false, false, false, false, nil_matches, NULL, NULL,
     851             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     852             :                                    "algebra.thetajoin");
     853             : }
     854             : 
     855             : static str
     856           0 : ALGbandjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     857             :                         const bat *srid, const void *c1, const void *c2, const bit *li,
     858             :                         const bit *hi, const lng *estimate)
     859             : {
     860           0 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     861           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     862             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     863             :                                    "algebra.bandjoin");
     864             : }
     865             : 
     866             : static str
     867           0 : ALGbandjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     868             :                          const bat *srid, const void *c1, const void *c2, const bit *li,
     869             :                          const bit *hi, const lng *estimate)
     870             : {
     871           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     872           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     873             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     874             :                                    "algebra.bandjoin");
     875             : }
     876             : 
     877             : static str
     878         118 : ALGrangejoin(bat *r1, bat *r2, const bat *lid, const bat *rlid, const bat *rhid,
     879             :                          const bat *slid, const bat *srid, const bit *li, const bit *hi,
     880             :                          const bit *anti, const bit *symmetric, const lng *estimate)
     881             : {
     882         240 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     883         118 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     884             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     885             :                                    "algebra.rangejoin");
     886             : }
     887             : 
     888             : static str
     889          24 : ALGrangejoin1(bat *r1, const bat *lid, const bat *rlid, const bat *rhid,
     890             :                           const bat *slid, const bat *srid, const bit *li, const bit *hi,
     891             :                           const bit *anti, const bit *symmetric, const lng *estimate)
     892             : {
     893          49 :         return do_join(r1, NULL, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     894          24 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     895             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     896             :                                    "algebra.rangejoin");
     897             : }
     898             : 
     899             : static str
     900      160779 : 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      160779 :         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        9718 : 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        9718 :         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        1719 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     932             : {
     933        1719 :         bat *ret1, *ret2 = NULL;
     934        1719 :         bat bid, sid, gid;
     935        1719 :         BAT *b, *s = NULL, *g = NULL;
     936        1719 :         BAT *bn = NULL, *gn = NULL;
     937        1719 :         lng n;
     938        1719 :         bit asc, nilslast, distinct;
     939        1719 :         gdk_return rc;
     940             : 
     941        1719 :         (void) cntxt;
     942        1719 :         (void) mb;
     943             : 
     944        1719 :         assert(pci->retc == 1 || pci->retc == 2);
     945        1719 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     946             : 
     947        1719 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     948        1719 :         if (n < 0)
     949           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     950        1719 :         if (n > (lng) BUN_MAX)
     951             :                 n = BUN_MAX;
     952        1719 :         ret1 = getArgReference_bat(stk, pci, 0);
     953        1719 :         if (pci->retc == 2)
     954         618 :                 ret2 = getArgReference_bat(stk, pci, 1);
     955        1719 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     956        1719 :         if ((b = BATdescriptor(bid)) == NULL)
     957           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     958        1721 :         if (pci->argc - pci->retc > 5) {
     959        1722 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     960        1722 :                 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        1725 :                 if (pci->argc - pci->retc > 6) {
     966        1725 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     967        1725 :                         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        1724 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     976        1724 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     977        1724 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
     978        2826 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
     979             :                                    distinct);
     980        1721 :         BBPunfix(b->batCacheid);
     981        1723 :         BBPreclaim(s);
     982        1723 :         BBPreclaim(g);
     983        1723 :         if (rc != GDK_SUCCEED)
     984           0 :                 throw(MAL, "algebra.firstn", GDK_EXCEPTION);
     985        1723 :         *ret1 = bn->batCacheid;
     986        1723 :         BBPkeepref(bn);
     987        1720 :         if (ret2) {
     988         623 :                 *ret2 = gn->batCacheid;
     989         623 :                 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       45274 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1121             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1122             : {
    1123       45274 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1124       45274 :         BAT *sl = NULL, *sr = NULL;
    1125       45274 :         gdk_return ret;
    1126             : 
    1127       45274 :         L = BATdescriptor(*left);
    1128       46794 :         R = BATdescriptor(*right);
    1129       46854 :         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       46854 :         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       48667 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1145       46854 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1146       46388 :         BBPunfix(L->batCacheid);
    1147       46758 :         BBPunfix(R->batCacheid);
    1148       46860 :         BBPreclaim(sl);
    1149       46861 :         BBPreclaim(sr);
    1150       46864 :         if (ret != GDK_SUCCEED)
    1151          88 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1152       46776 :         *l = bn1->batCacheid;
    1153       46776 :         BBPkeepref(bn1);
    1154       46705 :         if (r) {
    1155       44911 :                 *r = bn2->batCacheid;
    1156       44911 :                 BBPkeepref(bn2);
    1157             :         }
    1158             :         return MAL_SUCCEED;
    1159             : }
    1160             : 
    1161             : static str
    1162        1748 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1163             : {
    1164        1748 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1165             : }
    1166             : 
    1167             : static str
    1168       43595 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1169             :                                  const bit *max_one)
    1170             : {
    1171       43595 :         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         424 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1190             : {
    1191         424 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1192         424 :         BAT *sl = NULL, *sr = NULL;
    1193         424 :         gdk_return ret;
    1194             : 
    1195         424 :         L = BATdescriptor(*left);
    1196         424 :         R = BATdescriptor(*right);
    1197         424 :         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         424 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1203         424 :                 (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         424 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1211         424 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1212         424 :         BBPunfix(L->batCacheid);
    1213         424 :         BBPunfix(R->batCacheid);
    1214         424 :         BBPreclaim(sl);
    1215         424 :         BBPreclaim(sr);
    1216         424 :         if (ret != GDK_SUCCEED)
    1217           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1218         424 :         *l = bn1->batCacheid;
    1219         424 :         BBPkeepref(bn1);
    1220         424 :         if (r) {
    1221         424 :                 *r = bn2->batCacheid;
    1222         424 :                 BBPkeepref(bn2);
    1223             :         }
    1224             :         return MAL_SUCCEED;
    1225             : }
    1226             : 
    1227             : static str
    1228     1979300 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1229             : {
    1230     1979300 :         BAT *l, *r1, *r2 = NULL, *bn;
    1231             : 
    1232     1979300 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1233           0 :                 throw(MAL, "algebra.projection",
    1234             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1235             :         }
    1236     1992013 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1237           0 :                 BBPunfix(l->batCacheid);
    1238           0 :                 throw(MAL, "algebra.projection",
    1239             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1240             :         }
    1241     1991209 :         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     1991209 :         bn = BATproject2(l, r1, r2);
    1248     1975943 :         BBPunfix(l->batCacheid);
    1249     1989886 :         BBPunfix(r1->batCacheid);
    1250     1990464 :         BBPreclaim(r2);
    1251     1989784 :         if (bn == NULL)
    1252           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1253     1989784 :         *result = bn->batCacheid;
    1254     1989784 :         BBPkeepref(bn);
    1255     1989784 :         return MAL_SUCCEED;
    1256             : }
    1257             : 
    1258             : str
    1259     1981229 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1260             : {
    1261     1981229 :         return ALGprojection2(result, lid, rid, NULL);
    1262             : }
    1263             : 
    1264             : static str
    1265       27208 : 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       27208 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1270       27208 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1271             : 
    1272       27208 :         if ((b = BATdescriptor(*bid)) == NULL)
    1273           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1274       27209 :         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       27209 :         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       30958 :         if (BATsort(result ? &bn : NULL,
    1284             :                                 norder ? &on : NULL,
    1285             :                                 ngroup ? &gn : NULL,
    1286       27209 :                                 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       27209 :         BBPunfix(b->batCacheid);
    1293       27209 :         BBPreclaim(o);
    1294       27209 :         BBPreclaim(g);
    1295       27209 :         if (result) {
    1296       27209 :                 *result = bn->batCacheid;
    1297       27209 :                 BBPkeepref(bn);
    1298             :         }
    1299       27209 :         if (norder) {
    1300       23460 :                 *norder = on->batCacheid;
    1301       23460 :                 BBPkeepref(on);
    1302             :         }
    1303       27209 :         if (ngroup) {
    1304       14120 :                 *ngroup = gn->batCacheid;
    1305       14120 :                 BBPkeepref(gn);
    1306             :         }
    1307             :         return MAL_SUCCEED;
    1308             : }
    1309             : 
    1310             : static str
    1311        4307 : 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        4307 :         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        6645 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1354             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1355             : {
    1356        6645 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1357             :                                          stable);
    1358             : }
    1359             : 
    1360             : static str
    1361        5033 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1362             :                   const bit *nilslast, const bit *stable)
    1363             : {
    1364        5033 :         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       71379 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1378             :                                 const bit *ignore_nils)
    1379             : {
    1380       71379 :         BAT *b, *s = NULL;
    1381             : 
    1382       71379 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1383           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1384             :         }
    1385       71623 :         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       71623 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1390          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1391       71593 :         } else if (*ignore_nils) {
    1392        1767 :                 *result = (lng) BATcount_no_nil(b, s);
    1393             :         } else {
    1394       69826 :                 struct canditer ci;
    1395       69826 :                 canditer_init(&ci, b, s);
    1396       69794 :                 *result = (lng) ci.ncand;
    1397             :         }
    1398       71591 :         BBPreclaim(s);
    1399       71591 :         BBPunfix(b->batCacheid);
    1400       71591 :         return MAL_SUCCEED;
    1401             : }
    1402             : 
    1403             : static str
    1404        1767 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1405             : {
    1406        1767 :         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       69601 : ALGcount_bat(lng *result, const bat *bid)
    1417             : {
    1418       69601 :         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       17455 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1482             : {
    1483       17455 :         BAT *b, *bn;
    1484       17455 :         BUN s, e;
    1485             : 
    1486       17455 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1487           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1488       17455 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1489           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1490       17460 :         s = (BUN) *start;
    1491       17460 :         if (s > BATcount(b))
    1492             :                 s = BATcount(b);
    1493       17460 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1494       17460 :         if (e > BATcount(b))
    1495             :                 e = BATcount(b);
    1496       17460 :         if (e < s)
    1497             :                 e = s;
    1498       17460 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1499       17455 :         if (bn == NULL)
    1500           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1501       17455 :         *ret = bn->batCacheid;
    1502       17455 :         BBPkeepref(bn);
    1503       17455 :         return MAL_SUCCEED;
    1504             : }
    1505             : 
    1506             : /*
    1507             :  * BUN Get/Fetch
    1508             :  */
    1509             : 
    1510             : static str
    1511      185984 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1512             : {
    1513      185984 :         assert(pos <= BUN_MAX);
    1514      185984 :         BATiter bi = bat_iterator(b);
    1515      185984 :         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      185784 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1527      185784 :                 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      185784 :                 } else if (_s == 4) {
    1532      185697 :                         *(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      185984 :         bat_iterator_end(&bi);
    1548      185984 :         return MAL_SUCCEED;
    1549             : }
    1550             : 
    1551             : static str
    1552      185986 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1553             : {
    1554      185986 :         BAT *b;
    1555      185986 :         str msg;
    1556             : 
    1557      185986 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1558           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1559             :         }
    1560      185986 :         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      185986 :         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      185984 :         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      185984 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1577      185984 :         BBPunfix(b->batCacheid);
    1578      185984 :         return msg;
    1579             : }
    1580             : 
    1581             : str
    1582      185986 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1583             : {
    1584      185986 :         lng o = *pos;
    1585             : 
    1586      185986 :         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      296724 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1629             : {
    1630      296724 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1631      296724 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1632      296724 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1633      296724 :         BAT *b, *bn;
    1634             : 
    1635      296724 :         (void) cntxt;
    1636      296724 :         (void) mb;
    1637      296724 :         if (isaBatType(getArgType(mb, pci, 2)))
    1638           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1639      296724 :         if ((b = BBPquickdesc(bid)) == NULL)
    1640           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1641      297168 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1642      296954 :         if (bn == NULL) {
    1643           0 :                 *ret = bat_nil;
    1644           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1645             :         }
    1646      296954 :         *ret = bn->batCacheid;
    1647      296954 :         BBPkeepref(bn);
    1648      296954 :         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           4 : ALGcovariance(dbl *res, const bat *bid1, const bat *bid2)
    1760             : {
    1761           4 :         BAT *b1, *b2;
    1762           4 :         dbl covariance;
    1763             : 
    1764           4 :         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           4 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1775           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1776           4 :         *res = covariance;
    1777           4 :         return MAL_SUCCEED;
    1778             : }
    1779             : 
    1780             : static str
    1781           8 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1782             : {
    1783           8 :         BAT *b1, *b2;
    1784           8 :         dbl covariance;
    1785             : 
    1786           8 :         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           8 :         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          18 :         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         351 : LIB_STARTUP_FUNC(init_algebra_mal)
    1913         351 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14