LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 761 993 76.6 %
Date: 2024-04-26 00:35:57 Functions: 67 82 81.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * (c) Peter Boncz, Martin Kersten, Niels Nes, Sjoerd Mullender
      15             :  * BAT Algebra
      16             :  * This modules contains the most common algebraic BAT manipulation
      17             :  * commands. We call them algebra, because all operations take
      18             :  * values as parameters, and produce new result values, but
      19             :  * do not modify their parameters.
      20             :  *
      21             :  * Unlike the previous Monet versions, we reduce the number
      22             :  * of functions returning a BAT reference. This was previously needed
      23             :  * to simplify recursive bat-expression and manage reference counts.
      24             :  * In the current version we return only a BAT identifier when a new
      25             :  * bat is being created.
      26             :  *
      27             :  * All parameters to the modules are passed by reference.
      28             :  * In particular, this means that
      29             :  * string values are passed to the module layer as (str *)
      30             :  * and we have to de-reference them before entering the gdk library.
      31             :  * This calls for knowlegde 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        2361 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts)
      60             : {
      61        2361 :         BUN j;
      62        2361 :         BATiter gi = bat_iterator(gids);
      63        2361 :         BAT *r = COLnew(0, TYPE_oid, gi.count * 2, TRANSIENT);
      64             : 
      65        2361 :         if (r == NULL) {
      66           0 :                 bat_iterator_end(&gi);
      67           0 :                 return GDK_FAIL;
      68             :         }
      69        2361 :         BATiter ci = bat_iterator(cnts);
      70        2361 :         if (gi.type == TYPE_void) {
      71        1022 :                 oid id = gi.tseq;
      72        1022 :                 lng *cnt = (lng *) ci.base;
      73       46312 :                 for (j = 0; j < gi.count; j++) {
      74       45290 :                         lng i, sz = cnt[j];
      75       90526 :                         for (i = 0; i < sz; i++) {
      76       45236 :                                 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       45290 :                         id ++;
      84             :                 }
      85             :         } else {
      86        1339 :                 oid *id = (oid *) gi.base;
      87        1339 :                 lng *cnt = (lng *) ci.base;
      88      140533 :                 for (j = 0; j < gi.count; j++) {
      89      139194 :                         lng i, sz = cnt[j];
      90      274900 :                         for (i = 0; i < sz; i++) {
      91      135706 :                                 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      139194 :                         id ++;
      99             :                 }
     100             :         }
     101        2361 :         bat_iterator_end(&ci);
     102        2361 :         r->tkey = false;
     103        2361 :         r->tseqbase = oid_nil;
     104        2361 :         r->tsorted = gi.sorted;
     105        2361 :         r->trevsorted = gi.revsorted;
     106        2361 :         r->tnonil = gi.nonil;
     107        2361 :         bat_iterator_end(&gi);
     108        2361 :         *result = r;
     109        2361 :         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         627 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         627 :         BAT *b;
     143         627 :         ptr p;
     144         627 :         str msg = MAL_SUCCEED;
     145             : 
     146         627 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         627 :         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         627 :                 if (ATOMextern(b->ttype)) {
     155          26 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         601 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         601 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         627 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         627 :         BBPunfix(b->batCacheid);
     166         627 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         627 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         627 :         bit skipnil = TRUE;
     173         627 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         632 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         632 :         BAT *b;
     180         632 :         ptr p;
     181         632 :         str msg = MAL_SUCCEED;
     182             : 
     183         632 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         633 :         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         633 :                 if (ATOMextern(b->ttype)) {
     192          51 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         582 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         582 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         633 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         633 :         BBPunfix(b->batCacheid);
     203         633 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         632 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         632 :         bit skipnil = TRUE;
     210         632 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     211             : }
     212             : 
     213             : static str
     214        2361 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     215             : {
     216        2361 :         BAT *bn, *g, *c;
     217             : 
     218        2361 :         g = BATdescriptor(*gids);
     219        2361 :         if (g == NULL) {
     220           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     221             :         }
     222        2361 :         c = BATdescriptor(*cnts);
     223        2361 :         if (c == NULL) {
     224           0 :                 BBPunfix(g->batCacheid);
     225           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     226             :         }
     227        2361 :         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        2361 :         *res = bn->batCacheid;
     233        2361 :         BBPkeepref(bn);
     234        2361 :         BBPunfix(g->batCacheid);
     235        2361 :         BBPunfix(c->batCacheid);
     236        2361 :         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      136622 : ALGselect2(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             : {
     263      136622 :         BAT *b, *s = NULL, *bn;
     264      136622 :         const void *nilptr;
     265             : 
     266      136622 :         if ((*li != 0 && *li != 1) ||
     267      136622 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270      136767 :         if ((b = BATdescriptor(*bid)) == NULL) {
     271           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     272             :         }
     273      137500 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     274           0 :                 BBPunfix(b->batCacheid);
     275           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     276             :         }
     277      137512 :         derefStr(b, low);
     278      137512 :         derefStr(b, high);
     279      137512 :         nilptr = ATOMnilptr(b->ttype);
     280      274214 :         if (*li == 1 && *hi == 1 && nilptr != NULL &&
     281      164866 :                 ATOMcmp(b->ttype, low, nilptr) == 0 &&
     282       27568 :                 ATOMcmp(b->ttype, high, nilptr) == 0) {
     283             :                 /* special case: equi-select for NIL */
     284      136916 :                 high = NULL;
     285             :         }
     286      136916 :         bn = BATselect(b, s, low, high, *li, *hi, *anti);
     287      135985 :         BBPunfix(b->batCacheid);
     288      136952 :         BBPreclaim(s);
     289      137189 :         if (bn == NULL)
     290           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     291      137189 :         *result = bn->batCacheid;
     292      137189 :         BBPkeepref(bn);
     293      137189 :         return MAL_SUCCEED;
     294             : }
     295             : 
     296             : static str
     297        7339 : ALGselect2nil(bat *result, const bat *bid, const bat *sid, const void *low,
     298             :                           const void *high, const bit *li, const bit *hi, const bit *anti,
     299             :                           const bit *unknown)
     300             : {
     301        7339 :         BAT *b, *s = NULL, *bn;
     302        7339 :         bit nanti = *anti, nli = *li, nhi = *hi;
     303             : 
     304        7339 :         if (!*unknown)
     305           0 :                 return ALGselect2(result, bid, sid, low, high, li, hi, anti);
     306             : 
     307        7339 :         if ((nli != 0 && nli != 1) ||
     308        7339 :                 (nhi != 0 && nhi != 1) || (nanti != 0 && nanti != 1)) {
     309           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     310             :         }
     311        7340 :         if ((b = BATdescriptor(*bid)) == NULL) {
     312           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     313             :         }
     314        7363 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     315           0 :                 BBPunfix(b->batCacheid);
     316           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     317             :         }
     318        7368 :         derefStr(b, low);
     319        7368 :         derefStr(b, high);
     320             :         /* here we don't need open ended parts with nil */
     321        7368 :         if (!nanti) {
     322        1362 :                 const void *nilptr = ATOMnilptr(b->ttype);
     323        1362 :                 if (nilptr) {
     324        1362 :                         if (nli == 1 && ATOMcmp(b->ttype, low, nilptr) == 0) {
     325          22 :                                 low = high;
     326          22 :                                 nli = 0;
     327             :                         }
     328        1360 :                         if (nhi == 1 && ATOMcmp(b->ttype, high, nilptr) == 0) {
     329          25 :                                 high = low;
     330          25 :                                 nhi = 0;
     331             :                         }
     332        1359 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     333        7367 :                                 nanti = 1;
     334             :                 }
     335             :         }
     336             : 
     337        7367 :         bn = BATselect(b, s, low, high, nli, nhi, nanti);
     338        7357 :         BBPunfix(b->batCacheid);
     339        7361 :         BBPreclaim(s);
     340        7363 :         if (bn == NULL)
     341           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     342        7363 :         *result = bn->batCacheid;
     343        7363 :         BBPkeepref(bn);
     344        7363 :         return MAL_SUCCEED;
     345             : }
     346             : 
     347             : static str
     348       83672 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     349             :                    const bit *li, const bit *hi, const bit *anti)
     350             : {
     351       83672 :         return ALGselect2(result, bid, NULL, low, high, li, hi, anti);
     352             : }
     353             : 
     354             : static str
     355         324 : ALGselect1nil(bat *result, const bat *bid, const void *low, const void *high,
     356             :                           const bit *li, const bit *hi, const bit *anti, const bit *unknown)
     357             : {
     358         324 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     359             : }
     360             : 
     361             : static str
     362      380815 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     363             :                                 const char **op)
     364             : {
     365      380815 :         BAT *b, *s = NULL, *bn;
     366             : 
     367      380815 :         if ((b = BATdescriptor(*bid)) == NULL) {
     368           0 :                 throw(MAL, "algebra.thetaselect",
     369             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     370             :         }
     371      382858 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     372           0 :                 BBPunfix(b->batCacheid);
     373           0 :                 throw(MAL, "algebra.thetaselect",
     374             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     375             :         }
     376      383256 :         derefStr(b, val);
     377      383256 :         bn = BATthetaselect(b, s, val, *op);
     378      380356 :         BBPunfix(b->batCacheid);
     379      382437 :         BBPreclaim(s);
     380      382596 :         if (bn == NULL)
     381           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     382      382596 :         *result = bn->batCacheid;
     383      382596 :         BBPkeepref(bn);
     384      382596 :         return MAL_SUCCEED;
     385             : }
     386             : 
     387             : static str
     388         383 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     389             : {
     390         383 :         BAT *g = BATdescriptor(*gid); /* oid */
     391         383 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     392         383 :         BAT *p = BATdescriptor(*pid); /* bit */
     393         383 :         BAT *res1 = NULL, *res2 = NULL;
     394         383 :         bit any = *Any; /* any or normal comparision semantics */
     395             : 
     396         383 :         if (!g || !m || !p) {
     397           0 :                 if (g) BBPreclaim(g);
     398           0 :                 if (m) BBPreclaim(m);
     399           0 :                 if (p) BBPreclaim(p);
     400           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     401             :         }
     402         383 :         BUN nr = BATcount(g), q = 0;
     403             : 
     404         383 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     405             :                 BBPreclaim(g);
     406           0 :                 BBPreclaim(m);
     407           0 :                 BBPreclaim(p);
     408           0 :                 if (res1) BBPreclaim(res1);
     409           0 :                 throw(MAL, "algebra.markselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     410             :         }
     411         383 :         assert(g->tsorted);
     412         383 :         oid *ri1 = Tloc(res1, 0);
     413         383 :         bit *ri2 = Tloc(res2, 0);
     414         383 :         bit *mi = Tloc(m, 0);
     415         383 :         bit *pi = Tloc(p, 0);
     416         383 :         oid cur = oid_nil;
     417             : 
     418         383 :         if (g->ttype == TYPE_void) { /* void case ? */
     419          30 :                 oid c = g->hseqbase;
     420         113 :                 for (BUN n = 0; n < nr; n++, c++) {
     421          83 :                         ri1[q] = c;
     422          83 :                         ri2[q] = FALSE;
     423          83 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     424           7 :                                 ri2[q] = TRUE;
     425          76 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     426           7 :                                 ri2[q] = bit_nil;
     427          83 :                         q++;
     428             :                 }
     429             :         } else {
     430         353 :                 oid *gi = Tloc(g, 0);
     431         353 :                 oid c = g->hseqbase;
     432         353 :                 if (nr)
     433         353 :                         cur = gi[0];
     434             :                 bit m = FALSE;
     435             :                 bool has_nil = false;
     436      233385 :                 for (BUN n = 0; n < nr; n++, c++) {
     437      233032 :                         if (c && cur != gi[n]) {
     438        8030 :                                 ri1[q] = c-1;
     439        8030 :                                 ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     440        8030 :                                 q++;
     441        8030 :                                 cur = gi[n];
     442        8030 :                                 m = FALSE;
     443        8030 :                                 has_nil = false;
     444             :                         }
     445      233032 :                         if (m == TRUE)
     446      192102 :                                 continue;
     447             : 
     448       40930 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     449             :                                 m = TRUE;
     450       33923 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     451      233032 :                                 has_nil = true;
     452             :                 }
     453         353 :                 if (nr) {
     454         353 :                         ri1[q] = c-1;
     455         353 :                         ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     456             :                 }
     457         353 :                 q++;
     458             :         }
     459         383 :         BATsetcount(res1, q);
     460         383 :         BATsetcount(res2, q);
     461         383 :         res1->tsorted = true;
     462         383 :         res1->tkey = true;
     463         383 :         res1->trevsorted = false;
     464         383 :         res2->tsorted = false;
     465         383 :         res2->trevsorted = false;
     466         383 :         res1->tnil = false;
     467         383 :         res1->tnonil = true;
     468         383 :         res2->tnonil = false;
     469         383 :         res2->tkey = false;
     470             : 
     471         383 :         BBPreclaim(g);
     472         383 :         BBPreclaim(m);
     473         383 :         BBPreclaim(p);
     474             : 
     475         383 :         BBPkeepref(res1);
     476         383 :         BBPkeepref(res2);
     477         383 :         *r1 = res1->batCacheid;
     478         383 :         *r2 = res2->batCacheid;
     479         383 :         return MAL_SUCCEED;
     480             : }
     481             : 
     482             : static str
     483          36 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     484             : {
     485          36 :         BAT *g = BATdescriptor(*gid); /* oid */
     486          36 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     487          36 :         BAT *p = BATdescriptor(*pid); /* bit */
     488          36 :         BAT *res1 = NULL, *res2 = NULL;
     489          36 :         bit any = *Any; /* any or normal comparision semantics */
     490             : 
     491          36 :         if (!g || !m || !p) {
     492           0 :                 if (g) BBPreclaim(g);
     493           0 :                 if (m) BBPreclaim(m);
     494           0 :                 if (p) BBPreclaim(p);
     495           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     496             :         }
     497          36 :         BUN nr = BATcount(g), q = 0;
     498             : 
     499          36 :         if ((res1 = COLnew(0, TYPE_oid, nr, TRANSIENT)) == NULL || (res2 = COLnew(0, TYPE_bit, nr, TRANSIENT)) == NULL) {
     500             :                 BBPreclaim(g);
     501           0 :                 BBPreclaim(m);
     502           0 :                 BBPreclaim(p);
     503           0 :                 if (res1) BBPreclaim(res1);
     504           0 :                 throw(MAL, "algebra.outerselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     505             :         }
     506          36 :         assert(g->tsorted);
     507          36 :         oid *ri1 = Tloc(res1, 0);
     508          36 :         bit *ri2 = Tloc(res2, 0);
     509          36 :         bit *mi = Tloc(m, 0);
     510          36 :         bit *pi = Tloc(p, 0);
     511          36 :         oid cur = oid_nil;
     512             : 
     513          36 :         if (g->ttype == TYPE_void) { /* void case ? */
     514          12 :                 oid c = g->hseqbase;
     515         101 :                 for (BUN n = 0; n < nr; n++, c++) {
     516          89 :                         ri1[q] = c;
     517         161 :                         ri2[q] = (any && (mi[n] == bit_nil || pi[n] == bit_nil))?bit_nil:(mi[n] == TRUE && pi[n] == TRUE)?TRUE:FALSE;
     518          89 :                         q++;
     519             :                 }
     520             :         } else {
     521          24 :                 oid *gi = Tloc(g, 0);
     522          24 :                 oid c = g->hseqbase;
     523          24 :                 if (nr)
     524          24 :                         cur = gi[0];
     525             :                 bool used = false;
     526         597 :                 for (BUN n = 0; n < nr; n++, c++) {
     527         573 :                         if (c && cur != gi[n]) {
     528         159 :                                 if (!used) {
     529           3 :                                         ri1[q] = c-1;
     530           3 :                                         ri2[q] = false;
     531           3 :                                         q++;
     532             :                                 }
     533         159 :                                 used = false;
     534         159 :                                 cur = gi[n];
     535             :                         }
     536         573 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     537         319 :                                 ri1[q] = c;
     538         319 :                                 ri2[q] = TRUE;
     539         319 :                                 used = true;
     540         319 :                                 q++;
     541         254 :                         } else if (mi[n] == FALSE) { /* empty */
     542          55 :                                 ri1[q] = c;
     543          55 :                                 ri2[q] = FALSE;
     544          55 :                                 used = true;
     545          55 :                                 q++;
     546         199 :                         } else if (any && (mi[n] == bit_nil /* ie has nil */ || pi[n] == bit_nil)) {
     547           6 :                                 ri1[q] = c;
     548           6 :                                 ri2[q] = bit_nil;
     549           6 :                                 used = true;
     550           6 :                                 q++;
     551             :                         }
     552             :                 }
     553          24 :                 if (nr && !used) {
     554           1 :                         ri1[q] = c-1;
     555           1 :                         ri2[q] = FALSE;
     556           1 :                         q++;
     557             :                 }
     558             :         }
     559          36 :         BATsetcount(res1, q);
     560          36 :         BATsetcount(res2, q);
     561          36 :         res1->tsorted = true;
     562          36 :         res1->tkey = true;
     563          36 :         res1->trevsorted = false;
     564          36 :         res2->tsorted = false;
     565          36 :         res2->trevsorted = false;
     566          36 :         res1->tnil = false;
     567          36 :         res1->tnonil = true;
     568          36 :         res2->tnonil = false;
     569          36 :         res2->tkey = false;
     570             : 
     571          36 :         BBPreclaim(g);
     572          36 :         BBPreclaim(m);
     573          36 :         BBPreclaim(p);
     574             : 
     575          36 :         BBPkeepref(res1);
     576          36 :         BBPkeepref(res2);
     577          36 :         *r1 = res1->batCacheid;
     578          36 :         *r2 = res2->batCacheid;
     579          36 :         return MAL_SUCCEED;
     580             : }
     581             : 
     582             : 
     583             : static str
     584        1540 : ALGselectNotNil(bat *result, const bat *bid)
     585             : {
     586        1540 :         BAT *b;
     587             : 
     588        1540 :         if ((b = BATdescriptor(*bid)) == NULL)
     589           0 :                 throw(MAL, "algebra.selectNotNil",
     590             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     591             : 
     592        1540 :         MT_lock_set(&b->theaplock);
     593        1540 :         bool bnonil = b->tnonil || b->ttype == TYPE_msk;
     594        1540 :         MT_lock_unset(&b->theaplock);
     595        1540 :         if (!bnonil) {
     596         557 :                 BAT *s;
     597         557 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true);
     598         556 :                 if (s) {
     599         556 :                         BAT *bn = BATproject(s, b);
     600         557 :                         BBPunfix(s->batCacheid);
     601         556 :                         if (bn) {
     602         556 :                                 BBPunfix(b->batCacheid);
     603         557 :                                 *result = bn->batCacheid;
     604         557 :                                 BBPkeepref(bn);
     605         557 :                                 return MAL_SUCCEED;
     606             :                         }
     607             :                 }
     608           0 :                 BBPunfix(b->batCacheid);
     609           0 :                 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
     610             :         }
     611             :         /* just pass on the result */
     612         983 :         *result = b->batCacheid;
     613         983 :         BBPkeepref(b);
     614         983 :         return MAL_SUCCEED;
     615             : }
     616             : 
     617             : static str
     618      479855 : 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 */
     619             :                 const bit *nil_matches, const bit *not_in, const bit *max_one,
     620             :                 const lng *estimate,
     621             :                 gdk_return (*joinfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     622             :                                                            bool, BUN),
     623             :                 gdk_return (*semifunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     624             :                                                           bool, bool, BUN),
     625             :                 gdk_return (*markfunc)(BAT **, BAT **, BAT **,
     626             :                                                            BAT *, BAT *, BAT *, BAT *, BUN),
     627             :                 gdk_return (*thetafunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     628             :                                                            int, bool, BUN),
     629             :                 gdk_return (*bandfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     630             :                                                           const void *, const void *, bool, bool, BUN),
     631             :                 gdk_return (*rangefunc)(BAT **, BAT **, BAT *, BAT *, BAT *,
     632             :                                                            BAT *, BAT *, bool, bool, bool, bool, BUN),
     633             :                 BAT * (*difffunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     634             :                 BAT * (*interfunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     635             :                 const char *funcname)
     636             : {
     637      479855 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     638      479855 :         BAT *candleft = NULL, *candright = NULL;
     639      479855 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     640      479855 :         BUN est;
     641      479855 :         const char *err = RUNTIME_OBJECT_MISSING;
     642             : 
     643      479855 :         assert(r2id == NULL || rangefunc != NULL);
     644             : 
     645      479855 :         if ((left = BATdescriptor(*lid)) == NULL)
     646           0 :                 goto fail;
     647      485661 :         if ((right = BATdescriptor(*rid)) == NULL)
     648           0 :                 goto fail;
     649      485894 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     650           0 :                 goto fail;
     651      485900 :         if (srid && !is_bat_nil(*srid)
     652           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     653           0 :                 goto fail;
     654      485900 :         if (estimate == NULL || *estimate < 0 || is_lng_nil(*estimate)
     655           0 :                 || *estimate > (lng) BUN_MAX)
     656             :                 est = BUN_NONE;
     657             :         else
     658           0 :                 est = (BUN) *estimate;
     659             : 
     660      485900 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     661             : 
     662      485900 :         if (thetafunc) {
     663       50998 :                 assert(joinfunc == NULL);
     664       50998 :                 assert(semifunc == NULL);
     665       50998 :                 assert(markfunc == NULL);
     666       50998 :                 assert(bandfunc == NULL);
     667       50998 :                 assert(rangefunc == NULL);
     668       50998 :                 assert(difffunc == NULL);
     669       50998 :                 assert(interfunc == NULL);
     670       50998 :                 if ((*thetafunc)
     671             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     672       50998 :                          op, *nil_matches, est) != GDK_SUCCEED)
     673           0 :                         goto fail;
     674      434902 :         } else if (joinfunc) {
     675      336561 :                 assert(semifunc == NULL);
     676      336561 :                 assert(markfunc == NULL);
     677      336561 :                 assert(bandfunc == NULL);
     678      336561 :                 assert(rangefunc == NULL);
     679      336561 :                 assert(difffunc == NULL);
     680      336561 :                 assert(interfunc == NULL);
     681      336561 :                 if ((*joinfunc)
     682             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     683      336561 :                          *nil_matches, est) != GDK_SUCCEED)
     684           1 :                         goto fail;
     685       98341 :         } else if (semifunc) {
     686         264 :                 assert(markfunc == NULL);
     687         264 :                 assert(bandfunc == NULL);
     688         264 :                 assert(rangefunc == NULL);
     689         264 :                 assert(difffunc == NULL);
     690         264 :                 assert(interfunc == NULL);
     691         264 :                 if ((*semifunc)
     692             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     693         264 :                          *nil_matches, *max_one, est) != GDK_SUCCEED)
     694          40 :                         goto fail;
     695       98077 :         } else if (markfunc) {
     696        4022 :                 assert(bandfunc == NULL);
     697        4022 :                 assert(rangefunc == NULL);
     698        4022 :                 assert(difffunc == NULL);
     699        4022 :                 assert(interfunc == NULL);
     700        8039 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     701             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     702           0 :                         goto fail;
     703       94055 :         } else if (bandfunc) {
     704           0 :                 assert(rangefunc == NULL);
     705           0 :                 assert(difffunc == NULL);
     706           0 :                 assert(interfunc == NULL);
     707           0 :                 if ((*bandfunc)
     708             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     709             :                          c1, c2, li, hi, est) != GDK_SUCCEED)
     710           0 :                         goto fail;
     711       94055 :         } else if (rangefunc) {
     712         138 :                 assert(difffunc == NULL);
     713         138 :                 assert(interfunc == NULL);
     714         138 :                 if ((right2 = BATdescriptor(*r2id)) == NULL) {
     715           0 :                         err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     716           0 :                         goto fail;
     717             :                 }
     718         164 :                 if ((*rangefunc)
     719             :                         (&result1, r2 ? &result2 : NULL, left, right, right2, candleft,
     720             :                          candright, li, hi, anti, symmetric, est) != GDK_SUCCEED)
     721           0 :                         goto fail;
     722         133 :                 BBPunfix(right2->batCacheid);
     723       93917 :         } else if (difffunc) {
     724       86574 :                 assert(r2 == NULL);
     725       86574 :                 assert(interfunc == NULL);
     726       86527 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     727       86574 :                                                                         *nil_matches, *not_in, est)) == NULL)
     728           0 :                         goto fail;
     729             :         } else {
     730        7343 :                 assert(r2 == NULL);
     731        7326 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     732        7343 :                                                                          *nil_matches, *max_one, est)) == NULL)
     733           1 :                         goto fail;
     734             :         }
     735      481478 :         *r1 = result1->batCacheid;
     736      481478 :         BBPkeepref(result1);
     737      482074 :         if (r2) {
     738      301091 :                 *r2 = result2->batCacheid;
     739      301091 :                 BBPkeepref(result2);
     740             :         }
     741      483301 :         if (r3) {
     742        4008 :                 *r3 = result3->batCacheid;
     743        4008 :                 BBPkeepref(result3);
     744             :         }
     745      483310 :         BBPunfix(left->batCacheid);
     746      484210 :         BBPunfix(right->batCacheid);
     747      485280 :         BBPreclaim(candleft);
     748      485337 :         BBPreclaim(candright);
     749             :         return MAL_SUCCEED;
     750             : 
     751          42 :   fail:
     752          42 :         BBPreclaim(left);
     753          42 :         BBPreclaim(right);
     754          42 :         BBPreclaim(right2);
     755          42 :         BBPreclaim(candleft);
     756          42 :         BBPreclaim(candright);
     757          42 :         if (err == NULL)
     758          42 :                 throw(MAL, funcname, GDK_EXCEPTION);
     759           0 :         throw(MAL, funcname, "%s", err);
     760             : }
     761             : 
     762             : static str
     763      291348 : ALGjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     764             :                 const bat *srid, const bit *nil_matches, const lng *estimate)
     765             : {
     766      291348 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     767             :                                    false, false, false, false, nil_matches, NULL, NULL,
     768             :                                    estimate, BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     769             :                                    "algebra.join");
     770             : }
     771             : 
     772             : static str
     773       41386 : ALGjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     774             :                  const bat *srid, const bit *nil_matches, const lng *estimate)
     775             : {
     776       41386 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     777             :                                    false, false, false, false, nil_matches, NULL, NULL,
     778             :                                    estimate, BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     779             :                                    "algebra.join");
     780             : }
     781             : 
     782             : static str
     783         645 : ALGleftjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     784             :                         const bat *srid, const bit *nil_matches, const lng *estimate)
     785             : {
     786         645 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     787             :                                    false, false, false, false, nil_matches, NULL, NULL,
     788             :                                    estimate, BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     789             :                                    "algebra.leftjoin");
     790             : }
     791             : 
     792             : static str
     793           0 : ALGleftjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     794             :                          const bat *srid, const bit *nil_matches, 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, NULL,
     798             :                                    estimate, BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     799             :                                    "algebra.leftjoin");
     800             : }
     801             : 
     802             : static str
     803          72 : ALGouterjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     804             :                          const bat *srid, const bit *nil_matches, const bit *match_one,
     805             :                          const lng *estimate)
     806             : {
     807          72 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     808             :                                    false, false, false, false, nil_matches, NULL, match_one,
     809             :                                    estimate, NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, NULL,
     810             :                                    "algebra.outerjoin");
     811             : }
     812             : 
     813             : static str
     814           0 : ALGouterjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     815             :                           const bat *srid, const bit *nil_matches, const bit *match_one,
     816             :                           const lng *estimate)
     817             : {
     818           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     819             :                                    false, false, false, false, nil_matches, NULL, match_one,
     820             :                                    estimate, NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, NULL,
     821             :                                    "algebra.outerjoin");
     822             : }
     823             : 
     824             : static str
     825         191 : ALGsemijoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     826             :                         const bat *srid, const bit *nil_matches, const bit *max_one,
     827             :                         const lng *estimate)
     828             : {
     829         191 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     830             :                                    false, false, false, false, nil_matches, NULL, max_one,
     831             :                                    estimate, NULL, BATsemijoin, NULL, NULL, NULL, NULL, NULL, NULL,
     832             :                                    "algebra.semijoin");
     833             : }
     834             : 
     835             : static str
     836        3990 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     837             :                          const bat *slid, const bat *srid, const lng *estimate)
     838             : {
     839        3990 :         return do_join(r1, NULL, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     840             :                                    false, false, false, false, NULL, NULL, NULL,
     841             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     842             :                                    "algebra.markjoin");
     843             : }
     844             : 
     845             : static str
     846           5 : ALGmark3join(bat *r1, bat *r2, bat *r3, const bat *lid, const bat *rid,
     847             :                          const bat *slid, const bat *srid, const lng *estimate)
     848             : {
     849           5 :         return do_join(r1, r2, r3, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     850             :                                    false, false, false, false, NULL, NULL, NULL,
     851             :                                    estimate, NULL, NULL, BATmarkjoin, NULL, NULL, NULL, NULL, NULL,
     852             :                                    "algebra.markjoin");
     853             : }
     854             : 
     855             : static str
     856        7525 : ALGthetajoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     857             :                          const bat *srid, const int *op, const bit *nil_matches,
     858             :                          const lng *estimate)
     859             : {
     860        7525 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     861             :                                    false, false, false, false, nil_matches, NULL, NULL,
     862             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     863             :                                    "algebra.thetajoin");
     864             : }
     865             : 
     866             : static str
     867       41162 : ALGthetajoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     868             :                           const bat *srid, const int *op, const bit *nil_matches,
     869             :                           const lng *estimate)
     870             : {
     871       41162 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     872             :                                    false, false, false, false, nil_matches, NULL, NULL,
     873             :                                    estimate, NULL, NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL,
     874             :                                    "algebra.thetajoin");
     875             : }
     876             : 
     877             : static str
     878           0 : ALGbandjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid,
     879             :                         const bat *srid, const void *c1, const void *c2, const bit *li,
     880             :                         const bit *hi, const lng *estimate)
     881             : {
     882           0 :         return do_join(r1, r2, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     883           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     884             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     885             :                                    "algebra.bandjoin");
     886             : }
     887             : 
     888             : static str
     889           0 : ALGbandjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     890             :                          const bat *srid, const void *c1, const void *c2, const bit *li,
     891             :                          const bit *hi, const lng *estimate)
     892             : {
     893           0 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     894           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     895             :                                    NULL, NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL,
     896             :                                    "algebra.bandjoin");
     897             : }
     898             : 
     899             : static str
     900         106 : ALGrangejoin(bat *r1, bat *r2, const bat *lid, const bat *rlid, const bat *rhid,
     901             :                          const bat *slid, const bat *srid, const bit *li, const bit *hi,
     902             :                          const bit *anti, const bit *symmetric, const lng *estimate)
     903             : {
     904         220 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     905         106 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     906             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     907             :                                    "algebra.rangejoin");
     908             : }
     909             : 
     910             : static str
     911          24 : ALGrangejoin1(bat *r1, const bat *lid, const bat *rlid, const bat *rhid,
     912             :                           const bat *slid, const bat *srid, const bit *li, const bit *hi,
     913             :                           const bit *anti, const bit *symmetric, const lng *estimate)
     914             : {
     915          49 :         return do_join(r1, NULL, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     916          24 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     917             :                                    NULL, NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL,
     918             :                                    "algebra.rangejoin");
     919             : }
     920             : 
     921             : static str
     922       86532 : ALGdifference(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     923             :                           const bat *srid, const bit *nil_matches, const bit *not_in,
     924             :                           const lng *estimate)
     925             : {
     926       86532 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     927             :                                    false, false, false, false, nil_matches, not_in, NULL,
     928             :                                    estimate, NULL, NULL, NULL, NULL, NULL, NULL, BATdiff, NULL,
     929             :                                    "algebra.difference");
     930             : }
     931             : 
     932             : static str
     933        7341 : ALGintersect(bat *r1, const bat *lid, const bat *rid, const bat *slid,
     934             :                          const bat *srid, const bit *nil_matches, const bit *max_one,
     935             :                          const lng *estimate)
     936             : {
     937        7341 :         return do_join(r1, NULL, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     938             :                                    false, false, false, false, nil_matches, NULL, max_one,
     939             :                                    estimate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, BATintersect,
     940             :                                    "algebra.intersect");
     941             : }
     942             : 
     943             : /* algebra.firstn(b:bat[:any],
     944             :  *                [ s:bat[:oid],
     945             :  *                [ g:bat[:oid], ] ]
     946             :  *                n:lng,
     947             :  *                asc:bit,
     948             :  *                nilslast:bit,
     949             :  *                distinct:bit)
     950             :  * returns :bat[:oid] [ , :bat[:oid] ]
     951             :  */
     952             : static str
     953        1744 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     954             : {
     955        1744 :         bat *ret1, *ret2 = NULL;
     956        1744 :         bat bid, sid, gid;
     957        1744 :         BAT *b, *s = NULL, *g = NULL;
     958        1744 :         BAT *bn = NULL, *gn = NULL;
     959        1744 :         lng n;
     960        1744 :         bit asc, nilslast, distinct;
     961        1744 :         gdk_return rc;
     962             : 
     963        1744 :         (void) cntxt;
     964        1744 :         (void) mb;
     965             : 
     966        1744 :         assert(pci->retc == 1 || pci->retc == 2);
     967        1744 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     968             : 
     969        1744 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     970        1744 :         if (n < 0)
     971           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     972        1744 :         if (n > (lng) BUN_MAX)
     973             :                 n = BUN_MAX;
     974        1744 :         ret1 = getArgReference_bat(stk, pci, 0);
     975        1744 :         if (pci->retc == 2)
     976         599 :                 ret2 = getArgReference_bat(stk, pci, 1);
     977        1744 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     978        1744 :         if ((b = BATdescriptor(bid)) == NULL)
     979           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     980        1745 :         if (pci->argc - pci->retc > 5) {
     981        1746 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     982        1746 :                 if (!is_bat_nil(sid) && (s = BATdescriptor(sid)) == NULL) {
     983           0 :                         BBPunfix(bid);
     984           0 :                         throw(MAL, "algebra.firstn",
     985             :                                   SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     986             :                 }
     987        1746 :                 if (pci->argc - pci->retc > 6) {
     988        1746 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     989        1746 :                         if (!is_bat_nil(gid) && (g = BATdescriptor(gid)) == NULL) {
     990           0 :                                 BBPunfix(bid);
     991           0 :                                 BBPunfix(sid);
     992           0 :                                 throw(MAL, "algebra.firstn",
     993             :                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     994             :                         }
     995             :                 }
     996             :         }
     997        1745 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     998        1745 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     999        1745 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
    1000        2891 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
    1001             :                                    distinct);
    1002        1741 :         BBPunfix(b->batCacheid);
    1003        1738 :         BBPreclaim(s);
    1004        1738 :         BBPreclaim(g);
    1005        1740 :         if (rc != GDK_SUCCEED)
    1006           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1007        1740 :         *ret1 = bn->batCacheid;
    1008        1740 :         BBPkeepref(bn);
    1009        1735 :         if (ret2) {
    1010         597 :                 *ret2 = gn->batCacheid;
    1011         597 :                 BBPkeepref(gn);
    1012             :         }
    1013             :         return MAL_SUCCEED;
    1014             : }
    1015             : 
    1016             : static str
    1017           9 : ALGunary(bat *result, const bat *bid, BAT *(*func)(BAT *), const char *name)
    1018             : {
    1019           9 :         BAT *b, *bn;
    1020             : 
    1021           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1022           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1023             :         }
    1024           9 :         bn = (*func) (b);
    1025           9 :         BBPunfix(b->batCacheid);
    1026           9 :         if (bn == NULL)
    1027           0 :                 throw(MAL, name, GDK_EXCEPTION);
    1028           9 :         *result = bn->batCacheid;
    1029           9 :         BBPkeepref(bn);
    1030           9 :         return MAL_SUCCEED;
    1031             : }
    1032             : 
    1033             : static inline BAT *
    1034           9 : BATwcopy(BAT *b)
    1035             : {
    1036           9 :         return COLcopy(b, b->ttype, true, TRANSIENT);
    1037             : }
    1038             : 
    1039             : static str
    1040           9 : ALGcopy(bat *result, const bat *bid)
    1041             : {
    1042           9 :         return ALGunary(result, bid, BATwcopy, "algebra.copy");
    1043             : }
    1044             : 
    1045             : static str
    1046          65 : ALGunique(bat *result, const bat *bid, const bat *sid)
    1047             : {
    1048          65 :         BAT *b, *s = NULL, *bn = NULL;
    1049             : 
    1050          65 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1051           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1052             :         }
    1053          65 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
    1054           0 :                 BBPunfix(b->batCacheid);
    1055           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1056             :         }
    1057          65 :         bn = BATunique(b, s);
    1058          65 :         BBPunfix(b->batCacheid);
    1059          65 :         BBPreclaim(s);
    1060          65 :         if (bn == NULL)
    1061           0 :                 throw(MAL, "algebra.unique", GDK_EXCEPTION);
    1062          65 :         *result = bn->batCacheid;
    1063          65 :         BBPkeepref(bn);
    1064          65 :         return MAL_SUCCEED;
    1065             : }
    1066             : 
    1067             : static str
    1068       44147 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1069             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1070             : {
    1071       44147 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1072       44147 :         BAT *sl = NULL, *sr = NULL;
    1073       44147 :         gdk_return ret;
    1074             : 
    1075       44147 :         L = BATdescriptor(*left);
    1076       45569 :         R = BATdescriptor(*right);
    1077       45678 :         if (L == NULL || R == NULL) {
    1078           0 :                 BBPreclaim(L);
    1079           0 :                 BBPreclaim(R);
    1080           0 :                 throw(MAL, "algebra.crossproduct",
    1081             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1082             :         }
    1083       45678 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1084           0 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1085           0 :                 BBPunfix(L->batCacheid);
    1086           0 :                 BBPunfix(R->batCacheid);
    1087           0 :                 BBPreclaim(sl);
    1088             :                 /* sr == NULL, so no need to unfix */
    1089           0 :                 throw(MAL, "algebra.crossproduct",
    1090             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1091             :         }
    1092       47285 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1093       45678 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1094       44881 :         BBPunfix(L->batCacheid);
    1095       45414 :         BBPunfix(R->batCacheid);
    1096       45660 :         BBPreclaim(sl);
    1097       45661 :         BBPreclaim(sr);
    1098       45651 :         if (ret != GDK_SUCCEED)
    1099          79 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1100       45572 :         *l = bn1->batCacheid;
    1101       45572 :         BBPkeepref(bn1);
    1102       45429 :         if (r) {
    1103       43832 :                 *r = bn2->batCacheid;
    1104       43832 :                 BBPkeepref(bn2);
    1105             :         }
    1106             :         return MAL_SUCCEED;
    1107             : }
    1108             : 
    1109             : static str
    1110        1550 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1111             : {
    1112        1550 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1113             : }
    1114             : 
    1115             : static str
    1116       42666 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1117             :                                  const bit *max_one)
    1118             : {
    1119       42666 :         return ALGcrossproduct(l, r, left, right, NULL, NULL, max_one);
    1120             : }
    1121             : 
    1122             : static str
    1123           0 : ALGcrossproduct3(bat *l, bat *r, const bat *left, const bat *right,
    1124             :                                  const bat *sl, const bat *sr, const bit *max_one)
    1125             : {
    1126           0 :         return ALGcrossproduct(l, r, left, right, sl, sr, max_one);
    1127             : }
    1128             : 
    1129             : static str
    1130           0 : ALGcrossproduct4(bat *l, const bat *left, const bat *right, const bat *sl,
    1131             :                                  const bat *sr, const bit *max_one)
    1132             : {
    1133           0 :         return ALGcrossproduct(l, NULL, left, right, sl, sr, max_one);
    1134             : }
    1135             : 
    1136             : static str
    1137         409 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1138             : {
    1139         409 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1140         409 :         BAT *sl = NULL, *sr = NULL;
    1141         409 :         gdk_return ret;
    1142             : 
    1143         409 :         L = BATdescriptor(*left);
    1144         409 :         R = BATdescriptor(*right);
    1145         409 :         if (L == NULL || R == NULL) {
    1146           0 :                 BBPreclaim(L);
    1147           0 :                 BBPreclaim(R);
    1148           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1149             :         }
    1150         409 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1151         409 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
    1152           0 :                 BBPunfix(L->batCacheid);
    1153           0 :                 BBPunfix(R->batCacheid);
    1154           0 :                 BBPreclaim(sl);
    1155             :                 /* sr == NULL, so no need to unfix */
    1156           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1157             :         }
    1158         409 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1159         409 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1160         409 :         BBPunfix(L->batCacheid);
    1161         409 :         BBPunfix(R->batCacheid);
    1162         409 :         BBPreclaim(sl);
    1163         409 :         BBPreclaim(sr);
    1164         409 :         if (ret != GDK_SUCCEED)
    1165           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1166         409 :         *l = bn1->batCacheid;
    1167         409 :         BBPkeepref(bn1);
    1168         409 :         if (r) {
    1169         409 :                 *r = bn2->batCacheid;
    1170         409 :                 BBPkeepref(bn2);
    1171             :         }
    1172             :         return MAL_SUCCEED;
    1173             : }
    1174             : 
    1175             : static str
    1176     1578629 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1177             : {
    1178     1578629 :         BAT *l, *r1, *r2 = NULL, *bn;
    1179             : 
    1180     1578629 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1181           0 :                 throw(MAL, "algebra.projection",
    1182             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1183             :         }
    1184     1590193 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1185           0 :                 BBPunfix(l->batCacheid);
    1186           0 :                 throw(MAL, "algebra.projection",
    1187             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1188             :         }
    1189     1589657 :         if (r2id && !is_bat_nil(*r2id) && (r2 = BATdescriptor(*r2id)) == NULL) {
    1190           0 :                 BBPunfix(l->batCacheid);
    1191           0 :                 BBPunfix(r1->batCacheid);
    1192           0 :                 throw(MAL, "algebra.projection",
    1193             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1194             :         }
    1195     1589657 :         bn = BATproject2(l, r1, r2);
    1196     1565717 :         BBPunfix(l->batCacheid);
    1197     1584673 :         BBPunfix(r1->batCacheid);
    1198     1588238 :         BBPreclaim(r2);
    1199     1588823 :         if (bn == NULL)
    1200           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1201     1588823 :         *result = bn->batCacheid;
    1202     1588823 :         BBPkeepref(bn);
    1203     1588823 :         return MAL_SUCCEED;
    1204             : }
    1205             : 
    1206             : str
    1207     1580492 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1208             : {
    1209     1580492 :         return ALGprojection2(result, lid, rid, NULL);
    1210             : }
    1211             : 
    1212             : static str
    1213       22478 : ALGsort33(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1214             :                   const bat *order, const bat *group, const bit *reverse,
    1215             :                   const bit *nilslast, const bit *stable)
    1216             : {
    1217       22478 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1218       22478 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1219             : 
    1220       22478 :         if ((b = BATdescriptor(*bid)) == NULL)
    1221           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1222       22478 :         if (order && !is_bat_nil(*order) && (o = BATdescriptor(*order)) == NULL) {
    1223           0 :                 BBPunfix(b->batCacheid);
    1224           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1225             :         }
    1226       22478 :         if (group &&!is_bat_nil(*group) && (g = BATdescriptor(*group)) == NULL) {
    1227           0 :                 BBPreclaim(o);
    1228           0 :                 BBPunfix(b->batCacheid);
    1229           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1230             :         }
    1231       26070 :         if (BATsort(result ? &bn : NULL,
    1232             :                                 norder ? &on : NULL,
    1233             :                                 ngroup ? &gn : NULL,
    1234       22478 :                                 b, o, g, *reverse, *nilslast, *stable) != GDK_SUCCEED) {
    1235           0 :                 BBPreclaim(o);
    1236           0 :                 BBPreclaim(g);
    1237           0 :                 BBPunfix(b->batCacheid);
    1238           0 :                 throw(MAL, "algebra.sort", GDK_EXCEPTION);
    1239             :         }
    1240       22478 :         BBPunfix(b->batCacheid);
    1241       22478 :         BBPreclaim(o);
    1242       22478 :         BBPreclaim(g);
    1243       22478 :         if (result) {
    1244       22478 :                 *result = bn->batCacheid;
    1245       22478 :                 BBPkeepref(bn);
    1246             :         }
    1247       22478 :         if (norder) {
    1248       18886 :                 *norder = on->batCacheid;
    1249       18886 :                 BBPkeepref(on);
    1250             :         }
    1251       22478 :         if (ngroup) {
    1252       12528 :                 *ngroup = gn->batCacheid;
    1253       12528 :                 BBPkeepref(gn);
    1254             :         }
    1255             :         return MAL_SUCCEED;
    1256             : }
    1257             : 
    1258             : static str
    1259        3746 : ALGsort32(bat *result, bat *norder, const bat *bid, const bat *order,
    1260             :                   const bat *group, const bit *reverse, const bit *nilslast,
    1261             :                   const bit *stable)
    1262             : {
    1263        3746 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast,
    1264             :                                          stable);
    1265             : }
    1266             : 
    1267             : static str
    1268        1937 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group,
    1269             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1270             : {
    1271        1937 :         return ALGsort33(result, NULL, NULL, bid, order, group, reverse, nilslast,
    1272             :                                          stable);
    1273             : }
    1274             : 
    1275             : static str
    1276           0 : ALGsort23(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1277             :                   const bat *order, const bit *reverse, const bit *nilslast,
    1278             :                   const bit *stable)
    1279             : {
    1280           0 :         return ALGsort33(result, norder, ngroup, bid, order, NULL, reverse,
    1281             :                                          nilslast, stable);
    1282             : }
    1283             : 
    1284             : static str
    1285           0 : ALGsort22(bat *result, bat *norder, const bat *bid, const bat *order,
    1286             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1287             : {
    1288           0 :         return ALGsort33(result, norder, NULL, bid, order, NULL, reverse, nilslast,
    1289             :                                          stable);
    1290             : }
    1291             : 
    1292             : static str
    1293           0 : ALGsort21(bat *result, const bat *bid, const bat *order, const bit *reverse,
    1294             :                   const bit *nilslast, const bit *stable)
    1295             : {
    1296           0 :         return ALGsort33(result, NULL, NULL, bid, order, NULL, reverse, nilslast,
    1297             :                                          stable);
    1298             : }
    1299             : 
    1300             : static str
    1301        5931 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1302             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1303             : {
    1304        5931 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1305             :                                          stable);
    1306             : }
    1307             : 
    1308             : static str
    1309        2612 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1310             :                   const bit *nilslast, const bit *stable)
    1311             : {
    1312        2612 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast,
    1313             :                                          stable);
    1314             : }
    1315             : 
    1316             : static str
    1317        1655 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast,
    1318             :                   const bit *stable)
    1319             : {
    1320        1655 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast,
    1321             :                                          stable);
    1322             : }
    1323             : 
    1324             : static str
    1325       68112 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1326             :                                 const bit *ignore_nils)
    1327             : {
    1328       68112 :         BAT *b, *s = NULL;
    1329             : 
    1330       68112 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1331           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1332             :         }
    1333       68326 :         if (cnd && !is_bat_nil(*cnd) && (s = BATdescriptor(*cnd)) == NULL) {
    1334           0 :                 BBPunfix(b->batCacheid);
    1335           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1336             :         }
    1337       68326 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1338          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1339       68296 :         } else if (*ignore_nils) {
    1340        1933 :                 *result = (lng) BATcount_no_nil(b, s);
    1341             :         } else {
    1342       66363 :                 struct canditer ci;
    1343       66363 :                 canditer_init(&ci, b, s);
    1344       66401 :                 *result = (lng) ci.ncand;
    1345             :         }
    1346       68364 :         BBPreclaim(s);
    1347       68364 :         BBPunfix(b->batCacheid);
    1348       68364 :         return MAL_SUCCEED;
    1349             : }
    1350             : 
    1351             : static str
    1352        1931 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1353             : {
    1354        1931 :         return ALGcountCND_nil(result, bid, NULL, ignore_nils);
    1355             : }
    1356             : 
    1357             : static str
    1358           0 : ALGcountCND_bat(lng *result, const bat *bid, const bat *cnd)
    1359             : {
    1360           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 0 });
    1361             : }
    1362             : 
    1363             : static str
    1364       66185 : ALGcount_bat(lng *result, const bat *bid)
    1365             : {
    1366       66185 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 0 });
    1367             : }
    1368             : 
    1369             : static str
    1370           0 : ALGcountCND_no_nil(lng *result, const bat *bid, const bat *cnd)
    1371             : {
    1372           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit) { 1 });
    1373             : }
    1374             : 
    1375             : static str
    1376           0 : ALGcount_no_nil(lng *result, const bat *bid)
    1377             : {
    1378           0 :         return ALGcountCND_nil(result, bid, NULL, &(bit) { 1 });
    1379             : }
    1380             : 
    1381             : static str
    1382           6 : ALGslice(bat *ret, const bat *bid, const lng *start, const lng *end)
    1383             : {
    1384           6 :         BAT *b, *bn = NULL;
    1385             : 
    1386           6 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1387           0 :                 throw(MAL, "algebra.slice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1388             :         }
    1389           6 :         if (slice(&bn, b, *start, *end) == GDK_SUCCEED) {
    1390           6 :                 *ret = bn->batCacheid;
    1391           6 :                 BBPkeepref(bn);
    1392           6 :                 BBPunfix(b->batCacheid);
    1393           6 :                 return MAL_SUCCEED;
    1394             :         }
    1395           0 :         BBPunfix(b->batCacheid);
    1396           0 :         throw(MAL, "algebra.slice", GDK_EXCEPTION);
    1397             : }
    1398             : 
    1399             : static str
    1400           1 : ALGslice_int(bat *ret, const bat *bid, const int *start, const int *end)
    1401             : {
    1402           1 :         lng s = *start;
    1403           1 :         lng e = (is_int_nil(*end) ? lng_nil : *end);
    1404             : 
    1405           1 :         return ALGslice(ret, bid, &s, &e);
    1406             : }
    1407             : 
    1408             : static str
    1409           0 : ALGslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1410             : {
    1411           0 :         lng s = *start;
    1412           0 :         lng e = *end;
    1413             : 
    1414           0 :         return ALGslice(ret, bid, &s, &e);
    1415             : }
    1416             : 
    1417             : /* carve out a slice based on the OIDs */
    1418             : /* beware that BATs may have different OID bases */
    1419             : static str
    1420           5 : ALGslice_oid(bat *ret, const bat *bid, const oid *start, const oid *end)
    1421             : {
    1422           5 :         lng s = (lng) (is_oid_nil(*start) ? 0 : (lng) *start);
    1423           5 :         lng e = (is_oid_nil(*end) ? lng_nil : (lng) *end);
    1424             : 
    1425           5 :         return ALGslice(ret, bid, &s, &e);
    1426             : }
    1427             : 
    1428             : static str
    1429       17227 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1430             : {
    1431       17227 :         BAT *b, *bn;
    1432       17227 :         BUN s, e;
    1433             : 
    1434       17227 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1435           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1436       17227 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1437           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1438       17229 :         s = (BUN) *start;
    1439       17229 :         if (s > BATcount(b))
    1440             :                 s = BATcount(b);
    1441       17229 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1442       17229 :         if (e > BATcount(b))
    1443             :                 e = BATcount(b);
    1444       17229 :         if (e < s)
    1445             :                 e = s;
    1446       17229 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1447       17228 :         if (bn == NULL)
    1448           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1449       17228 :         *ret = bn->batCacheid;
    1450       17228 :         BBPkeepref(bn);
    1451       17228 :         return MAL_SUCCEED;
    1452             : }
    1453             : 
    1454             : /*
    1455             :  * BUN Get/Fetch
    1456             :  */
    1457             : 
    1458             : static str
    1459       87801 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1460             : {
    1461       87801 :         assert(pos <= BUN_MAX);
    1462       87801 :         BATiter bi = bat_iterator(b);
    1463       87801 :         if (ATOMextern(b->ttype)) {
    1464         150 :                 ptr _src = BUNtail(bi, pos);
    1465         150 :                 size_t _len = ATOMlen(b->ttype, _src);
    1466         150 :                 ptr _dst = GDKmalloc(_len);
    1467         150 :                 if (_dst == NULL) {
    1468           0 :                         bat_iterator_end(&bi);
    1469           0 :                         throw(MAL, "doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1470             :                 }
    1471         150 :                 memcpy(_dst, _src, _len);
    1472         150 :                 *(ptr *) ret = _dst;
    1473             :         } else {
    1474       87651 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1475       87651 :                 if (b->ttype == TYPE_void) {
    1476           0 :                         *(oid *) ret = b->tseqbase;
    1477           0 :                         if (!is_oid_nil(b->tseqbase))
    1478           0 :                                 *(oid *) ret += pos;
    1479       87651 :                 } else if (_s == 4) {
    1480       87573 :                         *(int *) ret = ((int *) bi.base)[pos];
    1481             :                 } else if (_s == 1) {
    1482           3 :                         *(bte *) ret = ((bte *) bi.base)[pos];
    1483             :                 } else if (_s == 2) {
    1484           1 :                         *(sht *) ret = ((sht *) bi.base)[pos];
    1485             :                 } else if (_s == 8) {
    1486          74 :                         *(lng *) ret = ((lng *) bi.base)[pos];
    1487             : #ifdef HAVE_HGE
    1488             :                 } else if (_s == 16) {
    1489           0 :                         *(hge *) ret = ((hge *) bi.base)[pos];
    1490             : #endif
    1491             :                 } else {
    1492           0 :                         memcpy(ret, (const char *) bi.base + (pos << bi.shift), _s);
    1493             :                 }
    1494             :         }
    1495       87801 :         bat_iterator_end(&bi);
    1496       87801 :         return MAL_SUCCEED;
    1497             : }
    1498             : 
    1499             : static str
    1500       87803 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1501             : {
    1502       87803 :         BAT *b;
    1503       87803 :         str msg;
    1504             : 
    1505       87803 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1506           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1507             :         }
    1508       87803 :         if (*pos < (lng) 0) {
    1509           0 :                 BBPunfix(b->batCacheid);
    1510           0 :                 throw(MAL, "algebra.fetch",
    1511             :                           ILLEGAL_ARGUMENT ": row index to fetch must be non negative\n");
    1512             :         }
    1513       87803 :         if (BATcount(b) == 0) {
    1514           2 :                 BBPunfix(b->batCacheid);
    1515           2 :                 throw(MAL, "algebra.fetch",
    1516             :                           ILLEGAL_ARGUMENT
    1517             :                           ": cannot fetch a single row from an empty input\n");
    1518             :         }
    1519       87801 :         if (*pos >= (lng) BATcount(b)) {
    1520           0 :                 BBPunfix(b->batCacheid);
    1521           0 :                 throw(MAL, "algebra.fetch",
    1522             :                           ILLEGAL_ARGUMENT ": row index to fetch is out of range\n");
    1523             :         }
    1524       87801 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1525       87801 :         BBPunfix(b->batCacheid);
    1526       87801 :         return msg;
    1527             : }
    1528             : 
    1529             : str
    1530       87803 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1531             : {
    1532       87803 :         lng o = *pos;
    1533             : 
    1534       87803 :         return ALGfetch(ret, bid, &o);
    1535             : }
    1536             : 
    1537             : static str
    1538           0 : ALGexist(bit *ret, const bat *bid, const void *val)
    1539             : {
    1540           0 :         BAT *b;
    1541           0 :         BUN q;
    1542             : 
    1543           0 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1544           0 :                 throw(MAL, "algebra.exist", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1545             :         }
    1546           0 :         derefStr(b, val);
    1547           0 :         q = BUNfnd(b, val);
    1548           0 :         *ret = (q != BUN_NONE);
    1549           0 :         BBPunfix(b->batCacheid);
    1550           0 :         return MAL_SUCCEED;
    1551             : }
    1552             : 
    1553             : static str
    1554           9 : ALGfind(oid *ret, const bat *bid, ptr val)
    1555             : {
    1556           9 :         BAT *b;
    1557           9 :         BUN q;
    1558           9 :         str msg = MAL_SUCCEED;
    1559             : 
    1560           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1561           0 :                 throw(MAL, "algebra.find", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1562             :         }
    1563           9 :         derefStr(b, val);
    1564           9 :         q = BUNfnd(b, val);
    1565             : 
    1566           9 :         if (q == BUN_NONE) {
    1567           3 :                 *ret = oid_nil;
    1568             :         } else
    1569           6 :                 *ret = (oid) q;
    1570           9 :         BBPunfix(b->batCacheid);
    1571           9 :         return msg;
    1572             : }
    1573             : 
    1574             : 
    1575             : static str
    1576      147074 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1577             : {
    1578      147074 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1579      147074 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1580      147074 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1581      147074 :         BAT *b, *bn;
    1582             : 
    1583      147074 :         (void) cntxt;
    1584      147074 :         (void) mb;
    1585      147074 :         if (isaBatType(getArgType(mb, pci, 2)))
    1586           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1587      147074 :         if ((b = BBPquickdesc(bid)) == NULL)
    1588           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1589      147050 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1590      147077 :         if (bn == NULL) {
    1591           0 :                 *ret = bat_nil;
    1592           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1593             :         }
    1594      147077 :         *ret = bn->batCacheid;
    1595      147077 :         BBPkeepref(bn);
    1596      147077 :         return MAL_SUCCEED;
    1597             : }
    1598             : 
    1599             : 
    1600             : static str
    1601           0 : ALGreuse(bat *ret, const bat *bid)
    1602             : {
    1603           0 :         BAT *b, *bn;
    1604           0 :         if ((b = BATdescriptor(*bid)) == NULL)
    1605           0 :                 throw(MAL, "algebra.reuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1606             : 
    1607           0 :         if (!b->batTransient || b->batRestricted != BAT_WRITE) {
    1608           0 :                 if (ATOMvarsized(b->ttype)) {
    1609           0 :                         bn = BATwcopy(b);
    1610           0 :                         if (bn == NULL) {
    1611           0 :                                 BBPunfix(b->batCacheid);
    1612           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1613             :                         }
    1614             :                 } else {
    1615           0 :                         bn = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
    1616           0 :                         if (bn == NULL) {
    1617           0 :                                 BBPunfix(b->batCacheid);
    1618           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1619             :                         }
    1620           0 :                         BATsetcount(bn, BATcount(b));
    1621           0 :                         bn->tsorted = false;
    1622           0 :                         bn->trevsorted = false;
    1623           0 :                         BATkey(bn, false);
    1624             :                 }
    1625           0 :                 *ret = bn->batCacheid;
    1626           0 :                 BBPkeepref(bn);
    1627           0 :                 BBPunfix(b->batCacheid);
    1628             :         } else
    1629           0 :                 BBPkeepref(b);
    1630             :         return MAL_SUCCEED;
    1631             : }
    1632             : 
    1633             : /*
    1634             :  * BAT standard deviation
    1635             :  */
    1636             : static str
    1637           7 : ALGstdev(dbl *res, const bat *bid)
    1638             : {
    1639           7 :         BAT *b;
    1640           7 :         dbl stdev;
    1641             : 
    1642           7 :         if ((b = BATdescriptor(*bid)) == NULL)
    1643           0 :                 throw(MAL, "aggr.stdev", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1644           7 :         stdev = BATcalcstdev_sample(NULL, b);
    1645           7 :         BBPunfix(b->batCacheid);
    1646           7 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1647           0 :                 throw(MAL, "aggr.stdev", GDK_EXCEPTION);
    1648           7 :         *res = stdev;
    1649           7 :         return MAL_SUCCEED;
    1650             : }
    1651             : 
    1652             : static str
    1653          13 : ALGstdevp(dbl *res, const bat *bid)
    1654             : {
    1655          13 :         BAT *b;
    1656          13 :         dbl stdev;
    1657             : 
    1658          13 :         if ((b = BATdescriptor(*bid)) == NULL)
    1659           0 :                 throw(MAL, "aggr.stdevp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1660          13 :         stdev = BATcalcstdev_population(NULL, b);
    1661          13 :         BBPunfix(b->batCacheid);
    1662          13 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1663           1 :                 throw(MAL, "aggr.stdevp", GDK_EXCEPTION);
    1664          12 :         *res = stdev;
    1665          12 :         return MAL_SUCCEED;
    1666             : }
    1667             : 
    1668             : /*
    1669             :  * BAT variance
    1670             :  */
    1671             : static str
    1672           2 : ALGvariance(dbl *res, const bat *bid)
    1673             : {
    1674           2 :         BAT *b;
    1675           2 :         dbl variance;
    1676             : 
    1677           2 :         if ((b = BATdescriptor(*bid)) == NULL)
    1678           0 :                 throw(MAL, "aggr.variance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1679           2 :         variance = BATcalcvariance_sample(NULL, b);
    1680           2 :         BBPunfix(b->batCacheid);
    1681           2 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1682           0 :                 throw(MAL, "aggr.variance", GDK_EXCEPTION);
    1683           2 :         *res = variance;
    1684           2 :         return MAL_SUCCEED;
    1685             : }
    1686             : 
    1687             : static str
    1688           3 : ALGvariancep(dbl *res, const bat *bid)
    1689             : {
    1690           3 :         BAT *b;
    1691           3 :         dbl variance;
    1692             : 
    1693           3 :         if ((b = BATdescriptor(*bid)) == NULL)
    1694           0 :                 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1695           3 :         variance = BATcalcvariance_population(NULL, b);
    1696           3 :         BBPunfix(b->batCacheid);
    1697           3 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1698           1 :                 throw(MAL, "aggr.variancep", GDK_EXCEPTION);
    1699           2 :         *res = variance;
    1700           2 :         return MAL_SUCCEED;
    1701             : }
    1702             : 
    1703             : /*
    1704             :  * BAT covariance
    1705             :  */
    1706             : static str
    1707           4 : ALGcovariance(dbl *res, const bat *bid1, const bat *bid2)
    1708             : {
    1709           4 :         BAT *b1, *b2;
    1710           4 :         dbl covariance;
    1711             : 
    1712           4 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1713           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1714           5 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1715           0 :                 BBPunfix(b1->batCacheid);
    1716           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1717             :         }
    1718             : 
    1719           5 :         covariance = BATcalccovariance_sample(b1, b2);
    1720           5 :         BBPunfix(b1->batCacheid);
    1721           5 :         BBPunfix(b2->batCacheid);
    1722           5 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1723           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1724           5 :         *res = covariance;
    1725           5 :         return MAL_SUCCEED;
    1726             : }
    1727             : 
    1728             : static str
    1729           8 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1730             : {
    1731           8 :         BAT *b1, *b2;
    1732           8 :         dbl covariance;
    1733             : 
    1734           8 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1735           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1736           8 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1737           0 :                 BBPunfix(b1->batCacheid);
    1738           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1739             :         }
    1740             : 
    1741           8 :         covariance = BATcalccovariance_population(b1, b2);
    1742           8 :         BBPunfix(b1->batCacheid);
    1743           8 :         BBPunfix(b2->batCacheid);
    1744           8 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1745           1 :                 throw(MAL, "aggr.covariancep", GDK_EXCEPTION);
    1746           7 :         *res = covariance;
    1747           7 :         return MAL_SUCCEED;
    1748             : }
    1749             : 
    1750             : /*
    1751             :  * BAT correlation
    1752             :  */
    1753             : static str
    1754          19 : ALGcorr(dbl *res, const bat *bid1, const bat *bid2)
    1755             : {
    1756          19 :         BAT *b1, *b2;
    1757          19 :         dbl covariance;
    1758             : 
    1759          19 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1760           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1761          19 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1762           0 :                 BBPunfix(b1->batCacheid);
    1763           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1764             :         }
    1765             : 
    1766          19 :         covariance = BATcalccorrelation(b1, b2);
    1767          19 :         BBPunfix(b1->batCacheid);
    1768          19 :         BBPunfix(b2->batCacheid);
    1769          19 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1770           1 :                 throw(MAL, "aggr.corr", GDK_EXCEPTION);
    1771          18 :         *res = covariance;
    1772          18 :         return MAL_SUCCEED;
    1773             : }
    1774             : 
    1775             : #include "mel.h"
    1776             : mel_func algebra_init_funcs[] = {
    1777             :  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))),
    1778             :  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))),
    1779             :  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))),
    1780             :  pattern("algebra", "project", ALGprojecttail, false, "Fill the tail with a constant", args(1,3, batargany("",2),batargany("b",1),argany("v",2))),
    1781             :  command("algebra", "projection", ALGprojection, false, "Project left input onto right input.", args(1,3, batargany("",1),batarg("left",oid),batargany("right",1))),
    1782             :  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))),
    1783             :  command("algebra", "copy", ALGcopy, false, "Returns physical copy of a BAT.", args(1,2, batargany("",1),batargany("b",1))),
    1784             :  command("algebra", "exist", ALGexist, false, "Returns whether 'val' occurs in b.", args(1,3, arg("",bit),batargany("b",1),argany("val",1))),
    1785             :  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))),
    1786             :  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))),
    1787             :  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))),
    1788             :  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))),
    1789             :  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))),
    1790             :  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))),
    1791             :  command("algebra", "outerselect", ALGouterselect, false, "Per input lid return atleast 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))),
    1792             :  command("algebra", "selectNotNil", ALGselectNotNil, false, "Select all not-nil values", args(1,2, batargany("",1),batargany("b",1))),
    1793             :  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))),
    1794             :  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))),
    1795             :  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))),
    1796             :  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))),
    1797             :  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))),
    1798             :  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))),
    1799             :  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))),
    1800             :  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))),
    1801             :  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))),
    1802             :  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))),
    1803             :  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))),
    1804             :  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))),
    1805             :  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))),
    1806             :  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))),
    1807             :  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))),
    1808             :  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))),
    1809             :  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))),
    1810             :  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))),
    1811             :  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))),
    1812             :  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))),
    1813             :  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))),
    1814             :  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))),
    1815             :  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))),
    1816             :  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))),
    1817             :  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))),
    1818             :  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))),
    1819             :  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))),
    1820             :  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))),
    1821             :  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))),
    1822             :  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))),
    1823             :  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))),
    1824             :  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))),
    1825             :  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))),
    1826             :  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))),
    1827             :  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))),
    1828             :  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))),
    1829             :  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))),
    1830             :  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))),
    1831             :  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))),
    1832             :  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))),
    1833             :  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))),
    1834             :  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))),
    1835             :  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))),
    1836             :  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))),
    1837             :  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))),
    1838             :  command("aggr", "cardinality", ALGcard, false, "Return the cardinality of the BAT tail values.", args(1,2, arg("",lng),batargany("b",2))),
    1839             :  command("aggr", "min", ALGminany, false, "Return the lowest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1840             :  command("aggr", "min", ALGminany_skipnil, false, "Return the lowest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1841             :  command("aggr", "max", ALGmaxany, false, "Return the highest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1842             :  command("aggr", "max", ALGmaxany_skipnil, false, "Return the highest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1843             :  command("aggr", "stdev", ALGstdev, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1844             :  command("aggr", "stdevp", ALGstdevp, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1845             :  command("aggr", "variance", ALGvariance, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1846             :  command("aggr", "variancep", ALGvariancep, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1847             :  command("aggr", "covariance", ALGcovariance, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1848             :  command("aggr", "covariancep", ALGcovariancep, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1849             :  command("aggr", "corr", ALGcorr, false, "Gives the correlation of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1850             :  // sql
    1851             :  command("aggr", "exist", ALGexist, false, "", args(1,3, arg("",bit),batargany("b",2),argany("h",1))),
    1852             :  { .imp=NULL }
    1853             : };
    1854             : #include "mal_import.h"
    1855             : #ifdef _MSC_VER
    1856             : #undef read
    1857             : #pragma section(".CRT$XCU",read)
    1858             : #endif
    1859         334 : LIB_STARTUP_FUNC(init_algebra_mal)
    1860         334 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14