LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 758 991 76.5 %
Date: 2024-04-25 20:03:45 Functions: 67 82 81.7 %

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

Generated by: LCOV version 1.14