LCOV - code coverage report
Current view: top level - gdk - gdk_value.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 186 203 91.6 %
Date: 2024-10-03 20:03:20 Functions: 10 10 100.0 %

          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     5400985 : VALset(ValPtr v, int t, ptr p)
      51             : {
      52     5400985 :         assert(t < TYPE_any);
      53     5400985 :         v->bat = false;
      54     5400985 :         switch (ATOMstorage(v->vtype = t)) {
      55      105265 :         case TYPE_void:
      56      105265 :                 v->val.oval = *(oid *) p;
      57      105265 :                 break;
      58           0 :         case TYPE_msk:
      59           0 :                 v->val.mval = *(msk *) p;
      60           0 :                 break;
      61       19624 :         case TYPE_bte:
      62       19624 :                 v->val.btval = *(bte *) p;
      63       19624 :                 break;
      64       15181 :         case TYPE_sht:
      65       15181 :                 v->val.shval = *(sht *) p;
      66       15181 :                 break;
      67      241020 :         case TYPE_int:
      68      241020 :                 v->val.ival = *(int *) p;
      69      241020 :                 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      300304 :         case TYPE_lng:
      77      300304 :                 v->val.lval = *(lng *) p;
      78      300304 :                 break;
      79             : #ifdef HAVE_HGE
      80        1816 :         case TYPE_hge:
      81        1816 :                 v->val.hval = *(hge *) p;
      82        1816 :                 break;
      83             : #endif
      84         106 :         case TYPE_uuid:
      85         106 :                 v->val.uval = *(uuid *) p;
      86         106 :                 break;
      87     4443484 :         case TYPE_str:
      88     4443484 :                 v->val.sval = (str) p;
      89     4443484 :                 break;
      90      268238 :         case TYPE_ptr:
      91      268238 :                 v->val.pval = *(ptr *) p;
      92      268238 :                 break;
      93         360 :         default:
      94         360 :                 v->val.pval = p;
      95         360 :                 break;
      96             :         }
      97     5400985 :         v->len = ATOMlen(v->vtype, VALptr(v));
      98     5400938 :         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     9122042 : VALget(ValPtr v)
     105             : {
     106     9122042 :         assert(!v->bat);
     107     9122042 :         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     4834720 :         case TYPE_bte: return (void *) &v->val.btval;
     111      183505 :         case TYPE_sht: return (void *) &v->val.shval;
     112     2182529 :         case TYPE_int: return (void *) &v->val.ival;
     113        1135 :         case TYPE_flt: return (void *) &v->val.fval;
     114       23528 :         case TYPE_dbl: return (void *) &v->val.dval;
     115     1234081 :         case TYPE_lng: return (void *) &v->val.lval;
     116             : #ifdef HAVE_HGE
     117        5433 :         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      656661 :         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    48890062 : VALclear(ValPtr v)
     131             : {
     132    48890062 :         if (!v->bat && ATOMextern(v->vtype)) {
     133     7206160 :                 if (v->val.pval && v->val.pval != ATOMnilptr(v->vtype))
     134     7046141 :                         GDKfree(v->val.pval);
     135             :         }
     136    48890655 :         VALempty(v);
     137    48890012 : }
     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    67065525 : VALempty(ValPtr v)
     143             : {
     144    67065525 :         *v = (ValRecord) {
     145             :                 .bat = false,
     146             :                 .val.oval = oid_nil,
     147             :                 .vtype = TYPE_void,
     148             :         };
     149    67065525 : }
     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    39924821 : VALcopy(ValPtr d, const ValRecord *s)
     158             : {
     159    39924821 :         if (d == s)
     160             :                 return d;
     161    39921902 :         d->bat = false;
     162    39921902 :         if (s->bat || !ATOMextern(s->vtype)) {
     163    26133079 :                 *d = *s;
     164    13788823 :         } else if (s->val.pval == NULL) {
     165           0 :                 return VALinit(d, s->vtype, ATOMnilptr(s->vtype));
     166    13788823 :         } else if (s->vtype == TYPE_str) {
     167    13786256 :                 const char *p = s->val.sval;
     168    13786256 :                 d->vtype = TYPE_str;
     169    13786256 :                 d->len = strLen(p);
     170    13786256 :                 d->val.sval = GDKmalloc(d->len);
     171    13786551 :                 if (d->val.sval == NULL)
     172             :                         return NULL;
     173    13786551 :                 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     9204791 : VALinit(ValPtr d, int tpe, const void *s)
     194             : {
     195     9204791 :         d->bat = false;
     196     9204791 :         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      191487 :         case TYPE_bte:
     204      191487 :                 d->val.btval = *(const bte *) s;
     205      191487 :                 break;
     206      530802 :         case TYPE_sht:
     207      530802 :                 d->val.shval = *(const sht *) s;
     208      530802 :                 break;
     209     2830592 :         case TYPE_int:
     210     2830592 :                 d->val.ival = *(const int *) s;
     211     2830592 :                 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      277148 :         case TYPE_lng:
     219      277148 :                 d->val.lval = *(const lng *) s;
     220      277148 :                 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     4940455 :         case TYPE_str:
     230     4940455 :                 d->len = strLen(s);
     231     4940455 :                 d->val.sval = GDKmalloc(d->len);
     232     4940638 :                 if (d->val.sval == NULL)
     233             :                         return NULL;
     234     4940638 :                 memcpy(d->val.sval, s, d->len);
     235     4940638 :                 return d;
     236      408420 :         case TYPE_ptr:
     237      408420 :                 d->val.pval = *(const ptr *) s;
     238      408420 :                 d->len = ATOMlen(tpe, *(const ptr *) s);
     239      408420 :                 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     3855640 :         d->len = ATOMsize(d->vtype);
     250     3855640 :         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       21075 : VALformat(const ValRecord *res)
     257             : {
     258       21075 :         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       17730 :                 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      279148 : VALconvert(int typ, ValPtr t)
     273             : {
     274      279148 :         int src_tpe = t->vtype;
     275      279148 :         ValRecord dst = { .vtype = typ };
     276             : 
     277             :         /* first convert into a new location */
     278      279148 :         if (VARconvert(&dst, t, 0, 0, 0) != GDK_SUCCEED)
     279             :                 return NULL;
     280             : 
     281             :         /* then maybe free the old */
     282      279143 :         if (src_tpe != dst.vtype &&
     283      279133 :             t->vtype != typ &&
     284      279133 :             dst.vtype != TYPE_void &&
     285      278958 :             (src_tpe >= TYPE_str || dst.vtype >= TYPE_str))
     286       32176 :                 VALclear(t);
     287             :         /* and finally copy the result */
     288      279143 :         *t = dst;
     289             :         /* make sure we return the correct type (not the storage type) */
     290      279143 :         t->vtype = typ;
     291      279143 :         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     1582733 : VALcmp(const ValRecord *p, const ValRecord *q)
     300             : {
     301             : 
     302     1582733 :         int (*cmp)(const void *, const void *);
     303     1582733 :         int tpe;
     304     1582733 :         const void *nilptr, *pp, *pq;
     305             : 
     306     1582733 :         if (p == 0 || q == 0)
     307             :                 return -1;
     308     1582733 :         if ((tpe = p->vtype) != q->vtype)
     309             :                 return -1;
     310             : 
     311     1582685 :         if (tpe == TYPE_ptr)
     312             :                 return 0;       /* ignore comparing C pointers */
     313     1582685 :         cmp = ATOMcompare(tpe);
     314     1582685 :         nilptr = ATOMnilptr(tpe);
     315     1582685 :         pp = VALptr(p);
     316     1582685 :         pq = VALptr(q);
     317     1582685 :         if ((*cmp)(pp, nilptr) == 0 && (*cmp)(pq, nilptr) == 0)
     318             :                 return 0;       /* eq nil val */
     319     1582685 :         if ((*cmp)(pp, nilptr) == 0 || (*cmp)(pq, nilptr) == 0)
     320           0 :                 return -1;
     321     1582685 :         return (*cmp)(pp, pq);
     322             : 
     323             : }
     324             : 
     325             : /* Return TRUE if the value in V is NIL. */
     326             : bool
     327    10509150 : VALisnil(const ValRecord *v)
     328             : {
     329    10509150 :         if (v->bat)
     330           0 :                 return is_bat_nil(v->val.bval);
     331    10509150 :         switch (v->vtype) {
     332             :         case TYPE_void:
     333             :                 return true;
     334           0 :         case TYPE_msk:
     335           0 :                 return false;
     336       90642 :         case TYPE_bte:
     337       90642 :                 return is_bte_nil(v->val.btval);
     338     1021481 :         case TYPE_sht:
     339     1021481 :                 return is_sht_nil(v->val.shval);
     340     5537099 :         case TYPE_int:
     341     5537099 :                 return is_int_nil(v->val.ival);
     342      264807 :         case TYPE_lng:
     343      264807 :                 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        9402 :         case TYPE_dbl:
     353        9402 :                 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     3564227 :                 break;
     360             :         }
     361     3564227 :         return (*ATOMcompare(v->vtype))(VALptr(v), ATOMnilptr(v->vtype)) == 0;
     362             : }

Generated by: LCOV version 1.14