Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include "gdk.h"
15 : #include "gdk_private.h"
16 : #include "gdk_calc_private.h"
17 :
18 : /* BATfirstn select the smallest n elements from the input bat b (if
19 : * asc(ending) is set, else the largest n elements). Conceptually, b
20 : * is sorted in ascending or descending order (depending on the asc
21 : * argument) and then the OIDs of the first n elements are returned.
22 : * If there are NILs in the BAT, their relative ordering is set by
23 : * using the nilslast argument: if set, NILs come last (largest value
24 : * when ascending, smallest value when descending), so if there are
25 : * enough non-NIL values, no NILs will be returned. If unset (false),
26 : * NILs come first and will be returned.
27 : *
28 : * In addition to the input BAT b, there can be a standard candidate
29 : * list s. If s is specified (non-NULL), only elements in b that are
30 : * referred to in s are considered.
31 : *
32 : * If the third input bat g is non-NULL, then s must also be non-NULL
33 : * and must be aligned with g. G then specifies groups to which the
34 : * elements referred to in s belong. Conceptually, the group values
35 : * are sorted in ascending order together with the elements in b that
36 : * are referred to in s (in ascending or descending order depending on
37 : * asc), and the first n elements are then returned.
38 : *
39 : * If the output argument gids is NULL, only n elements are returned.
40 : * If the output argument gids is non-NULL, more than n elements may
41 : * be returned. If there are duplicate values (if g is given, the
42 : * group value counts in determining duplication), all duplicates are
43 : * returned.
44 : *
45 : * If distinct is set, the result contains n complete groups of values
46 : * instead of just n values (or slightly more than n if gids is set
47 : * since then the "last" group is returned completely).
48 : *
49 : * Note that BATfirstn can be called in cascading fashion to calculate
50 : * the first n values of a table of multiple columns:
51 : * BATfirstn(&s1, &g1, b1, NULL, NULL, n, asc, nilslast, distinct);
52 : * BATfirstn(&s2, &g2, b2, s1, g1, n, asc, nilslast, distinct);
53 : * BATfirstn(&s3, NULL, b3, s2, g2, n, asc, nilslast, distinct);
54 : * If the input BATs b1, b2, b3 are large enough, s3 will contain the
55 : * OIDs of the smallest (largest) n elements in the table consisting
56 : * of the columns b1, b2, b3 when ordered in ascending order with b1
57 : * the major key.
58 : */
59 :
60 : /* We use a binary heap for the implementation of the simplest form of
61 : * first-N. During processing, the oids list forms a heap with the
62 : * root at position 0 and the children of a node at position i at
63 : * positions 2*i+1 and 2*i+2. The parent node is always
64 : * smaller/larger (depending on the value of asc) than its children
65 : * (recursively). The heapify macro creates the heap from the input
66 : * in-place. We start off with a heap containing the first N elements
67 : * of the input, and then go over the rest of the input, replacing the
68 : * root of the heap with a new value if appropriate (if the new value
69 : * is among the first-N seen so far). The siftdown macro then
70 : * restores the heap property. */
71 : #define siftdown(OPER, START, SWAP) \
72 : do { \
73 : pos = (START); \
74 : childpos = (pos << 1) + 1; \
75 : while (childpos < n) { \
76 : /* find most extreme child */ \
77 : if (childpos + 1 < n && \
78 : !(OPER(childpos + 1, childpos))) \
79 : childpos++; \
80 : /* compare parent with most extreme child */ \
81 : if (!OPER(pos, childpos)) { \
82 : /* already correctly ordered */ \
83 : break; \
84 : } \
85 : /* exchange parent with child and sift child */ \
86 : /* further */ \
87 : SWAP(pos, childpos); \
88 : pos = childpos; \
89 : childpos = (pos << 1) + 1; \
90 : } \
91 : } while (0)
92 :
93 : #define heapify(OPER, SWAP) \
94 : do { \
95 : for (i = n / 2; i > 0; i--) \
96 : siftdown(OPER, i - 1, SWAP); \
97 : } while (0)
98 :
99 : /* we inherit LT and GT from gdk_calc_private.h */
100 :
101 : #define nLTbte(a, b) (!is_bte_nil(a) && (is_bte_nil(b) || (a) < (b)))
102 : #define nLTsht(a, b) (!is_sht_nil(a) && (is_sht_nil(b) || (a) < (b)))
103 : #define nLTint(a, b) (!is_int_nil(a) && (is_int_nil(b) || (a) < (b)))
104 : #define nLTlng(a, b) (!is_lng_nil(a) && (is_lng_nil(b) || (a) < (b)))
105 : #define nLThge(a, b) (!is_hge_nil(a) && (is_hge_nil(b) || (a) < (b)))
106 :
107 : #define nGTbte(a, b) (!is_bte_nil(b) && (is_bte_nil(a) || (a) > (b)))
108 : #define nGTsht(a, b) (!is_sht_nil(b) && (is_sht_nil(a) || (a) > (b)))
109 : #define nGTint(a, b) (!is_int_nil(b) && (is_int_nil(a) || (a) > (b)))
110 : #define nGTlng(a, b) (!is_lng_nil(b) && (is_lng_nil(a) || (a) > (b)))
111 : #define nGThge(a, b) (!is_hge_nil(b) && (is_hge_nil(a) || (a) > (b)))
112 :
113 : #define LTany(p1, p2) (cmp(BUNtail(*bi, oids[p1] - hseq), \
114 : BUNtail(*bi, oids[p2] - hseq)) < 0)
115 : #define GTany(p1, p2) (cmp(BUNtail(*bi, oids[p1] - hseq), \
116 : BUNtail(*bi, oids[p2] - hseq)) > 0)
117 :
118 : #define nLTany(p1, p2) (cmp(BUNtail(*bi, oids[p1] - hseq), nil) != 0 \
119 : && (cmp(BUNtail(*bi, oids[p2] - hseq), nil) == 0 \
120 : || cmp(BUNtail(*bi, oids[p1] - hseq), \
121 : BUNtail(*bi, oids[p2] - hseq)) < 0))
122 : #define nGTany(p1, p2) (cmp(BUNtail(*bi, oids[p2] - hseq), nil) != 0 \
123 : && (cmp(BUNtail(*bi, oids[p1] - hseq), nil) == 0 \
124 : || cmp(BUNtail(*bi, oids[p1] - hseq), \
125 : BUNtail(*bi, oids[p2] - hseq)) > 0))
126 :
127 : #define LTflt(a, b) (!is_flt_nil(b) && (is_flt_nil(a) || (a) < (b)))
128 : #define LTdbl(a, b) (!is_dbl_nil(b) && (is_dbl_nil(a) || (a) < (b)))
129 : #define GTflt(a, b) (!is_flt_nil(a) && (is_flt_nil(b) || (a) > (b)))
130 : #define GTdbl(a, b) (!is_dbl_nil(a) && (is_dbl_nil(b) || (a) > (b)))
131 :
132 : #define nLTflt(a, b) (!is_flt_nil(a) && (is_flt_nil(b) || (a) < (b)))
133 : #define nLTdbl(a, b) (!is_dbl_nil(a) && (is_dbl_nil(b) || (a) < (b)))
134 : #define nGTflt(a, b) (!is_flt_nil(b) && (is_flt_nil(a) || (a) > (b)))
135 : #define nGTdbl(a, b) (!is_dbl_nil(b) && (is_dbl_nil(a) || (a) > (b)))
136 :
137 : #define LTfltfix(p1, p2) LTflt(vals[oids[p1] - hseq], \
138 : vals[oids[p2] - hseq])
139 : #define GTfltfix(p1, p2) GTflt(vals[oids[p1] - hseq], \
140 : vals[oids[p2] - hseq])
141 : #define LTdblfix(p1, p2) LTdbl(vals[oids[p1] - hseq], \
142 : vals[oids[p2] - hseq])
143 : #define GTdblfix(p1, p2) GTdbl(vals[oids[p1] - hseq], \
144 : vals[oids[p2] - hseq])
145 : #define LTfix(p1, p2) LT(vals[oids[p1] - hseq], \
146 : vals[oids[p2] - hseq])
147 : #define GTfix(p1, p2) GT(vals[oids[p1] - hseq], \
148 : vals[oids[p2] - hseq])
149 :
150 : #define nLTfltfix(p1, p2) nLTflt(vals[oids[p1] - hseq], \
151 : vals[oids[p2] - hseq])
152 : #define nGTfltfix(p1, p2) nGTflt(vals[oids[p1] - hseq], \
153 : vals[oids[p2] - hseq])
154 : #define nLTdblfix(p1, p2) nLTdbl(vals[oids[p1] - hseq], \
155 : vals[oids[p2] - hseq])
156 : #define nGTdblfix(p1, p2) nGTdbl(vals[oids[p1] - hseq], \
157 : vals[oids[p2] - hseq])
158 : #define nLTbtefix(p1, p2) nLTbte(vals[oids[p1] - hseq], \
159 : vals[oids[p2] - hseq])
160 : #define nGTbtefix(p1, p2) nGTbte(vals[oids[p1] - hseq], \
161 : vals[oids[p2] - hseq])
162 : #define nLTshtfix(p1, p2) nLTsht(vals[oids[p1] - hseq], \
163 : vals[oids[p2] - hseq])
164 : #define nGTshtfix(p1, p2) nGTsht(vals[oids[p1] - hseq], \
165 : vals[oids[p2] - hseq])
166 : #define nLTintfix(p1, p2) nLTint(vals[oids[p1] - hseq], \
167 : vals[oids[p2] - hseq])
168 : #define nGTintfix(p1, p2) nGTint(vals[oids[p1] - hseq], \
169 : vals[oids[p2] - hseq])
170 : #define nLTlngfix(p1, p2) nLTlng(vals[oids[p1] - hseq], \
171 : vals[oids[p2] - hseq])
172 : #define nGTlngfix(p1, p2) nGTlng(vals[oids[p1] - hseq], \
173 : vals[oids[p2] - hseq])
174 : #define nLThgefix(p1, p2) nLThge(vals[oids[p1] - hseq], \
175 : vals[oids[p2] - hseq])
176 : #define nGThgefix(p1, p2) nGThge(vals[oids[p1] - hseq], \
177 : vals[oids[p2] - hseq])
178 :
179 : #define SWAP1(p1, p2) \
180 : do { \
181 : item = oids[p1]; \
182 : oids[p1] = oids[p2]; \
183 : oids[p2] = item; \
184 : } while (0)
185 :
186 : #define shuffle_unique(TYPE, OP) \
187 : do { \
188 : const TYPE *restrict vals = (const TYPE *) bi->base; \
189 : heapify(OP##fix, SWAP1); \
190 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) { \
191 : i = canditer_next(&ci); \
192 : if (OP(vals[i - hseq], \
193 : vals[oids[0] - hseq])) { \
194 : oids[0] = i; \
195 : siftdown(OP##fix, 0, SWAP1); \
196 : } \
197 : } \
198 : } while (0)
199 :
200 : /* This version of BATfirstn returns a list of N oids (where N is the
201 : * smallest among BATcount(b), BATcount(s), and n). The oids returned
202 : * refer to the N smallest/largest (depending on asc) tail values of b
203 : * (taking the optional candidate list s into account). If there are
204 : * multiple equal values to take us past N, we return a subset of those.
205 : *
206 : * If lastp is non-NULL, it is filled in with the oid of the "last"
207 : * value, i.e. the value of which there may be multiple occurrences
208 : * that are not all included in the first N.
209 : */
210 : static BAT *
211 741 : BATfirstn_unique(BATiter *bi, BAT *s, BUN n, bool asc, bool nilslast, oid *lastp, lng t0)
212 : {
213 741 : BAT *bn;
214 741 : oid *restrict oids;
215 741 : oid hseq = bi->b->hseqbase;
216 741 : BUN i;
217 741 : struct canditer ci;
218 741 : int tpe = bi->type;
219 741 : int (*cmp)(const void *, const void *);
220 741 : const void *nil;
221 : /* variables used in heapify/siftdown macros */
222 741 : oid item;
223 741 : BUN pos, childpos;
224 :
225 741 : MT_thread_setalgorithm(__func__);
226 741 : canditer_init(&ci, bi->b, s);
227 :
228 741 : if (n >= ci.ncand) {
229 : /* trivial: return all candidates */
230 414 : bn = canditer_slice(&ci, 0, ci.ncand);
231 414 : if (bn && lastp)
232 115 : *lastp = oid_nil;
233 414 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
234 : ",n=" BUNFMT " -> " ALGOOPTBATFMT
235 : " (trivial -- " LLFMT " usec)\n",
236 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
237 : ALGOOPTBATPAR(bn), GDKusec() - t0);
238 414 : return bn;
239 : }
240 :
241 327 : if (BATtvoid(bi->b)) {
242 : /* nilslast doesn't make a difference: either all are
243 : * nil, or none are */
244 0 : if (asc || is_oid_nil(bi->tseq)) {
245 : /* return the first part of the candidate list
246 : * or of the BAT itself */
247 0 : bn = canditer_slice(&ci, 0, n);
248 0 : if (bn && lastp)
249 0 : *lastp = BUNtoid(bn, n - 1);
250 0 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
251 : ",n=" BUNFMT " -> " ALGOOPTBATFMT
252 : " (initial slice -- " LLFMT " usec)\n",
253 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
254 : ALGOOPTBATPAR(bn), GDKusec() - t0);
255 0 : return bn;
256 : }
257 : /* return the last part of the candidate list or of
258 : * the BAT itself */
259 0 : bn = canditer_slice(&ci, ci.ncand - n, ci.ncand);
260 0 : if (bn && lastp)
261 0 : *lastp = BUNtoid(bn, 0);
262 0 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
263 : ",n=" BUNFMT " -> " ALGOOPTBATFMT
264 : " (final slice -- " LLFMT " usec)\n",
265 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
266 : ALGOOPTBATPAR(bn), GDKusec() - t0);
267 0 : return bn;
268 : }
269 327 : if (bi->sorted || bi->revsorted) {
270 : /* trivial: b is sorted so we just need to return the
271 : * initial or final part of it (or of the candidate
272 : * list); however, if nilslast == asc, then the nil
273 : * values (if any) are in the wrong place, so we need
274 : * to do a little more work */
275 :
276 : /* after we create the to-be-returned BAT, we set pos
277 : * to the BUN in the new BAT whose value we should
278 : * return through *lastp */
279 179 : if (nilslast == asc && !bi->nonil) {
280 0 : pos = SORTfndlast(bi->b, ATOMnilptr(tpe));
281 0 : pos = canditer_search(&ci, hseq + pos, true);
282 : /* 0 <= pos <= ci.ncand
283 : * 0 < n < ci.ncand
284 : */
285 0 : if (bi->sorted) {
286 : /* [0..pos) -- nil
287 : * [pos..ci.ncand) -- non-nil <<<
288 : */
289 0 : if (asc) { /* i.e. nilslast */
290 : /* prefer non-nil and
291 : * smallest */
292 0 : if (ci.ncand - pos < n) {
293 0 : bn = canditer_slice(&ci, ci.ncand - n, ci.ncand);
294 0 : pos = 0;
295 : } else {
296 0 : bn = canditer_slice(&ci, pos, pos + n);
297 0 : pos = n - 1;
298 : }
299 : } else { /* i.e. !asc, !nilslast */
300 : /* prefer nil and largest */
301 0 : if (pos < n) {
302 0 : bn = canditer_slice2(&ci, 0, pos, ci.ncand - (n - pos), ci.ncand);
303 : /* pos = pos; */
304 : } else {
305 0 : bn = canditer_slice(&ci, 0, n);
306 0 : pos = 0;
307 : }
308 : }
309 : } else { /* i.e. trevsorted */
310 : /* [0..pos) -- non-nil >>>
311 : * [pos..ci.ncand) -- nil
312 : */
313 0 : if (asc) { /* i.e. nilslast */
314 : /* prefer non-nil and
315 : * smallest */
316 0 : if (pos < n) {
317 0 : bn = canditer_slice(&ci, 0, n);
318 : /* pos = pos; */
319 : } else {
320 0 : bn = canditer_slice(&ci, pos - n, pos);
321 0 : pos = 0;
322 : }
323 : } else { /* i.e. !asc, !nilslast */
324 : /* prefer nil and largest */
325 0 : if (ci.ncand - pos < n) {
326 0 : bn = canditer_slice2(&ci, 0, n - (ci.ncand - pos), pos, ci.ncand);
327 0 : pos = n - (ci.ncand - pos) - 1;
328 : } else {
329 0 : bn = canditer_slice(&ci, pos, pos + n);
330 0 : pos = 0;
331 : }
332 : }
333 : }
334 : } else {
335 : /* either there are no nils, or they are in
336 : * the appropriate position already, so we can
337 : * just slice */
338 179 : if (asc ? bi->sorted : bi->revsorted) {
339 : /* return copy of first part of
340 : * candidate list */
341 162 : bn = canditer_slice(&ci, 0, n);
342 162 : pos = n - 1;
343 : } else {
344 : /* return copy of last part of
345 : * candidate list */
346 17 : bn = canditer_slice(&ci, ci.ncand - n, ci.ncand);
347 17 : pos = 0;
348 : }
349 : }
350 179 : if (bn && lastp)
351 39 : *lastp = BUNtoid(bn, pos);
352 179 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
353 : ",n=" BUNFMT " -> " ALGOOPTBATFMT
354 : " (ordered -- " LLFMT " usec)\n",
355 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
356 : ALGOOPTBATPAR(bn), GDKusec() - t0);
357 179 : return bn;
358 : }
359 :
360 148 : bn = COLnew(0, TYPE_oid, n, TRANSIENT);
361 148 : if (bn == NULL)
362 : return NULL;
363 148 : BATsetcount(bn, n);
364 148 : oids = (oid *) Tloc(bn, 0);
365 148 : cmp = ATOMcompare(tpe);
366 148 : nil = ATOMnilptr(tpe);
367 : /* if base type has same comparison function as type itself, we
368 : * can use the base type */
369 148 : tpe = ATOMbasetype(tpe); /* takes care of oid */
370 : /* if the input happens to be almost sorted in ascending order
371 : * (likely a common use case), it is more efficient to start
372 : * off with the first n elements when doing a firstn-ascending
373 : * and to start off with the last n elements when doing a
374 : * firstn-descending so that most values that we look at after
375 : * this will be skipped. However, when using a bitmask
376 : * candidate list, the manipulation of the canditer structure
377 : * doesn't work like this, so we still work from the
378 : * beginning. */
379 148 : if (asc || ci.tpe == cand_mask) {
380 305568 : for (i = 0; i < n; i++)
381 305482 : oids[i] = canditer_next(&ci);
382 : } else {
383 62 : item = canditer_idx(&ci, ci.ncand - n);
384 62 : ci.next = ci.ncand - n;
385 62 : ci.add = item - ci.seq - (ci.ncand - n);
386 642 : for (i = n; i > 0; i--)
387 580 : oids[i - 1] = canditer_next(&ci);
388 62 : canditer_reset(&ci);
389 : }
390 :
391 148 : QryCtx *qry_ctx = MT_thread_get_qry_ctx();
392 :
393 148 : if (asc) {
394 86 : if (nilslast && !bi->nonil) {
395 14 : switch (tpe) {
396 2 : case TYPE_bte:
397 24 : shuffle_unique(bte, nLTbte);
398 : break;
399 0 : case TYPE_sht:
400 0 : shuffle_unique(sht, nLTsht);
401 : break;
402 2 : case TYPE_int:
403 22 : shuffle_unique(int, nLTint);
404 : break;
405 4 : case TYPE_lng:
406 47 : shuffle_unique(lng, nLTlng);
407 : break;
408 : #ifdef HAVE_HGE
409 0 : case TYPE_hge:
410 0 : shuffle_unique(hge, nLThge);
411 : break;
412 : #endif
413 2 : case TYPE_flt:
414 25 : shuffle_unique(flt, nLTflt);
415 : break;
416 0 : case TYPE_dbl:
417 0 : shuffle_unique(dbl, nLTdbl);
418 : break;
419 4 : default:
420 29 : heapify(nLTany, SWAP1);
421 14 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
422 6 : i = canditer_next(&ci);
423 6 : if (cmp(BUNtail(*bi, i - hseq), nil) != 0
424 5 : && (cmp(BUNtail(*bi, oids[0] - hseq), nil) == 0
425 1 : || cmp(BUNtail(*bi, i - hseq),
426 1 : BUNtail(*bi, oids[0] - hseq)) < 0)) {
427 5 : oids[0] = i;
428 15 : siftdown(nLTany, 0, SWAP1);
429 : }
430 : }
431 : break;
432 : }
433 : } else {
434 72 : switch (tpe) {
435 0 : case TYPE_bte:
436 0 : shuffle_unique(bte, LT);
437 : break;
438 0 : case TYPE_sht:
439 0 : shuffle_unique(sht, LT);
440 : break;
441 25 : case TYPE_int:
442 7025 : shuffle_unique(int, LT);
443 : break;
444 5 : case TYPE_lng:
445 7451861 : shuffle_unique(lng, LT);
446 : break;
447 : #ifdef HAVE_HGE
448 8 : case TYPE_hge:
449 100283 : shuffle_unique(hge, LT);
450 : break;
451 : #endif
452 0 : case TYPE_flt:
453 0 : shuffle_unique(flt, LTflt);
454 : break;
455 3 : case TYPE_dbl:
456 77670 : shuffle_unique(dbl, LTdbl);
457 : break;
458 31 : default:
459 3523 : heapify(LTany, SWAP1);
460 142957 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
461 142893 : i = canditer_next(&ci);
462 142893 : if (cmp(BUNtail(*bi, i - hseq),
463 142893 : BUNtail(*bi, oids[0] - hseq)) < 0) {
464 5724 : oids[0] = i;
465 172792 : siftdown(LTany, 0, SWAP1);
466 : }
467 : }
468 : break;
469 : }
470 : }
471 : } else {
472 62 : if (nilslast || bi->nonil) {
473 41 : switch (tpe) {
474 0 : case TYPE_bte:
475 0 : shuffle_unique(bte, GT);
476 : break;
477 0 : case TYPE_sht:
478 0 : shuffle_unique(sht, GT);
479 : break;
480 24 : case TYPE_int:
481 216 : shuffle_unique(int, GT);
482 : break;
483 1 : case TYPE_lng:
484 2085 : shuffle_unique(lng, GT);
485 : break;
486 : #ifdef HAVE_HGE
487 5 : case TYPE_hge:
488 1446 : shuffle_unique(hge, GT);
489 : break;
490 : #endif
491 0 : case TYPE_flt:
492 0 : shuffle_unique(flt, GTflt);
493 : break;
494 2 : case TYPE_dbl:
495 24 : shuffle_unique(dbl, GTdbl);
496 : break;
497 9 : default:
498 51 : heapify(GTany, SWAP1);
499 49 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
500 31 : i = canditer_next(&ci);
501 31 : if (cmp(BUNtail(*bi, i - hseq),
502 31 : BUNtail(*bi, oids[0] - hseq)) > 0) {
503 19 : oids[0] = i;
504 60 : siftdown(GTany, 0, SWAP1);
505 : }
506 : }
507 : break;
508 : }
509 : } else {
510 21 : switch (tpe) {
511 1 : case TYPE_bte:
512 10 : shuffle_unique(bte, nGTbte);
513 : break;
514 0 : case TYPE_sht:
515 0 : shuffle_unique(sht, nGTsht);
516 : break;
517 2 : case TYPE_int:
518 20 : shuffle_unique(int, nGTint);
519 : break;
520 8 : case TYPE_lng:
521 80 : shuffle_unique(lng, nGTlng);
522 : break;
523 : #ifdef HAVE_HGE
524 0 : case TYPE_hge:
525 0 : shuffle_unique(hge, nGThge);
526 : break;
527 : #endif
528 2 : case TYPE_flt:
529 20 : shuffle_unique(flt, nGTflt);
530 : break;
531 2 : case TYPE_dbl:
532 20 : shuffle_unique(dbl, nGTdbl);
533 : break;
534 6 : default:
535 38 : heapify(nGTany, SWAP1);
536 25 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
537 13 : i = canditer_next(&ci);
538 13 : if (cmp(BUNtail(*bi, oids[0] - hseq), nil) != 0
539 13 : && (cmp(BUNtail(*bi, i - hseq), nil) == 0
540 11 : || cmp(BUNtail(*bi, i - hseq),
541 11 : BUNtail(*bi, oids[0] - hseq)) > 0)) {
542 13 : oids[0] = i;
543 34 : siftdown(nGTany, 0, SWAP1);
544 : }
545 : }
546 : break;
547 : }
548 : }
549 : }
550 148 : TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
551 148 : if (lastp)
552 56 : *lastp = oids[0]; /* store id of largest value */
553 : /* output must be sorted since it's a candidate list */
554 148 : GDKqsort(oids, NULL, NULL, (size_t) n, sizeof(oid), 0, TYPE_oid, false, false);
555 148 : bn->tsorted = true;
556 148 : bn->trevsorted = n <= 1;
557 148 : bn->tkey = true;
558 148 : bn->tseqbase = n <= 1 ? oids[0] : oid_nil;
559 148 : bn->tnil = false;
560 148 : bn->tnonil = true;
561 148 : bn = virtualize(bn);
562 148 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
563 : ",n=" BUNFMT " -> " ALGOOPTBATFMT
564 : " (" LLFMT " usec)\n",
565 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
566 : ALGOOPTBATPAR(bn), GDKusec() - t0);
567 : return bn;
568 :
569 0 : bailout:
570 0 : BBPreclaim(bn);
571 0 : return NULL;
572 : }
573 :
574 : #define LTfixgrp(p1, p2) \
575 : (goids[p1] < goids[p2] || \
576 : (goids[p1] == goids[p2] && \
577 : LTfix(p1, p2)))
578 : #define nLTbtefixgrp(p1, p2) \
579 : (goids[p1] < goids[p2] || \
580 : (goids[p1] == goids[p2] && \
581 : nLTbtefix(p1, p2)))
582 : #define nLTshtfixgrp(p1, p2) \
583 : (goids[p1] < goids[p2] || \
584 : (goids[p1] == goids[p2] && \
585 : nLTshtfix(p1, p2)))
586 : #define nLTintfixgrp(p1, p2) \
587 : (goids[p1] < goids[p2] || \
588 : (goids[p1] == goids[p2] && \
589 : nLTintfix(p1, p2)))
590 : #define nLTlngfixgrp(p1, p2) \
591 : (goids[p1] < goids[p2] || \
592 : (goids[p1] == goids[p2] && \
593 : nLTlngfix(p1, p2)))
594 : #define nLThgefixgrp(p1, p2) \
595 : (goids[p1] < goids[p2] || \
596 : (goids[p1] == goids[p2] && \
597 : nLThgefix(p1, p2)))
598 : #define LTfltfixgrp(p1, p2) \
599 : (goids[p1] < goids[p2] || \
600 : (goids[p1] == goids[p2] && \
601 : LTfltfix(p1, p2)))
602 : #define LTdblfixgrp(p1, p2) \
603 : (goids[p1] < goids[p2] || \
604 : (goids[p1] == goids[p2] && \
605 : LTdblfix(p1, p2)))
606 : #define nLTfltfixgrp(p1, p2) \
607 : (goids[p1] < goids[p2] || \
608 : (goids[p1] == goids[p2] && \
609 : nLTfltfix(p1, p2)))
610 : #define nLTdblfixgrp(p1, p2) \
611 : (goids[p1] < goids[p2] || \
612 : (goids[p1] == goids[p2] && \
613 : nLTdblfix(p1, p2)))
614 : #define GTfixgrp(p1, p2) \
615 : (goids[p1] < goids[p2] || \
616 : (goids[p1] == goids[p2] && \
617 : GTfix(p1, p2)))
618 : #define nGTbtefixgrp(p1, p2) \
619 : (goids[p1] < goids[p2] || \
620 : (goids[p1] == goids[p2] && \
621 : nGTbtefix(p1, p2)))
622 : #define nGTshtfixgrp(p1, p2) \
623 : (goids[p1] < goids[p2] || \
624 : (goids[p1] == goids[p2] && \
625 : nGTshtfix(p1, p2)))
626 : #define nGTintfixgrp(p1, p2) \
627 : (goids[p1] < goids[p2] || \
628 : (goids[p1] == goids[p2] && \
629 : nGTintfix(p1, p2)))
630 : #define nGTlngfixgrp(p1, p2) \
631 : (goids[p1] < goids[p2] || \
632 : (goids[p1] == goids[p2] && \
633 : nGTlngfix(p1, p2)))
634 : #define nGThgefixgrp(p1, p2) \
635 : (goids[p1] < goids[p2] || \
636 : (goids[p1] == goids[p2] && \
637 : nGThgefix(p1, p2)))
638 : #define GTfltfixgrp(p1, p2) \
639 : (goids[p1] < goids[p2] || \
640 : (goids[p1] == goids[p2] && \
641 : GTfltfix(p1, p2)))
642 : #define GTdblfixgrp(p1, p2) \
643 : (goids[p1] < goids[p2] || \
644 : (goids[p1] == goids[p2] && \
645 : GTdblfix(p1, p2)))
646 : #define nGTfltfixgrp(p1, p2) \
647 : (goids[p1] < goids[p2] || \
648 : (goids[p1] == goids[p2] && \
649 : nGTfltfix(p1, p2)))
650 : #define nGTdblfixgrp(p1, p2) \
651 : (goids[p1] < goids[p2] || \
652 : (goids[p1] == goids[p2] && \
653 : nGTdblfix(p1, p2)))
654 : #define LTvoidgrp(p1, p2) \
655 : (goids[p1] < goids[p2] || \
656 : (goids[p1] == goids[p2] && oids[p1] < oids[p2]))
657 : #define GTvoidgrp(p1, p2) \
658 : (goids[p1] < goids[p2] || \
659 : (goids[p1] == goids[p2] && oids[p1] > oids[p2]))
660 : #define LTanygrp(p1, p2) \
661 : (goids[p1] < goids[p2] || \
662 : (goids[p1] == goids[p2] && \
663 : LTany(p1, p2)))
664 : #define GTanygrp(p1, p2) \
665 : (goids[p1] < goids[p2] || \
666 : (goids[p1] == goids[p2] && \
667 : GTany(p1, p2)))
668 : #define nLTanygrp(p1, p2) \
669 : (goids[p1] < goids[p2] || \
670 : (goids[p1] == goids[p2] && \
671 : nLTany(p1, p2)))
672 : #define nGTanygrp(p1, p2) \
673 : (goids[p1] < goids[p2] || \
674 : (goids[p1] == goids[p2] && \
675 : nGTany(p1, p2)))
676 : #define SWAP2(p1, p2) \
677 : do { \
678 : item = oids[p1]; \
679 : oids[p1] = oids[p2]; \
680 : oids[p2] = item; \
681 : item = goids[p1]; \
682 : goids[p1] = goids[p2]; \
683 : goids[p2] = item; \
684 : } while (0)
685 :
686 : #define shuffle_unique_with_groups(TYPE, OP) \
687 : do { \
688 : const TYPE *restrict vals = (const TYPE *) bi->base; \
689 : heapify(OP##fixgrp, SWAP2); \
690 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) { \
691 : i = canditer_next(&ci); \
692 : if (gv[j] < goids[0] || \
693 : (gv[j] == goids[0] && \
694 : OP(vals[i - hseq], \
695 : vals[oids[0] - hseq]))) { \
696 : oids[0] = i; \
697 : goids[0] = gv[j]; \
698 : siftdown(OP##fixgrp, 0, SWAP2); \
699 : } \
700 : j++; \
701 : } \
702 : } while (0)
703 :
704 : /* This version of BATfirstn is like the one above, except that it
705 : * also looks at groups. The values of the group IDs are important:
706 : * we return only the smallest N (i.e., not dependent on asc which
707 : * refers only to the values in the BAT b).
708 : *
709 : * If lastp is non-NULL, it is filled in with the oid of the "last"
710 : * value, i.e. the value of which there may be multiple occurrences
711 : * that are not all included in the first N. If lastgp is non-NULL,
712 : * it is filled with the group ID (not the oid of the group ID) for
713 : * that same value.
714 : */
715 : static BAT *
716 469 : BATfirstn_unique_with_groups(BATiter *bi, BAT *s, BAT *g, BUN n, bool asc, bool nilslast, oid *lastp, oid *lastgp, lng t0)
717 : {
718 469 : BAT *bn;
719 469 : oid *restrict oids, *restrict goids;
720 469 : oid hseq = bi->b->hseqbase;
721 469 : const oid *restrict gv;
722 469 : BUN i, j;
723 469 : struct canditer ci;
724 469 : int tpe = bi->type;
725 469 : int (*cmp)(const void *, const void *);
726 469 : const void *nil;
727 : /* variables used in heapify/siftdown macros */
728 469 : oid item;
729 469 : BUN pos, childpos;
730 :
731 469 : MT_thread_setalgorithm(__func__);
732 469 : canditer_init(&ci, bi->b, s);
733 :
734 469 : if (n > ci.ncand)
735 : n = ci.ncand;
736 :
737 469 : if (n == 0) {
738 : /* candidate list might refer only to values outside
739 : * of the bat and hence be effectively empty */
740 0 : if (lastp)
741 0 : *lastp = 0;
742 0 : if (lastgp)
743 0 : *lastgp = 0;
744 0 : bn = BATdense(0, 0, 0);
745 0 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
746 : ",g=" ALGOBATFMT ",n=" BUNFMT " -> " ALGOOPTBATFMT
747 : " (empty -- " LLFMT " usec)\n",
748 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), ALGOBATPAR(g), n,
749 : ALGOOPTBATPAR(bn), GDKusec() - t0);
750 0 : return bn;
751 : }
752 :
753 469 : if (BATtdense(g)) {
754 : /* trivial: g determines ordering, return reference to
755 : * initial part of b (or slice of s) */
756 37 : if (lastgp)
757 16 : *lastgp = g->tseqbase + n - 1;
758 37 : bn = canditer_slice(&ci, 0, n);
759 37 : if (bn && lastp)
760 16 : *lastp = BUNtoid(bn, n - 1);
761 37 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
762 : ",g=" ALGOBATFMT ",n=" BUNFMT " -> " ALGOOPTBATFMT
763 : " (dense group -- " LLFMT " usec)\n",
764 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), ALGOBATPAR(g), n,
765 : ALGOOPTBATPAR(bn), GDKusec() - t0);
766 37 : return bn;
767 : }
768 :
769 432 : bn = COLnew(0, TYPE_oid, n, TRANSIENT);
770 432 : if (bn == NULL)
771 : return NULL;
772 432 : BATsetcount(bn, n);
773 432 : oids = (oid *) Tloc(bn, 0);
774 432 : gv = (const oid *) Tloc(g, 0);
775 432 : goids = GDKmalloc(n * sizeof(oid));
776 432 : if (goids == NULL) {
777 0 : BBPreclaim(bn);
778 0 : return NULL;
779 : }
780 :
781 432 : cmp = ATOMcompare(tpe);
782 432 : nil = ATOMnilptr(tpe);
783 : /* if base type has same comparison function as type itself, we
784 : * can use the base type */
785 432 : tpe = ATOMbasetype(tpe); /* takes care of oid */
786 432 : j = 0;
787 11073225 : for (i = 0; i < n; i++) {
788 11072793 : oids[i] = canditer_next(&ci);
789 11072793 : goids[i] = gv[j++];
790 : }
791 :
792 432 : QryCtx *qry_ctx = MT_thread_get_qry_ctx();
793 :
794 432 : if (BATtvoid(bi->b)) {
795 : /* nilslast doesn't make a difference (all nil, or no nil) */
796 0 : if (asc) {
797 0 : heapify(LTvoidgrp, SWAP2);
798 0 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
799 0 : i = canditer_next(&ci);
800 0 : if (gv[j] < goids[0]
801 : /* || (gv[j] == goids[0]
802 : && i < oids[0]) -- always false */) {
803 0 : oids[0] = i;
804 0 : goids[0] = gv[j];
805 0 : siftdown(LTvoidgrp, 0, SWAP2);
806 : }
807 0 : j++;
808 : }
809 : } else {
810 0 : heapify(GTvoidgrp, SWAP2);
811 0 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
812 0 : i = canditer_next(&ci);
813 0 : if (gv[j] < goids[0]
814 0 : || (gv[j] == goids[0]
815 : /* && i > oids[0] -- always true */)) {
816 0 : oids[0] = i;
817 0 : goids[0] = gv[j];
818 0 : siftdown(GTvoidgrp, 0, SWAP2);
819 : }
820 0 : j++;
821 : }
822 : }
823 432 : } else if (asc) {
824 373 : if (nilslast && !bi->nonil) {
825 0 : switch (tpe) {
826 0 : case TYPE_bte:
827 0 : shuffle_unique_with_groups(bte, nLTbte);
828 : break;
829 0 : case TYPE_sht:
830 0 : shuffle_unique_with_groups(sht, nLTsht);
831 : break;
832 0 : case TYPE_int:
833 0 : shuffle_unique_with_groups(int, nLTint);
834 : break;
835 0 : case TYPE_lng:
836 0 : shuffle_unique_with_groups(lng, nLTlng);
837 : break;
838 : #ifdef HAVE_HGE
839 0 : case TYPE_hge:
840 0 : shuffle_unique_with_groups(hge, nLThge);
841 : break;
842 : #endif
843 0 : case TYPE_flt:
844 0 : shuffle_unique_with_groups(flt, nLTflt);
845 : break;
846 0 : case TYPE_dbl:
847 0 : shuffle_unique_with_groups(dbl, nLTdbl);
848 : break;
849 0 : default:
850 0 : heapify(nLTanygrp, SWAP2);
851 0 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
852 0 : i = canditer_next(&ci);
853 0 : if (gv[j] < goids[0]
854 0 : || (gv[j] == goids[0]
855 0 : && cmp(BUNtail(*bi, i - hseq), nil) != 0
856 0 : && (cmp(BUNtail(*bi, oids[0] - hseq), nil) == 0
857 0 : || cmp(BUNtail(*bi, i - hseq),
858 0 : BUNtail(*bi, oids[0] - hseq)) < 0))) {
859 0 : oids[0] = i;
860 0 : goids[0] = gv[j];
861 0 : siftdown(nLTanygrp, 0, SWAP2);
862 : }
863 0 : j++;
864 : }
865 : break;
866 : }
867 : } else {
868 373 : switch (tpe) {
869 21 : case TYPE_bte:
870 1597911 : shuffle_unique_with_groups(bte, LT);
871 : break;
872 14 : case TYPE_sht:
873 1000077 : shuffle_unique_with_groups(sht, LT);
874 : break;
875 126 : case TYPE_int:
876 34506 : shuffle_unique_with_groups(int, LT);
877 : break;
878 10 : case TYPE_lng:
879 597905 : shuffle_unique_with_groups(lng, LT);
880 : break;
881 : #ifdef HAVE_HGE
882 30 : case TYPE_hge:
883 2753 : shuffle_unique_with_groups(hge, LT);
884 : break;
885 : #endif
886 0 : case TYPE_flt:
887 0 : shuffle_unique_with_groups(flt, LTflt);
888 : break;
889 4 : case TYPE_dbl:
890 21 : shuffle_unique_with_groups(dbl, LTdbl);
891 : break;
892 168 : default:
893 260880 : heapify(LTanygrp, SWAP2);
894 16007 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
895 15671 : i = canditer_next(&ci);
896 15671 : if (gv[j] < goids[0] ||
897 15501 : (gv[j] == goids[0] &&
898 15501 : cmp(BUNtail(*bi, i - hseq),
899 15501 : BUNtail(*bi, oids[0] - hseq)) < 0)) {
900 2321 : oids[0] = i;
901 2321 : goids[0] = gv[j];
902 14484 : siftdown(LTanygrp, 0, SWAP2);
903 : }
904 15671 : j++;
905 : }
906 : break;
907 : }
908 : }
909 59 : } else if (nilslast || bi->nonil) {
910 40 : switch (tpe) {
911 5 : case TYPE_bte:
912 227250 : shuffle_unique_with_groups(bte, GT);
913 : break;
914 0 : case TYPE_sht:
915 0 : shuffle_unique_with_groups(sht, GT);
916 : break;
917 15 : case TYPE_int:
918 5301761 : shuffle_unique_with_groups(int, GT);
919 : break;
920 0 : case TYPE_lng:
921 0 : shuffle_unique_with_groups(lng, GT);
922 : break;
923 : #ifdef HAVE_HGE
924 5 : case TYPE_hge:
925 728 : shuffle_unique_with_groups(hge, GT);
926 : break;
927 : #endif
928 0 : case TYPE_flt:
929 0 : shuffle_unique_with_groups(flt, GTflt);
930 : break;
931 6 : case TYPE_dbl:
932 246231 : shuffle_unique_with_groups(dbl, GTdbl);
933 : break;
934 9 : default:
935 54 : heapify(GTanygrp, SWAP2);
936 21 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
937 3 : i = canditer_next(&ci);
938 3 : if (gv[j] < goids[0] ||
939 2 : (gv[j] == goids[0] &&
940 2 : cmp(BUNtail(*bi, i - hseq),
941 2 : BUNtail(*bi, oids[0] - hseq)) > 0)) {
942 2 : oids[0] = i;
943 2 : goids[0] = gv[j];
944 5 : siftdown(GTanygrp, 0, SWAP2);
945 : }
946 3 : j++;
947 : }
948 : break;
949 : }
950 : } else {
951 19 : switch (tpe) {
952 2 : case TYPE_bte:
953 441484 : shuffle_unique_with_groups(bte, nGTbte);
954 : break;
955 0 : case TYPE_sht:
956 0 : shuffle_unique_with_groups(sht, nGTsht);
957 : break;
958 0 : case TYPE_int:
959 0 : shuffle_unique_with_groups(int, nGTint);
960 : break;
961 0 : case TYPE_lng:
962 0 : shuffle_unique_with_groups(lng, nGTlng);
963 : break;
964 : #ifdef HAVE_HGE
965 17 : case TYPE_hge:
966 1619124 : shuffle_unique_with_groups(hge, nGThge);
967 : break;
968 : #endif
969 0 : case TYPE_flt:
970 0 : shuffle_unique_with_groups(flt, nGTflt);
971 : break;
972 0 : case TYPE_dbl:
973 0 : shuffle_unique_with_groups(dbl, nGTdbl);
974 : break;
975 0 : default:
976 0 : heapify(nGTanygrp, SWAP2);
977 0 : TIMEOUT_LOOP(ci.ncand - n, qry_ctx) {
978 0 : i = canditer_next(&ci);
979 0 : if (gv[j] < goids[0]
980 0 : || (gv[j] == goids[0]
981 0 : && cmp(BUNtail(*bi, oids[0] - hseq), nil) != 0
982 0 : && (cmp(BUNtail(*bi, i - hseq), nil) == 0
983 0 : || cmp(BUNtail(*bi, i - hseq),
984 0 : BUNtail(*bi, oids[0] - hseq)) > 0))) {
985 0 : oids[0] = i;
986 0 : goids[0] = gv[j];
987 0 : siftdown(nGTanygrp, 0, SWAP2);
988 : }
989 0 : j++;
990 : }
991 : break;
992 : }
993 : }
994 432 : TIMEOUT_CHECK(qry_ctx, GOTO_LABEL_TIMEOUT_HANDLER(bailout, qry_ctx));
995 431 : if (lastp)
996 258 : *lastp = oids[0];
997 431 : if (lastgp)
998 258 : *lastgp = goids[0];
999 431 : GDKfree(goids);
1000 : /* output must be sorted since it's a candidate list */
1001 432 : GDKqsort(oids, NULL, NULL, (size_t) n, sizeof(oid), 0, TYPE_oid, false, false);
1002 432 : bn->tsorted = true;
1003 432 : bn->trevsorted = n <= 1;
1004 432 : bn->tkey = true;
1005 432 : bn->tseqbase = n <= 1 ? oids[0] : oid_nil;
1006 432 : bn->tnil = false;
1007 432 : bn->tnonil = true;
1008 432 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
1009 : ",g=" ALGOBATFMT ",n=" BUNFMT " -> " ALGOOPTBATFMT
1010 : " (" LLFMT " usec)\n",
1011 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), ALGOBATPAR(g), n,
1012 : ALGOOPTBATPAR(bn), GDKusec() - t0);
1013 : return bn;
1014 :
1015 0 : bailout:
1016 0 : GDKfree(goids);
1017 0 : BBPreclaim(bn);
1018 0 : return NULL;
1019 : }
1020 :
1021 : static gdk_return
1022 210 : BATfirstn_grouped(BAT **topn, BAT **gids, BATiter *bi, BAT *s, BUN n, bool asc, bool nilslast, bool distinct, lng t0)
1023 : {
1024 210 : BAT *bn, *gn = NULL, *su = NULL;
1025 210 : oid last;
1026 210 : gdk_return rc;
1027 :
1028 210 : MT_thread_setalgorithm(__func__);
1029 210 : if (distinct && !bi->key) {
1030 0 : su = s;
1031 0 : s = BATunique(bi->b, s);
1032 0 : if (s == NULL)
1033 : return GDK_FAIL;
1034 : }
1035 210 : bn = BATfirstn_unique(bi, s, n, asc, nilslast, &last, t0);
1036 210 : if (bn == NULL)
1037 : return GDK_FAIL;
1038 210 : if (BATcount(bn) == 0) {
1039 0 : if (gids) {
1040 0 : gn = BATdense(0, 0, 0);
1041 0 : if (gn == NULL) {
1042 0 : BBPunfix(bn->batCacheid);
1043 0 : return GDK_FAIL;
1044 : }
1045 0 : *gids = gn;
1046 : }
1047 0 : *topn = bn;
1048 0 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
1049 : ",n=" BUNFMT " -> " ALGOOPTBATFMT "," ALGOOPTBATFMT
1050 : " (empty -- " LLFMT " usec)\n",
1051 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
1052 : ALGOOPTBATPAR(bn), ALGOOPTBATPAR(gn), GDKusec() - t0);
1053 0 : return GDK_SUCCEED;
1054 : }
1055 210 : if (!bi->key) {
1056 184 : if (distinct) {
1057 0 : BAT *bn1;
1058 :
1059 0 : bn1 = bn;
1060 0 : BBPunfix(s->batCacheid);
1061 0 : bn = BATintersect(bi->b, bi->b, su, bn1, true, false, BUN_NONE);
1062 0 : BBPunfix(bn1->batCacheid);
1063 0 : if (bn == NULL)
1064 : return GDK_FAIL;
1065 184 : } else if (last != oid_nil) {
1066 94 : BAT *bn1, *bn2;
1067 :
1068 94 : bn1 = bn;
1069 94 : bn2 = BATselect(bi->b, s, BUNtail(*bi, last - bi->b->hseqbase), NULL, true, false, false);
1070 94 : if (bn2 == NULL) {
1071 0 : BBPunfix(bn1->batCacheid);
1072 0 : return GDK_FAIL;
1073 : }
1074 94 : bn = BATmergecand(bn1, bn2);
1075 94 : BBPunfix(bn1->batCacheid);
1076 94 : BBPunfix(bn2->batCacheid);
1077 94 : if (bn == NULL)
1078 : return GDK_FAIL;
1079 : }
1080 : }
1081 210 : if (gids) {
1082 210 : BAT *bn1, *bn2, *bn3, *bn4;
1083 210 : bn1 = BATproject(bn, bi->b);
1084 210 : if (bn1 == NULL) {
1085 0 : BBPunfix(bn->batCacheid);
1086 0 : return GDK_FAIL;
1087 : }
1088 210 : rc = BATsort(NULL, &bn2, &bn3, bn1, NULL, NULL, !asc, !asc, false);
1089 210 : BBPunfix(bn1->batCacheid);
1090 210 : if (rc != GDK_SUCCEED) {
1091 0 : BBPunfix(bn->batCacheid);
1092 0 : return GDK_FAIL;
1093 : }
1094 210 : rc = BATsort(NULL, &bn4, NULL, bn2, NULL, NULL, false, false, false);
1095 210 : BBPunfix(bn2->batCacheid);
1096 210 : if (rc != GDK_SUCCEED) {
1097 0 : BBPunfix(bn->batCacheid);
1098 0 : BBPunfix(bn3->batCacheid);
1099 0 : return GDK_FAIL;
1100 : }
1101 210 : gn = BATproject(bn4, bn3);
1102 210 : BBPunfix(bn3->batCacheid);
1103 210 : BBPunfix(bn4->batCacheid);
1104 210 : if (gn == NULL) {
1105 0 : BBPunfix(bn->batCacheid);
1106 0 : return GDK_FAIL;
1107 : }
1108 210 : *gids = gn;
1109 210 : assert(BATcount(gn) == BATcount(bn));
1110 : }
1111 210 : *topn = bn;
1112 210 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
1113 : ",n=" BUNFMT " -> " ALGOOPTBATFMT "," ALGOOPTBATFMT
1114 : " (" LLFMT " usec)\n",
1115 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), n,
1116 : ALGOOPTBATPAR(bn), ALGOOPTBATPAR(gn), GDKusec() - t0);
1117 : return GDK_SUCCEED;
1118 : }
1119 :
1120 : static gdk_return
1121 275 : BATfirstn_grouped_with_groups(BAT **topn, BAT **gids, BATiter *bi, BAT *s, BAT *g, BUN n, bool asc, bool nilslast, bool distinct, lng t0)
1122 : {
1123 275 : BAT *bn, *gn = NULL;
1124 275 : oid hseq = bi->b->hseqbase;
1125 275 : oid last, lastg;
1126 275 : gdk_return rc;
1127 :
1128 275 : MT_thread_setalgorithm(__func__);
1129 275 : if (distinct) {
1130 0 : BAT *bn1, *bn2, *bn3, *bn4, *bn5, *bn6, *bn7;
1131 0 : if (BATgroup(&bn1, &bn2, NULL, bi->b, s, g, NULL, NULL) != GDK_SUCCEED)
1132 0 : return GDK_FAIL;
1133 0 : bn3 = BATproject(bn2, bi->b);
1134 0 : if (bn3 == NULL) {
1135 0 : BBPunfix(bn1->batCacheid);
1136 0 : BBPunfix(bn2->batCacheid);
1137 0 : return GDK_FAIL;
1138 : }
1139 0 : bn4 = BATintersect(s, bn2, NULL, NULL, false, false, BUN_NONE);
1140 0 : BBPunfix(bn2->batCacheid);
1141 0 : if (bn4 == NULL) {
1142 0 : BBPunfix(bn1->batCacheid);
1143 0 : return GDK_FAIL;
1144 : }
1145 0 : bn5 = BATproject(bn4, g);
1146 0 : BBPunfix(bn4->batCacheid);
1147 0 : if (bn5 == NULL) {
1148 0 : BBPunfix(bn1->batCacheid);
1149 0 : return GDK_FAIL;
1150 : }
1151 0 : BATiter bn3i = bat_iterator(bn3);
1152 0 : bn6 = BATfirstn_unique_with_groups(&bn3i, NULL, bn5, n, asc, nilslast, NULL, NULL, t0);
1153 0 : bat_iterator_end(&bn3i);
1154 0 : BBPunfix(bn3->batCacheid);
1155 0 : BBPunfix(bn5->batCacheid);
1156 0 : if (bn6 == NULL) {
1157 0 : BBPunfix(bn1->batCacheid);
1158 0 : return GDK_FAIL;
1159 : }
1160 0 : rc = BATleftjoin(&bn7, NULL, bn1, bn6, NULL, NULL, false, BUN_NONE);
1161 0 : BBPunfix(bn6->batCacheid);
1162 0 : if (rc != GDK_SUCCEED)
1163 : return GDK_FAIL;
1164 0 : bn = BATproject(bn7, s);
1165 0 : BBPunfix(bn7->batCacheid);
1166 0 : if (bn == NULL)
1167 : return GDK_FAIL;
1168 : } else {
1169 275 : bn = BATfirstn_unique_with_groups(bi, s, g, n, asc, nilslast, &last, &lastg, t0);
1170 275 : if (bn == NULL)
1171 : return GDK_FAIL;
1172 : }
1173 275 : if (BATcount(bn) == 0) {
1174 0 : if (gids) {
1175 0 : gn = BATdense(0, 0, 0);
1176 0 : if (gn == NULL) {
1177 0 : BBPunfix(bn->batCacheid);
1178 0 : return GDK_FAIL;
1179 : }
1180 0 : *gids = gn;
1181 : }
1182 0 : *topn = bn;
1183 0 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
1184 : ",g=" ALGOBATFMT ",n=" BUNFMT
1185 : " -> " ALGOOPTBATFMT "," ALGOOPTBATFMT
1186 : " (empty -- " LLFMT " usec)\n",
1187 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), ALGOBATPAR(g), n,
1188 : ALGOOPTBATPAR(bn), ALGOOPTBATPAR(gn), GDKusec() - t0);
1189 0 : return GDK_SUCCEED;
1190 : }
1191 275 : if (!distinct && !bi->key) {
1192 256 : BAT *bn1, *bn2, *bn3, *bn4;
1193 :
1194 256 : bn1 = bn;
1195 256 : bn2 = BATselect(g, NULL, &lastg, NULL, true, false, false);
1196 256 : if (bn2 == NULL) {
1197 0 : BBPunfix(bn1->batCacheid);
1198 0 : return GDK_FAIL;
1199 : }
1200 256 : bn3 = BATproject(bn2, s);
1201 256 : BBPunfix(bn2->batCacheid);
1202 256 : if (bn3 == NULL) {
1203 0 : BBPunfix(bn1->batCacheid);
1204 0 : return GDK_FAIL;
1205 : }
1206 256 : bn4 = BATselect(bi->b, bn3, BUNtail(*bi, last - hseq), NULL, true, false, false);
1207 256 : BBPunfix(bn3->batCacheid);
1208 256 : if (bn4 == NULL) {
1209 0 : BBPunfix(bn1->batCacheid);
1210 0 : return GDK_FAIL;
1211 : }
1212 256 : bn = BATmergecand(bn1, bn4);
1213 256 : BBPunfix(bn1->batCacheid);
1214 256 : BBPunfix(bn4->batCacheid);
1215 256 : if (bn == NULL)
1216 : return GDK_FAIL;
1217 : }
1218 275 : if (gids) {
1219 275 : BAT *bn1, *bn2, *bn3, *bn4, *bn5, *bn6, *bn7, *bn8;
1220 :
1221 275 : if ((bn1 = BATintersect(s, bn, NULL, NULL, false, false, BUN_NONE)) == NULL) {
1222 0 : BBPunfix(bn->batCacheid);
1223 0 : return GDK_FAIL;
1224 : }
1225 275 : bn2 = BATproject(bn1, g);
1226 275 : BBPunfix(bn1->batCacheid);
1227 275 : if (bn2 == NULL) {
1228 0 : BBPunfix(bn->batCacheid);
1229 0 : return GDK_FAIL;
1230 : }
1231 275 : bn3 = BATproject(bn, bi->b);
1232 275 : if (bn3 == NULL) {
1233 0 : BBPunfix(bn2->batCacheid);
1234 0 : return GDK_FAIL;
1235 : }
1236 275 : rc = BATsort(NULL, &bn4, &bn5, bn2, NULL, NULL, false, false, false);
1237 275 : BBPunfix(bn2->batCacheid);
1238 275 : if (rc != GDK_SUCCEED) {
1239 0 : BBPunfix(bn->batCacheid);
1240 0 : BBPunfix(bn3->batCacheid);
1241 0 : return GDK_FAIL;
1242 : }
1243 275 : rc = BATsort(NULL, &bn6, &bn7, bn3, bn4, bn5, !asc, !asc, false);
1244 275 : BBPunfix(bn3->batCacheid);
1245 275 : BBPunfix(bn4->batCacheid);
1246 275 : BBPunfix(bn5->batCacheid);
1247 275 : if (rc != GDK_SUCCEED) {
1248 0 : BBPunfix(bn->batCacheid);
1249 0 : return GDK_FAIL;
1250 : }
1251 275 : rc = BATsort(NULL, &bn8, NULL, bn6, NULL, NULL, false, false, false);
1252 275 : BBPunfix(bn6->batCacheid);
1253 275 : if (rc != GDK_SUCCEED) {
1254 0 : BBPunfix(bn->batCacheid);
1255 0 : BBPunfix(bn7->batCacheid);
1256 0 : return GDK_FAIL;
1257 : }
1258 275 : gn = BATproject(bn8, bn7);
1259 275 : BBPunfix(bn7->batCacheid);
1260 275 : BBPunfix(bn8->batCacheid);
1261 275 : if (gn == NULL) {
1262 0 : BBPunfix(bn->batCacheid);
1263 0 : return GDK_FAIL;
1264 : }
1265 275 : *gids = gn;
1266 275 : assert(BATcount(gn) == BATcount(bn));
1267 : }
1268 275 : *topn = bn;
1269 275 : TRC_DEBUG(ALGO, "b=" ALGOBATFMT ",s=" ALGOOPTBATFMT
1270 : ",g=" ALGOBATFMT ",n=" BUNFMT
1271 : " -> " ALGOOPTBATFMT "," ALGOOPTBATFMT
1272 : " (" LLFMT " usec)\n",
1273 : ALGOBATPAR(bi->b), ALGOOPTBATPAR(s), ALGOBATPAR(g), n,
1274 : ALGOOPTBATPAR(bn), ALGOOPTBATPAR(gn), GDKusec() - t0);
1275 : return GDK_SUCCEED;
1276 : }
1277 :
1278 : gdk_return
1279 1269 : BATfirstn(BAT **topn, BAT **gids, BAT *b, BAT *s, BAT *g, BUN n, bool asc, bool nilslast, bool distinct)
1280 : {
1281 1269 : lng t0 = 0;
1282 1269 : gdk_return rc = GDK_SUCCEED;
1283 :
1284 1269 : assert(topn != NULL);
1285 1269 : if (b == NULL) {
1286 0 : *topn = NULL;
1287 0 : return GDK_SUCCEED;
1288 : }
1289 :
1290 1269 : TRC_DEBUG_IF(ALGO) t0 = GDKusec();
1291 :
1292 1269 : (void) BATordered(b);
1293 1269 : (void) BATordered_rev(b);
1294 :
1295 1269 : BATiter bi = bat_iterator(b);
1296 :
1297 : /* if g specified, then so must s */
1298 1269 : assert(g == NULL || s != NULL);
1299 : /* g and s must be aligned (same size, same hseqbase) */
1300 1269 : assert(g == NULL || BATcount(s) == BATcount(g));
1301 492 : assert(g == NULL || BATcount(g) == 0 || s->hseqbase == g->hseqbase);
1302 :
1303 1269 : if (n == 0 || BATcount(b) == 0 || (s != NULL && BATcount(s) == 0)) {
1304 : /* trivial: empty result */
1305 59 : *topn = BATdense(0, 0, 0);
1306 59 : if (*topn == NULL) {
1307 : rc = GDK_FAIL;
1308 59 : } else if (gids) {
1309 25 : *gids = BATdense(0, 0, 0);
1310 25 : if (*gids == NULL) {
1311 0 : BBPreclaim(*topn);
1312 : rc = GDK_FAIL;
1313 : }
1314 : }
1315 1210 : } else if (g == NULL) {
1316 741 : if (gids == NULL && !distinct) {
1317 531 : *topn = BATfirstn_unique(&bi, s, n, asc, nilslast, NULL, t0);
1318 531 : rc = *topn ? GDK_SUCCEED : GDK_FAIL;
1319 : } else {
1320 210 : rc = BATfirstn_grouped(topn, gids, &bi, s, n, asc, nilslast, distinct, t0);
1321 : }
1322 469 : } else if (gids == NULL && !distinct) {
1323 194 : *topn = BATfirstn_unique_with_groups(&bi, s, g, n, asc, nilslast, NULL, NULL, t0);
1324 194 : rc = *topn ? GDK_SUCCEED : GDK_FAIL;
1325 : } else {
1326 275 : rc = BATfirstn_grouped_with_groups(topn, gids, &bi, s, g, n, asc, nilslast, distinct, t0);
1327 : }
1328 1269 : bat_iterator_end(&bi);
1329 1269 : return rc;
1330 : }
|