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