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-11-12 19:36:54 Functions: 67 82 81.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * (c) Peter Boncz, Martin Kersten, Niels Nes, Sjoerd Mullender
      15             :  * BAT Algebra
      16             :  * This modules contains the most common algebraic BAT manipulation
      17             :  * commands. We call them algebra, because all operations take
      18             :  * values as parameters, and produce new result values, but
      19             :  * do not modify their parameters.
      20             :  *
      21             :  * Unlike the previous Monet versions, we reduce the number
      22             :  * of functions returning a BAT reference. This was previously needed
      23             :  * to simplify recursive bat-expression and manage reference counts.
      24             :  * In the current version we return only a BAT identifier when a new
      25             :  * bat is being created.
      26             :  *
      27             :  * All parameters to the modules are passed by reference.
      28             :  * In particular, this means that
      29             :  * string values are passed to the module layer as (str *)
      30             :  * and we have to de-reference them before entering the gdk library.
      31             :  * This calls for knowledge on the underlying BAT typs`s
      32             :  */
      33             : #define derefStr(b, v)                                                  \
      34             :         do {                                                                            \
      35             :                 int _tpe= ATOMstorage((b)->ttype);           \
      36             :                 if (_tpe >= TYPE_str) {                                      \
      37             :                         if ((v) == 0 || *(str*) (v) == 0)       \
      38             :                                 (v) = (str) str_nil;                    \
      39             :                         else                                                            \
      40             :                                 (v) = *(str *) (v);                             \
      41             :                 }                                                                               \
      42             :         } while (0)
      43             : 
      44             : #include "monetdb_config.h"
      45             : #include "algebra.h"
      46             : 
      47             : /*
      48             :  * Command Implementations in C
      49             :  * This module contains just a wrapper implementations; since all described
      50             :  * operations are part of the GDK kernel.
      51             :  *
      52             :  * BAT sum operation
      53             :  * The sum aggregate only works for int and float fields.
      54             :  * The routines below assumes that the caller knows what type
      55             :  * is large enough to prevent overflow.
      56             :  */
      57             : 
      58             : static gdk_return
      59        2388 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts)
      60             : {
      61        2388 :         BUN j;
      62        2388 :         BATiter gi = bat_iterator(gids);
      63        2388 :         BAT *r = COLnew(0, TYPE_oid, gi.count * 2, TRANSIENT);
      64             : 
      65        2388 :         if (r == NULL) {
      66           0 :                 bat_iterator_end(&gi);
      67           0 :                 return GDK_FAIL;
      68             :         }
      69        2388 :         BATiter ci = bat_iterator(cnts);
      70        2388 :         if (gi.type == TYPE_void) {
      71        1049 :                 oid id = gi.tseq;
      72        1049 :                 lng *cnt = (lng *) ci.base;
      73       96195 :                 for (j = 0; j < gi.count; j++) {
      74       95146 :                         lng i, sz = cnt[j];
      75      190236 :                         for (i = 0; i < sz; i++) {
      76       95090 :                                 if (BUNappend(r, &id, false) != GDK_SUCCEED) {
      77           0 :                                         BBPreclaim(r);
      78           0 :                                         bat_iterator_end(&ci);
      79           0 :                                         bat_iterator_end(&gi);
      80           0 :                                         return GDK_FAIL;
      81             :                                 }
      82             :                         }
      83       95146 :                         id ++;
      84             :                 }
      85             :         } else {
      86        1339 :                 oid *id = (oid *) gi.base;
      87        1339 :                 lng *cnt = (lng *) ci.base;
      88      140494 :                 for (j = 0; j < gi.count; j++) {
      89      139155 :                         lng i, sz = cnt[j];
      90      274814 :                         for (i = 0; i < sz; i++) {
      91      135659 :                                 if (BUNappend(r, id, false) != GDK_SUCCEED) {
      92           0 :                                         BBPreclaim(r);
      93           0 :                                         bat_iterator_end(&ci);
      94           0 :                                         bat_iterator_end(&gi);
      95           0 :                                         return GDK_FAIL;
      96             :                                 }
      97             :                         }
      98      139155 :                         id ++;
      99             :                 }
     100             :         }
     101        2388 :         bat_iterator_end(&ci);
     102        2388 :         r->tkey = false;
     103        2388 :         r->tseqbase = oid_nil;
     104        2388 :         r->tsorted = gi.sorted;
     105        2388 :         r->trevsorted = gi.revsorted;
     106        2388 :         r->tnonil = gi.nonil;
     107        2388 :         bat_iterator_end(&gi);
     108        2388 :         *result = r;
     109        2388 :         return GDK_SUCCEED;
     110             : }
     111             : 
     112             : 
     113             : static gdk_return
     114           6 : slice(BAT **retval, BAT *b, lng start, lng end)
     115             : {
     116             :         /* the internal BATslice requires exclusive end */
     117           6 :         if (start < 0) {
     118           0 :                 GDKerror("start position of slice should >= 0\n");
     119           0 :                 return GDK_FAIL;
     120             :         }
     121           6 :         if (is_lng_nil(end))
     122           3 :                 end = BATcount(b);
     123             : 
     124           6 :         return (*retval = BATslice(b, (BUN) start, (BUN) end + 1)) ? GDK_SUCCEED : GDK_FAIL;
     125             : }
     126             : 
     127             : /*
     128             :  *
     129             :  * The remainder of this file contains the wrapper around the V4 code base
     130             :  * The BAT identifiers passed through this module may indicate
     131             :  * that the 'reverse' view applies. This should be taken into
     132             :  * account while resolving them.
     133             :  *
     134             :  * The sum aggregate only works for int and float fields.
     135             :  * The routines below assumes that the caller knows what type
     136             :  * is large enough to prevent overflow.
     137             :  */
     138             : 
     139             : static str
     140         770 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     141             : {
     142         770 :         BAT *b;
     143         770 :         ptr p;
     144         770 :         str msg = MAL_SUCCEED;
     145             : 
     146         770 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     147           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     148             : 
     149         771 :         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         771 :                 if (ATOMextern(b->ttype)) {
     155          42 :                         *(ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     156             :                 } else {
     157         729 :                         p = BATmin_skipnil(b, result, *skipnil);
     158         731 :                         if (p != result)
     159           0 :                                 msg = createException(MAL, "algebra.min",
     160             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     161             :                 }
     162         773 :                 if (msg == MAL_SUCCEED && p == NULL)
     163           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     164             :         }
     165         773 :         BBPunfix(b->batCacheid);
     166         773 :         return msg;
     167             : }
     168             : 
     169             : static str
     170         770 : ALGminany(ptr result, const bat *bid)
     171             : {
     172         770 :         bit skipnil = TRUE;
     173         770 :         return ALGminany_skipnil(result, bid, &skipnil);
     174             : }
     175             : 
     176             : static str
     177         541 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     178             : {
     179         541 :         BAT *b;
     180         541 :         ptr p;
     181         541 :         str msg = MAL_SUCCEED;
     182             : 
     183         541 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     184           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     185             : 
     186         541 :         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         541 :                 if (ATOMextern(b->ttype)) {
     192          68 :                         *(ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     193             :                 } else {
     194         473 :                         p = BATmax_skipnil(b, result, *skipnil);
     195         476 :                         if (p != result)
     196           0 :                                 msg = createException(MAL, "algebra.max",
     197             :                                                                           SQLSTATE(HY002) "INTERNAL ERROR");
     198             :                 }
     199         544 :                 if (msg == MAL_SUCCEED && p == NULL)
     200           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     201             :         }
     202         544 :         BBPunfix(b->batCacheid);
     203         544 :         return msg;
     204             : }
     205             : 
     206             : static str
     207         540 : ALGmaxany(ptr result, const bat *bid)
     208             : {
     209         540 :         bit skipnil = TRUE;
     210         540 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     211             : }
     212             : 
     213             : static str
     214        2388 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     215             : {
     216        2388 :         BAT *bn, *g, *c;
     217             : 
     218        2388 :         g = BATdescriptor(*gids);
     219        2388 :         if (g == NULL) {
     220           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     221             :         }
     222        2388 :         c = BATdescriptor(*cnts);
     223        2388 :         if (c == NULL) {
     224           0 :                 BBPunfix(g->batCacheid);
     225           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     226             :         }
     227        2388 :         if (CMDgen_group(&bn, g, c) != GDK_SUCCEED) {
     228           0 :                 BBPunfix(g->batCacheid);
     229           0 :                 BBPunfix(c->batCacheid);
     230           0 :                 throw(MAL, "algebra.groupby", GDK_EXCEPTION);
     231             :         }
     232        2388 :         *res = bn->batCacheid;
     233        2388 :         BBPkeepref(bn);
     234        2388 :         BBPunfix(g->batCacheid);
     235        2388 :         BBPunfix(c->batCacheid);
     236        2388 :         return MAL_SUCCEED;
     237             : }
     238             : 
     239             : static str
     240           1 : ALGcard(lng *result, const bat *bid)
     241             : {
     242           1 :         BAT *b, *en;
     243             : 
     244           1 :         if ((b = BATdescriptor(*bid)) == NULL) {
     245           0 :                 throw(MAL, "algebra.card", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     246             :         }
     247           1 :         en = BATunique(b, NULL);
     248           1 :         BBPunfix(b->batCacheid);
     249           1 :         if (en == NULL) {
     250           0 :                 throw(MAL, "algebra.card", GDK_EXCEPTION);
     251             :         }
     252           1 :         struct canditer ci;
     253           1 :         canditer_init(&ci, NULL, en);
     254           1 :         *result = (lng) ci.ncand;
     255           1 :         BBPunfix(en->batCacheid);
     256           1 :         return MAL_SUCCEED;
     257             : }
     258             : 
     259             : static str
     260      154286 : 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      154286 :         BAT *b, *s = NULL, *bn;
     264      154286 :         const void *nilptr;
     265             : 
     266      154286 :         if ((*li != 0 && *li != 1) ||
     267      154286 :                 (*hi != 0 && *hi != 1) || (*anti != 0 && *anti != 1)) {
     268           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     269             :         }
     270      154400 :         if ((b = BATdescriptor(*bid)) == NULL) {
     271           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     272             :         }
     273      155079 :         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      155091 :         derefStr(b, low);
     278      155091 :         derefStr(b, high);
     279      155091 :         nilptr = ATOMnilptr(b->ttype);
     280      309572 :         if (*li == 1 && *hi == 1 && nilptr != NULL &&
     281      182399 :                 ATOMcmp(b->ttype, low, nilptr) == 0 &&
     282       27593 :                 ATOMcmp(b->ttype, high, nilptr) == 0) {
     283             :                 /* special case: equi-select for NIL */
     284      154766 :                 high = NULL;
     285             :         }
     286      154766 :         bn = BATselect(b, s, low, high, *li, *hi, *anti);
     287      154129 :         BBPunfix(b->batCacheid);
     288      154876 :         BBPreclaim(s);
     289      154944 :         if (bn == NULL)
     290           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     291      154944 :         *result = bn->batCacheid;
     292      154944 :         BBPkeepref(bn);
     293      154944 :         return MAL_SUCCEED;
     294             : }
     295             : 
     296             : static str
     297        7363 : 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        7363 :         BAT *b, *s = NULL, *bn;
     302        7363 :         bit nanti = *anti, nli = *li, nhi = *hi;
     303             : 
     304        7363 :         if (!*unknown)
     305           0 :                 return ALGselect2(result, bid, sid, low, high, li, hi, anti);
     306             : 
     307        7363 :         if ((nli != 0 && nli != 1) ||
     308        7363 :                 (nhi != 0 && nhi != 1) || (nanti != 0 && nanti != 1)) {
     309           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     310             :         }
     311        7365 :         if ((b = BATdescriptor(*bid)) == NULL) {
     312           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     313             :         }
     314        7384 :         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        7386 :         derefStr(b, low);
     319        7386 :         derefStr(b, high);
     320             :         /* here we don't need open ended parts with nil */
     321        7386 :         if (!nanti) {
     322        1377 :                 const void *nilptr = ATOMnilptr(b->ttype);
     323        1377 :                 if (nilptr) {
     324        1377 :                         if (nli == 1 && ATOMcmp(b->ttype, low, nilptr) == 0) {
     325          22 :                                 low = high;
     326          22 :                                 nli = 0;
     327             :                         }
     328        1374 :                         if (nhi == 1 && ATOMcmp(b->ttype, high, nilptr) == 0) {
     329          24 :                                 high = low;
     330          24 :                                 nhi = 0;
     331             :                         }
     332        1377 :                         if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0)    /* ugh sql nil != nil */
     333        7387 :                                 nanti = 1;
     334             :                 }
     335             :         }
     336             : 
     337        7387 :         bn = BATselect(b, s, low, high, nli, nhi, nanti);
     338        7376 :         BBPunfix(b->batCacheid);
     339        7383 :         BBPreclaim(s);
     340        7383 :         if (bn == NULL)
     341           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     342        7383 :         *result = bn->batCacheid;
     343        7383 :         BBPkeepref(bn);
     344        7383 :         return MAL_SUCCEED;
     345             : }
     346             : 
     347             : static str
     348      103078 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high,
     349             :                    const bit *li, const bit *hi, const bit *anti)
     350             : {
     351      103078 :         return ALGselect2(result, bid, NULL, low, high, li, hi, anti);
     352             : }
     353             : 
     354             : static str
     355         312 : 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         312 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     359             : }
     360             : 
     361             : static str
     362      490610 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val,
     363             :                                 const char **op)
     364             : {
     365      490610 :         BAT *b, *s = NULL, *bn;
     366             : 
     367      490610 :         if ((b = BATdescriptor(*bid)) == NULL) {
     368           0 :                 throw(MAL, "algebra.thetaselect",
     369             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     370             :         }
     371      492817 :         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      493024 :         derefStr(b, val);
     377      493024 :         bn = BATthetaselect(b, s, val, *op);
     378      490564 :         BBPunfix(b->batCacheid);
     379      492601 :         BBPreclaim(s);
     380      492636 :         if (bn == NULL)
     381           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     382      492636 :         *result = bn->batCacheid;
     383      492636 :         BBPkeepref(bn);
     384      492636 :         return MAL_SUCCEED;
     385             : }
     386             : 
     387             : static str
     388         396 : ALGmarkselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     389             : {
     390         396 :         BAT *g = BATdescriptor(*gid); /* oid */
     391         396 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     392         396 :         BAT *p = BATdescriptor(*pid); /* bit */
     393         396 :         BAT *res1 = NULL, *res2 = NULL;
     394         396 :         bit any = *Any; /* any or normal comparison semantics */
     395             : 
     396         396 :         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         396 :         BUN nr = BATcount(g), q = 0;
     403             : 
     404         396 :         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         396 :         assert(g->tsorted);
     412         396 :         oid *ri1 = Tloc(res1, 0);
     413         396 :         bit *ri2 = Tloc(res2, 0);
     414         396 :         bit *mi = Tloc(m, 0);
     415         396 :         bit *pi = Tloc(p, 0);
     416         396 :         oid cur = oid_nil;
     417             : 
     418         396 :         if (g->ttype == TYPE_void) { /* void case ? */
     419          31 :                 oid c = g->hseqbase;
     420         127 :                 for (BUN n = 0; n < nr; n++, c++) {
     421          96 :                         ri1[q] = c;
     422          96 :                         ri2[q] = FALSE;
     423          96 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     424           7 :                                 ri2[q] = TRUE;
     425          89 :                         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          96 :                         q++;
     428             :                 }
     429             :         } else {
     430         365 :                 oid *gi = Tloc(g, 0);
     431         365 :                 oid c = g->hseqbase;
     432         365 :                 if (nr)
     433         365 :                         cur = gi[0];
     434             :                 bit m = FALSE;
     435             :                 bool has_nil = false;
     436      332661 :                 for (BUN n = 0; n < nr; n++, c++) {
     437      332296 :                         if (c && cur != gi[n]) {
     438       57735 :                                 ri1[q] = c-1;
     439       57735 :                                 ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     440       57735 :                                 q++;
     441       57735 :                                 cur = gi[n];
     442       57735 :                                 m = FALSE;
     443       57735 :                                 has_nil = false;
     444             :                         }
     445      332296 :                         if (m == TRUE)
     446      191843 :                                 continue;
     447             : 
     448      140453 :                         if (pi[n] == TRUE && mi[n] == TRUE)
     449             :                                 m = TRUE;
     450      133526 :                         else if ((mi[n] == bit_nil && pi[n] != bit_nil && !any) || (mi[n] != FALSE && pi[n] == bit_nil && any))
     451      332296 :                                 has_nil = true;
     452             :                 }
     453         365 :                 if (nr) {
     454         365 :                         ri1[q] = c-1;
     455         365 :                         ri2[q] = (m == TRUE)?TRUE:(has_nil)?bit_nil:FALSE;
     456             :                 }
     457         365 :                 q++;
     458             :         }
     459         396 :         BATsetcount(res1, q);
     460         396 :         BATsetcount(res2, q);
     461         396 :         res1->tsorted = true;
     462         396 :         res1->tkey = true;
     463         396 :         res1->trevsorted = false;
     464         396 :         res2->tsorted = false;
     465         396 :         res2->trevsorted = false;
     466         396 :         res1->tnil = false;
     467         396 :         res1->tnonil = true;
     468         396 :         res2->tnonil = false;
     469         396 :         res2->tkey = false;
     470             : 
     471         396 :         BBPreclaim(g);
     472         396 :         BBPreclaim(m);
     473         396 :         BBPreclaim(p);
     474             : 
     475         396 :         BBPkeepref(res1);
     476         396 :         BBPkeepref(res2);
     477         396 :         *r1 = res1->batCacheid;
     478         396 :         *r2 = res2->batCacheid;
     479         396 :         return MAL_SUCCEED;
     480             : }
     481             : 
     482             : static str
     483          38 : ALGouterselect(bat *r1, bat *r2, const bat *gid, const bat *mid, const bat *pid, const bit *Any)
     484             : {
     485          38 :         BAT *g = BATdescriptor(*gid); /* oid */
     486          38 :         BAT *m = BATdescriptor(*mid); /* bit, true: match, false: empty set, nil: nil on left */
     487          38 :         BAT *p = BATdescriptor(*pid); /* bit */
     488          38 :         BAT *res1 = NULL, *res2 = NULL;
     489          38 :         bit any = *Any; /* any or normal comparison semantics */
     490             : 
     491          38 :         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          38 :         BUN nr = BATcount(g), q = 0;
     498             : 
     499          38 :         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          38 :         assert(g->tsorted);
     507          38 :         oid *ri1 = Tloc(res1, 0);
     508          38 :         bit *ri2 = Tloc(res2, 0);
     509          38 :         bit *mi = Tloc(m, 0);
     510          38 :         bit *pi = Tloc(p, 0);
     511          38 :         oid cur = oid_nil;
     512             : 
     513          38 :         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          26 :                 oid *gi = Tloc(g, 0);
     522          26 :                 oid c = g->hseqbase;
     523          26 :                 if (nr)
     524          26 :                         cur = gi[0];
     525             :                 bool used = false;
     526         602 :                 for (BUN n = 0; n < nr; n++, c++) {
     527         576 :                         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         576 :                         if (mi[n] == TRUE && pi[n] == TRUE) {
     537         322 :                                 ri1[q] = c;
     538         322 :                                 ri2[q] = TRUE;
     539         322 :                                 used = true;
     540         322 :                                 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          26 :                 if (nr && !used) {
     554           1 :                         ri1[q] = c-1;
     555           1 :                         ri2[q] = FALSE;
     556           1 :                         q++;
     557             :                 }
     558             :         }
     559          38 :         BATsetcount(res1, q);
     560          38 :         BATsetcount(res2, q);
     561          38 :         res1->tsorted = true;
     562          38 :         res1->tkey = true;
     563          38 :         res1->trevsorted = false;
     564          38 :         res2->tsorted = false;
     565          38 :         res2->trevsorted = false;
     566          38 :         res1->tnil = false;
     567          38 :         res1->tnonil = true;
     568          38 :         res2->tnonil = false;
     569          38 :         res2->tkey = false;
     570             : 
     571          38 :         BBPreclaim(g);
     572          38 :         BBPreclaim(m);
     573          38 :         BBPreclaim(p);
     574             : 
     575          38 :         BBPkeepref(res1);
     576          38 :         BBPkeepref(res2);
     577          38 :         *r1 = res1->batCacheid;
     578          38 :         *r2 = res2->batCacheid;
     579          38 :         return MAL_SUCCEED;
     580             : }
     581             : 
     582             : 
     583             : static str
     584        1587 : ALGselectNotNil(bat *result, const bat *bid)
     585             : {
     586        1587 :         BAT *b;
     587             : 
     588        1587 :         if ((b = BATdescriptor(*bid)) == NULL)
     589           0 :                 throw(MAL, "algebra.selectNotNil",
     590             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     591             : 
     592        1587 :         MT_lock_set(&b->theaplock);
     593        1587 :         bool bnonil = b->tnonil || b->ttype == TYPE_msk;
     594        1587 :         MT_lock_unset(&b->theaplock);
     595        1587 :         if (!bnonil) {
     596         123 :                 BAT *s;
     597         123 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true);
     598         120 :                 if (s) {
     599         120 :                         BAT *bn = BATproject(s, b);
     600         121 :                         BBPunfix(s->batCacheid);
     601         123 :                         if (bn) {
     602         123 :                                 BBPunfix(b->batCacheid);
     603         123 :                                 *result = bn->batCacheid;
     604         123 :                                 BBPkeepref(bn);
     605         123 :                                 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        1464 :         *result = b->batCacheid;
     613        1464 :         BBPkeepref(b);
     614        1464 :         return MAL_SUCCEED;
     615             : }
     616             : 
     617             : static str
     618      642466 : 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      642466 :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     638      642466 :         BAT *candleft = NULL, *candright = NULL;
     639      642466 :         BAT *result1 = NULL, *result2 = NULL, *result3 = NULL;
     640      642466 :         BUN est;
     641      642466 :         const char *err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     642             : 
     643      642466 :         assert(r2id == NULL || rangefunc != NULL);
     644             : 
     645      642466 :         if ((left = BATdescriptor(*lid)) == NULL)
     646           0 :                 goto fail;
     647      648791 :         if ((right = BATdescriptor(*rid)) == NULL)
     648           0 :                 goto fail;
     649      648802 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     650           0 :                 goto fail;
     651      648806 :         if (srid && !is_bat_nil(*srid)
     652           0 :                 && (candright = BATdescriptor(*srid)) == NULL)
     653           0 :                 goto fail;
     654      648806 :         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      648806 :         err = NULL;                                     /* most likely error now is GDK_EXCEPTION */
     661             : 
     662      648806 :         if (thetafunc) {
     663       51329 :                 assert(joinfunc == NULL);
     664       51329 :                 assert(semifunc == NULL);
     665       51329 :                 assert(markfunc == NULL);
     666       51329 :                 assert(bandfunc == NULL);
     667       51329 :                 assert(rangefunc == NULL);
     668       51329 :                 assert(difffunc == NULL);
     669       51329 :                 assert(interfunc == NULL);
     670       51329 :                 if ((*thetafunc)
     671             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     672       51329 :                          op, *nil_matches, est) != GDK_SUCCEED)
     673           0 :                         goto fail;
     674      597477 :         } else if (joinfunc) {
     675      409101 :                 assert(semifunc == NULL);
     676      409101 :                 assert(markfunc == NULL);
     677      409101 :                 assert(bandfunc == NULL);
     678      409101 :                 assert(rangefunc == NULL);
     679      409101 :                 assert(difffunc == NULL);
     680      409101 :                 assert(interfunc == NULL);
     681      409101 :                 if ((*joinfunc)
     682             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     683      409101 :                          *nil_matches, est) != GDK_SUCCEED)
     684           1 :                         goto fail;
     685      188376 :         } else if (semifunc) {
     686         332 :                 assert(markfunc == NULL);
     687         332 :                 assert(bandfunc == NULL);
     688         332 :                 assert(rangefunc == NULL);
     689         332 :                 assert(difffunc == NULL);
     690         332 :                 assert(interfunc == NULL);
     691         332 :                 if ((*semifunc)
     692             :                         (&result1, r2 ? &result2 : NULL, left, right, candleft, candright,
     693         332 :                          *nil_matches, *max_one, est) != GDK_SUCCEED)
     694          42 :                         goto fail;
     695      188044 :         } else if (markfunc) {
     696       19118 :                 assert(bandfunc == NULL);
     697       19118 :                 assert(rangefunc == NULL);
     698       19118 :                 assert(difffunc == NULL);
     699       19118 :                 assert(interfunc == NULL);
     700       38231 :                 if ((*markfunc) (&result1, r2 ? &result2 : NULL, &result3,
     701             :                                                  left, right, candleft, candright, est) != GDK_SUCCEED)
     702           0 :                         goto fail;
     703      168926 :         } 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      168926 :         } else if (rangefunc) {
     712         151 :                 assert(difffunc == NULL);
     713         151 :                 assert(interfunc == NULL);
     714         151 :                 if ((right2 = BATdescriptor(*r2id)) == NULL) {
     715           0 :                         err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     716           0 :                         goto fail;
     717             :                 }
     718         176 :                 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         148 :                 BBPunfix(right2->batCacheid);
     723      168775 :         } else if (difffunc) {
     724      159510 :                 assert(r2 == NULL);
     725      159510 :                 assert(interfunc == NULL);
     726      159369 :                 if ((result1 = (*difffunc) (left, right, candleft, candright,
     727      159510 :                                                                         *nil_matches, *not_in, est)) == NULL)
     728           0 :                         goto fail;
     729             :         } else {
     730        9265 :                 assert(r2 == NULL);
     731        9244 :                 if ((result1 = (*interfunc) (left, right, candleft, candright,
     732        9265 :                                                                          *nil_matches, *max_one, est)) == NULL)
     733           1 :                         goto fail;
     734             :         }
     735      644686 :         *r1 = result1->batCacheid;
     736      644686 :         BBPkeepref(result1);
     737      646924 :         if (r2) {
     738      374076 :                 *r2 = result2->batCacheid;
     739      374076 :                 BBPkeepref(result2);
     740             :         }
     741      647526 :         if (r3) {
     742       19046 :                 *r3 = result3->batCacheid;
     743       19046 :                 BBPkeepref(result3);
     744             :         }
     745      647559 :         BBPunfix(left->batCacheid);
     746      648176 :         BBPunfix(right->batCacheid);
     747      648579 :         BBPreclaim(candleft);
     748      648613 :         BBPreclaim(candright);
     749             :         return MAL_SUCCEED;
     750             : 
     751          44 :   fail:
     752          44 :         BBPreclaim(left);
     753          44 :         BBPreclaim(right);
     754          44 :         BBPreclaim(right2);
     755          44 :         BBPreclaim(candleft);
     756          44 :         BBPreclaim(candright);
     757          44 :         if (err == NULL)
     758          44 :                 throw(MAL, funcname, GDK_EXCEPTION);
     759           0 :         throw(MAL, funcname, "%s", err);
     760             : }
     761             : 
     762             : static str
     763      363300 : 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      363300 :         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       42192 : 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       42192 :         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         122 : 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         122 :         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         209 : 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         209 :         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       19059 : ALGmark2join(bat *r1, bat *r3, const bat *lid, const bat *rid,
     837             :                          const bat *slid, const bat *srid, const lng *estimate)
     838             : {
     839       19059 :         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        7711 : 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        7711 :         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       41416 : 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       41416 :         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         122 : 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         248 :         return do_join(r1, r2, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     905         122 :                                    *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      159450 : 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      159450 :         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        9266 : 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        9266 :         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        1614 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     954             : {
     955        1614 :         bat *ret1, *ret2 = NULL;
     956        1614 :         bat bid, sid, gid;
     957        1614 :         BAT *b, *s = NULL, *g = NULL;
     958        1614 :         BAT *bn = NULL, *gn = NULL;
     959        1614 :         lng n;
     960        1614 :         bit asc, nilslast, distinct;
     961        1614 :         gdk_return rc;
     962             : 
     963        1614 :         (void) cntxt;
     964        1614 :         (void) mb;
     965             : 
     966        1614 :         assert(pci->retc == 1 || pci->retc == 2);
     967        1614 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     968             : 
     969        1614 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     970        1614 :         if (n < 0)
     971           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     972        1614 :         if (n > (lng) BUN_MAX)
     973             :                 n = BUN_MAX;
     974        1614 :         ret1 = getArgReference_bat(stk, pci, 0);
     975        1614 :         if (pci->retc == 2)
     976         527 :                 ret2 = getArgReference_bat(stk, pci, 1);
     977        1614 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     978        1614 :         if ((b = BATdescriptor(bid)) == NULL)
     979           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     980        1614 :         if (pci->argc - pci->retc > 5) {
     981        1614 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     982        1614 :                 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        1615 :                 if (pci->argc - pci->retc > 6) {
     988        1615 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     989        1615 :                         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        1615 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     998        1615 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     999        1615 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
    1000        2702 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast,
    1001             :                                    distinct);
    1002        1611 :         BBPunfix(b->batCacheid);
    1003        1616 :         BBPreclaim(s);
    1004        1615 :         BBPreclaim(g);
    1005        1616 :         if (rc != GDK_SUCCEED)
    1006           0 :                 throw(MAL, "algebra.firstn", GDK_EXCEPTION);
    1007        1616 :         *ret1 = bn->batCacheid;
    1008        1616 :         BBPkeepref(bn);
    1009        1616 :         if (ret2) {
    1010         527 :                 *ret2 = gn->batCacheid;
    1011         527 :                 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          72 : ALGunique(bat *result, const bat *bid, const bat *sid)
    1047             : {
    1048          72 :         BAT *b, *s = NULL, *bn = NULL;
    1049             : 
    1050          72 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1051           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1052             :         }
    1053          74 :         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          74 :         bn = BATunique(b, s);
    1058          73 :         BBPunfix(b->batCacheid);
    1059          73 :         BBPreclaim(s);
    1060          73 :         if (bn == NULL)
    1061           0 :                 throw(MAL, "algebra.unique", GDK_EXCEPTION);
    1062          73 :         *result = bn->batCacheid;
    1063          73 :         BBPkeepref(bn);
    1064          73 :         return MAL_SUCCEED;
    1065             : }
    1066             : 
    1067             : static str
    1068       44787 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right,
    1069             :                                 const bat *slid, const bat *srid, const bit *max_one)
    1070             : {
    1071       44787 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1072       44787 :         BAT *sl = NULL, *sr = NULL;
    1073       44787 :         gdk_return ret;
    1074             : 
    1075       44787 :         L = BATdescriptor(*left);
    1076       46170 :         R = BATdescriptor(*right);
    1077       46241 :         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       46241 :         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       47992 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1093       46241 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1094       45747 :         BBPunfix(L->batCacheid);
    1095       46130 :         BBPunfix(R->batCacheid);
    1096       46239 :         BBPreclaim(sl);
    1097       46239 :         BBPreclaim(sr);
    1098       46243 :         if (ret != GDK_SUCCEED)
    1099          86 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1100       46157 :         *l = bn1->batCacheid;
    1101       46157 :         BBPkeepref(bn1);
    1102       46097 :         if (r) {
    1103       44362 :                 *r = bn2->batCacheid;
    1104       44362 :                 BBPkeepref(bn2);
    1105             :         }
    1106             :         return MAL_SUCCEED;
    1107             : }
    1108             : 
    1109             : static str
    1110        1703 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
    1111             : {
    1112        1703 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
    1113             : }
    1114             : 
    1115             : static str
    1116       43144 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right,
    1117             :                                  const bit *max_one)
    1118             : {
    1119       43144 :         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         425 : ALGoutercrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
    1138             : {
    1139         425 :         BAT *L, *R, *bn1, *bn2 = NULL;
    1140         425 :         BAT *sl = NULL, *sr = NULL;
    1141         425 :         gdk_return ret;
    1142             : 
    1143         425 :         L = BATdescriptor(*left);
    1144         425 :         R = BATdescriptor(*right);
    1145         425 :         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         425 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
    1151         425 :                 (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         425 :         ret = BAToutercross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
    1159         425 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
    1160         425 :         BBPunfix(L->batCacheid);
    1161         425 :         BBPunfix(R->batCacheid);
    1162         425 :         BBPreclaim(sl);
    1163         425 :         BBPreclaim(sr);
    1164         425 :         if (ret != GDK_SUCCEED)
    1165           0 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
    1166         425 :         *l = bn1->batCacheid;
    1167         425 :         BBPkeepref(bn1);
    1168         425 :         if (r) {
    1169         425 :                 *r = bn2->batCacheid;
    1170         425 :                 BBPkeepref(bn2);
    1171             :         }
    1172             :         return MAL_SUCCEED;
    1173             : }
    1174             : 
    1175             : static str
    1176     1972559 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
    1177             : {
    1178     1972559 :         BAT *l, *r1, *r2 = NULL, *bn;
    1179             : 
    1180     1972559 :         if ((l = BATdescriptor(*lid)) == NULL) {
    1181           0 :                 throw(MAL, "algebra.projection",
    1182             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1183             :         }
    1184     1984206 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
    1185           0 :                 BBPunfix(l->batCacheid);
    1186           0 :                 throw(MAL, "algebra.projection",
    1187             :                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1188             :         }
    1189     1983215 :         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     1983215 :         bn = BATproject2(l, r1, r2);
    1196     1959091 :         BBPunfix(l->batCacheid);
    1197     1979937 :         BBPunfix(r1->batCacheid);
    1198     1982983 :         BBPreclaim(r2);
    1199     1983154 :         if (bn == NULL)
    1200           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
    1201     1983154 :         *result = bn->batCacheid;
    1202     1983154 :         BBPkeepref(bn);
    1203     1983154 :         return MAL_SUCCEED;
    1204             : }
    1205             : 
    1206             : str
    1207     1974851 : ALGprojection(bat *result, const bat *lid, const bat *rid)
    1208             : {
    1209     1974851 :         return ALGprojection2(result, lid, rid, NULL);
    1210             : }
    1211             : 
    1212             : static str
    1213       24063 : 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       24063 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
    1218       24063 :         BAT *b = NULL, *o = NULL, *g = NULL;
    1219             : 
    1220       24063 :         if ((b = BATdescriptor(*bid)) == NULL)
    1221           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1222       24065 :         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       24065 :         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       27666 :         if (BATsort(result ? &bn : NULL,
    1232             :                                 norder ? &on : NULL,
    1233             :                                 ngroup ? &gn : NULL,
    1234       24065 :                                 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       24065 :         BBPunfix(b->batCacheid);
    1241       24065 :         BBPreclaim(o);
    1242       24065 :         BBPreclaim(g);
    1243       24065 :         if (result) {
    1244       24065 :                 *result = bn->batCacheid;
    1245       24065 :                 BBPkeepref(bn);
    1246             :         }
    1247       24065 :         if (norder) {
    1248       20464 :                 *norder = on->batCacheid;
    1249       20464 :                 BBPkeepref(on);
    1250             :         }
    1251       24065 :         if (ngroup) {
    1252       13608 :                 *ngroup = gn->batCacheid;
    1253       13608 :                 BBPkeepref(gn);
    1254             :         }
    1255             :         return MAL_SUCCEED;
    1256             : }
    1257             : 
    1258             : static str
    1259        4118 : 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        4118 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast,
    1264             :                                          stable);
    1265             : }
    1266             : 
    1267             : static str
    1268        1959 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group,
    1269             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1270             : {
    1271        1959 :         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        6332 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid,
    1302             :                   const bit *reverse, const bit *nilslast, const bit *stable)
    1303             : {
    1304        6332 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast,
    1305             :                                          stable);
    1306             : }
    1307             : 
    1308             : static str
    1309        2738 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse,
    1310             :                   const bit *nilslast, const bit *stable)
    1311             : {
    1312        2738 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast,
    1313             :                                          stable);
    1314             : }
    1315             : 
    1316             : static str
    1317        1642 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast,
    1318             :                   const bit *stable)
    1319             : {
    1320        1642 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast,
    1321             :                                          stable);
    1322             : }
    1323             : 
    1324             : static str
    1325       70116 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd,
    1326             :                                 const bit *ignore_nils)
    1327             : {
    1328       70116 :         BAT *b, *s = NULL;
    1329             : 
    1330       70116 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1331           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1332             :         }
    1333       70359 :         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       70359 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
    1338          30 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false);
    1339       70329 :         } else if (*ignore_nils) {
    1340        1787 :                 *result = (lng) BATcount_no_nil(b, s);
    1341             :         } else {
    1342       68542 :                 struct canditer ci;
    1343       68542 :                 canditer_init(&ci, b, s);
    1344       68583 :                 *result = (lng) ci.ncand;
    1345             :         }
    1346       70400 :         BBPreclaim(s);
    1347       70400 :         BBPunfix(b->batCacheid);
    1348       70400 :         return MAL_SUCCEED;
    1349             : }
    1350             : 
    1351             : static str
    1352        1786 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1353             : {
    1354        1786 :         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       68340 : ALGcount_bat(lng *result, const bat *bid)
    1365             : {
    1366       68340 :         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       17225 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1430             : {
    1431       17225 :         BAT *b, *bn;
    1432       17225 :         BUN s, e;
    1433             : 
    1434       17225 :         if (*start < 0 || (*end < 0 && !is_lng_nil(*end)))
    1435           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1436       17226 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1437           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1438       17225 :         s = (BUN) *start;
    1439       17225 :         if (s > BATcount(b))
    1440             :                 s = BATcount(b);
    1441       17225 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1442       17225 :         if (e > BATcount(b))
    1443             :                 e = BATcount(b);
    1444       17225 :         if (e < s)
    1445             :                 e = s;
    1446       17225 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1447       17227 :         if (bn == NULL)
    1448           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1449       17227 :         *ret = bn->batCacheid;
    1450       17227 :         BBPkeepref(bn);
    1451       17227 :         return MAL_SUCCEED;
    1452             : }
    1453             : 
    1454             : /*
    1455             :  * BUN Get/Fetch
    1456             :  */
    1457             : 
    1458             : static str
    1459       88510 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1460             : {
    1461       88510 :         assert(pos <= BUN_MAX);
    1462       88510 :         BATiter bi = bat_iterator(b);
    1463       88510 :         if (ATOMextern(b->ttype)) {
    1464         190 :                 ptr _src = BUNtail(bi, pos);
    1465         190 :                 size_t _len = ATOMlen(b->ttype, _src);
    1466         190 :                 ptr _dst = GDKmalloc(_len);
    1467         190 :                 if (_dst == NULL) {
    1468           0 :                         bat_iterator_end(&bi);
    1469           0 :                         throw(MAL, "doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1470             :                 }
    1471         190 :                 memcpy(_dst, _src, _len);
    1472         190 :                 *(ptr *) ret = _dst;
    1473             :         } else {
    1474       88320 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1475       88320 :                 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       88320 :                 } else if (_s == 4) {
    1480       88233 :                         *(int *) ret = ((int *) bi.base)[pos];
    1481             :                 } else if (_s == 1) {
    1482          11 :                         *(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          75 :                         *(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       88510 :         bat_iterator_end(&bi);
    1496       88510 :         return MAL_SUCCEED;
    1497             : }
    1498             : 
    1499             : static str
    1500       88512 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1501             : {
    1502       88512 :         BAT *b;
    1503       88512 :         str msg;
    1504             : 
    1505       88512 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1506           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1507             :         }
    1508       88512 :         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       88512 :         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       88510 :         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       88510 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1525       88510 :         BBPunfix(b->batCacheid);
    1526       88510 :         return msg;
    1527             : }
    1528             : 
    1529             : str
    1530       88512 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1531             : {
    1532       88512 :         lng o = *pos;
    1533             : 
    1534       88512 :         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      291059 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1577             : {
    1578      291059 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1579      291059 :         bat bid = *getArgReference_bat(stk, pci, 1);
    1580      291059 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1581      291059 :         BAT *b, *bn;
    1582             : 
    1583      291059 :         (void) cntxt;
    1584      291059 :         (void) mb;
    1585      291059 :         if (isaBatType(getArgType(mb, pci, 2)))
    1586           0 :                 throw(MAL, "algebra.project", "Scalar value expected");
    1587      291059 :         if ((b = BBPquickdesc(bid)) == NULL)
    1588           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1589      290959 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1590      291160 :         if (bn == NULL) {
    1591           0 :                 *ret = bat_nil;
    1592           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1593             :         }
    1594      291160 :         *ret = bn->batCacheid;
    1595      291160 :         BBPkeepref(bn);
    1596      291160 :         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           5 : ALGvariancep(dbl *res, const bat *bid)
    1689             : {
    1690           5 :         BAT *b;
    1691           5 :         dbl variance;
    1692             : 
    1693           5 :         if ((b = BATdescriptor(*bid)) == NULL)
    1694           0 :                 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1695           5 :         variance = BATcalcvariance_population(NULL, b);
    1696           5 :         BBPunfix(b->batCacheid);
    1697           5 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1698           1 :                 throw(MAL, "aggr.variancep", GDK_EXCEPTION);
    1699           4 :         *res = variance;
    1700           4 :         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           9 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1730             : {
    1731           9 :         BAT *b1, *b2;
    1732           9 :         dbl covariance;
    1733             : 
    1734           9 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1735           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1736           9 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1737           0 :                 BBPunfix(b1->batCacheid);
    1738           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1739             :         }
    1740             : 
    1741           9 :         covariance = BATcalccovariance_population(b1, b2);
    1742           9 :         BBPunfix(b1->batCacheid);
    1743           9 :         BBPunfix(b2->batCacheid);
    1744           9 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1745           1 :                 throw(MAL, "aggr.covariancep", GDK_EXCEPTION);
    1746           8 :         *res = covariance;
    1747           8 :         return MAL_SUCCEED;
    1748             : }
    1749             : 
    1750             : /*
    1751             :  * BAT correlation
    1752             :  */
    1753             : static str
    1754          18 : ALGcorr(dbl *res, const bat *bid1, const bat *bid2)
    1755             : {
    1756          18 :         BAT *b1, *b2;
    1757          18 :         dbl covariance;
    1758             : 
    1759          18 :         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          18 :         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 at least one row, if none of the predicates (p) hold, return a nil, else 'all' true cases.", args(2,6, batarg("",oid), batarg("", bit), batarg("lid", oid), batarg("rid", bit), batarg("predicate", bit), arg("any", bit))),
    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         321 : LIB_STARTUP_FUNC(init_algebra_mal)
    1860         321 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14