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 - 2019 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#include <math.h>
43
44/*
45 * Command Implementations in C
46 * This module contains just a wrapper implementations; since all described
47 * operations are part of the GDK kernel.
48 *
49 * BAT sum operation
50 * The sum aggregate only works for int and float fields.
51 * The routines below assumes that the caller knows what type
52 * is large enough to prevent overflow.
53 */
54
55static gdk_return
56CMDgen_group(BAT **result, BAT *gids, BAT *cnts )
57{
58 lng j, gcnt = BATcount(gids);
59 BAT *r = COLnew(0, TYPE_oid, BATcount(gids)*2, TRANSIENT);
60
61 if (r == NULL)
62 return GDK_FAIL;
63 if (gids->ttype == TYPE_void) {
64 oid id = gids->tseqbase;
65 lng *cnt = (lng*)Tloc(cnts, 0);
66 for(j = 0; j < gcnt; j++) {
67 lng i, sz = cnt[j];
68 for(i = 0; i < sz; i++) {
69 if (BUNappend(r, &id, false) != GDK_SUCCEED) {
70 BBPreclaim(r);
71 return GDK_FAIL;
72 }
73 }
74 id++;
75 }
76 } else {
77 oid *id = (oid*)Tloc(gids, 0);
78 lng *cnt = (lng*)Tloc(cnts, 0);
79 for(j = 0; j < gcnt; j++) {
80 lng i, sz = cnt[j];
81 for(i = 0; i < sz; i++) {
82 if (BUNappend(r, id, false) != GDK_SUCCEED) {
83 BBPreclaim(r);
84 return GDK_FAIL;
85 }
86 }
87 id++;
88 }
89 }
90 r -> tkey = false;
91 r -> tseqbase = oid_nil;
92 r -> tsorted = BATtordered(gids);
93 r -> trevsorted = BATtrevordered(gids);
94 r -> tnonil = gids->tnonil;
95 *result = r;
96 return GDK_SUCCEED;
97}
98
99
100static gdk_return
101slice(BAT **retval, BAT *b, lng start, lng end)
102{
103 /* the internal BATslice requires exclusive end */
104 if (start < 0) {
105 GDKerror("CMDslice: start position of slice should >= 0\n");
106 return GDK_FAIL;
107 }
108 if (is_lng_nil(end))
109 end = BATcount(b);
110 if (start > (lng) BUN_MAX || end >= (lng) BUN_MAX) {
111 GDKerror("CMDslice: argument out of range\n");
112 return GDK_FAIL;
113 }
114
115 return (*retval = BATslice(b, (BUN) start, (BUN) end + 1)) ? GDK_SUCCEED : GDK_FAIL;
116}
117/*
118 *
119 * The remainder of this file contains the wrapper around the V4 code base
120 * The BAT identifiers passed through this module may indicate
121 * that the 'reverse' view applies. This should be taken into
122 * account while resolving them.
123 *
124 * The sum aggregate only works for int and float fields.
125 * The routines below assumes that the caller knows what type
126 * is large enough to prevent overflow.
127 */
128
129str
130ALGminany_skipnil(ptr result, const bat *bid, const bit *skipnil)
131{
132 BAT *b;
133 ptr p;
134 str msg = MAL_SUCCEED;
135
136 if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
137 throw(MAL, "algebra.min", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
138
139 if (!ATOMlinear(b->ttype)) {
140 msg = createException(MAL, "algebra.min",
141 "atom '%s' cannot be ordered linearly",
142 ATOMname(b->ttype));
143 } else {
144 if (ATOMextern(b->ttype)) {
145 * (ptr *) result = p = BATmin_skipnil(b, NULL, *skipnil);
146 } else {
147 p = BATmin_skipnil(b, result, *skipnil);
148 if ( p != result )
149 msg = createException(MAL, "algebra.min", SQLSTATE(HY002) "INTERNAL ERROR");
150 }
151 if (msg == MAL_SUCCEED && p == NULL)
152 msg = createException(MAL, "algebra.min", GDK_EXCEPTION);
153 }
154 BBPunfix(b->batCacheid);
155 return msg;
156}
157
158str
159ALGminany(ptr result, const bat *bid)
160{
161 bit skipnil = TRUE;
162 return ALGminany_skipnil(result, bid, &skipnil);
163}
164
165str
166ALGmaxany_skipnil(ptr result, const bat *bid, const bit *skipnil)
167{
168 BAT *b;
169 ptr p;
170 str msg = MAL_SUCCEED;
171
172 if (result == NULL || (b = BATdescriptor(*bid)) == NULL)
173 throw(MAL, "algebra.max", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
174
175 if (!ATOMlinear(b->ttype)) {
176 msg = createException(MAL, "algebra.max",
177 "atom '%s' cannot be ordered linearly",
178 ATOMname(b->ttype));
179 } else {
180 if (ATOMextern(b->ttype)) {
181 * (ptr *) result = p = BATmax_skipnil(b, NULL, *skipnil);
182 } else {
183 p = BATmax_skipnil(b, result, *skipnil);
184 if ( p != result )
185 msg = createException(MAL, "algebra.max", SQLSTATE(HY002) "INTERNAL ERROR");
186 }
187 if ( msg == MAL_SUCCEED && p == NULL)
188 msg = createException(MAL, "algebra.max", GDK_EXCEPTION);
189 }
190 BBPunfix(b->batCacheid);
191 return msg;
192}
193
194str
195ALGmaxany(ptr result, const bat *bid)
196{
197 bit skipnil = TRUE;
198 return ALGmaxany_skipnil(result, bid, &skipnil);
199}
200
201str
202ALGgroupby(bat *res, const bat *gids, const bat *cnts)
203{
204 BAT *bn, *g, *c;
205
206 g = BATdescriptor(*gids);
207 if (g == NULL) {
208 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
209 }
210 c = BATdescriptor(*cnts);
211 if (c == NULL) {
212 BBPunfix(g->batCacheid);
213 throw(MAL, "algebra.groupby", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
214 }
215 if( CMDgen_group(&bn, g, c) != GDK_SUCCEED){
216 BBPunfix(g->batCacheid);
217 BBPunfix(c->batCacheid);
218 throw(MAL, "algebra.groupby",GDK_EXCEPTION);
219 }
220 *res = bn->batCacheid;
221 BBPkeepref(bn->batCacheid);
222 BBPunfix(g->batCacheid);
223 BBPunfix(c->batCacheid);
224 return MAL_SUCCEED;
225}
226
227str
228ALGcard(lng *result, const bat *bid)
229{
230 BAT *b, *en;
231
232 if ((b = BATdescriptor(*bid)) == NULL) {
233 throw(MAL, "algebra.card", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
234 }
235 en = BATunique(b, NULL);
236 BBPunfix(b->batCacheid);
237 if (en == NULL) {
238 throw(MAL, "algebra.card", GDK_EXCEPTION);
239 }
240 *result = BATcount(en);
241 BBPunfix(en->batCacheid);
242 return MAL_SUCCEED;
243}
244
245str
246ALGselect2(bat *result, const bat *bid, const bat *sid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti)
247{
248 BAT *b, *s = NULL, *bn;
249 const void *nilptr;
250
251 if ((*li != 0 && *li != 1) ||
252 (*hi != 0 && *hi != 1) ||
253 (*anti != 0 && *anti != 1)) {
254 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
255 }
256 if ((b = BATdescriptor(*bid)) == NULL) {
257 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
258 }
259 if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
260 BBPunfix(b->batCacheid);
261 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
262 }
263 derefStr(b, low);
264 derefStr(b, high);
265 nilptr = ATOMnilptr(b->ttype);
266 if (*li == 1 && *hi == 1 &&
267 ATOMcmp(b->ttype, low, nilptr) == 0 &&
268 ATOMcmp(b->ttype, high, nilptr) == 0) {
269 /* special case: equi-select for NIL */
270 high = NULL;
271 }
272 bn = BATselect(b, s, low, high, *li, *hi, *anti);
273 BBPunfix(b->batCacheid);
274 if (s)
275 BBPunfix(s->batCacheid);
276 if (bn == NULL)
277 throw(MAL, "algebra.select", GDK_EXCEPTION);
278 *result = bn->batCacheid;
279 BBPkeepref(bn->batCacheid);
280 return MAL_SUCCEED;
281}
282
283str
284ALGselect2nil(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)
285{
286 BAT *b, *s = NULL, *bn;
287 const void *nilptr;
288
289 if (!*unknown)
290 return ALGselect2(result, bid, sid, low, high, li, hi, anti);
291
292 if ((*li != 0 && *li != 1) ||
293 (*hi != 0 && *hi != 1) ||
294 (*anti != 0 && *anti != 1)) {
295 throw(MAL, "algebra.select", ILLEGAL_ARGUMENT);
296 }
297 if ((b = BATdescriptor(*bid)) == NULL) {
298 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
299 }
300 if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
301 BBPunfix(b->batCacheid);
302 throw(MAL, "algebra.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
303 }
304 derefStr(b, low);
305 derefStr(b, high);
306 /* here we don't need open ended parts with nil */
307 nilptr = ATOMnilptr(b->ttype);
308 if (*li == 1 && ATOMcmp(b->ttype, low, nilptr) == 0)
309 low = high;
310 else if (*hi == 1 && ATOMcmp(b->ttype, high, nilptr) == 0)
311 high = low;
312 bn = BATselect(b, s, low, high, *li, *hi, *anti);
313 BBPunfix(b->batCacheid);
314 if (s)
315 BBPunfix(s->batCacheid);
316 if (bn == NULL)
317 throw(MAL, "algebra.select", GDK_EXCEPTION);
318 *result = bn->batCacheid;
319 BBPkeepref(bn->batCacheid);
320 return MAL_SUCCEED;
321}
322
323str
324ALGselect1(bat *result, const bat *bid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti)
325{
326 return ALGselect2(result, bid, NULL, low, high, li, hi, anti);
327}
328
329str
330ALGselect1nil(bat *result, const bat *bid, const void *low, const void *high, const bit *li, const bit *hi, const bit *anti, const bit *unknown)
331{
332 return ALGselect2nil(result, bid, NULL, low, high, li, hi, anti, unknown);
333}
334
335str
336ALGthetaselect2(bat *result, const bat *bid, const bat *sid, const void *val, const char **op)
337{
338 BAT *b, *s = NULL, *bn;
339
340 if ((b = BATdescriptor(*bid)) == NULL) {
341 throw(MAL, "algebra.thetaselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
342 }
343 if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
344 BBPunfix(b->batCacheid);
345 throw(MAL, "algebra.thetaselect", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
346 }
347 derefStr(b, val);
348 bn = BATthetaselect(b, s, val, *op);
349 BBPunfix(b->batCacheid);
350 if (s)
351 BBPunfix(s->batCacheid);
352 if (bn == NULL)
353 throw(MAL, "algebra.select", GDK_EXCEPTION);
354 *result = bn->batCacheid;
355 BBPkeepref(bn->batCacheid);
356 return MAL_SUCCEED;
357}
358
359str
360ALGthetaselect1(bat *result, const bat *bid, const void *val, const char **op)
361{
362 return ALGthetaselect2(result, bid, NULL, val, op);
363}
364
365str
366ALGselectNotNil(bat *result, const bat *bid)
367{
368 BAT *b, *bn = NULL;
369
370 if ((b = BATdescriptor(*bid)) == NULL)
371 throw(MAL, "algebra.selectNotNil", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
372
373 if( BATcount_no_nil(b) != BATcount(b) ){
374 BAT *s = NULL;
375
376 s = BATselect(b, s, ATOMnilptr(b->ttype), NULL, true, true, true);
377 if (s) {
378 bn = BATproject(s, b);
379 BBPunfix(s->batCacheid);
380 }
381 BBPunfix(b->batCacheid);
382 if (bn) {
383 *result = bn->batCacheid;
384 BBPkeepref(*result);
385 return MAL_SUCCEED;
386 }
387 throw(MAL, "algebra.selectNotNil", GDK_EXCEPTION);
388 }
389 /* just pass on the result */
390 *result = b->batCacheid;
391 BBPkeepref(*result);
392 return MAL_SUCCEED;
393}
394
395static str
396do_join(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *r2id,
397 const bat *slid, const bat *srid,
398 int op, const void *c1, const void *c2, bool li, bool hi,
399 bool anti, bool symmetric, /* these two only for rangejoin */
400 const bit *nil_matches, const bit *not_in, const lng *estimate,
401 gdk_return (*joinfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
402 bool, BUN),
403 gdk_return (*thetafunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
404 int, bool, BUN),
405 gdk_return (*bandfunc)(BAT **, BAT **, BAT *, BAT *, BAT *, BAT *,
406 const void *, const void *, bool, bool, BUN),
407 gdk_return (*rangefunc)(BAT **, BAT **, BAT *, BAT *, BAT *,
408 BAT *, BAT *, bool, bool, bool, bool, BUN),
409 BAT *(*difffunc)(BAT *, BAT *, BAT *, BAT *, bool, bool, BUN),
410 BAT *(*interfunc)(BAT *, BAT *, BAT *, BAT *, bool, BUN),
411 const char *funcname)
412{
413 BAT *left = NULL, *right = NULL, *right2 = NULL;
414 BAT *candleft = NULL, *candright = NULL;
415 BAT *result1, *result2;
416 BUN est;
417 const char *err = RUNTIME_OBJECT_MISSING;
418
419 assert(r2id == NULL || rangefunc != NULL);
420
421 if ((left = BATdescriptor(*lid)) == NULL)
422 goto fail;
423 if ((right = BATdescriptor(*rid)) == NULL)
424 goto fail;
425 if (slid && !is_bat_nil(*slid) && (candleft = BATdescriptor(*slid)) == NULL)
426 goto fail;
427 if (srid && !is_bat_nil(*srid) && (candright = BATdescriptor(*srid)) == NULL)
428 goto fail;
429 if (estimate == NULL || *estimate < 0 || is_lng_nil(*estimate) || *estimate > (lng) BUN_MAX)
430 est = BUN_NONE;
431 else
432 est = (BUN) *estimate;
433
434 err = NULL; /* most likely error now is GDK_EXCEPTION */
435
436 if (thetafunc) {
437 assert(joinfunc == NULL);
438 assert(bandfunc == NULL);
439 assert(rangefunc == NULL);
440 assert(difffunc == NULL);
441 assert(interfunc == NULL);
442 if ((*thetafunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, op, *nil_matches, est) != GDK_SUCCEED)
443 goto fail;
444 } else if (joinfunc) {
445 assert(bandfunc == NULL);
446 assert(rangefunc == NULL);
447 assert(difffunc == NULL);
448 assert(interfunc == NULL);
449 result2 = NULL;
450 if ((*joinfunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, *nil_matches, est) != GDK_SUCCEED)
451 goto fail;
452 } else if (bandfunc) {
453 assert(rangefunc == NULL);
454 assert(difffunc == NULL);
455 assert(interfunc == NULL);
456 if ((*bandfunc)(&result1, r2 ? &result2 : NULL, left, right, candleft, candright, c1, c2, li, hi, est) != GDK_SUCCEED)
457 goto fail;
458 } else if (rangefunc) {
459 assert(difffunc == NULL);
460 assert(interfunc == NULL);
461 if ((right2 = BATdescriptor(*r2id)) == NULL) {
462 err = SQLSTATE(HY002) RUNTIME_OBJECT_MISSING;
463 goto fail;
464 }
465 if ((*rangefunc)(&result1, r2 ? &result2 : NULL, left, right, right2, candleft, candright, li, hi, anti, symmetric, est) != GDK_SUCCEED)
466 goto fail;
467 BBPunfix(right2->batCacheid);
468 } else if (difffunc) {
469 assert(r2 == NULL);
470 assert(interfunc == NULL);
471 if ((result1 = (*difffunc)(left, right, candleft, candright, *nil_matches, *not_in, est)) == NULL)
472 goto fail;
473 result2 = NULL;
474 } else {
475 assert(r2 == NULL);
476 if ((result1 = (*interfunc)(left, right, candleft, candright, *nil_matches, est)) == NULL)
477 goto fail;
478 result2 = NULL;
479 }
480 *r1 = result1->batCacheid;
481 BBPkeepref(*r1);
482 if (r2) {
483 *r2 = result2->batCacheid;
484 BBPkeepref(*r2);
485 }
486 BBPunfix(left->batCacheid);
487 BBPunfix(right->batCacheid);
488 if (candleft)
489 BBPunfix(candleft->batCacheid);
490 if (candright)
491 BBPunfix(candright->batCacheid);
492 return MAL_SUCCEED;
493
494 fail:
495 if (left)
496 BBPunfix(left->batCacheid);
497 if (right)
498 BBPunfix(right->batCacheid);
499 if (right2)
500 BBPunfix(right2->batCacheid);
501 if (candleft)
502 BBPunfix(candleft->batCacheid);
503 if (candright)
504 BBPunfix(candright->batCacheid);
505 if (err == NULL)
506 throw(MAL, funcname, GDK_EXCEPTION);
507 throw(MAL, funcname, "%s", err);
508}
509
510str
511ALGjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
512 const bit *nil_matches, const lng *estimate)
513{
514 return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
515 false, false, false, false, nil_matches, NULL, estimate,
516 BATjoin, NULL, NULL, NULL, NULL, NULL, "algebra.join");
517}
518
519str
520ALGjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
521 const bit *nil_matches, const lng *estimate)
522{
523 return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
524 false, false, false, false, nil_matches, NULL, estimate,
525 BATjoin, NULL, NULL, NULL, NULL, NULL, "algebra.join");
526}
527
528str
529ALGleftjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
530 const bit *nil_matches, const lng *estimate)
531{
532 return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
533 false, false, false, false, nil_matches, NULL, estimate,
534 BATleftjoin, NULL, NULL, NULL, NULL, NULL, "algebra.leftjoin");
535}
536
537str
538ALGleftjoin1(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
539 const bit *nil_matches, const lng *estimate)
540{
541 return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
542 false, false, false, false, nil_matches, NULL, estimate,
543 BATleftjoin, NULL, NULL, NULL, NULL, NULL, "algebra.leftjoin");
544}
545
546str
547ALGouterjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
548 const bit *nil_matches, const lng *estimate)
549{
550 return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
551 false, false, false, false, nil_matches, NULL, estimate,
552 BATouterjoin, NULL, NULL, NULL, NULL, NULL, "algebra.outerjoin");
553}
554
555str
556ALGsemijoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
557 const bit *nil_matches, const lng *estimate)
558{
559 return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, NULL, NULL,
560 false, false, false, false, nil_matches, NULL, estimate,
561 BATsemijoin, NULL, NULL, NULL, NULL, NULL, "algebra.semijoin");
562}
563
564str
565ALGthetajoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
566 const int *op, const bit *nil_matches, const lng *estimate)
567{
568 return do_join(r1, r2, lid, rid, NULL, slid, srid, *op, NULL, NULL,
569 false, false, false, false, nil_matches, NULL, estimate,
570 NULL, BATthetajoin, NULL, NULL, NULL, NULL, "algebra.thetajoin");
571}
572
573str
574ALGbandjoin(bat *r1, bat *r2, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
575 const void *c1, const void *c2, const bit *li, const bit *hi,
576 const lng *estimate)
577{
578 return do_join(r1, r2, lid, rid, NULL, slid, srid, 0, c1, c2,
579 *li, *hi, false, false, NULL, NULL, estimate,
580 NULL, NULL, BATbandjoin, NULL, NULL, NULL, "algebra.bandjoin");
581}
582
583str
584ALGrangejoin(bat *r1, bat *r2, const bat *lid, const bat *rlid, const bat *rhid, const bat *slid, const bat *srid, const bit *li, const bit *hi, const bit *anti, const bit *symmetric, const lng *estimate)
585{
586 return do_join(r1, r2, lid, rlid, rhid, slid, srid, 0, NULL, NULL,
587 *li, *hi, *anti, *symmetric, NULL, NULL, estimate,
588 NULL, NULL, NULL, BATrangejoin, NULL, NULL, "algebra.rangejoin");
589}
590
591str
592ALGdifference(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
593 const bit *nil_matches, const bit *not_in, const lng *estimate)
594{
595 return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
596 false, false, false, false, nil_matches, not_in, estimate,
597 NULL, NULL, NULL, NULL, BATdiff, NULL, "algebra.difference");
598}
599
600str
601ALGintersect(bat *r1, const bat *lid, const bat *rid, const bat *slid, const bat *srid,
602 const bit *nil_matches, const lng *estimate)
603{
604 return do_join(r1, NULL, lid, rid, NULL, slid, srid, 0, NULL, NULL,
605 false, false, false, false, nil_matches, NULL, estimate,
606 NULL, NULL, NULL, NULL, NULL, BATintersect, "algebra.intersect");
607}
608
609/* algebra.firstn(b:bat[:any],
610 * [ s:bat[:oid],
611 * [ g:bat[:oid], ] ]
612 * n:lng,
613 * asc:bit,
614 * nilslast:bit,
615 * distinct:bit)
616 * returns :bat[:oid] [ , :bat[:oid] ]
617 */
618str
619ALGfirstn(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
620{
621 bat *ret1, *ret2 = NULL;
622 bat bid, sid, gid;
623 BAT *b, *s = NULL, *g = NULL;
624 BAT *bn, *gn;
625 lng n;
626 bit asc, nilslast, distinct;
627 gdk_return rc;
628
629 (void) cntxt;
630 (void) mb;
631
632 assert(pci->retc == 1 || pci->retc == 2);
633 assert(pci->argc - pci->retc >= 5 && pci->argc - pci->retc <= 7);
634
635 n = * getArgReference_lng(stk, pci, pci->argc - 4);
636 if (n < 0 || (lng) n >= (lng) BUN_MAX)
637 throw(MAL, "algebra.firstn", ILLEGAL_ARGUMENT);
638 ret1 = getArgReference_bat(stk, pci, 0);
639 if (pci->retc == 2)
640 ret2 = getArgReference_bat(stk, pci, 1);
641 bid = *getArgReference_bat(stk, pci, pci->retc);
642 if ((b = BATdescriptor(bid)) == NULL)
643 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
644 if (pci->argc - pci->retc > 5) {
645 sid = *getArgReference_bat(stk, pci, pci->retc + 1);
646 if ((s = BATdescriptor(sid)) == NULL) {
647 BBPunfix(bid);
648 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
649 }
650 if (pci->argc - pci->retc > 6) {
651 gid = *getArgReference_bat(stk, pci, pci->retc + 2);
652 if ((g = BATdescriptor(gid)) == NULL) {
653 BBPunfix(bid);
654 BBPunfix(sid);
655 throw(MAL, "algebra.firstn", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
656 }
657 }
658 }
659 asc = * getArgReference_bit(stk, pci, pci->argc - 3);
660 nilslast = * getArgReference_bit(stk, pci, pci->argc - 2);
661 distinct = * getArgReference_bit(stk, pci, pci->argc - 1);
662 rc = BATfirstn(&bn, ret2 ? &gn : NULL, b, s, g, (BUN) n, asc, nilslast, distinct);
663 BBPunfix(b->batCacheid);
664 if (s)
665 BBPunfix(s->batCacheid);
666 if (g)
667 BBPunfix(g->batCacheid);
668 if (rc != GDK_SUCCEED)
669 throw(MAL, "algebra.firstn", SQLSTATE(HY001) MAL_MALLOC_FAIL);
670 BBPkeepref(*ret1 = bn->batCacheid);
671 if (ret2)
672 BBPkeepref(*ret2 = gn->batCacheid);
673 return MAL_SUCCEED;
674}
675
676static str
677ALGunary(bat *result, const bat *bid, BAT *(*func)(BAT *), const char *name)
678{
679 BAT *b,*bn;
680
681 if ((b= BATdescriptor(*bid)) == NULL) {
682 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
683 }
684 bn = (*func)(b);
685 BBPunfix(b->batCacheid);
686 if (bn == NULL)
687 throw(MAL, name, GDK_EXCEPTION);
688 *result = bn->batCacheid;
689 BBPkeepref(*result);
690 return MAL_SUCCEED;
691}
692
693static str
694ALGbinary(bat *result, const bat *lid, const bat *rid, BAT *(*func)(BAT *, BAT *), const char *name)
695{
696 BAT *left, *right,*bn= NULL;
697
698 if ((left = BATdescriptor(*lid)) == NULL) {
699 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
700 }
701 if ((right = BATdescriptor(*rid)) == NULL) {
702 BBPunfix(left->batCacheid);
703 throw(MAL, name, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
704 }
705 bn = (*func)(left, right);
706 BBPunfix(left->batCacheid);
707 BBPunfix(right->batCacheid);
708 if (bn == NULL)
709 throw(MAL, name, GDK_EXCEPTION);
710 *result = bn->batCacheid;
711 BBPkeepref(*result);
712 return MAL_SUCCEED;
713}
714
715static BAT *
716BATwcopy(BAT *b)
717{
718 return COLcopy(b, b->ttype, true, TRANSIENT);
719}
720
721str
722ALGcopy(bat *result, const bat *bid)
723{
724 return ALGunary(result, bid, BATwcopy, "algebra.copy");
725}
726
727str
728ALGunique2(bat *result, const bat *bid, const bat *sid)
729{
730 BAT *b, *s = NULL, *bn = NULL;
731
732 if ((b = BATdescriptor(*bid)) == NULL) {
733 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
734 }
735 if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
736 BBPunfix(b->batCacheid);
737 throw(MAL, "algebra.unique", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
738 }
739 bn = BATunique(b, s);
740 BBPunfix(b->batCacheid);
741 if (s)
742 BBPunfix(s->batCacheid);
743 if (bn == NULL)
744 throw(MAL, "algebra.unique", GDK_EXCEPTION);
745 *result = bn->batCacheid;
746 BBPkeepref(*result);
747 return MAL_SUCCEED;
748}
749
750str
751ALGunique1(bat *result, const bat *bid)
752{
753 return ALGunique2(result, bid, NULL);
754}
755
756str
757ALGcrossproduct2( bat *l, bat *r, const bat *left, const bat *right)
758{
759 BAT *L, *R, *bn1, *bn2;
760 gdk_return ret;
761
762 if ((L = BATdescriptor(*left)) == NULL) {
763 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
764 }
765 if ((R = BATdescriptor(*right)) == NULL) {
766 BBPunfix(L->batCacheid);
767 throw(MAL, "algebra.crossproduct", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
768 }
769 ret = BATsubcross(&bn1, &bn2, L, R, NULL, NULL);
770 BBPunfix(L->batCacheid);
771 BBPunfix(R->batCacheid);
772 if (ret != GDK_SUCCEED)
773 throw(MAL, "algebra.crossproduct", GDK_EXCEPTION);
774 BBPkeepref(*l = bn1->batCacheid);
775 BBPkeepref(*r = bn2->batCacheid);
776 return MAL_SUCCEED;
777}
778
779str
780ALGprojection(bat *result, const bat *lid, const bat *rid)
781{
782 return ALGbinary(result, lid, rid, BATproject, "algebra.projection");
783}
784
785str
786ALGsort33(bat *result, bat *norder, bat *ngroup, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
787{
788 BAT *bn = NULL, *on = NULL, *gn = NULL;
789 BAT *b = NULL, *o = NULL, *g = NULL;
790
791 if ((b = BATdescriptor(*bid)) == NULL)
792 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
793 if (order && !is_bat_nil(*order) && (o = BATdescriptor(*order)) == NULL) {
794 BBPunfix(b->batCacheid);
795 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
796 }
797 if (group && !is_bat_nil(*group) && (g = BATdescriptor(*group)) == NULL) {
798 if (o)
799 BBPunfix(o->batCacheid);
800 BBPunfix(b->batCacheid);
801 throw(MAL, "algebra.sort", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
802 }
803 if (BATsort(result ? &bn : NULL,
804 norder ? &on : NULL,
805 ngroup ? &gn : NULL,
806 b, o, g, *reverse, *nilslast, *stable) != GDK_SUCCEED) {
807 if (o)
808 BBPunfix(o->batCacheid);
809 if (g)
810 BBPunfix(g->batCacheid);
811 BBPunfix(b->batCacheid);
812 throw(MAL, "algebra.sort", OPERATION_FAILED);
813 }
814 BBPunfix(b->batCacheid);
815 if (o)
816 BBPunfix(o->batCacheid);
817 if (g)
818 BBPunfix(g->batCacheid);
819 if (result)
820 BBPkeepref(*result = bn->batCacheid);
821 if (norder)
822 BBPkeepref(*norder = on->batCacheid);
823 if (ngroup)
824 BBPkeepref(*ngroup = gn->batCacheid);
825 return MAL_SUCCEED;
826}
827
828str
829ALGsort32(bat *result, bat *norder, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
830{
831 return ALGsort33(result, norder, NULL, bid, order, group, reverse, nilslast, stable);
832}
833
834str
835ALGsort31(bat *result, const bat *bid, const bat *order, const bat *group, const bit *reverse, const bit *nilslast, const bit *stable)
836{
837 return ALGsort33(result, NULL, NULL, bid, order, group, reverse, nilslast, stable);
838}
839
840str
841ALGsort23(bat *result, bat *norder, bat *ngroup, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
842{
843 return ALGsort33(result, norder, ngroup, bid, order, NULL, reverse, nilslast, stable);
844}
845
846str
847ALGsort22(bat *result, bat *norder, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
848{
849 return ALGsort33(result, norder, NULL, bid, order, NULL, reverse, nilslast, stable);
850}
851
852str
853ALGsort21(bat *result, const bat *bid, const bat *order, const bit *reverse, const bit *nilslast, const bit *stable)
854{
855 return ALGsort33(result, NULL, NULL, bid, order, NULL, reverse, nilslast, stable);
856}
857
858str
859ALGsort13(bat *result, bat *norder, bat *ngroup, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
860{
861 return ALGsort33(result, norder, ngroup, bid, NULL, NULL, reverse, nilslast, stable);
862}
863
864str
865ALGsort12(bat *result, bat *norder, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
866{
867 return ALGsort33(result, norder, NULL, bid, NULL, NULL, reverse, nilslast, stable);
868}
869
870str
871ALGsort11(bat *result, const bat *bid, const bit *reverse, const bit *nilslast, const bit *stable)
872{
873 return ALGsort33(result, NULL, NULL, bid, NULL, NULL, reverse, nilslast, stable);
874}
875
876str
877ALGcount_bat(lng *result, const bat *bid)
878{
879 BAT *b;
880
881 if ((b = BATdescriptor(*bid)) == NULL) {
882 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
883 }
884 *result = (lng) BATcount(b);
885 BBPunfix(b->batCacheid);
886 return MAL_SUCCEED;
887}
888
889str
890ALGcount_nil(lng *result, const bat *bid, const bit *ignore_nils)
891{
892 BAT *b;
893 BUN cnt;
894
895 if ((b = BATdescriptor(*bid)) == NULL) {
896 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
897 }
898 if (*ignore_nils)
899 cnt = BATcount_no_nil(b);
900 else
901 cnt = BATcount(b);
902 *result = (lng) cnt;
903 BBPunfix(b->batCacheid);
904 return MAL_SUCCEED;
905}
906
907str
908ALGcount_no_nil(lng *result, const bat *bid)
909{
910 bit ignore_nils = 1;
911
912 return ALGcount_nil(result, bid, &ignore_nils);
913}
914
915str
916ALGcountCND_bat(lng *result, const bat *bid, const bat *cnd)
917{
918 BAT *b;
919
920 if ( *cnd) {
921 if ((b = BATdescriptor(*cnd)) == NULL) {
922 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
923 }
924 *result = (lng) BATcount(b);
925 BBPunfix(b->batCacheid);
926 return MAL_SUCCEED;
927 }
928 if ((b = BATdescriptor(*bid)) == NULL) {
929 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
930 }
931 *result = (lng) BATcount(b);
932 BBPunfix(b->batCacheid);
933 return MAL_SUCCEED;
934}
935
936str
937ALGcountCND_nil(lng *result, const bat *bid, const bat *cnd, const bit *ignore_nils)
938{
939 BAT *b;
940 BUN cnt;
941
942 if (*ignore_nils){
943 if ((b = BATdescriptor(*bid)) == NULL) {
944 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
945 }
946 cnt = BATcount_no_nil(b);
947 } else{
948 if ( *cnd) {
949 if ((b = BATdescriptor(*cnd)) == NULL) {
950 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
951 }
952 *result = (lng) BATcount(b);
953 BBPunfix(b->batCacheid);
954 return MAL_SUCCEED;
955 }
956 if ((b = BATdescriptor(*bid)) == NULL) {
957 throw(MAL, "aggr.count", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
958 }
959 cnt = BATcount(b);
960 }
961 *result = (lng) cnt;
962 BBPunfix(b->batCacheid);
963 return MAL_SUCCEED;
964}
965
966str
967ALGcountCND_no_nil(lng *result, const bat *bid, const bat *cnd)
968{
969 bit ignore_nils = 1;
970
971 return ALGcountCND_nil(result, bid, cnd, &ignore_nils);
972}
973
974str
975ALGslice(bat *ret, const bat *bid, const lng *start, const lng *end)
976{
977 BAT *b, *bn = NULL;
978
979 if ((b = BATdescriptor(*bid)) == NULL) {
980 throw(MAL, "algebra.slice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
981 }
982 if (slice(&bn, b, *start, *end) == GDK_SUCCEED) {
983 *ret = bn->batCacheid;
984 BBPkeepref(*ret);
985 BBPunfix(b->batCacheid);
986 return MAL_SUCCEED;
987 }
988 BBPunfix(b->batCacheid);
989 throw(MAL, "algebra.slice", GDK_EXCEPTION);
990}
991
992str
993ALGslice_int(bat *ret, const bat *bid, const int *start, const int *end)
994{
995 lng s = *start;
996 lng e = (is_int_nil(*end) ? lng_nil : *end);
997
998 return ALGslice(ret, bid, &s, &e);
999}
1000
1001str
1002ALGslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
1003{
1004 lng s = *start;
1005 lng e = *end;
1006
1007 return ALGslice(ret, bid, &s, &e);
1008}
1009
1010/* carve out a slice based on the OIDs */
1011/* beware that BATs may have different OID bases */
1012str
1013ALGslice_oid(bat *ret, const bat *bid, const oid *start, const oid *end)
1014{
1015 lng s = (lng) (is_oid_nil(*start) ? 0 : (lng) *start);
1016 lng e = (is_oid_nil(*end) ? lng_nil : (lng) *end);
1017
1018 return ALGslice(ret, bid, &s, &e) ;
1019}
1020
1021str
1022ALGsubslice_lng(bat *ret, const bat *bid, const lng *start, const lng *end)
1023{
1024 BAT *b, *bn;
1025 BUN s, e;
1026
1027 if (*start < 0 || *start > (lng) BUN_MAX ||
1028 (*end < 0 && !is_lng_nil(*end)) || *end >= (lng) BUN_MAX)
1029 throw(MAL, "algebra.subslice", ILLEGAL_ARGUMENT);
1030 if ((b = BATdescriptor(*bid)) == NULL)
1031 throw(MAL, "algebra.subslice", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1032 s = (BUN) *start;
1033 if (s > BATcount(b))
1034 s = BATcount(b);
1035 e = is_lng_nil(*end) ? BATcount(b) : (BUN) *end + 1;
1036 if (e > BATcount(b))
1037 e = BATcount(b);
1038 if (e < s)
1039 e = s;
1040 bn = BATdense(0, b->hseqbase + s, e - s);
1041 BBPunfix(*bid);
1042 if (bn == NULL)
1043 throw(MAL, "algebra.subslice", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1044 *ret = bn->batCacheid;
1045 BBPkeepref(*ret);
1046 return MAL_SUCCEED;
1047}
1048
1049/*
1050 * BUN Get/Fetch
1051 */
1052
1053static str
1054doALGfetch(ptr ret, BAT *b, BUN pos)
1055{
1056 BATiter bi = bat_iterator(b);
1057
1058 assert(pos <= BUN_MAX);
1059 if (ATOMextern(b->ttype)) {
1060 ptr _src = BUNtail(bi,pos);
1061 size_t _len = ATOMlen(b->ttype, _src);
1062 ptr _dst = GDKmalloc(_len);
1063 if( _dst == NULL)
1064 throw(MAL,"doAlgFetch", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1065 memcpy(_dst, _src, _len);
1066 *(ptr*) ret = _dst;
1067 } else {
1068 size_t _s = ATOMsize(ATOMtype(b->ttype));
1069 if (b->ttype == TYPE_void) {
1070 *(oid*) ret = b->tseqbase;
1071 if (!is_oid_nil(b->tseqbase))
1072 *(oid*)ret += pos;
1073 } else if (_s == 4) {
1074 *(int*) ret = *(int*) Tloc(b, pos);
1075 } else if (_s == 1) {
1076 *(bte*) ret = *(bte*) Tloc(b, pos);
1077 } else if (_s == 2) {
1078 *(sht*) ret = *(sht*) Tloc(b, pos);
1079 } else if (_s == 8) {
1080 *(lng*) ret = *(lng*) Tloc(b, pos);
1081#ifdef HAVE_HGE
1082 } else if (_s == 16) {
1083 *(hge*) ret = *(hge*) Tloc(b, pos);
1084#endif
1085 } else {
1086 memcpy(ret, Tloc(b, pos), _s);
1087 }
1088 }
1089 return MAL_SUCCEED;
1090}
1091
1092static str
1093ALGfetch(ptr ret, const bat *bid, const lng *pos)
1094{
1095 BAT *b;
1096 str msg;
1097
1098 if ((b = BATdescriptor(*bid)) == NULL) {
1099 throw(MAL, "algebra.fetch", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1100 }
1101 if ((*pos < (lng) 0) || (*pos >= (lng) BUNlast(b))) {
1102 BBPunfix(b->batCacheid);
1103 throw(MAL, "algebra.fetch", ILLEGAL_ARGUMENT " Idx out of range\n");
1104 }
1105 msg = doALGfetch(ret, b, (BUN) *pos);
1106 BBPunfix(b->batCacheid);
1107 return msg;
1108}
1109
1110str
1111ALGfetchoid(ptr ret, const bat *bid, const oid *pos)
1112{
1113 lng o = *pos;
1114
1115 return ALGfetch(ret, bid, &o);
1116}
1117
1118str
1119ALGexist(bit *ret, const bat *bid, const void *val)
1120{
1121 BAT *b;
1122 BUN q;
1123
1124 if ((b = BATdescriptor(*bid)) == NULL) {
1125 throw(MAL, "algebra.exist", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1126 }
1127 derefStr(b, val);
1128 q = BUNfnd(b, val);
1129 *ret = (q != BUN_NONE);
1130 BBPunfix(b->batCacheid);
1131 return MAL_SUCCEED;
1132}
1133
1134str
1135ALGfind(oid *ret, const bat *bid, ptr val)
1136{
1137 BAT *b;
1138 BUN q;
1139 str msg= MAL_SUCCEED;
1140
1141 if ((b = BATdescriptor(*bid)) == NULL) {
1142 throw(MAL, "algebra.find", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1143 }
1144 derefStr(b, val);
1145 q = BUNfnd(b, val);
1146
1147 if (q == BUN_NONE){
1148 *ret = oid_nil;
1149 } else
1150 *ret = (oid) q;
1151 BBPunfix(b->batCacheid);
1152 return msg;
1153}
1154
1155
1156str
1157ALGprojecttail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1158{
1159 bat *ret = getArgReference_bat(stk, pci, 0);
1160 bat bid = * getArgReference_bat(stk, pci, 1);
1161 const ValRecord *v = &stk->stk[getArg(pci, 2)];
1162 BAT *b, *bn;
1163
1164 (void) cntxt;
1165 (void) mb;
1166 if( isaBatType(getArgType(mb,pci,2)) )
1167 throw(MAL,"algebra.project","Scalar value expected");
1168 if ((b = BATdescriptor(bid)) == NULL)
1169 throw(MAL, "algebra.project", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1170 bn = BATconstant(b->hseqbase, v->vtype, VALptr(v), BATcount(b), TRANSIENT);
1171 BBPunfix(b->batCacheid);
1172 if (bn == NULL) {
1173 *ret = bat_nil;
1174 throw(MAL, "algebra.project", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1175 }
1176 *ret= bn->batCacheid;
1177 BBPkeepref(bn->batCacheid);
1178 return MAL_SUCCEED;
1179}
1180
1181
1182str ALGreuse(bat *ret, const bat *bid)
1183{
1184 BAT *b,*bn;
1185 if ((b = BATdescriptor(*bid)) == NULL)
1186 throw(MAL, "algebra.reuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1187
1188 if( !b->batTransient || b->batRestricted != BAT_WRITE){
1189 if( ATOMvarsized(b->ttype) ){
1190 bn= BATwcopy(b);
1191 if (bn == NULL) {
1192 BBPunfix(b->batCacheid);
1193 throw(MAL, "algebra.reuse", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1194 }
1195 } else {
1196 bn = COLnew(b->hseqbase, b->ttype, BATcount(b), TRANSIENT);
1197 if (bn == NULL) {
1198 BBPunfix(b->batCacheid);
1199 throw(MAL, "algebra.reuse", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1200 }
1201 BATsetcount(bn,BATcount(b));
1202 bn->tsorted = false;
1203 bn->trevsorted = false;
1204 BATkey(bn, false);
1205 }
1206 BBPkeepref(*ret= bn->batCacheid);
1207 BBPunfix(b->batCacheid);
1208 } else
1209 BBPkeepref(*ret = *bid);
1210 return MAL_SUCCEED;
1211}
1212
1213/*
1214 * BAT standard deviation
1215 */
1216str
1217ALGstdev(dbl *res, const bat *bid)
1218{
1219 BAT *b;
1220 dbl stdev;
1221
1222 if ((b = BATdescriptor(*bid)) == NULL)
1223 throw(MAL, "aggr.stdev", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1224 stdev = BATcalcstdev_sample(NULL, b);
1225 BBPunfix(b->batCacheid);
1226 if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
1227 throw(MAL, "aggr.stdev", SEMANTIC_TYPE_MISMATCH);
1228 *res = stdev;
1229 return MAL_SUCCEED;
1230}
1231
1232str
1233ALGstdevp(dbl *res, const bat *bid)
1234{
1235 BAT *b;
1236 dbl stdev;
1237
1238 if ((b = BATdescriptor(*bid)) == NULL)
1239 throw(MAL, "aggr.stdevp", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1240 stdev = BATcalcstdev_population(NULL, b);
1241 BBPunfix(b->batCacheid);
1242 if (is_dbl_nil(stdev) && GDKerrbuf && GDKerrbuf[0])
1243 throw(MAL, "aggr.stdevp", SEMANTIC_TYPE_MISMATCH);
1244 *res = stdev;
1245 return MAL_SUCCEED;
1246}
1247
1248/*
1249 * BAT variance
1250 */
1251str
1252ALGvariance(dbl *res, const bat *bid)
1253{
1254 BAT *b;
1255 dbl variance;
1256
1257 if ((b = BATdescriptor(*bid)) == NULL)
1258 throw(MAL, "aggr.variance", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1259 variance = BATcalcvariance_sample(NULL, b);
1260 BBPunfix(b->batCacheid);
1261 if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
1262 throw(MAL, "aggr.variance", SEMANTIC_TYPE_MISMATCH);
1263 *res = variance;
1264 return MAL_SUCCEED;
1265}
1266
1267str
1268ALGvariancep(dbl *res, const bat *bid)
1269{
1270 BAT *b;
1271 dbl variance;
1272
1273 if ((b = BATdescriptor(*bid)) == NULL)
1274 throw(MAL, "aggr.variancep", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1275 variance = BATcalcvariance_population(NULL, b);
1276 BBPunfix(b->batCacheid);
1277 if (is_dbl_nil(variance) && GDKerrbuf && GDKerrbuf[0])
1278 throw(MAL, "aggr.variancep", SEMANTIC_TYPE_MISMATCH);
1279 *res = variance;
1280 return MAL_SUCCEED;
1281}
1282