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