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 5392815 : VALset(ValPtr v, int t, ptr p)
51 : {
52 5392815 : assert(t < TYPE_any);
53 5392815 : v->bat = false;
54 5392815 : switch (ATOMstorage(v->vtype = t)) {
55 105286 : case TYPE_void:
56 105286 : v->val.oval = *(oid *) p;
57 105286 : break;
58 0 : case TYPE_msk:
59 0 : v->val.mval = *(msk *) p;
60 0 : break;
61 19810 : case TYPE_bte:
62 19810 : v->val.btval = *(bte *) p;
63 19810 : break;
64 15340 : case TYPE_sht:
65 15340 : v->val.shval = *(sht *) p;
66 15340 : break;
67 237460 : case TYPE_int:
68 237460 : v->val.ival = *(int *) p;
69 237460 : break;
70 2759 : case TYPE_flt:
71 2759 : v->val.fval = *(flt *) p;
72 2759 : break;
73 2828 : case TYPE_dbl:
74 2828 : v->val.dval = *(dbl *) p;
75 2828 : break;
76 294028 : case TYPE_lng:
77 294028 : v->val.lval = *(lng *) p;
78 294028 : break;
79 : #ifdef HAVE_HGE
80 1821 : case TYPE_hge:
81 1821 : v->val.hval = *(hge *) p;
82 1821 : break;
83 : #endif
84 106 : case TYPE_uuid:
85 106 : v->val.uval = *(uuid *) p;
86 106 : break;
87 4444754 : case TYPE_str:
88 4444754 : v->val.sval = (str) p;
89 4444754 : break;
90 268263 : case TYPE_ptr:
91 268263 : v->val.pval = *(ptr *) p;
92 268263 : break;
93 360 : default:
94 360 : v->val.pval = p;
95 360 : break;
96 : }
97 5392815 : v->len = ATOMlen(v->vtype, VALptr(v));
98 5392706 : 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 9123703 : VALget(ValPtr v)
105 : {
106 9123703 : assert(!v->bat);
107 9123703 : switch (ATOMstorage(v->vtype)) {
108 244 : case TYPE_void: return (void *) &v->val.oval;
109 0 : case TYPE_msk: return (void *) &v->val.mval;
110 4834728 : case TYPE_bte: return (void *) &v->val.btval;
111 183519 : case TYPE_sht: return (void *) &v->val.shval;
112 2182672 : case TYPE_int: return (void *) &v->val.ival;
113 1135 : case TYPE_flt: return (void *) &v->val.fval;
114 23542 : case TYPE_dbl: return (void *) &v->val.dval;
115 1234214 : case TYPE_lng: return (void *) &v->val.lval;
116 : #ifdef HAVE_HGE
117 5446 : 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 657997 : 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 49080983 : VALclear(ValPtr v)
131 : {
132 49080983 : if (!v->bat && ATOMextern(v->vtype)) {
133 7211155 : if (v->val.pval && v->val.pval != ATOMnilptr(v->vtype))
134 7055456 : GDKfree(v->val.pval);
135 : }
136 49081579 : VALempty(v);
137 49081955 : }
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 67322559 : VALempty(ValPtr v)
143 : {
144 67322559 : *v = (ValRecord) {
145 : .bat = false,
146 : .val.oval = oid_nil,
147 : .vtype = TYPE_void,
148 : };
149 67322559 : }
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 39988310 : VALcopy(ValPtr d, const ValRecord *s)
158 : {
159 39988310 : if (d == s)
160 : return d;
161 39985391 : d->bat = false;
162 39985391 : if (s->bat || !ATOMextern(s->vtype)) {
163 26191689 : *d = *s;
164 13793702 : } else if (s->val.pval == NULL) {
165 0 : return VALinit(d, s->vtype, ATOMnilptr(s->vtype));
166 13793702 : } else if (s->vtype == TYPE_str) {
167 13791135 : const char *p = s->val.sval;
168 13791135 : d->vtype = TYPE_str;
169 13791135 : d->len = strLen(p);
170 13791135 : d->val.sval = GDKmalloc(d->len);
171 13791449 : if (d->val.sval == NULL)
172 : return NULL;
173 13791449 : memcpy(d->val.sval, p, d->len);
174 : } else {
175 2567 : const void *p = s->val.pval;
176 2567 : d->vtype = s->vtype;
177 2567 : d->len = ATOMlen(d->vtype, p);
178 2567 : d->val.pval = GDKmalloc(d->len);
179 2567 : if (d->val.pval == NULL)
180 : return NULL;
181 2567 : 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 9227663 : VALinit(ValPtr d, int tpe, const void *s)
194 : {
195 9227663 : d->bat = false;
196 9227663 : 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 191707 : case TYPE_bte:
204 191707 : d->val.btval = *(const bte *) s;
205 191707 : break;
206 531427 : case TYPE_sht:
207 531427 : d->val.shval = *(const sht *) s;
208 531427 : break;
209 2838446 : case TYPE_int:
210 2838446 : d->val.ival = *(const int *) s;
211 2838446 : break;
212 12622 : case TYPE_flt:
213 12622 : d->val.fval = *(const flt *) s;
214 12622 : break;
215 10765 : case TYPE_dbl:
216 10765 : d->val.dval = *(const dbl *) s;
217 10765 : break;
218 276633 : case TYPE_lng:
219 276633 : d->val.lval = *(const lng *) s;
220 276633 : break;
221 : #ifdef HAVE_HGE
222 2108 : case TYPE_hge:
223 2108 : d->val.hval = *(const hge *) s;
224 2108 : break;
225 : #endif
226 117 : case TYPE_uuid:
227 117 : d->val.uval = *(const uuid *) s;
228 117 : break;
229 4950732 : case TYPE_str:
230 4950732 : d->len = strLen(s);
231 4950732 : d->val.sval = GDKmalloc(d->len);
232 4951025 : if (d->val.sval == NULL)
233 : return NULL;
234 4951025 : memcpy(d->val.sval, s, d->len);
235 4951025 : return d;
236 412830 : case TYPE_ptr:
237 412830 : d->val.pval = *(const ptr *) s;
238 412830 : d->len = ATOMlen(tpe, *(const ptr *) s);
239 412830 : 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 3863825 : d->len = ATOMsize(d->vtype);
250 3863825 : 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 21178 : VALformat(const ValRecord *res)
257 : {
258 21178 : if (res->bat) {
259 3345 : if (is_bat_nil(res->val.bval))
260 345 : return GDKstrdup("nil");
261 : else
262 3000 : return ATOMformat(TYPE_int, (const void *) &res->val.ival);
263 : } else
264 17833 : 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 279648 : VALconvert(int typ, ValPtr t)
273 : {
274 279648 : int src_tpe = t->vtype;
275 279648 : ValRecord dst = { .vtype = typ };
276 :
277 : /* first convert into a new location */
278 279648 : if (VARconvert(&dst, t, 0, 0, 0) != GDK_SUCCEED)
279 : return NULL;
280 :
281 : /* then maybe free the old */
282 279642 : if (src_tpe != dst.vtype &&
283 279632 : t->vtype != typ &&
284 279631 : dst.vtype != TYPE_void &&
285 279456 : (src_tpe >= TYPE_str || dst.vtype >= TYPE_str))
286 32426 : VALclear(t);
287 : /* and finally copy the result */
288 279642 : *t = dst;
289 : /* make sure we return the correct type (not the storage type) */
290 279642 : t->vtype = typ;
291 279642 : 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 1585294 : VALcmp(const ValRecord *p, const ValRecord *q)
300 : {
301 :
302 1585294 : int (*cmp)(const void *, const void *);
303 1585294 : int tpe;
304 1585294 : const void *nilptr, *pp, *pq;
305 :
306 1585294 : if (p == 0 || q == 0)
307 : return -1;
308 1585294 : if ((tpe = p->vtype) != q->vtype)
309 : return -1;
310 :
311 1585246 : if (tpe == TYPE_ptr)
312 : return 0; /* ignore comparing C pointers */
313 1585246 : cmp = ATOMcompare(tpe);
314 1585246 : nilptr = ATOMnilptr(tpe);
315 1585246 : pp = VALptr(p);
316 1585246 : pq = VALptr(q);
317 1585246 : if ((*cmp)(pp, nilptr) == 0 && (*cmp)(pq, nilptr) == 0)
318 : return 0; /* eq nil val */
319 1585246 : if ((*cmp)(pp, nilptr) == 0 || (*cmp)(pq, nilptr) == 0)
320 0 : return -1;
321 1585246 : return (*cmp)(pp, pq);
322 :
323 : }
324 :
325 : /* Return TRUE if the value in V is NIL. */
326 : bool
327 10520819 : VALisnil(const ValRecord *v)
328 : {
329 10520819 : if (v->bat)
330 0 : return is_bat_nil(v->val.bval);
331 10520819 : switch (v->vtype) {
332 : case TYPE_void:
333 : return true;
334 0 : case TYPE_msk:
335 0 : return false;
336 90714 : case TYPE_bte:
337 90714 : return is_bte_nil(v->val.btval);
338 1022421 : case TYPE_sht:
339 1022421 : return is_sht_nil(v->val.shval);
340 5549389 : case TYPE_int:
341 5549389 : return is_int_nil(v->val.ival);
342 259435 : case TYPE_lng:
343 259435 : 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 9401 : case TYPE_dbl:
353 9401 : 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 3567967 : break;
360 : }
361 3567967 : return (*ATOMcompare(v->vtype))(VALptr(v), ATOMnilptr(v->vtype)) == 0;
362 : }
|