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 199660 : CMDBATnew(Client cntxt, MalBlkPtr m, MalStkPtr s, InstrPtr p)
42 : {
43 199660 : int tt;
44 199660 : role_t kind = TRANSIENT;
45 199660 : BUN cap = 0;
46 199660 : bat *res;
47 :
48 199660 : (void) cntxt;
49 199660 : res = getArgReference_bat(s, p, 0);
50 199660 : tt = getArgType(m, p, 1);
51 199660 : 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 199660 : kind = PERSISTENT;
67 : }
68 :
69 199660 : if (tt == TYPE_any || isaBatType(tt))
70 1 : throw(MAL, "bat.new", SEMANTIC_TYPE_ERROR);
71 199659 : return (str) BKCnewBAT(res, &tt, &cap, kind);
72 : }
73 :
74 : static str
75 2294 : CMDBATdup(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
76 : {
77 2294 : BAT *b, *i;
78 2294 : bat *ret = getArgReference_bat(stk, pci, 0);
79 2294 : int tt = getArgType(mb, pci, 1);
80 2294 : bat input = *getArgReference_bat(stk, pci, 2);
81 :
82 2294 : (void) cntxt;
83 2294 : if ((i = BBPquickdesc(input)) == NULL)
84 0 : throw(MAL, "bat.new", INTERNAL_BAT_ACCESS);
85 2294 : b = COLnew(i->hseqbase, tt, BATcount(i), TRANSIENT);
86 2294 : if (b == 0)
87 0 : throw(MAL, "bat.new", SQLSTATE(HY013) MAL_MALLOC_FAIL);
88 2294 : *ret = b->batCacheid;
89 2294 : BBPretain(b->batCacheid);
90 2294 : BBPunfix(b->batCacheid);
91 2294 : return MAL_SUCCEED;
92 : }
93 :
94 : static str
95 12340 : CMDBATsingle(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
96 : {
97 12340 : BAT *b;
98 12340 : int *ret = getArgReference_bat(stk, pci, 0);
99 12340 : void *u = (void *) getArgReference(stk, pci, 1);
100 :
101 12342 : (void) cntxt;
102 :
103 12342 : b = COLnew(0, getArgType(mb, pci, 1), 0, TRANSIENT);
104 12343 : if (b == 0)
105 0 : throw(MAL, "bat.single", SQLSTATE(HY013) MAL_MALLOC_FAIL);
106 12343 : if (ATOMextern(b->ttype))
107 3506 : u = (ptr) *(ptr *) u;
108 12343 : if (BUNappend(b, u, false) != GDK_SUCCEED) {
109 0 : BBPreclaim(b);
110 0 : throw(MAL, "bat.single", SQLSTATE(HY013) MAL_MALLOC_FAIL);
111 : }
112 12337 : *ret = b->batCacheid;
113 12337 : BBPkeepref(b);
114 12337 : 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 137714 : CMDBATappend_bulk(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
199 : {
200 137714 : bat *r = getArgReference_bat(stk, pci, 0),
201 137714 : *bid = getArgReference_bat(stk, pci, 1);
202 137714 : bit force = *getArgReference_bit(stk, pci, 2);
203 137714 : BAT *b;
204 137714 : BUN inputs = (BUN) (pci->argc - 3), number_existing = 0, total = 0;
205 :
206 137714 : (void) cntxt;
207 137714 : if ((b = BATdescriptor(*bid)) == NULL)
208 0 : throw(MAL, "bat.append_bulk", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
209 :
210 137697 : if (inputs > 0) {
211 137697 : number_existing = BATcount(b);
212 :
213 137697 : if (isaBatType(getArgType(mb, pci, 3))) { /* use BATappend for the bulk case */
214 0 : gdk_return rt;
215 0 : for (int i = 3, args = pci->argc; i < args; i++) {
216 0 : BAT *d = BATdescriptor(*getArgReference_bat(stk, pci, i));
217 0 : if (!d) {
218 0 : BBPunfix(b->batCacheid);
219 0 : throw(MAL, "bat.append_bulk",
220 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
221 : }
222 0 : if (mask_cand(d)) {
223 0 : BAT *du = d;
224 0 : d = BATunmask(d);
225 0 : BBPunfix(du->batCacheid);
226 0 : if (!d) {
227 0 : BBPunfix(b->batCacheid);
228 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
229 : }
230 : }
231 0 : rt = BATappend(b, d, NULL, force);
232 0 : BBPunfix(d->batCacheid);
233 0 : if (rt != GDK_SUCCEED) {
234 0 : BBPunfix(b->batCacheid);
235 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
236 : }
237 : }
238 : } else {
239 137697 : bool external = ATOMextern(b->ttype);
240 137697 : total = number_existing + inputs;
241 137697 : if (BATextend(b, total) != GDK_SUCCEED) {
242 0 : BBPunfix(b->batCacheid);
243 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
244 : }
245 874770 : for (int i = 3, args = pci->argc; i < args; i++) {
246 737053 : ptr u = getArgReference(stk, pci, i);
247 734927 : if (external)
248 143092 : u = (ptr) *(ptr *) u;
249 734927 : if (BUNappend(b, u, force) != GDK_SUCCEED) {
250 0 : BBPunfix(b->batCacheid);
251 0 : throw(MAL, "bat.append_bulk", GDK_EXCEPTION);
252 : }
253 : }
254 : }
255 : }
256 :
257 137717 : *r = b->batCacheid;
258 137717 : BBPretain(b->batCacheid);
259 137727 : BBPunfix(b->batCacheid);
260 137727 : return MAL_SUCCEED;
261 : }
262 :
263 : static str
264 1 : CMDBATvacuum(bat *r, const bat *bid)
265 : {
266 1 : BAT *b, *bn;
267 :
268 1 : if ((b = BATdescriptor(*bid)) == NULL)
269 0 : throw(MAL, "bat.vacuum", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
270 1 : if ((bn = COLcopy(b, b->ttype, true, b->batRole)) == NULL) {
271 0 : BBPunfix(b->batCacheid);
272 0 : throw(MAL, "bat.vacuum", GDK_EXCEPTION);
273 : }
274 :
275 1 : *r = bn->batCacheid;
276 1 : BBPkeepref(bn);
277 1 : BBPunfix(b->batCacheid);
278 1 : return MAL_SUCCEED;
279 : }
280 :
281 : #include "mel.h"
282 : mel_func batExtensions_init_funcs[] = {
283 : pattern("bat", "new", CMDBATnew, false, "", args(1,2, batargany("",1),argany("tt",1))),
284 : pattern("bat", "new", CMDBATnew, false, "", args(1,3, batargany("",1),argany("tt",1),arg("size",int))),
285 : pattern("bat", "new", CMDBATnew, false, "", args(1,4, batargany("",1),argany("tt",1),arg("size",lng),arg("persist",bit))),
286 : pattern("bat", "new", CMDBATnew, false, "", args(1,4, batargany("",1),argany("tt",1),arg("size",int),arg("persist",bit))),
287 : 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))),
288 : 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))),
289 : pattern("bat", "single", CMDBATsingle, false, "Create a BAT with a single element", args(1,2, batargany("",1),argany("val",1))),
290 : pattern("bat", "partition", CMDBATpartition, false, "Create a series of slices over the BAT argument. The BUNs are distributed evenly.", args(1,2, batvarargany("",1),batargany("b",1))),
291 : 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))),
292 : 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))),
293 : 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))),
294 : command("bat", "vacuum", CMDBATvacuum, false, "", args(1,2, batarg("",str),batarg("b",str))),
295 : { .imp=NULL }
296 : };
297 : #include "mal_import.h"
298 : #ifdef _MSC_VER
299 : #undef read
300 : #pragma section(".CRT$XCU",read)
301 : #endif
302 323 : LIB_STARTUP_FUNC(init_batExtensions_mal)
303 323 : { mal_module("batExtensions", NULL, batExtensions_init_funcs); }
|