LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - algebra.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 518 734 70.6 %
Date: 2021-10-13 02:24:04 Functions: 60 77 77.9 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (c) Peter Boncz, Martin Kersten, Niels Nes, Sjoerd Mullender
      11             :  * BAT Algebra
      12             :  * This modules contains the most common algebraic BAT manipulation
      13             :  * commands. We call them algebra, because all operations take
      14             :  * values as parameters, and produce new result values, but
      15             :  * do not modify their parameters.
      16             :  *
      17             :  * Unlike the previous Monet versions, we reduce the number
      18             :  * of functions returning a BAT reference. This was previously needed
      19             :  * to simplify recursive bat-expression and manage reference counts.
      20             :  * In the current version we return only a BAT identifier when a new
      21             :  * bat is being created.
      22             :  *
      23             :  * All parameters to the modules are passed by reference.
      24             :  * In particular, this means that
      25             :  * string values are passed to the module layer as (str *)
      26             :  * and we have to de-reference them before entering the gdk library.
      27             :  * This calls for knowlegde on the underlying BAT typs`s
      28             :  */
      29             : #define derefStr(b, v)                                                  \
      30             :         do {                                                                            \
      31             :                 int _tpe= ATOMstorage((b)->ttype);           \
      32             :                 if (_tpe >= TYPE_str) {                                      \
      33             :                         if ((v) == 0 || *(str*) (v) == 0)       \
      34             :                                 (v) = (str) str_nil;                    \
      35             :                         else                                                            \
      36             :                                 (v) = *(str *) (v);                             \
      37             :                 }                                                                               \
      38             :         } while (0)
      39             : 
      40             : #include "monetdb_config.h"
      41             : #include "algebra.h"
      42             : 
      43             : /*
      44             :  * Command Implementations in C
      45             :  * This module contains just a wrapper implementations; since all described
      46             :  * operations are part of the GDK kernel.
      47             :  *
      48             :  * BAT sum operation
      49             :  * The sum aggregate only works for int and float fields.
      50             :  * The routines below assumes that the caller knows what type
      51             :  * is large enough to prevent overflow.
      52             :  */
      53             : 
      54             : static gdk_return
      55        2438 : CMDgen_group(BAT **result, BAT *gids, BAT *cnts )
      56             : {
      57        2438 :         lng j, gcnt = BATcount(gids);
      58        2438 :         BAT *r = COLnew(0, TYPE_oid, BATcount(gids)*2, TRANSIENT);
      59             : 
      60        2438 :         if (r == NULL)
      61             :                 return GDK_FAIL;
      62        2438 :         BATiter ci = bat_iterator(cnts);
      63        2438 :         if (gids->ttype == TYPE_void) {
      64        1089 :                 oid id = gids->tseqbase;
      65        1089 :                 lng *cnt = (lng*)ci.base;
      66       21844 :                 for(j = 0; j < gcnt; j++) {
      67       20755 :                         lng i, sz = cnt[j];
      68       41339 :                         for(i = 0; i < sz; i++) {
      69       20584 :                                 if (BUNappend(r, &id, false) != GDK_SUCCEED) {
      70           0 :                                         BBPreclaim(r);
      71           0 :                                         bat_iterator_end(&ci);
      72           0 :                                         return GDK_FAIL;
      73             :                                 }
      74             :                         }
      75       20755 :                         id++;
      76             :                 }
      77             :         } else {
      78        1349 :                 BATiter gi = bat_iterator(gids);
      79        1349 :                 oid *id = (oid*)gi.base;
      80        1349 :                 lng *cnt = (lng*)ci.base;
      81      140700 :                 for(j = 0; j < gcnt; j++) {
      82      139351 :                         lng i, sz = cnt[j];
      83      275213 :                         for(i = 0; i < sz; i++) {
      84      135862 :                                 if (BUNappend(r, id, false) != GDK_SUCCEED) {
      85           0 :                                         BBPreclaim(r);
      86           0 :                                         bat_iterator_end(&ci);
      87           0 :                                         bat_iterator_end(&gi);
      88           0 :                                         return GDK_FAIL;
      89             :                                 }
      90             :                         }
      91      139351 :                         id++;
      92             :                 }
      93        1349 :                 bat_iterator_end(&gi);
      94             :         }
      95        2438 :         bat_iterator_end(&ci);
      96        2438 :         r -> tkey = false;
      97        2438 :         r -> tseqbase = oid_nil;
      98        2438 :         r -> tsorted = BATtordered(gids);
      99        2438 :         r -> trevsorted = BATtrevordered(gids);
     100        2438 :         r -> tnonil = gids->tnonil;
     101        2438 :         *result = r;
     102        2438 :         return GDK_SUCCEED;
     103             : }
     104             : 
     105             : 
     106             : static gdk_return
     107           6 : slice(BAT **retval, BAT *b, lng start, lng end)
     108             : {
     109             :         /* the internal BATslice requires exclusive end */
     110           6 :         if (start < 0) {
     111           0 :                 GDKerror("start position of slice should >= 0\n");
     112           0 :                 return GDK_FAIL;
     113             :         }
     114           6 :         if (is_lng_nil(end))
     115           3 :                 end = BATcount(b);
     116           6 :         if (start > (lng) BUN_MAX || end >= (lng) BUN_MAX) {
     117           0 :                 GDKerror("argument out of range\n");
     118           0 :                 return GDK_FAIL;
     119             :         }
     120             : 
     121           6 :         return (*retval = BATslice(b, (BUN) start, (BUN) end + 1)) ? GDK_SUCCEED : GDK_FAIL;
     122             : }
     123             : /*
     124             :  *
     125             :  * The remainder of this file contains the wrapper around the V4 code base
     126             :  * The BAT identifiers passed through this module may indicate
     127             :  * that the 'reverse' view applies. This should be taken into
     128             :  * account while resolving them.
     129             :  *
     130             :  * The sum aggregate only works for int and float fields.
     131             :  * The routines below assumes that the caller knows what type
     132             :  * is large enough to prevent overflow.
     133             :  */
     134             : 
     135             : static str
     136         463 : ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     137             : {
     138             :         BAT *b;
     139             :         ptr p;
     140             :         str msg = MAL_SUCCEED;
     141             : 
     142         463 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     143           0 :                 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     144             : 
     145         463 :         if (!ATOMlinear(b->ttype)) {
     146           0 :                 msg = createException(MAL, "algebra.min",
     147             :                                                           "atom '%s' cannot be ordered linearly",
     148             :                                                           ATOMname(b->ttype));
     149             :         } else {
     150         463 :                 if (ATOMextern(b->ttype)) {
     151          37 :                         * (ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
     152             :                 } else {
     153         426 :                         p = BATmin_skipnil(b, result, *skipnil);
     154         426 :                         if ( p != result )
     155           0 :                                 msg = createException(MAL, "algebra.min", SQLSTATE(HY002) "INTERNAL ERROR");
     156             :                 }
     157         463 :                 if (msg == MAL_SUCCEED && p == NULL)
     158           0 :                         msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
     159             :         }
     160         463 :         BBPunfix(b->batCacheid);
     161         463 :         return msg;
     162             : }
     163             : 
     164             : static str
     165         463 : ALGminany(ptr result, const bat *bid)
     166             : {
     167         463 :         bit skipnil = TRUE;
     168         463 :         return ALGminany_skipnil(result, bid, &skipnil);
     169             : }
     170             : 
     171             : static str
     172         303 : ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
     173             : {
     174             :         BAT *b;
     175             :         ptr p;
     176             :         str msg = MAL_SUCCEED;
     177             : 
     178         303 :         if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
     179           0 :                 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     180             : 
     181         303 :         if (!ATOMlinear(b->ttype)) {
     182           0 :                 msg = createException(MAL, "algebra.max",
     183             :                                                           "atom '%s' cannot be ordered linearly",
     184             :                                                           ATOMname(b->ttype));
     185             :         } else {
     186         303 :                 if (ATOMextern(b->ttype)) {
     187          11 :                         * (ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
     188             :                 } else {
     189         292 :                         p = BATmax_skipnil(b, result, *skipnil);
     190         292 :                         if ( p != result )
     191           0 :                                 msg = createException(MAL, "algebra.max", SQLSTATE(HY002) "INTERNAL ERROR");
     192             :                 }
     193         303 :                 if ( msg == MAL_SUCCEED && p == NULL)
     194           0 :                         msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
     195             :         }
     196         303 :         BBPunfix(b->batCacheid);
     197         303 :         return msg;
     198             : }
     199             : 
     200             : static str
     201         303 : ALGmaxany(ptr result, const bat *bid)
     202             : {
     203         303 :         bit skipnil = TRUE;
     204         303 :         return ALGmaxany_skipnil(result, bid, &skipnil);
     205             : }
     206             : 
     207             : static str
     208        2438 : ALGgroupby(bat *res, const bat *gids, const bat *cnts)
     209             : {
     210             :         BAT *bn, *g, *c;
     211             : 
     212        2438 :         g = BATdescriptor(*gids);
     213        2438 :         if (g == NULL) {
     214           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     215             :         }
     216        2438 :         c = BATdescriptor(*cnts);
     217        2438 :         if (c == NULL) {
     218           0 :                 BBPunfix(g->batCacheid);
     219           0 :                 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     220             :         }
     221        2438 :         if( CMDgen_group(&bn, g, c) != GDK_SUCCEED){
     222           0 :                 BBPunfix(g->batCacheid);
     223           0 :                 BBPunfix(c->batCacheid);
     224           0 :                 throw(MAL, "algebra.groupby",GDK_EXCEPTION);
     225             :         }
     226        2438 :         *res = bn->batCacheid;
     227        2438 :         BBPkeepref(bn->batCacheid);
     228        2438 :         BBPunfix(g->batCacheid);
     229        2438 :         BBPunfix(c->batCacheid);
     230        2438 :         return MAL_SUCCEED;
     231             : }
     232             : 
     233             : static str
     234           1 : ALGcard(lng *result, const bat *bid)
     235             : {
     236             :         BAT *b, *en;
     237             : 
     238           1 :         if ((b = BATdescriptor(*bid)) == NULL) {
     239           0 :                 throw(MAL, "algebra.card", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     240             :         }
     241           1 :         en = BATunique(b, NULL);
     242           1 :         BBPunfix(b->batCacheid);
     243           1 :         if (en == NULL) {
     244           0 :                 throw(MAL, "algebra.card", GDK_EXCEPTION);
     245             :         }
     246             :         struct canditer ci;
     247           1 :         *result = canditer_init(&ci, NULL, en);
     248           1 :         BBPunfix(en->batCacheid);
     249           1 :         return MAL_SUCCEED;
     250             : }
     251             : 
     252             : static str
     253       73545 : ALGselect2(bat *result, const bat *bid, const bat *sid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti)
     254             : {
     255             :         BAT *b, *s = NULL, *bn;
     256             :         const void *nilptr;
     257             : 
     258       73545 :         if ((*li != 0 && *li != 1) ||
     259       73545 :                 (*hi != 0 && *hi != 1) ||
     260       73545 :                 (*anti != 0 && *anti != 1)) {
     261           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     262             :         }
     263       73545 :         if ((b = BATdescriptor(*bid)) == NULL) {
     264           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     265             :         }
     266       73545 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     267           0 :                 BBPunfix(b->batCacheid);
     268           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     269             :         }
     270       73546 :         derefStr(b, low);
     271       73546 :         derefStr(b, high);
     272       73546 :         nilptr = ATOMnilptr(b->ttype);
     273      146935 :         if (*li == 1 && *hi == 1 &&
     274       98044 :                 ATOMcmp(b->ttype, low, nilptr) == 0 &&
     275       24659 :                 ATOMcmp(b->ttype, high, nilptr) == 0) {
     276             :                 /* special case: equi-select for NIL */
     277             :                 high = NULL;
     278             :         }
     279       73544 :         bn = BATselect(b, s, low, high, *li, *hi, *anti);
     280       73541 :         BBPunfix(b->batCacheid);
     281       73543 :         if (s)
     282       26194 :                 BBPunfix(s->batCacheid);
     283       73543 :         if (bn == NULL)
     284           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     285       73543 :         *result = bn->batCacheid;
     286       73543 :         BBPkeepref(bn->batCacheid);
     287       73545 :         return MAL_SUCCEED;
     288             : }
     289             : 
     290             : static str
     291        5083 : ALGselect2nil(bat *result, const bat *bid, const bat *sid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti, const bit *unknown)
     292             : {
     293             :         BAT *b, *s = NULL, *bn;
     294        5083 :         bit nanti = *anti, nli = *li, nhi = *hi;
     295             : 
     296        5083 :         if (!*unknown)
     297           0 :                 return ALGselect2(result, bid, sid, low, high, li, hi, anti);
     298             : 
     299        5083 :         if ((nli != 0 && nli != 1) ||
     300        5083 :                 (nhi != 0 && nhi != 1) ||
     301        5083 :                 (nanti != 0 && nanti != 1)) {
     302           0 :                 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
     303             :         }
     304        5083 :         if ((b = BATdescriptor(*bid)) == NULL) {
     305           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     306             :         }
     307        5083 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     308           0 :                 BBPunfix(b->batCacheid);
     309           0 :                 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     310             :         }
     311        5083 :         derefStr(b, low);
     312        5083 :         derefStr(b, high);
     313             :         /* here we don't need open ended parts with nil */
     314        5083 :         if (!nanti) {
     315        1863 :                 const void *nilptr = ATOMnilptr(b->ttype);
     316        1863 :                 if (nli == 1 && ATOMcmp(b->ttype, low, nilptr) == 0) {
     317             :                         low = high;
     318             :                         nli = 0;
     319             :                 }
     320        1863 :                 if (nhi == 1 && ATOMcmp(b->ttype, high, nilptr) == 0) {
     321             :                         high = low;
     322             :                         nhi = 0;
     323             :                 }
     324        1863 :                 if (ATOMcmp(b->ttype, low, high) == 0 && ATOMcmp(b->ttype, high, nilptr) == 0) /* ugh sql nil != nil */
     325             :                         nanti = 1;
     326             :         }
     327             : 
     328        5083 :         bn = BATselect(b, s, low, high, nli, nhi, nanti);
     329        5083 :         BBPunfix(b->batCacheid);
     330        5083 :         if (s)
     331        4609 :                 BBPunfix(s->batCacheid);
     332        5083 :         if (bn == NULL)
     333           1 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     334        5082 :         *result = bn->batCacheid;
     335        5082 :         BBPkeepref(bn->batCacheid);
     336        5082 :         return MAL_SUCCEED;
     337             : }
     338             : 
     339             : static str
     340       44141 : ALGselect1(bat *result, const bat *bid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti)
     341             : {
     342       44141 :         return ALGselect2(result, bid, NULL, low, high, li, hi, anti);
     343             : }
     344             : 
     345             : static str
     346         437 : ALGselect1nil(bat *result, const bat *bid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti, const bit *unknown)
     347             : {
     348         437 :         return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
     349             : }
     350             : 
     351             : static str
     352      358856 : ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val, const char **op)
     353             : {
     354             :         BAT *b, *s = NULL, *bn;
     355             : 
     356      358856 :         if ((b = BATdescriptor(*bid)) == NULL) {
     357           0 :                 throw(MAL, "algebra.thetaselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     358             :         }
     359      358839 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     360           0 :                 BBPunfix(b->batCacheid);
     361           0 :                 throw(MAL, "algebra.thetaselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     362             :         }
     363      358854 :         derefStr(b, val);
     364      358854 :         bn = BATthetaselect(b, s, val, *op);
     365      358827 :         BBPunfix(b->batCacheid);
     366      358859 :         if (s)
     367      220656 :                 BBPunfix(s->batCacheid);
     368      358848 :         if (bn == NULL)
     369           0 :                 throw(MAL, "algebra.select", GDK_EXCEPTION);
     370      358848 :         *result = bn->batCacheid;
     371      358848 :         BBPkeepref(bn->batCacheid);
     372      358827 :         return MAL_SUCCEED;
     373             : }
     374             : 
     375             : static str
     376        1924 : ALGselectNotNil(bat *result, const bat *bid)
     377             : {
     378             :         BAT *b;
     379             : 
     380        1924 :         if ((b = BATdescriptor(*bid)) == NULL)
     381           0 :                 throw(MAL, "algebra.selectNotNil", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     382             : 
     383        1924 :         if (!b->tnonil) {
     384             :                 BAT *s;
     385         923 :                 s = BATselect(b, NULL, ATOMnilptr(b->ttype), NULL, true, true, true);
     386         923 :                 if (s) {
     387         923 :                         BAT *bn = BATproject(s, b);
     388         923 :                         BBPunfix(s->batCacheid);
     389         923 :                         if (bn) {
     390         923 :                                 BBPunfix(b->batCacheid);
     391         923 :                                 *result = bn->batCacheid;
     392         923 :                                 BBPkeepref(*result);
     393         923 :                                 return MAL_SUCCEED;
     394             :                         }
     395             :                 }
     396           0 :                 BBPunfix(b->batCacheid);
     397           0 :                 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
     398             :         }
     399             :         /* just pass on the result */
     400        1001 :         *result = b->batCacheid;
     401        1001 :         BBPkeepref(*result);
     402        1001 :         return MAL_SUCCEED;
     403             : }
     404             : 
     405             : static str
     406      432848 : do_join(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *r2id,
     407             :                 const bat *slid, const bat *srid,
     408             :                 int op, const void *c1, const void *c2, bool li, bool hi,
     409             :                 bool anti, bool symmetric, /* these two only for rangejoin */
     410             :                 const bit *nil_matches, const bit *not_in, const bit *max_one,
     411             :                 const lng *estimate,
     412             :                 gdk_return (*joinfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     413             :                                                            bool, BUN),
     414             :                 gdk_return (*semifunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     415             :                                                            bool, bool, BUN),
     416             :                 gdk_return (*thetafunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     417             :                                                                 int, bool, BUN),
     418             :                 gdk_return (*bandfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
     419             :                                                            const void *, const void *, bool, bool, BUN),
     420             :                 gdk_return (*rangefunc)(BAT **, BAT **, BAT *, BAT *, BAT *,
     421             :                                                                 BAT *, BAT *, bool, bool, bool, bool, BUN),
     422             :                 BAT *(*difffunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     423             :                 BAT *(*interfunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
     424             :                 const char *funcname)
     425             : {
     426             :         BAT *left = NULL, *right = NULL, *right2 = NULL;
     427             :         BAT *candleft = NULL, *candright = NULL;
     428             :         BAT *result1, *result2;
     429             :         BUN est;
     430             :         const char *err = RUNTIME_OBJECT_MISSING;
     431             : 
     432      432848 :         assert(r2id == NULL || rangefunc != NULL);
     433             : 
     434      432848 :         if ((left = BATdescriptor(*lid)) == NULL)
     435           0 :                 goto fail;
     436      432792 :         if ((right = BATdescriptor(*rid)) == NULL)
     437           0 :                 goto fail;
     438      432821 :         if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
     439           0 :                 goto fail;
     440      432822 :         if (srid && !is_bat_nil(*srid) && (candright = BATdescriptor(*srid)) == NULL)
     441           0 :                 goto fail;
     442      432822 :         if (estimate == NULL || *estimate < 0 || is_lng_nil(*estimate) || *estimate > (lng) BUN_MAX)
     443             :                 est = BUN_NONE;
     444             :         else
     445           0 :                 est = (BUN) *estimate;
     446             : 
     447             :         err = NULL;             /* most likely error now is GDK_EXCEPTION */
     448             : 
     449      432822 :         if (thetafunc) {
     450       19837 :                 assert(joinfunc == NULL);
     451       19837 :                 assert(semifunc == NULL);
     452       19837 :                 assert(bandfunc == NULL);
     453       19837 :                 assert(rangefunc == NULL);
     454       19837 :                 assert(difffunc == NULL);
     455       19837 :                 assert(interfunc == NULL);
     456       35374 :                 if ((*thetafunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, op, *nil_matches, est) != GDK_SUCCEED)
     457           0 :                         goto fail;
     458      412985 :         } else if (joinfunc) {
     459      318567 :                 assert(semifunc == NULL);
     460      318567 :                 assert(bandfunc == NULL);
     461      318567 :                 assert(rangefunc == NULL);
     462      318567 :                 assert(difffunc == NULL);
     463      318567 :                 assert(interfunc == NULL);
     464      318567 :                 result2 = NULL;
     465      356443 :                 if ((*joinfunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, *nil_matches, est) != GDK_SUCCEED)
     466           1 :                         goto fail;
     467       94418 :         } else if (semifunc) {
     468         176 :                 assert(bandfunc == NULL);
     469         176 :                 assert(rangefunc == NULL);
     470         176 :                 assert(difffunc == NULL);
     471         176 :                 assert(interfunc == NULL);
     472         176 :                 result2 = NULL;
     473         176 :                 if ((*semifunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, *nil_matches, *max_one, est) != GDK_SUCCEED)
     474          36 :                         goto fail;
     475       94242 :         } else if (bandfunc) {
     476           0 :                 assert(rangefunc == NULL);
     477           0 :                 assert(difffunc == NULL);
     478           0 :                 assert(interfunc == NULL);
     479           0 :                 if ((*bandfunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, c1, c2, li, hi, est) != GDK_SUCCEED)
     480           0 :                         goto fail;
     481       94242 :         } else if (rangefunc) {
     482         134 :                 assert(difffunc == NULL);
     483         134 :                 assert(interfunc == NULL);
     484         134 :                 if ((right2 = BATdescriptor(*r2id)) == NULL) {
     485             :                         err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
     486           0 :                         goto fail;
     487             :                 }
     488         157 :                 if ((*rangefunc)(&result1, r2 ? &result2 : NULL, left, right, right2, candleft, candright, li, hi, anti, symmetric, est) != GDK_SUCCEED)
     489           0 :                         goto fail;
     490         134 :                 BBPunfix(right2->batCacheid);
     491       94108 :         } else if (difffunc) {
     492       87423 :                 assert(r2 == NULL);
     493       87423 :                 assert(interfunc == NULL);
     494       87423 :                 if ((result1 = (*difffunc)(left, right, candleft, candright, *nil_matches, *not_in, est)) == NULL)
     495           0 :                         goto fail;
     496       87422 :                 result2 = NULL;
     497             :         } else {
     498        6685 :                 assert(r2 == NULL);
     499        6685 :                 if ((result1 = (*interfunc)(left, right, candleft, candright, *nil_matches, *max_one, est)) == NULL)
     500           4 :                         goto fail;
     501        6682 :                 result2 = NULL;
     502             :         }
     503      432781 :         *r1 = result1->batCacheid;
     504      432781 :         BBPkeepref(*r1);
     505      432730 :         if (r2) {
     506      285203 :                 *r2 = result2->batCacheid;
     507      285203 :                 BBPkeepref(*r2);
     508             :         }
     509      432731 :         BBPunfix(left->batCacheid);
     510      432759 :         BBPunfix(right->batCacheid);
     511      432769 :         if (candleft)
     512        5905 :                 BBPunfix(candleft->batCacheid);
     513      432767 :         if (candright)
     514           0 :                 BBPunfix(candright->batCacheid);
     515             :         return MAL_SUCCEED;
     516             : 
     517          41 :   fail:
     518          41 :         if (left)
     519          41 :                 BBPunfix(left->batCacheid);
     520          41 :         if (right)
     521          41 :                 BBPunfix(right->batCacheid);
     522          41 :         if (right2)
     523           0 :                 BBPunfix(right2->batCacheid);
     524          41 :         if (candleft)
     525           0 :                 BBPunfix(candleft->batCacheid);
     526          41 :         if (candright)
     527           0 :                 BBPunfix(candright->batCacheid);
     528          41 :         if (err == NULL)
     529          41 :                 throw(MAL, funcname, GDK_EXCEPTION);
     530           0 :         throw(MAL, funcname, "%s", err);
     531             : }
     532             : 
     533             : static str
     534      280059 : ALGjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     535             :                    const bit *nil_matches, const lng *estimate)
     536             : {
     537      280059 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     538             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     539             :                                    BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, "algebra.join");
     540             : }
     541             : 
     542             : static str
     543       37877 : ALGjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     544             :                    const bit *nil_matches, const lng *estimate)
     545             : {
     546       37877 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     547             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     548             :                                    BATjoin, NULL, NULL, NULL, NULL, NULL, NULL, "algebra.join");
     549             : }
     550             : 
     551             : static str
     552         647 : ALGleftjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     553             :                            const bit *nil_matches, const lng *estimate)
     554             : {
     555         647 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     556             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     557             :                                    BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, "algebra.leftjoin");
     558             : }
     559             : 
     560             : static str
     561           0 : ALGleftjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     562             :                            const bit *nil_matches, const lng *estimate)
     563             : {
     564           0 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     565             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     566             :                                    BATleftjoin, NULL, NULL, NULL, NULL, NULL, NULL, "algebra.leftjoin");
     567             : }
     568             : 
     569             : static str
     570           0 : ALGouterjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     571             :                          const bit *nil_matches, const bit *match_one, const lng *estimate)
     572             : {
     573           0 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     574             :                                    false, false, false, false, nil_matches, NULL, match_one, estimate,
     575             :                                    NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, "algebra.outerjoin");
     576             : }
     577             : 
     578             : static str
     579           0 : ALGouterjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     580             :                           const bit *nil_matches, const bit *match_one, const lng *estimate)
     581             : {
     582           0 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     583             :                                    false, false, false, false, nil_matches, NULL, match_one, estimate,
     584             :                                    NULL, BATouterjoin, NULL, NULL, NULL, NULL, NULL, "algebra.outerjoin");
     585             : }
     586             : 
     587             : static str
     588         176 : ALGsemijoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     589             :                         const bit *nil_matches, const bit *max_one, const lng *estimate)
     590             : {
     591         176 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     592             :                                    false, false, false, false, nil_matches, NULL, max_one, estimate,
     593             :                                    NULL, BATsemijoin, NULL, NULL, NULL, NULL, NULL, "algebra.semijoin");
     594             : }
     595             : 
     596             : static str
     597        4301 : ALGthetajoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     598             :                                 const int *op, const bit *nil_matches, const lng *estimate)
     599             : {
     600        4301 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     601             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     602             :                                    NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL, "algebra.thetajoin");
     603             : }
     604             : 
     605             : static str
     606       15538 : ALGthetajoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     607             :                                 const int *op, const bit *nil_matches, const lng *estimate)
     608             : {
     609       15538 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, *op, NULL, NULL,
     610             :                                    false, false, false, false, nil_matches, NULL, NULL, estimate,
     611             :                                    NULL, NULL, BATthetajoin, NULL, NULL, NULL, NULL, "algebra.thetajoin");
     612             : }
     613             : 
     614             : static str
     615           0 : ALGbandjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     616             :                            const void *c1, const void *c2, const bit *li, const bit *hi,
     617             :                            const lng *estimate)
     618             : {
     619           0 :         return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, c1, c2,
     620           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     621             :                                    NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL, "algebra.bandjoin");
     622             : }
     623             : 
     624             : static str
     625           0 : ALGbandjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     626             :                            const void *c1, const void *c2, const bit *li, const bit *hi,
     627             :                            const lng *estimate)
     628             : {
     629           0 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, c1, c2,
     630           0 :                                    *li, *hi, false, false, NULL, NULL, NULL, estimate,
     631             :                                    NULL, NULL, NULL, BATbandjoin, NULL, NULL, NULL, "algebra.bandjoin");
     632             : }
     633             : 
     634             : static str
     635         111 : ALGrangejoin(bat *r1, bat *r2, const bat *lid, const bat *rlid, const bat *rhid, const bat *slid, const bat *srid,
     636             :                          const bit *li, const bit *hi, const bit *anti, const bit *symmetric, const lng *estimate)
     637             : {
     638         222 :         return do_join(r1, r2, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     639         111 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     640             :                                    NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL, "algebra.rangejoin");
     641             : }
     642             : 
     643             : static str
     644          23 : ALGrangejoin1(bat *r1, const bat *lid, const bat *rlid, const bat *rhid, const bat *slid, const bat *srid,
     645             :                           const bit *li, const bit *hi, const bit *anti, const bit *symmetric, const lng *estimate)
     646             : {
     647          46 :         return do_join(r1, NULL, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
     648          23 :                                    *li, *hi, *anti, *symmetric, NULL, NULL, NULL, estimate,
     649             :                                    NULL, NULL, NULL, NULL, BATrangejoin, NULL, NULL, "algebra.rangejoin");
     650             : }
     651             : 
     652             : static str
     653       87433 : ALGdifference(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     654             :                           const bit *nil_matches, const bit *not_in, const lng *estimate)
     655             : {
     656       87433 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     657             :                                    false, false, false, false, nil_matches, not_in, NULL, estimate,
     658             :                                    NULL, NULL, NULL, NULL, NULL, BATdiff, NULL, "algebra.difference");
     659             : }
     660             : 
     661             : static str
     662        6686 : ALGintersect(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
     663             :                          const bit *nil_matches, const bit *max_one, const lng *estimate)
     664             : {
     665        6686 :         return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
     666             :                                    false, false, false, false, nil_matches, NULL, max_one, estimate,
     667             :                                    NULL, NULL, NULL, NULL, NULL, NULL, BATintersect, "algebra.intersect");
     668             : }
     669             : 
     670             : /* algebra.firstn(b:bat[:any],
     671             :  *                [ s:bat[:oid],
     672             :  *                [ g:bat[:oid], ] ]
     673             :  *                n:lng,
     674             :  *                asc:bit,
     675             :  *                nilslast:bit,
     676             :  *                distinct:bit)
     677             :  * returns :bat[:oid] [ , :bat[:oid] ]
     678             :  */
     679             : static str
     680        1065 : ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     681             : {
     682             :         bat *ret1, *ret2 = NULL;
     683             :         bat bid, sid, gid;
     684             :         BAT *b, *s = NULL, *g = NULL;
     685             :         BAT *bn, *gn;
     686             :         lng n;
     687             :         bit asc, nilslast, distinct;
     688             :         gdk_return rc;
     689             : 
     690             :         (void) cntxt;
     691             :         (void) mb;
     692             : 
     693        1065 :         assert(pci->retc == 1 || pci->retc == 2);
     694        1065 :         assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
     695             : 
     696        1065 :         n = *getArgReference_lng(stk, pci, pci->argc - 4);
     697        1065 :         if (n < 0 || (lng) n >= (lng) BUN_MAX)
     698           0 :                 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
     699        1065 :         ret1 = getArgReference_bat(stk, pci, 0);
     700        1065 :         if (pci->retc == 2)
     701         565 :                 ret2 = getArgReference_bat(stk, pci, 1);
     702        1065 :         bid = *getArgReference_bat(stk, pci, pci->retc);
     703        1065 :         if ((b = BATdescriptor(bid)) == NULL)
     704           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     705        1065 :         if (pci->argc - pci->retc > 5) {
     706        1065 :                 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
     707        1065 :                 if (!is_bat_nil(sid) && (s = BATdescriptor(sid)) == NULL) {
     708           0 :                         BBPunfix(bid);
     709           0 :                         throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     710             :                 }
     711        1065 :                 if (pci->argc - pci->retc > 6) {
     712        1065 :                         gid = *getArgReference_bat(stk, pci, pci->retc + 2);
     713        1065 :                         if (!is_bat_nil(gid) && (g = BATdescriptor(gid)) == NULL) {
     714           0 :                                 BBPunfix(bid);
     715           0 :                                 BBPunfix(sid);
     716           0 :                                 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     717             :                         }
     718             :                 }
     719             :         }
     720        1065 :         asc = *getArgReference_bit(stk, pci, pci->argc - 3);
     721        1065 :         nilslast = *getArgReference_bit(stk, pci, pci->argc - 2);
     722        1065 :         distinct = *getArgReference_bit(stk, pci, pci->argc - 1);
     723        1565 :         rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast, distinct);
     724        1065 :         BBPunfix(b->batCacheid);
     725        1065 :         if (s)
     726         547 :                 BBPunfix(s->batCacheid);
     727        1065 :         if (g)
     728         547 :                 BBPunfix(g->batCacheid);
     729        1065 :         if (rc != GDK_SUCCEED)
     730           0 :                 throw(MAL, "algebra.firstn", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     731        1065 :         BBPkeepref(*ret1 = bn->batCacheid);
     732        1065 :         if (ret2)
     733         565 :                 BBPkeepref(*ret2 = gn->batCacheid);
     734             :         return MAL_SUCCEED;
     735             : }
     736             : 
     737             : static str
     738          15 : ALGunary(bat *result, const bat *bid, BAT *(*func)(BAT *), const char *name)
     739             : {
     740             :         BAT *b,*bn;
     741             : 
     742          15 :         if ((b= BATdescriptor(*bid)) == NULL) {
     743           0 :                 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     744             :         }
     745          15 :         bn = (*func)(b);
     746          15 :         BBPunfix(b->batCacheid);
     747          15 :         if (bn == NULL)
     748           0 :                 throw(MAL, name, GDK_EXCEPTION);
     749          15 :         *result = bn->batCacheid;
     750          15 :         BBPkeepref(*result);
     751          15 :         return MAL_SUCCEED;
     752             : }
     753             : 
     754             : static BAT *
     755          15 : BATwcopy(BAT *b)
     756             : {
     757          15 :         return COLcopy(b, b->ttype, true, TRANSIENT);
     758             : }
     759             : 
     760             : static str
     761          15 : ALGcopy(bat *result, const bat *bid)
     762             : {
     763          15 :         return ALGunary(result, bid, BATwcopy, "algebra.copy");
     764             : }
     765             : 
     766             : static str
     767          64 : ALGunique(bat *result, const bat *bid, const bat *sid)
     768             : {
     769             :         BAT *b, *s = NULL, *bn = NULL;
     770             : 
     771          64 :         if ((b = BATdescriptor(*bid)) == NULL) {
     772           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     773             :         }
     774          64 :         if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
     775           0 :                 BBPunfix(b->batCacheid);
     776           0 :                 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     777             :         }
     778          64 :         bn = BATunique(b, s);
     779          64 :         BBPunfix(b->batCacheid);
     780          64 :         if (s)
     781           0 :                 BBPunfix(s->batCacheid);
     782          64 :         if (bn == NULL)
     783           0 :                 throw(MAL, "algebra.unique", GDK_EXCEPTION);
     784          64 :         *result = bn->batCacheid;
     785          64 :         BBPkeepref(*result);
     786          64 :         return MAL_SUCCEED;
     787             : }
     788             : 
     789             : static str
     790       13481 : ALGcrossproduct(bat *l, bat *r, const bat *left, const bat *right, const bat *slid, const bat *srid, const bit *max_one)
     791             : {
     792       13481 :         BAT *L, *R, *bn1, *bn2 = NULL;
     793             :         BAT *sl = NULL, *sr = NULL;
     794             :         gdk_return ret;
     795             : 
     796       13481 :         L = BATdescriptor(*left);
     797       13481 :         R = BATdescriptor(*right);
     798       13481 :         if (L == NULL || R == NULL) {
     799           0 :                 if (L)
     800           0 :                         BBPunfix(L->batCacheid);
     801           0 :                 if (R)
     802           0 :                         BBPunfix(R->batCacheid);
     803           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     804             :         }
     805       13481 :         if ((slid && !is_bat_nil(*slid) && (sl = BATdescriptor(*slid)) == NULL) ||
     806           0 :                 (srid && !is_bat_nil(*srid) && (sr = BATdescriptor(*srid)) == NULL)) {
     807           0 :                 BBPunfix(L->batCacheid);
     808           0 :                 BBPunfix(R->batCacheid);
     809           0 :                 if (sl)
     810           0 :                         BBPunfix(sl->batCacheid);
     811             :                 /* sr == NULL, so no need to unfix */
     812           0 :                 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     813             :         }
     814       14151 :         ret = BATsubcross(&bn1, r ? &bn2 : NULL, L, R, sl, sr,
     815       13481 :                                           max_one && !is_bit_nil(*max_one) && *max_one);
     816       13481 :         BBPunfix(L->batCacheid);
     817       13481 :         BBPunfix(R->batCacheid);
     818       13481 :         if (sl)
     819           0 :                 BBPunfix(sl->batCacheid);
     820       13481 :         if (sr)
     821           0 :                 BBPunfix(sr->batCacheid);
     822       13481 :         if (ret != GDK_SUCCEED)
     823          52 :                 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
     824       13429 :         BBPkeepref(*l = bn1->batCacheid);
     825       13429 :         if (r)
     826       12761 :                 BBPkeepref(*r = bn2->batCacheid);
     827             :         return MAL_SUCCEED;
     828             : }
     829             : 
     830             : static str
     831         670 : ALGcrossproduct1(bat *l, const bat *left, const bat *right, const bit *max_one)
     832             : {
     833         670 :         return ALGcrossproduct(l, NULL, left, right, NULL, NULL, max_one);
     834             : }
     835             : 
     836             : static str
     837       12811 : ALGcrossproduct2(bat *l, bat *r, const bat *left, const bat *right, const bit *max_one)
     838             : {
     839       12811 :         return ALGcrossproduct(l, r, left, right, NULL, NULL, max_one);
     840             : }
     841             : 
     842             : static str
     843           0 : ALGcrossproduct3(bat *l, bat *r, const bat *left, const bat *right, const bat *sl, const bat *sr, const bit *max_one)
     844             : {
     845           0 :         return ALGcrossproduct(l, r, left, right, sl, sr, max_one);
     846             : }
     847             : 
     848             : static str
     849           0 : ALGcrossproduct4(bat *l, const bat *left, const bat *right, const bat *sl, const bat *sr, const bit *max_one)
     850             : {
     851           0 :         return ALGcrossproduct(l, NULL, left, right, sl, sr, max_one);
     852             : }
     853             : 
     854             : static str
     855     1713082 : ALGprojection2(bat *result, const bat *lid, const bat *r1id, const bat *r2id)
     856             : {
     857             :         BAT *l, *r1, *r2 = NULL, *bn;
     858             : 
     859     1713082 :         if ((l = BATdescriptor(*lid)) == NULL) {
     860           0 :                 throw(MAL, "algebra.projection", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     861             :         }
     862     1712867 :         if ((r1 = BATdescriptor(*r1id)) == NULL) {
     863           0 :                 BBPunfix(l->batCacheid);
     864           0 :                 throw(MAL, "algebra.projection", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     865             :         }
     866     1712749 :         if (r2id && !is_bat_nil(*r2id) && (r2 = BATdescriptor(*r2id)) == NULL) {
     867           0 :                 BBPunfix(l->batCacheid);
     868           0 :                 BBPunfix(r1->batCacheid);
     869           0 :                 throw(MAL, "algebra.projection", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     870             :         }
     871     1712749 :         bn = BATproject2(l, r1, r2);
     872     1712715 :         BBPunfix(l->batCacheid);
     873     1712971 :         BBPunfix(r1->batCacheid);
     874     1712963 :         if (r2)
     875           0 :                 BBPunfix(r2->batCacheid);
     876     1712961 :         if (bn == NULL)
     877           0 :                 throw(MAL, "algebra.projection", GDK_EXCEPTION);
     878     1712961 :         *result = bn->batCacheid;
     879     1712961 :         BBPkeepref(*result);
     880     1712840 :         return MAL_SUCCEED;
     881             : }
     882             : 
     883             : str
     884     1713098 : ALGprojection(bat *result, const bat *lid, const bat *rid)
     885             : {
     886     1713098 :         return ALGprojection2(result, lid, rid, NULL);
     887             : }
     888             : 
     889             : static str
     890       32739 : ALGsort33(bat *result, bat *norder, bat *ngroup, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
     891             : {
     892       32739 :         BAT *bn = NULL, *on = NULL, *gn = NULL;
     893             :         BAT *b = NULL, *o = NULL, *g = NULL;
     894             : 
     895       32739 :         if ((b = BATdescriptor(*bid)) == NULL)
     896           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     897       32739 :         if (order && !is_bat_nil(*order) && (o = BATdescriptor(*order)) == NULL) {
     898           0 :                 BBPunfix(b->batCacheid);
     899           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     900             :         }
     901       32739 :         if (group && !is_bat_nil(*group) && (g = BATdescriptor(*group)) == NULL) {
     902           0 :                 if (o)
     903           0 :                         BBPunfix(o->batCacheid);
     904           0 :                 BBPunfix(b->batCacheid);
     905           0 :                 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     906             :         }
     907       32936 :         if (BATsort(result ? &bn : NULL,
     908             :                                    norder ? &on : NULL,
     909             :                                    ngroup ? &gn : NULL,
     910       32739 :                                 b, o, g, *reverse, *nilslast, *stable) != GDK_SUCCEED) {
     911           0 :                 if (o)
     912           0 :                         BBPunfix(o->batCacheid);
     913           0 :                 if (g)
     914           0 :                         BBPunfix(g->batCacheid);
     915           0 :                 BBPunfix(b->batCacheid);
     916           0 :                 throw(MAL, "algebra.sort", GDK_EXCEPTION);
     917             :         }
     918       32739 :         BBPunfix(b->batCacheid);
     919       32739 :         if (o)
     920       17245 :                 BBPunfix(o->batCacheid);
     921       32739 :         if (g)
     922       17245 :                 BBPunfix(g->batCacheid);
     923       32739 :         if (result)
     924       32739 :                 BBPkeepref(*result = bn->batCacheid);
     925       32739 :         if (norder)
     926       32542 :                 BBPkeepref(*norder = on->batCacheid);
     927       32739 :         if (ngroup)
     928       17488 :                 BBPkeepref(*ngroup = gn->batCacheid);
     929             :         return MAL_SUCCEED;
     930             : }
     931             : 
     932             : static str
     933        9637 : ALGsort32(bat *result, bat *norder, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
     934             : {
     935        9637 :         return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast, stable);
     936             : }
     937             : 
     938             : static str
     939           0 : ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
     940             : {
     941           0 :         return ALGsort33(result, NULL, NULL, bid, order, group, reverse, nilslast, stable);
     942             : }
     943             : 
     944             : static str
     945           0 : ALGsort23(bat *result, bat *norder, bat *ngroup, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
     946             : {
     947           0 :         return ALGsort33(result, norder, ngroup, bid, order, NULL, reverse, nilslast, stable);
     948             : }
     949             : 
     950             : static str
     951           0 : ALGsort22(bat *result, bat *norder, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
     952             : {
     953           0 :         return ALGsort33(result, norder, NULL, bid, order, NULL, reverse, nilslast, stable);
     954             : }
     955             : 
     956             : static str
     957           0 : ALGsort21(bat *result, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
     958             : {
     959           0 :         return ALGsort33(result, NULL, NULL, bid, order, NULL, reverse, nilslast, stable);
     960             : }
     961             : 
     962             : static str
     963        9880 : ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
     964             : {
     965        9880 :         return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast, stable);
     966             : }
     967             : 
     968             : static str
     969        5417 : ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
     970             : {
     971        5417 :         return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast, stable);
     972             : }
     973             : 
     974             : static str
     975         197 : ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
     976             : {
     977         197 :         return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast, stable);
     978             : }
     979             : 
     980             : static str
     981       36423 : ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd, const bit *ignore_nils)
     982             : {
     983             :         BAT *b, *s = NULL;
     984             : 
     985       36423 :         if ((b = BATdescriptor(*bid)) == NULL) {
     986           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     987             :         }
     988       36422 :         if (cnd && !is_bat_nil(*cnd) && (s = BATdescriptor(*cnd)) == NULL) {
     989           0 :                 BBPunfix(b->batCacheid);
     990           0 :                 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     991             :         }
     992       36422 :         if (b->ttype == TYPE_msk || mask_cand(b)) {
     993           4 :                 BATsum(result, TYPE_lng, b, s, *ignore_nils, false, false);
     994             :         } else
     995       36418 :         if (*ignore_nils) {
     996         315 :                         *result = (lng) BATcount_no_nil(b, s);
     997             :         } else {
     998             :                         struct canditer ci;
     999       36103 :                         *result = (lng) canditer_init(&ci, b, s);
    1000             :         }
    1001       36423 :         if (s)
    1002           0 :                 BBPunfix(s->batCacheid);
    1003       36423 :         BBPunfix(b->batCacheid);
    1004       36424 :         return MAL_SUCCEED;
    1005             : }
    1006             : 
    1007             : static str
    1008         315 : ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
    1009             : {
    1010         315 :         return ALGcountCND_nil(result, bid, NULL, ignore_nils);
    1011             : }
    1012             : 
    1013             : static str
    1014           0 : ALGcountCND_bat(lng *result, const bat *bid, const bat *cnd)
    1015             : {
    1016           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit){0});
    1017             : }
    1018             : 
    1019             : static str
    1020       36109 : ALGcount_bat(lng *result, const bat *bid)
    1021             : {
    1022       36109 :         return ALGcountCND_nil(result, bid, NULL, &(bit){0});
    1023             : }
    1024             : 
    1025             : static str
    1026           0 : ALGcountCND_no_nil(lng *result, const bat *bid, const bat *cnd)
    1027             : {
    1028           0 :         return ALGcountCND_nil(result, bid, cnd, &(bit){1});
    1029             : }
    1030             : 
    1031             : static str
    1032           0 : ALGcount_no_nil(lng *result, const bat *bid)
    1033             : {
    1034           0 :         return ALGcountCND_nil(result, bid, NULL, &(bit){1});
    1035             : }
    1036             : 
    1037             : static str
    1038           6 : ALGslice(bat *ret, const bat *bid, const lng *start, const lng *end)
    1039             : {
    1040           6 :         BAT *b, *bn = NULL;
    1041             : 
    1042           6 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1043           0 :                 throw(MAL, "algebra.slice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1044             :         }
    1045           6 :         if (slice(&bn, b, *start, *end) == GDK_SUCCEED) {
    1046           6 :                 *ret = bn->batCacheid;
    1047           6 :                 BBPkeepref(*ret);
    1048           6 :                 BBPunfix(b->batCacheid);
    1049           6 :                 return MAL_SUCCEED;
    1050             :         }
    1051           0 :         BBPunfix(b->batCacheid);
    1052           0 :         throw(MAL, "algebra.slice", GDK_EXCEPTION);
    1053             : }
    1054             : 
    1055             : static str
    1056           1 : ALGslice_int(bat *ret, const bat *bid, const int *start, const int *end)
    1057             : {
    1058           1 :         lng s = *start;
    1059           1 :         lng e = (is_int_nil(*end) ? lng_nil : *end);
    1060             : 
    1061           1 :         return ALGslice(ret, bid, &s, &e);
    1062             : }
    1063             : 
    1064             : static str
    1065           0 : ALGslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1066             : {
    1067           0 :         lng s = *start;
    1068           0 :         lng e = *end;
    1069             : 
    1070           0 :         return ALGslice(ret, bid, &s, &e);
    1071             : }
    1072             : 
    1073             : /* carve out a slice based on the OIDs */
    1074             : /* beware that BATs may have different OID bases */
    1075             : static str
    1076           5 : ALGslice_oid(bat *ret, const bat *bid, const oid *start, const oid *end)
    1077             : {
    1078           5 :         lng s = (lng) (is_oid_nil(*start) ? 0 : (lng) *start);
    1079           5 :         lng e = (is_oid_nil(*end) ? lng_nil : (lng) *end);
    1080             : 
    1081           5 :         return ALGslice(ret, bid, &s, &e) ;
    1082             : }
    1083             : 
    1084             : static str
    1085        1174 : ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
    1086             : {
    1087             :         BAT *b, *bn;
    1088             :         BUN s, e;
    1089             : 
    1090        1174 :         if (*start < 0 || *start > (lng) BUN_MAX ||
    1091        1174 :                 (*end < 0 && !is_lng_nil(*end)) || *end >= (lng) BUN_MAX)
    1092           0 :                 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
    1093        1174 :         if ((b = BBPquickdesc(*bid)) == NULL)
    1094           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1095        1174 :         s = (BUN) *start;
    1096        1174 :         if (s > BATcount(b))
    1097             :                 s = BATcount(b);
    1098        1174 :         e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
    1099             :         if (e > BATcount(b))
    1100             :                 e = BATcount(b);
    1101             :         if (e < s)
    1102             :                 e = s;
    1103        1174 :         bn = BATdense(0, b->hseqbase + s, e - s);
    1104        1174 :         if (bn == NULL)
    1105           0 :                 throw(MAL, "algebra.subslice", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1106        1174 :         *ret = bn->batCacheid;
    1107        1174 :         BBPkeepref(*ret);
    1108        1174 :         return MAL_SUCCEED;
    1109             : }
    1110             : 
    1111             : /*
    1112             :  * BUN Get/Fetch
    1113             :  */
    1114             : 
    1115             : static str
    1116       48150 : doALGfetch(ptr ret, BAT *b, BUN pos)
    1117             : {
    1118       48150 :         assert(pos <= BUN_MAX);
    1119       48150 :         BATiter bi = bat_iterator(b);
    1120       48150 :         if (ATOMextern(b->ttype)) {
    1121        2732 :                 ptr _src = BUNtail(bi,pos);
    1122        2732 :                 size_t _len = ATOMlen(b->ttype, _src);
    1123        2732 :                 ptr _dst = GDKmalloc(_len);
    1124        2732 :                 if( _dst == NULL) {
    1125           0 :                         bat_iterator_end(&bi);
    1126           0 :                         throw(MAL,"doAlgFetch", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1127             :                 }
    1128        2732 :                 memcpy(_dst, _src, _len);
    1129        2732 :                 *(ptr*) ret = _dst;
    1130             :         } else {
    1131       45418 :                 size_t _s = ATOMsize(ATOMtype(b->ttype));
    1132       45418 :                 if (b->ttype == TYPE_void) {
    1133           0 :                         *(oid*) ret = b->tseqbase;
    1134           0 :                         if (!is_oid_nil(b->tseqbase))
    1135           0 :                                 *(oid*)ret += pos;
    1136       45418 :                 } else if (_s == 4) {
    1137       45320 :                         *(int*) ret = ((int*) bi.base)[pos];
    1138          98 :                 } else if (_s == 1) {
    1139           3 :                         *(bte*) ret = ((bte*) bi.base)[pos];
    1140          95 :                 } else if (_s == 2) {
    1141           1 :                         *(sht*) ret = ((sht*) bi.base)[pos];
    1142          94 :                 } else if (_s == 8) {
    1143          89 :                         *(lng*) ret = ((lng*) bi.base)[pos];
    1144             : #ifdef HAVE_HGE
    1145           5 :                 } else if (_s == 16) {
    1146           5 :                         *(hge*) ret = ((hge*) bi.base)[pos];
    1147             : #endif
    1148             :                 } else {
    1149           0 :                         memcpy(ret, (const char *) bi.base + (pos << bi.shift), _s);
    1150             :                 }
    1151             :         }
    1152       48150 :         bat_iterator_end(&bi);
    1153       48150 :         return MAL_SUCCEED;
    1154             : }
    1155             : 
    1156             : static str
    1157       48154 : ALGfetch(ptr ret, const bat *bid, const lng *pos)
    1158             : {
    1159             :         BAT *b;
    1160             :         str msg;
    1161             : 
    1162       48154 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1163           0 :                 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1164             :         }
    1165       48154 :         if (*pos < (lng) 0) {
    1166           0 :                 BBPunfix(b->batCacheid);
    1167           0 :                 throw(MAL, "algebra.fetch", ILLEGAL_ARGUMENT ": row index to fetch must be non negative\n");
    1168             :         }
    1169       48154 :         if (BATcount(b) == 0) {
    1170           4 :                 BBPunfix(b->batCacheid);
    1171           4 :                 throw(MAL, "algebra.fetch", ILLEGAL_ARGUMENT ": cannot fetch a single row from an empty input\n");
    1172             :         }
    1173       48150 :         if (*pos >= (lng) BUNlast(b)) {
    1174           0 :                 BBPunfix(b->batCacheid);
    1175           0 :                 throw(MAL, "algebra.fetch", ILLEGAL_ARGUMENT ": row index to fetch is out of range\n");
    1176             :         }
    1177       48150 :         msg = doALGfetch(ret, b, (BUN) *pos);
    1178       48150 :         BBPunfix(b->batCacheid);
    1179       48150 :         return msg;
    1180             : }
    1181             : 
    1182             : str
    1183       48154 : ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
    1184             : {
    1185       48154 :         lng o = *pos;
    1186             : 
    1187       48154 :         return ALGfetch(ret, bid, &o);
    1188             : }
    1189             : 
    1190             : static str
    1191           0 : ALGexist(bit *ret, const bat *bid, const void *val)
    1192             : {
    1193             :         BAT *b;
    1194             :         BUN q;
    1195             : 
    1196           0 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1197           0 :                 throw(MAL, "algebra.exist", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1198             :         }
    1199           0 :         derefStr(b, val);
    1200           0 :         q = BUNfnd(b, val);
    1201           0 :         *ret = (q != BUN_NONE);
    1202           0 :         BBPunfix(b->batCacheid);
    1203           0 :         return MAL_SUCCEED;
    1204             : }
    1205             : 
    1206             : static str
    1207           9 : ALGfind(oid *ret, const bat *bid, ptr val)
    1208             : {
    1209             :         BAT *b;
    1210             :         BUN q;
    1211             :         str msg= MAL_SUCCEED;
    1212             : 
    1213           9 :         if ((b = BATdescriptor(*bid)) == NULL) {
    1214           0 :                 throw(MAL, "algebra.find", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1215             :         }
    1216           9 :         derefStr(b, val);
    1217           9 :         q = BUNfnd(b, val);
    1218             : 
    1219           9 :         if (q == BUN_NONE){
    1220           3 :                 *ret = oid_nil;
    1221             :         } else
    1222           6 :                 *ret = (oid) q;
    1223           9 :         BBPunfix(b->batCacheid);
    1224           9 :         return msg;
    1225             : }
    1226             : 
    1227             : 
    1228             : static str
    1229      125472 : ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1230             : {
    1231      125472 :         bat *ret = getArgReference_bat(stk, pci, 0);
    1232      125472 :         bat bid = * getArgReference_bat(stk, pci, 1);
    1233      125472 :         const ValRecord *v = &stk->stk[getArg(pci, 2)];
    1234             :         BAT *b, *bn;
    1235             : 
    1236             :         (void) cntxt;
    1237             :         (void) mb;
    1238      125472 :         if( isaBatType(getArgType(mb,pci,2)) )
    1239           0 :                 throw(MAL,"algebra.project","Scalar value expected");
    1240      125472 :         if ((b = BBPquickdesc(bid)) == NULL)
    1241           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1242      125471 :         bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
    1243      125468 :         if (bn == NULL) {
    1244           0 :                 *ret = bat_nil;
    1245           0 :                 throw(MAL, "algebra.project", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1246             :         }
    1247      125468 :         BBPkeepref(*ret= bn->batCacheid);
    1248      125468 :         return MAL_SUCCEED;
    1249             : }
    1250             : 
    1251             : 
    1252             : static str
    1253           0 : ALGreuse(bat *ret, const bat *bid)
    1254             : {
    1255             :         BAT *b,*bn;
    1256           0 :         if ((b = BATdescriptor(*bid)) == NULL)
    1257           0 :                 throw(MAL, "algebra.reuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1258             : 
    1259           0 :         if( !b->batTransient || b->batRestricted != BAT_WRITE){
    1260           0 :                 if( ATOMvarsized(b->ttype) ){
    1261           0 :                         bn= BATwcopy(b);
    1262           0 :                         if (bn == NULL) {
    1263           0 :                                 BBPunfix(b->batCacheid);
    1264           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1265             :                         }
    1266             :                 } else {
    1267           0 :                         bn = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
    1268           0 :                         if (bn == NULL) {
    1269           0 :                                 BBPunfix(b->batCacheid);
    1270           0 :                                 throw(MAL, "algebra.reuse", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1271             :                         }
    1272           0 :                         BATsetcount(bn,BATcount(b));
    1273           0 :                         bn->tsorted = false;
    1274           0 :                         bn->trevsorted = false;
    1275           0 :                         BATkey(bn, false);
    1276             :                 }
    1277           0 :                 BBPkeepref(*ret= bn->batCacheid);
    1278           0 :                 BBPunfix(b->batCacheid);
    1279             :         } else
    1280           0 :                 BBPkeepref(*ret = *bid);
    1281             :         return MAL_SUCCEED;
    1282             : }
    1283             : 
    1284             : /*
    1285             :  * BAT standard deviation
    1286             :  */
    1287             : static str
    1288           7 : ALGstdev(dbl *res, const bat *bid)
    1289             : {
    1290             :         BAT *b;
    1291             :         dbl stdev;
    1292             : 
    1293           7 :         if ((b = BATdescriptor(*bid)) == NULL)
    1294           0 :                 throw(MAL, "aggr.stdev", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1295           7 :         stdev = BATcalcstdev_sample(NULL, b);
    1296           7 :         BBPunfix(b->batCacheid);
    1297           7 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1298           0 :                 throw(MAL, "aggr.stdev", GDK_EXCEPTION);
    1299           7 :         *res = stdev;
    1300           7 :         return MAL_SUCCEED;
    1301             : }
    1302             : 
    1303             : static str
    1304          13 : ALGstdevp(dbl *res, const bat *bid)
    1305             : {
    1306             :         BAT *b;
    1307             :         dbl stdev;
    1308             : 
    1309          13 :         if ((b = BATdescriptor(*bid)) == NULL)
    1310           0 :                 throw(MAL, "aggr.stdevp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1311          13 :         stdev = BATcalcstdev_population(NULL, b);
    1312          13 :         BBPunfix(b->batCacheid);
    1313          13 :         if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
    1314           1 :                 throw(MAL, "aggr.stdevp", GDK_EXCEPTION);
    1315          12 :         *res = stdev;
    1316          12 :         return MAL_SUCCEED;
    1317             : }
    1318             : 
    1319             : /*
    1320             :  * BAT variance
    1321             :  */
    1322             : static str
    1323           2 : ALGvariance(dbl *res, const bat *bid)
    1324             : {
    1325             :         BAT *b;
    1326             :         dbl variance;
    1327             : 
    1328           2 :         if ((b = BATdescriptor(*bid)) == NULL)
    1329           0 :                 throw(MAL, "aggr.variance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1330           2 :         variance = BATcalcvariance_sample(NULL, b);
    1331           2 :         BBPunfix(b->batCacheid);
    1332           2 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1333           0 :                 throw(MAL, "aggr.variance", GDK_EXCEPTION);
    1334           2 :         *res = variance;
    1335           2 :         return MAL_SUCCEED;
    1336             : }
    1337             : 
    1338             : static str
    1339           4 : ALGvariancep(dbl *res, const bat *bid)
    1340             : {
    1341             :         BAT *b;
    1342             :         dbl variance;
    1343             : 
    1344           4 :         if ((b = BATdescriptor(*bid)) == NULL)
    1345           0 :                 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1346           4 :         variance = BATcalcvariance_population(NULL, b);
    1347           4 :         BBPunfix(b->batCacheid);
    1348           4 :         if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
    1349           1 :                 throw(MAL, "aggr.variancep", GDK_EXCEPTION);
    1350           3 :         *res = variance;
    1351           3 :         return MAL_SUCCEED;
    1352             : }
    1353             : 
    1354             : /*
    1355             :  * BAT covariance
    1356             :  */
    1357             : static str
    1358           5 : ALGcovariance(dbl *res, const bat *bid1, const bat *bid2)
    1359             : {
    1360             :         BAT *b1, *b2;
    1361             :         dbl covariance;
    1362             : 
    1363           5 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1364           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1365           5 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1366           0 :                 BBPunfix(b1->batCacheid);
    1367           0 :                 throw(MAL, "aggr.covariance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1368             :         }
    1369             : 
    1370           5 :         covariance = BATcalccovariance_sample(b1, b2);
    1371           5 :         BBPunfix(b1->batCacheid);
    1372           5 :         BBPunfix(b2->batCacheid);
    1373           5 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1374           0 :                 throw(MAL, "aggr.covariance", GDK_EXCEPTION);
    1375           5 :         *res = covariance;
    1376           5 :         return MAL_SUCCEED;
    1377             : }
    1378             : 
    1379             : static str
    1380           8 : ALGcovariancep(dbl *res, const bat *bid1, const bat *bid2)
    1381             : {
    1382             :         BAT *b1, *b2;
    1383             :         dbl covariance;
    1384             : 
    1385           8 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1386           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1387           8 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1388           0 :                 BBPunfix(b1->batCacheid);
    1389           0 :                 throw(MAL, "aggr.covariancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1390             :         }
    1391             : 
    1392           8 :         covariance = BATcalccovariance_population(b1, b2);
    1393           8 :         BBPunfix(b1->batCacheid);
    1394           8 :         BBPunfix(b2->batCacheid);
    1395           8 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1396           1 :                 throw(MAL, "aggr.covariancep", GDK_EXCEPTION);
    1397           7 :         *res = covariance;
    1398           7 :         return MAL_SUCCEED;
    1399             : }
    1400             : 
    1401             : /*
    1402             :  * BAT correlation
    1403             :  */
    1404             : static str
    1405          19 : ALGcorr(dbl *res, const bat *bid1, const bat *bid2)
    1406             : {
    1407             :         BAT *b1, *b2;
    1408             :         dbl covariance;
    1409             : 
    1410          19 :         if ((b1 = BATdescriptor(*bid1)) == NULL)
    1411           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1412          19 :         if ((b2 = BATdescriptor(*bid2)) == NULL) {
    1413           0 :                 BBPunfix(b1->batCacheid);
    1414           0 :                 throw(MAL, "aggr.corr", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1415             :         }
    1416             : 
    1417          19 :         covariance = BATcalccorrelation(b1, b2);
    1418          19 :         BBPunfix(b1->batCacheid);
    1419          19 :         BBPunfix(b2->batCacheid);
    1420          19 :         if (is_dbl_nil(covariance) && GDKerrbuf && GDKerrbuf[0])
    1421           1 :                 throw(MAL, "aggr.corr", GDK_EXCEPTION);
    1422          18 :         *res = covariance;
    1423          18 :         return MAL_SUCCEED;
    1424             : }
    1425             : 
    1426             : #include "mel.h"
    1427             : mel_func algebra_init_funcs[] = {
    1428             :  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))),
    1429             :  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))),
    1430             :  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))),
    1431             :  pattern("algebra", "project", ALGprojecttail, false, "Fill the tail with a constant", args(1,3, batargany("",3),batargany("b",1),argany("v",3))),
    1432             :  command("algebra", "projection", ALGprojection, false, "Project left input onto right input.", args(1,3, batargany("",3),batarg("left",oid),batargany("right",3))),
    1433             :  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))),
    1434             :  command("algebra", "copy", ALGcopy, false, "Returns physical copy of a BAT.", args(1,2, batargany("",1),batargany("b",1))),
    1435             :  command("algebra", "exist", ALGexist, false, "Returns whether 'val' occurs in b.", args(1,3, arg("",bit),batargany("b",1),argany("val",1))),
    1436             :  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))),
    1437             :  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))),
    1438             :  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))),
    1439             :  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))),
    1440             :  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))),
    1441             :  command("algebra", "selectNotNil", ALGselectNotNil, false, "Select all not-nil values", args(1,2, batargany("",2),batargany("b",2))),
    1442             :  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))),
    1443             :  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))),
    1444             :  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))),
    1445             :  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))),
    1446             :  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))),
    1447             :  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))),
    1448             :  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))),
    1449             :  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))),
    1450             :  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))),
    1451             :  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))),
    1452             :  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))),
    1453             :  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))),
    1454             :  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))),
    1455             :  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))),
    1456             :  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))),
    1457             :  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))),
    1458             :  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))),
    1459             :  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))),
    1460             :  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))),
    1461             :  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))),
    1462             :  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))),
    1463             :  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))),
    1464             :  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))),
    1465             :  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))),
    1466             :  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))),
    1467             :  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))),
    1468             :  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))),
    1469             :  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))),
    1470             :  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))),
    1471             :  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))),
    1472             :  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))),
    1473             :  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))),
    1474             :  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))),
    1475             :  command("algebra", "slice", ALGslice, 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))),
    1476             :  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))),
    1477             :  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))),
    1478             :  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))),
    1479             :  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))),
    1480             :  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))),
    1481             :  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))),
    1482             :  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))),
    1483             :  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))),
    1484             :  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))),
    1485             :  command("aggr", "cardinality", ALGcard, false, "Return the cardinality of the BAT tail values.", args(1,2, arg("",lng),batargany("b",2))),
    1486             :  command("aggr", "min", ALGminany, false, "Return the lowest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1487             :  command("aggr", "min", ALGminany_skipnil, false, "Return the lowest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1488             :  command("aggr", "max", ALGmaxany, false, "Return the highest tail value or nil.", args(1,2, argany("",2),batargany("b",2))),
    1489             :  command("aggr", "max", ALGmaxany_skipnil, false, "Return the highest tail value or nil.", args(1,3, argany("",2),batargany("b",2),arg("skipnil",bit))),
    1490             :  command("aggr", "stdev", ALGstdev, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1491             :  command("aggr", "stdevp", ALGstdevp, false, "Gives the standard deviation of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1492             :  command("aggr", "variance", ALGvariance, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1493             :  command("aggr", "variancep", ALGvariancep, false, "Gives the variance of all tail values", args(1,2, arg("",dbl),batargany("b",2))),
    1494             :  command("aggr", "covariance", ALGcovariance, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1495             :  command("aggr", "covariancep", ALGcovariancep, false, "Gives the covariance of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1496             :  command("aggr", "corr", ALGcorr, false, "Gives the correlation of all tail values", args(1,3, arg("",dbl),batargany("b1",2),batargany("b2",2))),
    1497             :  // sql
    1498             :  command("aggr", "exist", ALGexist, false, "", args(1,3, arg("",bit),batargany("b",2),argany("h",1))),
    1499             :  { .imp=NULL }
    1500             : };
    1501             : #include "mal_import.h"
    1502             : #ifdef _MSC_VER
    1503             : #undef read
    1504             : #pragma section(".CRT$XCU",read)
    1505             : #endif
    1506         259 : LIB_STARTUP_FUNC(init_algebra_mal)
    1507         259 : { mal_module("algebra", NULL, algebra_init_funcs); }

Generated by: LCOV version 1.14