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 : * @a Martin L. Kersten & Peter Boncz
15 : * @v 2.0
16 : * @+ Value representation
17 : *
18 : *
19 : * When manipulating values, MonetDB puts them into value records.
20 : * The built-in types have a direct entry in the union. Others should
21 : * be represented as a pointer of memory in pval or as a string, which
22 : * is basically the same. In such cases the len field indicates the
23 : * size of this piece of memory.
24 : *
25 : * MonetDB extenders will use value records for passing parameters to
26 : * their new operators. MonetDB algebraic commands receive an (argc,
27 : * argv) combination, where argc is an integer indicating the size of
28 : * the the argv array of value records. On call, the first record,
29 : * argv[0], is always empty. The routine must place its return value -
30 : * if any - there. The other values are the parameters.
31 : *
32 : * Actually, the gdk value type defined here should become a built-in
33 : * type in the kernel. Next step will be to define the corresponding
34 : * extension module.
35 : *
36 : * @+ Value operations
37 : * The following primitives are required to manipulate value records.
38 : * Note that binding a BAT requires upgrading its reference count.
39 : * The receiver of the value should have been cleared or represent
40 : * free space.
41 : */
42 : #include "monetdb_config.h"
43 : #include "gdk.h"
44 : #include "gdk_private.h"
45 :
46 : /* Set V to the type/value combination in T/P. Also see VALinit. In
47 : * this version, if P refers to an external type, no new memory is
48 : * allocated, but instead the pointer P is given to V. */
49 : ValPtr
50 5605029 : VALset(ValPtr v, int t, ptr p)
51 : {
52 5605029 : assert(t < TYPE_any);
53 5605029 : v->bat = false;
54 5605029 : switch (ATOMstorage(v->vtype = t)) {
55 105267 : case TYPE_void:
56 105267 : v->val.oval = *(oid *) p;
57 105267 : break;
58 0 : case TYPE_msk:
59 0 : v->val.mval = *(msk *) p;
60 0 : break;
61 19631 : case TYPE_bte:
62 19631 : v->val.btval = *(bte *) p;
63 19631 : break;
64 15181 : case TYPE_sht:
65 15181 : v->val.shval = *(sht *) p;
66 15181 : break;
67 318869 : case TYPE_int:
68 318869 : v->val.ival = *(int *) p;
69 318869 : break;
70 2759 : case TYPE_flt:
71 2759 : v->val.fval = *(flt *) p;
72 2759 : break;
73 2827 : case TYPE_dbl:
74 2827 : v->val.dval = *(dbl *) p;
75 2827 : break;
76 300530 : case TYPE_lng:
77 300530 : v->val.lval = *(lng *) p;
78 300530 : break;
79 : #ifdef HAVE_HGE
80 1815 : case TYPE_hge:
81 1815 : v->val.hval = *(hge *) p;
82 1815 : break;
83 : #endif
84 106 : case TYPE_uuid:
85 106 : v->val.uval = *(uuid *) p;
86 106 : break;
87 4567511 : case TYPE_str:
88 4567511 : v->val.sval = (str) p;
89 4567511 : break;
90 270170 : case TYPE_ptr:
91 270170 : v->val.pval = *(ptr *) p;
92 270170 : break;
93 363 : default:
94 363 : v->val.pval = p;
95 363 : break;
96 : }
97 5605029 : v->len = ATOMlen(v->vtype, VALptr(v));
98 5604959 : return v;
99 : }
100 :
101 : /* Return a pointer to the value contained in V. Also see VALptr
102 : * which returns a const void *. */
103 : void *
104 8199316 : VALget(ValPtr v)
105 : {
106 8199316 : assert(!v->bat);
107 8199316 : switch (ATOMstorage(v->vtype)) {
108 242 : case TYPE_void: return (void *) &v->val.oval;
109 0 : case TYPE_msk: return (void *) &v->val.mval;
110 4853056 : case TYPE_bte: return (void *) &v->val.btval;
111 183270 : case TYPE_sht: return (void *) &v->val.shval;
112 2229250 : case TYPE_int: return (void *) &v->val.ival;
113 1134 : case TYPE_flt: return (void *) &v->val.fval;
114 23552 : case TYPE_dbl: return (void *) &v->val.dval;
115 234122 : case TYPE_lng: return (void *) &v->val.lval;
116 : #ifdef HAVE_HGE
117 5409 : case TYPE_hge: return (void *) &v->val.hval;
118 : #endif
119 70 : case TYPE_uuid: return (void *) &v->val.uval;
120 1 : case TYPE_ptr: return (void *) &v->val.pval;
121 669075 : case TYPE_str: return (void *) v->val.sval;
122 135 : default: return (void *) v->val.pval;
123 : }
124 : }
125 :
126 : /* Clear V to an empty value (type void, value nil), freeing any
127 : * memory allocated for external types. See VALempty for when V does
128 : * not yet contain a value. */
129 : void
130 50131207 : VALclear(ValPtr v)
131 : {
132 50131207 : if (!v->bat && ATOMextern(v->vtype)) {
133 7527638 : if (v->val.pval && v->val.pval != ATOMnilptr(v->vtype))
134 7367479 : GDKfree(v->val.pval);
135 : }
136 50131927 : VALempty(v);
137 50132109 : }
138 :
139 : /* Initialize V to an empty value (type void, value nil). See
140 : * VALclear for when V already contains a value. */
141 : void
142 68874141 : VALempty(ValPtr v)
143 : {
144 68874141 : *v = (ValRecord) {
145 : .bat = false,
146 : .val.oval = oid_nil,
147 : .vtype = TYPE_void,
148 : };
149 68874141 : }
150 :
151 : /* Create a copy of S into D, allocating space for external values
152 : * (non-fixed sized values). See VALinit for a version where the
153 : * source is not in a VALRecord.
154 : *
155 : * Returns NULL In case of (malloc) failure. */
156 : ValPtr
157 40721277 : VALcopy(ValPtr d, const ValRecord *s)
158 : {
159 40721277 : if (d == s)
160 : return d;
161 40718358 : d->bat = false;
162 40718358 : if (s->bat || !ATOMextern(s->vtype)) {
163 26680491 : *d = *s;
164 14037867 : } else if (s->val.pval == NULL) {
165 0 : return VALinit(d, s->vtype, ATOMnilptr(s->vtype));
166 14037867 : } else if (s->vtype == TYPE_str) {
167 14035302 : const char *p = s->val.sval;
168 14035302 : d->vtype = TYPE_str;
169 14035302 : d->len = strLen(p);
170 14035302 : d->val.sval = GDKmalloc(d->len);
171 14035590 : if (d->val.sval == NULL)
172 : return NULL;
173 14035590 : memcpy(d->val.sval, p, d->len);
174 : } else {
175 2565 : const void *p = s->val.pval;
176 2565 : d->vtype = s->vtype;
177 2565 : d->len = ATOMlen(d->vtype, p);
178 2565 : d->val.pval = GDKmalloc(d->len);
179 2565 : if (d->val.pval == NULL)
180 : return NULL;
181 2565 : memcpy(d->val.pval, p, d->len);
182 : }
183 : return d;
184 : }
185 :
186 : /* Create a copy of the type value combination in TPE/S, allocating
187 : * space for external values (non-fixed sized values). See VALcopy
188 : * for a version where the source is in a ValRecord, and see VALset
189 : * for a version where ownership of the source is transferred.
190 : *
191 : * Returns NULL in case of (malloc) failure. */
192 : ValPtr
193 9534660 : VALinit(ValPtr d, int tpe, const void *s)
194 : {
195 9534660 : d->bat = false;
196 9534660 : switch (ATOMstorage(d->vtype = tpe)) {
197 0 : case TYPE_void:
198 0 : d->val.oval = *(const oid *) s;
199 0 : break;
200 0 : case TYPE_msk:
201 0 : d->val.mval = *(const msk *) s;
202 0 : break;
203 199382 : case TYPE_bte:
204 199382 : d->val.btval = *(const bte *) s;
205 199382 : break;
206 530888 : case TYPE_sht:
207 530888 : d->val.shval = *(const sht *) s;
208 530888 : break;
209 2879833 : case TYPE_int:
210 2879833 : d->val.ival = *(const int *) s;
211 2879833 : break;
212 12622 : case TYPE_flt:
213 12622 : d->val.fval = *(const flt *) s;
214 12622 : break;
215 10777 : case TYPE_dbl:
216 10777 : d->val.dval = *(const dbl *) s;
217 10777 : break;
218 277246 : case TYPE_lng:
219 277246 : d->val.lval = *(const lng *) s;
220 277246 : break;
221 : #ifdef HAVE_HGE
222 2107 : case TYPE_hge:
223 2107 : d->val.hval = *(const hge *) s;
224 2107 : break;
225 : #endif
226 117 : case TYPE_uuid:
227 117 : d->val.uval = *(const uuid *) s;
228 117 : break;
229 5208232 : case TYPE_str:
230 5208232 : d->len = strLen(s);
231 5208232 : d->val.sval = GDKmalloc(d->len);
232 5208412 : if (d->val.sval == NULL)
233 : return NULL;
234 5208412 : memcpy(d->val.sval, s, d->len);
235 5208412 : return d;
236 413180 : case TYPE_ptr:
237 413180 : d->val.pval = *(const ptr *) s;
238 413180 : d->len = ATOMlen(tpe, *(const ptr *) s);
239 413180 : return d;
240 276 : default:
241 276 : assert(ATOMextern(ATOMstorage(tpe)));
242 276 : d->len = ATOMlen(tpe, s);
243 276 : d->val.pval = GDKmalloc(d->len);
244 276 : if (d->val.pval == NULL)
245 : return NULL;
246 276 : memcpy(d->val.pval, s, d->len);
247 276 : return d;
248 : }
249 3912972 : d->len = ATOMsize(d->vtype);
250 3912972 : return d;
251 : }
252 :
253 : /* Format the value in RES in the standard way for the type of RES
254 : * into a newly allocated buffer. Also see ATOMformat. */
255 : char *
256 21071 : VALformat(const ValRecord *res)
257 : {
258 21071 : if (res->bat) {
259 3347 : if (is_bat_nil(res->val.bval))
260 347 : return GDKstrdup("nil");
261 : else
262 3000 : return ATOMformat(TYPE_int, (const void *) &res->val.ival);
263 : } else
264 17724 : return ATOMformat(res->vtype, VALptr(res));
265 : }
266 :
267 : /* Convert (cast) the value in T to the type TYP, do this in place.
268 : * Return a pointer to the converted value, or NULL if the conversion
269 : * didn't succeed. If the conversion didn't succeed, the original
270 : * value is not modified. Also see VARconvert. */
271 : ptr
272 279276 : VALconvert(int typ, ValPtr t)
273 : {
274 279276 : int src_tpe = t->vtype;
275 279276 : ValRecord dst = { .vtype = typ };
276 :
277 : /* first convert into a new location */
278 279276 : if (VARconvert(&dst, t, 0, 0, 0) != GDK_SUCCEED)
279 : return NULL;
280 :
281 : /* then maybe free the old */
282 279272 : if (src_tpe != dst.vtype &&
283 279262 : t->vtype != typ &&
284 279262 : dst.vtype != TYPE_void &&
285 279087 : (src_tpe >= TYPE_str || dst.vtype >= TYPE_str))
286 32172 : VALclear(t);
287 : /* and finally copy the result */
288 279272 : *t = dst;
289 : /* make sure we return the correct type (not the storage type) */
290 279272 : t->vtype = typ;
291 279272 : return VALget(t);
292 : }
293 :
294 : /* Compare two values in P and Q and return -1/0/1 depending on
295 : * whether P is less than, equal to, or larger than Q. Also return -1
296 : * if P or Q is NULL or NIL, or if the types of P and Q are not
297 : * equal. */
298 : int
299 1585620 : VALcmp(const ValRecord *p, const ValRecord *q)
300 : {
301 :
302 1585620 : int (*cmp)(const void *, const void *);
303 1585620 : int tpe;
304 1585620 : const void *nilptr, *pp, *pq;
305 :
306 1585620 : if (p == 0 || q == 0)
307 : return -1;
308 1585620 : if ((tpe = p->vtype) != q->vtype)
309 : return -1;
310 :
311 1585572 : if (tpe == TYPE_ptr)
312 : return 0; /* ignore comparing C pointers */
313 1585572 : cmp = ATOMcompare(tpe);
314 1585572 : nilptr = ATOMnilptr(tpe);
315 1585572 : pp = VALptr(p);
316 1585572 : pq = VALptr(q);
317 1585572 : if ((*cmp)(pp, nilptr) == 0 && (*cmp)(pq, nilptr) == 0)
318 : return 0; /* eq nil val */
319 1585572 : if ((*cmp)(pp, nilptr) == 0 || (*cmp)(pq, nilptr) == 0)
320 0 : return -1;
321 1585572 : return (*cmp)(pp, pq);
322 :
323 : }
324 :
325 : /* Return TRUE if the value in V is NIL. */
326 : bool
327 10716607 : VALisnil(const ValRecord *v)
328 : {
329 10716607 : if (v->bat)
330 0 : return is_bat_nil(v->val.bval);
331 10716607 : switch (v->vtype) {
332 : case TYPE_void:
333 : return true;
334 0 : case TYPE_msk:
335 0 : return false;
336 106046 : case TYPE_bte:
337 106046 : return is_bte_nil(v->val.btval);
338 1021659 : case TYPE_sht:
339 1021659 : return is_sht_nil(v->val.shval);
340 5674433 : case TYPE_int:
341 5674433 : return is_int_nil(v->val.ival);
342 264996 : case TYPE_lng:
343 264996 : return is_lng_nil(v->val.lval);
344 : #ifdef HAVE_HGE
345 2895 : case TYPE_hge:
346 2895 : return is_hge_nil(v->val.hval);
347 : #endif
348 5 : case TYPE_uuid:
349 5 : return is_uuid_nil(v->val.uval);
350 18580 : case TYPE_flt:
351 18580 : return is_flt_nil(v->val.fval);
352 9426 : case TYPE_dbl:
353 9426 : return is_dbl_nil(v->val.dval);
354 10 : case TYPE_oid:
355 10 : return is_oid_nil(v->val.oval);
356 0 : case TYPE_ptr:
357 0 : return v->val.pval == NULL;
358 : default:
359 3618555 : break;
360 : }
361 3618555 : return (*ATOMcompare(v->vtype))(VALptr(v), ATOMnilptr(v->vtype)) == 0;
362 : }
|