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/* monetdb_config.h must be the first include in each .c file */
10#include "monetdb_config.h"
11#include "udf.h"
12
13/* Reverse a string */
14
15/* actual implementation */
16/* all non-exported functions must be declared static */
17static char *
18UDFreverse_(char **ret, const char *src)
19{
20 size_t len = 0;
21 char *dst = NULL;
22
23 /* assert calling sanity */
24 assert(ret != NULL);
25
26 /* handle NULL pointer and NULL value */
27 if (src == NULL || strcmp(src, str_nil) == 0) {
28 *ret = GDKstrdup(str_nil);
29 if (*ret == NULL)
30 throw(MAL, "udf.reverse",
31 "failed to create copy of str_nil");
32
33 return MAL_SUCCEED;
34 }
35
36 /* allocate result string */
37 len = strlen(src);
38 *ret = dst = GDKmalloc(len + 1);
39 if (dst == NULL)
40 throw(MAL, "udf.reverse",
41 "failed to allocate string of length %zu", len + 1);
42
43 /* copy characters from src to dst in reverse order */
44 dst[len] = 0;
45 while (len > 0)
46 *dst++ = src[--len];
47
48 return MAL_SUCCEED;
49}
50
51/* MAL wrapper */
52char *
53UDFreverse(char **ret, const char **arg)
54{
55 /* assert calling sanity */
56 assert(ret != NULL && arg != NULL);
57
58 return UDFreverse_ ( ret, *arg );
59}
60
61
62/* Reverse a BAT of strings */
63/*
64 * Generic "type-oblivious" version,
65 * using generic "type-oblivious" BAT access interface.
66 */
67
68/* actual implementation */
69static char *
70UDFBATreverse_(BAT **ret, BAT *src)
71{
72 BATiter li;
73 BAT *bn = NULL;
74 BUN p = 0, q = 0;
75
76 /* assert calling sanity */
77 assert(ret != NULL);
78
79 /* handle NULL pointer */
80 if (src == NULL)
81 throw(MAL, "batudf.reverse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
82
83 /* check tail type */
84 if (src->ttype != TYPE_str) {
85 throw(MAL, "batudf.reverse",
86 "tail-type of input BAT must be TYPE_str");
87 }
88
89 /* allocate void-headed result BAT */
90 bn = COLnew(src->hseqbase, TYPE_str, BATcount(src), TRANSIENT);
91 if (bn == NULL) {
92 throw(MAL, "batudf.reverse", SQLSTATE(HY001) MAL_MALLOC_FAIL);
93 }
94
95 /* create BAT iterator */
96 li = bat_iterator(src);
97
98 /* the core of the algorithm, expensive due to malloc/frees */
99 BATloop(src, p, q) {
100 char *tr = NULL, *err = NULL;
101
102 const char *t = (const char *) BUNtvar(li, p);
103
104 /* revert tail value */
105 err = UDFreverse_(&tr, t);
106 if (err != MAL_SUCCEED) {
107 /* error -> bail out */
108 BBPunfix(bn->batCacheid);
109 return err;
110 }
111
112 /* assert logical sanity */
113 assert(tr != NULL);
114
115 /* append reversed tail in result BAT */
116 if (BUNappend(bn, tr, false) != GDK_SUCCEED) {
117 BBPunfix(bn->batCacheid);
118 throw(MAL, "batudf.reverse", SQLSTATE(HY001) MAL_MALLOC_FAIL);
119 }
120
121 /* free memory allocated in UDFreverse_() */
122 GDKfree(tr);
123 }
124
125 *ret = bn;
126
127 return MAL_SUCCEED;
128}
129
130/* MAL wrapper */
131char *
132UDFBATreverse(bat *ret, const bat *arg)
133{
134 BAT *res = NULL, *src = NULL;
135 char *msg = NULL;
136
137 /* assert calling sanity */
138 assert(ret != NULL && arg != NULL);
139
140 /* bat-id -> BAT-descriptor */
141 if ((src = BATdescriptor(*arg)) == NULL)
142 throw(MAL, "batudf.reverse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
143
144 /* do the work */
145 msg = UDFBATreverse_ ( &res, src );
146
147 /* release input BAT-descriptor */
148 BBPunfix(src->batCacheid);
149
150 if (msg == MAL_SUCCEED) {
151 /* register result BAT in buffer pool */
152 BBPkeepref((*ret = res->batCacheid));
153 }
154
155 return msg;
156}
157
158
159
160/* fuse */
161
162/* instantiate type-specific functions */
163
164#define UI bte
165#define UU unsigned char
166#define UO sht
167#include "udf_impl.h"
168#undef UI
169#undef UU
170#undef UO
171
172#define UI sht
173#define UU unsigned short
174#define UO int
175#include "udf_impl.h"
176#undef UI
177#undef UU
178#undef UO
179
180#define UI int
181#define UU unsigned int
182#define UO lng
183#include "udf_impl.h"
184#undef UI
185#undef UU
186#undef UO
187
188#ifdef HAVE_HGE
189#define UI lng
190#define UU ulng
191#define UO hge
192#include "udf_impl.h"
193#undef UI
194#undef UU
195#undef UO
196#endif
197
198/* BAT fuse */
199
200/* actual implementation */
201static char *
202UDFBATfuse_(BAT **ret, const BAT *bone, const BAT *btwo)
203{
204 BAT *bres = NULL;
205 bit two_tail_sorted_unsigned = FALSE;
206 bit two_tail_revsorted_unsigned = FALSE;
207 BUN n;
208 char *msg = NULL;
209
210 /* assert calling sanity */
211 assert(ret != NULL);
212
213 /* handle NULL pointer */
214 if (bone == NULL || btwo == NULL)
215 throw(MAL, "batudf.fuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
216
217 /* check for aligned heads */
218 if (BATcount(bone) != BATcount(btwo) ||
219 bone->hseqbase != btwo->hseqbase) {
220 throw(MAL, "batudf.fuse",
221 "heads of input BATs must be aligned");
222 }
223 n = BATcount(bone);
224
225 /* check tail types */
226 if (bone->ttype != btwo->ttype) {
227 throw(MAL, "batudf.fuse",
228 "tails of input BATs must be identical");
229 }
230
231 /* allocate result BAT */
232 switch (bone->ttype) {
233 case TYPE_bte:
234 bres = COLnew(bone->hseqbase, TYPE_sht, n, TRANSIENT);
235 break;
236 case TYPE_sht:
237 bres = COLnew(bone->hseqbase, TYPE_int, n, TRANSIENT);
238 break;
239 case TYPE_int:
240 bres = COLnew(bone->hseqbase, TYPE_lng, n, TRANSIENT);
241 break;
242#ifdef HAVE_HGE
243 case TYPE_lng:
244 bres = COLnew(bone->hseqbase, TYPE_hge, n, TRANSIENT);
245 break;
246#endif
247 default:
248 throw(MAL, "batudf.fuse",
249 "tails of input BATs must be one of {bte, sht, int"
250#ifdef HAVE_HGE
251 ", lng"
252#endif
253 "}");
254 }
255 if (bres == NULL)
256 throw(MAL, "batudf.fuse", SQLSTATE(HY001) MAL_MALLOC_FAIL);
257
258 /* call type-specific core algorithm */
259 switch (bone->ttype) {
260 case TYPE_bte:
261 msg = UDFBATfuse_bte_sht ( bres, bone, btwo, n,
262 &two_tail_sorted_unsigned, &two_tail_revsorted_unsigned );
263 break;
264 case TYPE_sht:
265 msg = UDFBATfuse_sht_int ( bres, bone, btwo, n,
266 &two_tail_sorted_unsigned, &two_tail_revsorted_unsigned );
267 break;
268 case TYPE_int:
269 msg = UDFBATfuse_int_lng ( bres, bone, btwo, n,
270 &two_tail_sorted_unsigned, &two_tail_revsorted_unsigned );
271 break;
272#ifdef HAVE_HGE
273 case TYPE_lng:
274 msg = UDFBATfuse_lng_hge ( bres, bone, btwo, n,
275 &two_tail_sorted_unsigned, &two_tail_revsorted_unsigned );
276 break;
277#endif
278 default:
279 BBPunfix(bres->batCacheid);
280 throw(MAL, "batudf.fuse",
281 "tails of input BATs must be one of {bte, sht, int"
282#ifdef HAVE_HGE
283 ", lng"
284#endif
285 "}");
286 }
287
288 if (msg != MAL_SUCCEED) {
289 BBPunfix(bres->batCacheid);
290 } else {
291 /* set number of tuples in result BAT */
292 BATsetcount(bres, n);
293
294 /* Result tail is sorted, if the left/first input tail is
295 * sorted and key (unique), or if the left/first input tail is
296 * sorted and the second/right input tail is sorted and the
297 * second/right tail values are either all >= 0 or all < 0;
298 * otherwise, we cannot tell.
299 */
300 if (BATtordered(bone)
301 && (BATtkey(bone) || two_tail_sorted_unsigned))
302 bres->tsorted = true;
303 else
304 bres->tsorted = (BATcount(bres) <= 1);
305 if (BATtrevordered(bone)
306 && (BATtkey(bone) || two_tail_revsorted_unsigned))
307 bres->trevsorted = true;
308 else
309 bres->trevsorted = (BATcount(bres) <= 1);
310 /* result tail is key (unique), iff both input tails are */
311 BATkey(bres, BATtkey(bone) || BATtkey(btwo));
312
313 *ret = bres;
314 }
315
316 return msg;
317}
318
319/* MAL wrapper */
320char *
321UDFBATfuse(bat *ires, const bat *ione, const bat *itwo)
322{
323 BAT *bres = NULL, *bone = NULL, *btwo = NULL;
324 char *msg = NULL;
325
326 /* assert calling sanity */
327 assert(ires != NULL && ione != NULL && itwo != NULL);
328
329 /* bat-id -> BAT-descriptor */
330 if ((bone = BATdescriptor(*ione)) == NULL)
331 throw(MAL, "batudf.fuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
332
333 /* bat-id -> BAT-descriptor */
334 if ((btwo = BATdescriptor(*itwo)) == NULL) {
335 BBPunfix(bone->batCacheid);
336 throw(MAL, "batudf.fuse", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
337 }
338
339 /* do the work */
340 msg = UDFBATfuse_ ( &bres, bone, btwo );
341
342 /* release input BAT-descriptors */
343 BBPunfix(bone->batCacheid);
344 BBPunfix(btwo->batCacheid);
345
346 if (msg == MAL_SUCCEED) {
347 /* register result BAT in buffer pool */
348 BBPkeepref((*ires = bres->batCacheid));
349 }
350
351 return msg;
352}
353