Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * M.L.Kersten
15 : * BAT Algebra Extensions
16 : * The kernel libraries are unaware of the MAL runtime semantics.
17 : * This calls for declaring some operations in the MAL module section
18 : * and register them in the kernel modules explicitly.
19 : *
20 : * A good example of this borderline case are BAT creation operations,
21 : * which require a mapping of the type identifier to the underlying
22 : * implementation type.
23 : *
24 : * Another example concerns the (un)pack operations, which direct
25 : * access the runtime stack to (push)pull the values needed.
26 : */
27 : #include "monetdb_config.h"
28 : #include "mal_client.h"
29 : #include "mal_interpreter.h"
30 : #include "bat5.h"
31 : #include "gdk_time.h"
32 : #include "mal_instruction.h"
33 : #include "mal_exception.h"
34 :
35 : /*
36 : * BAT enhancements
37 : * The code to enhance the kernel.
38 : */
39 :
40 : static str
41 208709 : CMDBATnew(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
42 : {
43 208709 : int tt;
44 208709 : role_t kind = TRANSIENT;
45 208709 : BUN cap = 0;
46 208709 : bat *res;
47 :
48 208709 : (void) cntxt;
49 208709 : res = getArgReference_bat(s, p, 0);
50 208709 : tt = getArgType(m, p, 1);
51 208709 : if (p->argc > 2) {
52 2 : lng lcap;
53 :
54 2 : if (getArgType(m, p, 2) == TYPE_lng)
55 0 : lcap = *getArgReference_lng(s, p, 2);
56 2 : else if (getArgType(m, p, 2) == TYPE_int)
57 2 : lcap = (lng) *getArgReference_int(s, p, 2);
58 : else
59 0 : throw(MAL, "bat.new", ILLEGAL_ARGUMENT " Incorrect type for size");
60 2 : if (lcap < 0)
61 0 : throw(MAL, "bat.new", POSITIVE_EXPECTED);
62 2 : if (lcap > (lng) BUN_MAX)
63 0 : throw(MAL, "bat.new", ILLEGAL_ARGUMENT " Capacity too large");
64 2 : cap = (BUN) lcap;
65 2 : if (p->argc == 4 && getVarConstant(m, getArg(p, 3)).val.ival)
66 208709 : kind = PERSISTENT;
67 : }
68 :
69 208709 : if (tt == TYPE_any || isaBatType(tt))
70 1 : throw(MAL, "bat.new", SEMANTIC_TYPE_ERROR);
71 208708 : return (str) BKCnewBAT(res, &tt, &cap, kind);
72 : }
73 :
74 : static str
75 623 : CMDBATdup(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
76 : {
77 623 : BAT *b, *i;
78 623 : bat *ret = getArgReference_bat(stk, pci, 0);
79 623 : int tt = getArgType(mb, pci, 1);
80 623 : bat input = *getArgReference_bat(stk, pci, 2);
81 :
82 623 : (void) cntxt;
83 623 : if ((i = BBPquickdesc(input)) == NULL)
84 0 : throw(MAL, "bat.new", INTERNAL_BAT_ACCESS);
85 623 : b = COLnew(i->hseqbase, tt, BATcount(i), TRANSIENT);
86 623 : if (b == 0)
87 0 : throw(MAL, "bat.new", SQLSTATE(HY013) MAL_MALLOC_FAIL);
88 623 : *ret = b->batCacheid;
89 623 : BBPretain(b->batCacheid);
90 623 : BBPunfix(b->batCacheid);
91 623 : return MAL_SUCCEED;
92 : }
93 :
94 : static str
95 8110 : CMDBATsingle(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
96 : {
97 8110 : BAT *b;
98 8110 : int *ret = getArgReference_bat(stk, pci, 0);
99 8110 : void *u = (void *) getArgReference(stk, pci, 1);
100 :
101 8111 : (void) cntxt;
102 :
103 8111 : b = COLnew(0, getArgType(mb, pci, 1), 0, TRANSIENT);
104 8110 : if (b == 0)
105 0 : throw(MAL, "bat.single", SQLSTATE(HY013) MAL_MALLOC_FAIL);
106 8110 : if (ATOMextern(b->ttype))
107 1868 : u = (ptr) *(ptr *) u;
108 8110 : if (BUNappend(b, u, false) != GDK_SUCCEED) {
109 0 : BBPreclaim(b);
110 0 : throw(MAL, "bat.single", SQLSTATE(HY013) MAL_MALLOC_FAIL);
111 : }
112 8104 : *ret = b->batCacheid;
113 8104 : BBPkeepref(b);
114 8104 : return MAL_SUCCEED;
115 : }
116 :
117 : /* If the optimizer has not determined the partition bounds we derive one here. */
118 : static str
119 2 : CMDBATpartition(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
120 : {
121 2 : BAT *b, *bn;
122 2 : bat *ret;
123 2 : int i;
124 2 : bat bid;
125 2 : oid lval, hval = 0, step;
126 :
127 2 : (void) mb;
128 2 : (void) cntxt;
129 2 : bid = *getArgReference_bat(stk, pci, pci->retc);
130 :
131 2 : if ((b = BATdescriptor(bid)) == NULL) {
132 0 : throw(MAL, "bat.partition", INTERNAL_BAT_ACCESS);
133 : }
134 2 : step = BATcount(b) / pci->retc + 1;
135 :
136 : /* create the slices slightly overshoot to make sure it all is taken */
137 5 : for (i = 0; i < pci->retc; i++) {
138 3 : lval = i * step;
139 3 : hval = lval + step;
140 3 : if (i == pci->retc - 1)
141 2 : hval = BATcount(b);
142 3 : bn = BATslice(b, lval, hval);
143 3 : if (bn == NULL) {
144 0 : BBPunfix(b->batCacheid);
145 0 : throw(MAL, "bat.partition", SQLSTATE(HY013) MAL_MALLOC_FAIL);
146 : }
147 3 : BAThseqbase(bn, lval);
148 3 : stk->stk[getArg(pci, i)].val.bval = bn->batCacheid;
149 3 : ret = getArgReference_bat(stk, pci, i);
150 3 : *ret = bn->batCacheid;
151 3 : BBPkeepref(bn);
152 : }
153 2 : BBPunfix(b->batCacheid);
154 2 : return MAL_SUCCEED;
155 : }
156 :
157 : static str
158 9 : CMDBATpartition2(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
159 : {
160 9 : BAT *b, *bn;
161 9 : bat *ret, bid;
162 9 : int pieces = *getArgReference_int(stk, pci, 2);
163 9 : int idx = *getArgReference_int(stk, pci, 3);
164 9 : oid lval, hval = 0, step;
165 :
166 9 : (void) mb;
167 9 : (void) cntxt;
168 9 : if (pieces <= 0)
169 0 : throw(MAL, "bat.partition", POSITIVE_EXPECTED);
170 9 : if (idx >= pieces || idx < 0)
171 1 : throw(MAL, "bat.partition", ILLEGAL_ARGUMENT " Illegal piece index");
172 :
173 8 : bid = *getArgReference_bat(stk, pci, pci->retc);
174 :
175 8 : if ((b = BATdescriptor(bid)) == NULL) {
176 0 : throw(MAL, "bat.partition", INTERNAL_BAT_ACCESS);
177 : }
178 8 : step = BATcount(b) / pieces;
179 :
180 8 : lval = idx * step;
181 8 : if (idx == pieces - 1)
182 : hval = BATcount(b);
183 : else
184 4 : hval = lval + step;
185 8 : bn = BATslice(b, lval, hval);
186 8 : BAThseqbase(bn, lval + b->hseqbase);
187 8 : BBPunfix(b->batCacheid);
188 8 : if (bn == NULL) {
189 0 : throw(MAL, "bat.partition", INTERNAL_OBJ_CREATE);
190 : }
191 8 : ret = getArgReference_bat(stk, pci, 0);
192 8 : *ret = bn->batCacheid;
193 8 : BBPkeepref(bn);
194 8 : return MAL_SUCCEED;
195 : }
196 :
197 : static str
198 1 : CMDBATimprints(void *ret, bat *bid)
199 : {
200 1 : BAT *b;
201 1 : gdk_return r;
202 :
203 1 : (void) ret;
204 1 : if ((b = BATdescriptor(*bid)) == NULL)
205 0 : throw(MAL, "bat.imprints", INTERNAL_BAT_ACCESS);
206 :
207 1 : r = BATimprints(b);
208 1 : BBPunfix(b->batCacheid);
209 1 : if (r != GDK_SUCCEED)
210 0 : throw(MAL, "bat.imprints", GDK_EXCEPTION);
211 : return MAL_SUCCEED;
212 : }
213 :
214 : static str
215 0 : CMDBATimprintsize(lng *ret, bat *bid)
216 : {
217 0 : BAT *b;
218 :
219 0 : if ((b = BATdescriptor(*bid)) == NULL)
220 0 : throw(MAL, "bat.imprints", INTERNAL_BAT_ACCESS);
221 :
222 0 : *ret = IMPSimprintsize(b);
223 0 : BBPunfix(b->batCacheid);
224 0 : return MAL_SUCCEED;
225 : }
226 :
227 : static str
228 137080 : CMDBATappend_bulk(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
229 : {
230 137080 : bat *r = getArgReference_bat(stk, pci, 0),
231 137080 : *bid = getArgReference_bat(stk, pci, 1);
232 137080 : bit force = *getArgReference_bit(stk, pci, 2);
233 137080 : BAT *b;
234 137080 : BUN inputs = (BUN) (pci->argc - 3), number_existing = 0, total = 0;
235 :
236 137080 : (void) cntxt;
237 137080 : if ((b = BATdescriptor(*bid)) == NULL)
238 0 : throw(MAL, "bat.append_bulk", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
239 :
240 137087 : if (inputs > 0) {
241 137087 : number_existing = BATcount(b);
242 :
243 137087 : if (isaBatType(getArgType(mb, pci, 3))) { /* use BATappend for the bulk case */
244 0 : gdk_return rt;
245 0 : for (int i = 3, args = pci->argc; i < args; i++) {
246 0 : BAT *d = BATdescriptor(*getArgReference_bat(stk, pci, i));
247 0 : if (!d) {
248 0 : BBPunfix(b->batCacheid);
249 0 : throw(MAL, "bat.append_bulk",
250 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
251 : }
252 0 : if (mask_cand(d)) {
253 0 : BAT *du = d;
254 0 : d = BATunmask(d);
255 0 : BBPunfix(du->batCacheid);
256 0 : if (!d) {
257 0 : BBPunfix(b->batCacheid);
258 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
259 : }
260 : }
261 0 : rt = BATappend(b, d, NULL, force);
262 0 : BBPunfix(d->batCacheid);
263 0 : if (rt != GDK_SUCCEED) {
264 0 : BBPunfix(b->batCacheid);
265 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
266 : }
267 : }
268 : } else {
269 137087 : bool external = ATOMextern(b->ttype);
270 137087 : total = number_existing + inputs;
271 137087 : if (BATextend(b, total) != GDK_SUCCEED) {
272 0 : BBPunfix(b->batCacheid);
273 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
274 : }
275 857362 : for (int i = 3, args = pci->argc; i < args; i++) {
276 720315 : ptr u = getArgReference(stk, pci, i);
277 717851 : if (external)
278 139379 : u = (ptr) *(ptr *) u;
279 717851 : if (BUNappend(b, u, force) != GDK_SUCCEED) {
280 0 : BBPunfix(b->batCacheid);
281 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
282 : }
283 : }
284 : }
285 : }
286 :
287 137047 : *r = b->batCacheid;
288 137047 : BBPretain(b->batCacheid);
289 137099 : BBPunfix(b->batCacheid);
290 137099 : return MAL_SUCCEED;
291 : }
292 :
293 : static str
294 1 : CMDBATvacuum(bat *r, const bat *bid)
295 : {
296 1 : BAT *b, *bn;
297 :
298 1 : if ((b = BATdescriptor(*bid)) == NULL)
299 0 : throw(MAL, "bat.vacuum", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
300 1 : if ((bn = COLcopy(b, b->ttype, true, b->batRole)) == NULL) {
301 0 : BBPunfix(b->batCacheid);
302 0 : throw(MAL, "bat.vacuum", GDK_EXCEPTION);
303 : }
304 :
305 1 : *r = bn->batCacheid;
306 1 : BBPkeepref(bn);
307 1 : BBPunfix(b->batCacheid);
308 1 : return MAL_SUCCEED;
309 : }
310 :
311 : #include "mel.h"
312 : mel_func batExtensions_init_funcs[] = {
313 : pattern("bat", "new", CMDBATnew, false, "", args(1,2, batargany("",1),argany("tt",1))),
314 : pattern("bat", "new", CMDBATnew, false, "", args(1,3, batargany("",1),argany("tt",1),arg("size",int))),
315 : pattern("bat", "new", CMDBATnew, false, "", args(1,4, batargany("",1),argany("tt",1),arg("size",lng),arg("persist",bit))),
316 : pattern("bat", "new", CMDBATnew, false, "", args(1,4, batargany("",1),argany("tt",1),arg("size",int),arg("persist",bit))),
317 : pattern("bat", "new", CMDBATnew, false, "Creates a new empty transient BAT, with tail-types as indicated.", args(1,3, batargany("",1),argany("tt",1),arg("size",lng))),
318 : pattern("bat", "new", CMDBATdup, false, "Creates a new empty transient BAT, with tail-type tt and hseqbase and size from the input bat argument.", args(1,3, batargany("",1), argany("tt",1),batargany("i",2))),
319 : pattern("bat", "single", CMDBATsingle, false, "Create a BAT with a single elemenet", args(1,2, batargany("",1),argany("val",1))),
320 : pattern("bat", "partition", CMDBATpartition, false, "Create a serie of slices over the BAT argument. The BUNs are distributed evenly.", args(1,2, batvarargany("",1),batargany("b",1))),
321 : pattern("bat", "partition", CMDBATpartition2, false, "Create the n-th slice over the BAT broken into several pieces.", args(1,4, batargany("",1),batargany("b",1),arg("pieces",int),arg("n",int))),
322 : command("bat", "imprints", CMDBATimprints, false, "", args(1,2, arg("",void),batarg("b",bte))),
323 : command("bat", "imprints", CMDBATimprints, false, "", args(1,2, arg("",void),batarg("b",sht))),
324 : command("bat", "imprints", CMDBATimprints, false, "", args(1,2, arg("",void),batarg("b",int))),
325 : command("bat", "imprints", CMDBATimprints, false, "", args(1,2, arg("",void),batarg("b",lng))),
326 : command("bat", "imprints", CMDBATimprints, false, "", args(1,2, arg("",void),batarg("b",flt))),
327 : command("bat", "imprints", CMDBATimprints, false, "Check for existence or create an imprint index on the BAT.", args(1,2, arg("",void),batarg("b",dbl))),
328 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",bte))),
329 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",sht))),
330 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",int))),
331 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",lng))),
332 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",flt))),
333 : command("bat", "imprintsize", CMDBATimprintsize, false, "Return the storage size of the imprints index structure.", args(1,2, arg("",lng),batarg("b",dbl))),
334 : #ifdef HAVE_HGE
335 : command("bat", "imprints", CMDBATimprints, false, "", args(0,1, batarg("b",hge))),
336 : command("bat", "imprintsize", CMDBATimprintsize, false, "", args(1,2, arg("",lng),batarg("b",hge))),
337 : #endif
338 : pattern("bat", "appendBulk", CMDBATappend_bulk, false, "append the arguments ins to i", args(1,4, batargany("",1), batargany("i",1),arg("force",bit),varargany("ins",1))),
339 : pattern("bat", "appendBulk", CMDBATappend_bulk, false, "append the arguments ins to i", args(1,4, batargany("",1), batargany("i",1),arg("force",bit),batvarargany("ins",1))),
340 : command("bat", "vacuum", CMDBATvacuum, false, "", args(1,2, batarg("",str),batarg("b",str))),
341 : { .imp=NULL }
342 : };
343 : #include "mal_import.h"
344 : #ifdef _MSC_VER
345 : #undef read
346 : #pragma section(".CRT$XCU",read)
347 : #endif
348 329 : LIB_STARTUP_FUNC(init_batExtensions_mal)
349 329 : { mal_module("batExtensions", NULL, batExtensions_init_funcs); }
|