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 : * @f blob
15 : * @v 1.0
16 : * @a Wilko Quak, Peter Boncz, M. Kersten, N. Nes
17 : * @+ The blob data type
18 : * The datatype 'blob' introduced here illustrates the power
19 : * in the hands of a programmer to extend the functionality of the
20 : * Monet GDK library. It consists of an interface specification for
21 : * the necessary operators, a startup routine to register the
22 : * type in thekernel, and some additional operators used outside
23 : * the kernel itself.
24 : *
25 : * The 'blob' data type is used in many database engines to
26 : * store a variable sized atomary value.
27 : * Its definition forms a generic base to store arbitrary structures
28 : * in the database, without knowing its internal coding, layout,
29 : * or interpretation.
30 : *
31 : * The blob memory layout consists of first 4 bytes containing
32 : * the bytes-size of the blob (excluding the integer), and then just binary data.
33 : *
34 : * @+ Module Definition
35 : */
36 : #include "monetdb_config.h"
37 : #include "mal_client.h"
38 : #include "mal_interpreter.h"
39 : #include "mal_exception.h"
40 :
41 : static str
42 1 : BLOBnitems(int *ret, blob **b)
43 : {
44 1 : if (is_blob_nil(*b)) {
45 1 : *ret = int_nil;
46 : } else {
47 0 : assert((*b)->nitems < INT_MAX);
48 0 : *ret = (int) (*b)->nitems;
49 : }
50 1 : return MAL_SUCCEED;
51 : }
52 :
53 : static str
54 85 : BLOBnitems_bulk(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
55 : {
56 85 : BATiter bi;
57 85 : BAT *bn = NULL, *b = NULL, *bs = NULL;
58 85 : int *restrict vals;
59 85 : str msg = MAL_SUCCEED;
60 85 : bool nils = false;
61 85 : struct canditer ci1 = { 0 };
62 85 : oid off1;
63 85 : bat *res = getArgReference_bat(stk, pci, 0),
64 85 : *bid = getArgReference_bat(stk, pci, 1),
65 85 : *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
66 :
67 85 : (void) cntxt;
68 85 : (void) mb;
69 85 : if (!(b = BATdescriptor(*bid))) {
70 0 : msg = createException(MAL, "blob.nitems_bulk",
71 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
72 0 : goto bailout;
73 : }
74 85 : if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
75 0 : msg = createException(MAL, "blob.nitems_bulk",
76 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
77 0 : goto bailout;
78 : }
79 85 : canditer_init(&ci1, b, bs);
80 85 : if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
81 0 : msg = createException(MAL, "blob.nitems_bulk",
82 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
83 0 : goto bailout;
84 : }
85 :
86 85 : off1 = b->hseqbase;
87 85 : bi = bat_iterator(b);
88 85 : vals = Tloc(bn, 0);
89 85 : if (ci1.tpe == cand_dense) {
90 4800096 : for (BUN i = 0; i < ci1.ncand; i++) {
91 4800011 : oid p1 = (canditer_next_dense(&ci1) - off1);
92 4800011 : const blob *b = BUNtvar(bi, p1);
93 :
94 4800011 : if (is_blob_nil(b)) {
95 2 : vals[i] = int_nil;
96 2 : nils = true;
97 : } else {
98 4800009 : assert((int) b->nitems < INT_MAX);
99 4800009 : vals[i] = (int) b->nitems;
100 : }
101 : }
102 : } else {
103 0 : for (BUN i = 0; i < ci1.ncand; i++) {
104 0 : oid p1 = (canditer_next(&ci1) - off1);
105 0 : const blob *b = BUNtvar(bi, p1);
106 :
107 0 : if (is_blob_nil(b)) {
108 0 : vals[i] = int_nil;
109 0 : nils = true;
110 : } else {
111 0 : assert((int) b->nitems < INT_MAX);
112 0 : vals[i] = (int) b->nitems;
113 : }
114 : }
115 : }
116 85 : bat_iterator_end(&bi);
117 :
118 85 : BATsetcount(bn, ci1.ncand);
119 85 : bn->tnil = nils;
120 85 : bn->tnonil = !nils;
121 85 : bn->tkey = BATcount(bn) <= 1;
122 85 : bn->tsorted = BATcount(bn) <= 1;
123 85 : bn->trevsorted = BATcount(bn) <= 1;
124 85 : *res = bn->batCacheid;
125 85 : BBPkeepref(bn);
126 85 : bailout:
127 85 : BBPreclaim(b);
128 85 : BBPreclaim(bs);
129 85 : return msg;
130 : }
131 :
132 : static str
133 1 : BLOBtoblob(blob **retval, str *s)
134 : {
135 1 : size_t len = strLen(*s);
136 1 : blob *b = (blob *) GDKmalloc(blobsize(len));
137 :
138 1 : if (b == NULL)
139 0 : throw(MAL, "blob.toblob", SQLSTATE(HY013) MAL_MALLOC_FAIL);
140 1 : b->nitems = len;
141 1 : memcpy(b->data, *s, len);
142 1 : *retval = b;
143 1 : return MAL_SUCCEED;
144 : }
145 :
146 : static str
147 1 : BLOBblob_blob(blob **d, blob **s)
148 : {
149 1 : size_t len = blobsize((*s)->nitems);
150 1 : blob *b;
151 :
152 1 : *d = b = GDKmalloc(len);
153 1 : if (b == NULL)
154 0 : throw(MAL, "blob", SQLSTATE(HY013) MAL_MALLOC_FAIL);
155 1 : b->nitems = (*s)->nitems;
156 1 : if (!is_blob_nil(b) && b->nitems != 0)
157 0 : memcpy(b->data, (*s)->data, b->nitems);
158 : return MAL_SUCCEED;
159 : }
160 :
161 : static str
162 1 : BLOBblob_blob_bulk(bat *res, const bat *bid, const bat *sid)
163 : {
164 1 : BAT *b = NULL, *s = NULL, *dst = NULL;
165 1 : BATiter bi;
166 1 : str msg = NULL;
167 1 : struct canditer ci;
168 1 : oid off;
169 1 : bool nils = false;
170 :
171 1 : if (sid && !is_bat_nil(*sid)) {
172 0 : if ((s = BATdescriptor(*sid)) == NULL) {
173 0 : msg = createException(SQL, "batcalc.blob_blob_bulk",
174 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
175 0 : goto bailout;
176 : }
177 : } else {
178 1 : BBPretain(*res = *bid); /* nothing to convert, return */
179 1 : return MAL_SUCCEED;
180 : }
181 0 : if ((b = BATdescriptor(*bid)) == NULL) {
182 0 : msg = createException(SQL, "batcalc.blob_blob_bulk",
183 : SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
184 0 : goto bailout;
185 : }
186 0 : off = b->hseqbase;
187 0 : canditer_init(&ci, b, s);
188 0 : if (!(dst = COLnew(ci.hseq, TYPE_blob, ci.ncand, TRANSIENT))) {
189 0 : msg = createException(SQL, "batcalc.blob_blob_bulk",
190 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
191 0 : goto bailout;
192 : }
193 :
194 0 : bi = bat_iterator(b);
195 0 : if (ci.tpe == cand_dense) {
196 0 : for (BUN i = 0; i < ci.ncand; i++) {
197 0 : oid p = (canditer_next_dense(&ci) - off);
198 0 : const blob *v = BUNtvar(bi, p);
199 :
200 0 : if (tfastins_nocheckVAR(dst, i, v) != GDK_SUCCEED) {
201 0 : msg = createException(SQL, "batcalc.blob_blob_bulk",
202 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
203 0 : goto bailout1;
204 : }
205 0 : nils |= is_blob_nil(v);
206 : }
207 : } else {
208 0 : for (BUN i = 0; i < ci.ncand; i++) {
209 0 : oid p = (canditer_next(&ci) - off);
210 0 : const blob *v = BUNtvar(bi, p);
211 :
212 0 : if (tfastins_nocheckVAR(dst, i, v) != GDK_SUCCEED) {
213 0 : msg = createException(SQL, "batcalc.blob_blob_bulk",
214 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
215 0 : goto bailout1;
216 : }
217 0 : nils |= is_blob_nil(v);
218 : }
219 : }
220 0 : bailout1:
221 0 : bat_iterator_end(&bi);
222 :
223 0 : bailout:
224 0 : BBPreclaim(b);
225 0 : BBPreclaim(s);
226 0 : if (dst && !msg) {
227 0 : BATsetcount(dst, ci.ncand);
228 0 : dst->tnil = nils;
229 0 : dst->tnonil = !nils;
230 0 : dst->tkey = BATcount(dst) <= 1;
231 0 : dst->tsorted = BATcount(dst) <= 1;
232 0 : dst->trevsorted = BATcount(dst) <= 1;
233 0 : *res = dst->batCacheid;
234 0 : BBPkeepref(dst);
235 0 : } else if (dst)
236 0 : BBPreclaim(dst);
237 : return msg;
238 : }
239 :
240 : static str
241 23 : BLOBblob_fromstr(blob **b, const char **s)
242 : {
243 23 : size_t len = 0;
244 :
245 23 : if (BATatoms[TYPE_blob].atomFromStr(*s, &len, (void **) b, false) < 0)
246 2 : throw(MAL, "blob", GDK_EXCEPTION);
247 : return MAL_SUCCEED;
248 : }
249 :
250 : static str
251 9 : BLOBblob_fromstr_bulk(bat *res, const bat *bid, const bat *sid)
252 : {
253 9 : BAT *b, *s = NULL, *bn;
254 :
255 9 : if ((b = BATdescriptor(*bid)) == NULL)
256 0 : throw(MAL, "batcalc.blob", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
257 9 : if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
258 0 : BBPunfix(b->batCacheid);
259 0 : throw(MAL, "batcalc.blob", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
260 : }
261 9 : bn = BATconvert(b, s, TYPE_blob, 0, 0, 0);
262 9 : BBPunfix(b->batCacheid);
263 9 : BBPreclaim(s);
264 9 : if (bn == NULL)
265 0 : throw(MAL, "batcalc.blob", GDK_EXCEPTION);
266 9 : *res = bn->batCacheid;
267 9 : BBPkeepref(bn);
268 9 : return MAL_SUCCEED;
269 : }
270 :
271 : #include "mel.h"
272 : static mel_func blob_init_funcs[] = {
273 : command("blob", "blob", BLOBblob_blob, false, "Noop routine.", args(1,2, arg("",blob),arg("s",blob))),
274 : command("blob", "blob", BLOBblob_fromstr, false, "", args(1,2, arg("",blob),arg("s",str))),
275 : command("blob", "toblob", BLOBtoblob, false, "store a string as a blob.", args(1,2, arg("",blob),arg("v",str))),
276 : command("blob", "nitems", BLOBnitems, false, "get the number of bytes in this blob.", args(1,2, arg("",int),arg("b",blob))),
277 : pattern("batblob", "nitems", BLOBnitems_bulk, false, "", args(1,2, batarg("",int),batarg("b",blob))),
278 : pattern("batblob", "nitems", BLOBnitems_bulk, false, "", args(1,3, batarg("",int),batarg("b",blob),batarg("s",oid))),
279 : command("calc", "blob", BLOBblob_blob, false, "", args(1,2, arg("",blob),arg("b",blob))),
280 : command("batcalc", "blob", BLOBblob_blob_bulk, false, "", args(1,3, batarg("",blob),batarg("b",blob),batarg("s",oid))),
281 : command("calc", "blob", BLOBblob_fromstr, false, "", args(1,2, arg("",blob),arg("s",str))),
282 : command("batcalc", "blob", BLOBblob_fromstr_bulk, false, "", args(1,3, batarg("",blob),batarg("b",str),batarg("s",oid))),
283 : { .imp=NULL }
284 : };
285 : #include "mal_import.h"
286 : #ifdef _MSC_VER
287 : #undef read
288 : #pragma section(".CRT$XCU",read)
289 : #endif
290 334 : LIB_STARTUP_FUNC(init_blob_mal)
291 334 : { mal_module("blob", NULL, blob_init_funcs); }
|