LCOV - code coverage report
Current view: top level - src/backend/utils/adt - datum.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 89.8 % 176 158
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 74.5 % 98 73

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * datum.c
       4                 :             :  *    POSTGRES Datum (abstract data type) manipulation routines.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/utils/adt/datum.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : /*
      17                 :             :  * In the implementation of these routines we assume the following:
      18                 :             :  *
      19                 :             :  * A) if a type is "byVal" then all the information is stored in the
      20                 :             :  * Datum itself (i.e. no pointers involved!). In this case the
      21                 :             :  * length of the type is always greater than zero and not more than
      22                 :             :  * "sizeof(Datum)"
      23                 :             :  *
      24                 :             :  * B) if a type is not "byVal" and it has a fixed length (typlen > 0),
      25                 :             :  * then the "Datum" always contains a pointer to a stream of bytes.
      26                 :             :  * The number of significant bytes are always equal to the typlen.
      27                 :             :  *
      28                 :             :  * C) if a type is not "byVal" and has typlen == -1,
      29                 :             :  * then the "Datum" always points to a "varlena".
      30                 :             :  * This varlena structure has information about the actual length of this
      31                 :             :  * particular instance of the type and about its value.
      32                 :             :  *
      33                 :             :  * D) if a type is not "byVal" and has typlen == -2,
      34                 :             :  * then the "Datum" always points to a null-terminated C string.
      35                 :             :  *
      36                 :             :  * Note that we do not treat "toasted" datums specially; therefore what
      37                 :             :  * will be copied or compared is the compressed data or toast reference.
      38                 :             :  * An exception is made for datumCopy() of an expanded object, however,
      39                 :             :  * because most callers expect to get a simple contiguous (and pfree'able)
      40                 :             :  * result from datumCopy().  See also datumTransfer().
      41                 :             :  */
      42                 :             : 
      43                 :             : #include "postgres.h"
      44                 :             : 
      45                 :             : #include "access/detoast.h"
      46                 :             : #include "common/hashfn.h"
      47                 :             : #include "fmgr.h"
      48                 :             : #include "utils/datum.h"
      49                 :             : #include "utils/expandeddatum.h"
      50                 :             : #include "utils/fmgrprotos.h"
      51                 :             : 
      52                 :             : 
      53                 :             : /*-------------------------------------------------------------------------
      54                 :             :  * datumGetSize
      55                 :             :  *
      56                 :             :  * Find the "real" size of a datum, given the datum value,
      57                 :             :  * whether it is a "by value", and the declared type length.
      58                 :             :  * (For TOAST pointer datums, this is the size of the pointer datum.)
      59                 :             :  *
      60                 :             :  * This is essentially an out-of-line version of the att_addlength_datum()
      61                 :             :  * macro in access/tupmacs.h.  We do a tad more error checking though.
      62                 :             :  *-------------------------------------------------------------------------
      63                 :             :  */
      64                 :             : Size
      65                 :     7376615 : datumGetSize(Datum value, bool typByVal, int typLen)
      66                 :             : {
      67                 :             :     Size        size;
      68                 :             : 
      69         [ +  + ]:     7376615 :     if (typByVal)
      70                 :             :     {
      71                 :             :         /* Pass-by-value types are always fixed-length */
      72                 :             :         Assert(typLen > 0 && typLen <= sizeof(Datum));
      73                 :     1066997 :         size = (Size) typLen;
      74                 :             :     }
      75                 :             :     else
      76                 :             :     {
      77         [ +  + ]:     6309618 :         if (typLen > 0)
      78                 :             :         {
      79                 :             :             /* Fixed-length pass-by-ref type */
      80                 :     4397665 :             size = (Size) typLen;
      81                 :             :         }
      82         [ +  + ]:     1911953 :         else if (typLen == -1)
      83                 :             :         {
      84                 :             :             /* It is a varlena datatype */
      85                 :     1628367 :             varlena    *s = (varlena *) DatumGetPointer(value);
      86                 :             : 
      87         [ -  + ]:     1628367 :             if (!s)
      88         [ #  # ]:           0 :                 ereport(ERROR,
      89                 :             :                         (errcode(ERRCODE_DATA_EXCEPTION),
      90                 :             :                          errmsg("invalid Datum pointer")));
      91                 :             : 
      92                 :     1628367 :             size = (Size) VARSIZE_ANY(s);
      93                 :             :         }
      94         [ +  - ]:      283586 :         else if (typLen == -2)
      95                 :             :         {
      96                 :             :             /* It is a cstring datatype */
      97                 :      283586 :             char       *s = (char *) DatumGetPointer(value);
      98                 :             : 
      99         [ -  + ]:      283586 :             if (!s)
     100         [ #  # ]:           0 :                 ereport(ERROR,
     101                 :             :                         (errcode(ERRCODE_DATA_EXCEPTION),
     102                 :             :                          errmsg("invalid Datum pointer")));
     103                 :             : 
     104                 :      283586 :             size = (Size) (strlen(s) + 1);
     105                 :             :         }
     106                 :             :         else
     107                 :             :         {
     108         [ #  # ]:           0 :             elog(ERROR, "invalid typLen: %d", typLen);
     109                 :             :             size = 0;           /* keep compiler quiet */
     110                 :             :         }
     111                 :             :     }
     112                 :             : 
     113                 :     7376615 :     return size;
     114                 :             : }
     115                 :             : 
     116                 :             : /*-------------------------------------------------------------------------
     117                 :             :  * datumCopy
     118                 :             :  *
     119                 :             :  * Make a copy of a non-NULL datum.
     120                 :             :  *
     121                 :             :  * If the datatype is pass-by-reference, memory is obtained with palloc().
     122                 :             :  *
     123                 :             :  * If the value is a reference to an expanded object, we flatten into memory
     124                 :             :  * obtained with palloc().  We need to copy because one of the main uses of
     125                 :             :  * this function is to copy a datum out of a transient memory context that's
     126                 :             :  * about to be destroyed, and the expanded object is probably in a child
     127                 :             :  * context that will also go away.  Moreover, many callers assume that the
     128                 :             :  * result is a single pfree-able chunk.
     129                 :             :  *-------------------------------------------------------------------------
     130                 :             :  */
     131                 :             : Datum
     132                 :    16764953 : datumCopy(Datum value, bool typByVal, int typLen)
     133                 :             : {
     134                 :             :     Datum       res;
     135                 :             : 
     136         [ +  + ]:    16764953 :     if (typByVal)
     137                 :     8354411 :         res = value;
     138         [ +  + ]:     8410542 :     else if (typLen == -1)
     139                 :             :     {
     140                 :             :         /* It is a varlena datatype */
     141                 :     4693714 :         varlena    *vl = (varlena *) DatumGetPointer(value);
     142                 :             : 
     143         [ +  + ]:     4693714 :         if (VARATT_IS_EXTERNAL_EXPANDED(vl))
     144                 :             :         {
     145                 :             :             /* Flatten into the caller's memory context */
     146                 :         582 :             ExpandedObjectHeader *eoh = DatumGetEOHP(value);
     147                 :             :             Size        resultsize;
     148                 :             :             char       *resultptr;
     149                 :             : 
     150                 :         582 :             resultsize = EOH_get_flat_size(eoh);
     151                 :         582 :             resultptr = (char *) palloc(resultsize);
     152                 :         582 :             EOH_flatten_into(eoh, resultptr, resultsize);
     153                 :         582 :             res = PointerGetDatum(resultptr);
     154                 :             :         }
     155                 :             :         else
     156                 :             :         {
     157                 :             :             /* Otherwise, just copy the varlena datum verbatim */
     158                 :             :             Size        realSize;
     159                 :             :             char       *resultptr;
     160                 :             : 
     161                 :     4693132 :             realSize = (Size) VARSIZE_ANY(vl);
     162                 :     4693132 :             resultptr = (char *) palloc(realSize);
     163                 :     4693132 :             memcpy(resultptr, vl, realSize);
     164                 :     4693132 :             res = PointerGetDatum(resultptr);
     165                 :             :         }
     166                 :             :     }
     167                 :             :     else
     168                 :             :     {
     169                 :             :         /* Pass by reference, but not varlena, so not toasted */
     170                 :             :         Size        realSize;
     171                 :             :         char       *resultptr;
     172                 :             : 
     173                 :     3716828 :         realSize = datumGetSize(value, typByVal, typLen);
     174                 :             : 
     175                 :     3716828 :         resultptr = (char *) palloc(realSize);
     176                 :     3716828 :         memcpy(resultptr, DatumGetPointer(value), realSize);
     177                 :     3716828 :         res = PointerGetDatum(resultptr);
     178                 :             :     }
     179                 :    16764953 :     return res;
     180                 :             : }
     181                 :             : 
     182                 :             : /*-------------------------------------------------------------------------
     183                 :             :  * datumTransfer
     184                 :             :  *
     185                 :             :  * Transfer a non-NULL datum into the current memory context.
     186                 :             :  *
     187                 :             :  * This is equivalent to datumCopy() except when the datum is a read-write
     188                 :             :  * pointer to an expanded object.  In that case we merely reparent the object
     189                 :             :  * into the current context, and return its standard R/W pointer (in case the
     190                 :             :  * given one is a transient pointer of shorter lifespan).
     191                 :             :  *-------------------------------------------------------------------------
     192                 :             :  */
     193                 :             : Datum
     194                 :       75836 : datumTransfer(Datum value, bool typByVal, int typLen)
     195                 :             : {
     196   [ +  +  +  +  :      149671 :     if (!typByVal && typLen == -1 &&
                   +  + ]
     197                 :       73835 :         VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)))
     198                 :        2065 :         value = TransferExpandedObject(value, CurrentMemoryContext);
     199                 :             :     else
     200                 :       73771 :         value = datumCopy(value, typByVal, typLen);
     201                 :       75836 :     return value;
     202                 :             : }
     203                 :             : 
     204                 :             : /*-------------------------------------------------------------------------
     205                 :             :  * datumIsEqual
     206                 :             :  *
     207                 :             :  * Return true if two datums are equal, false otherwise
     208                 :             :  *
     209                 :             :  * NOTE: XXX!
     210                 :             :  * We just compare the bytes of the two values, one by one.
     211                 :             :  * This routine will return false if there are 2 different
     212                 :             :  * representations of the same value (something along the lines
     213                 :             :  * of say the representation of zero in one's complement arithmetic).
     214                 :             :  * Also, it will probably not give the answer you want if either
     215                 :             :  * datum has been "toasted".
     216                 :             :  *
     217                 :             :  * Do not try to make this any smarter than it currently is with respect
     218                 :             :  * to "toasted" datums, because some of the callers could be working in the
     219                 :             :  * context of an aborted transaction.
     220                 :             :  *-------------------------------------------------------------------------
     221                 :             :  */
     222                 :             : bool
     223                 :     2602152 : datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
     224                 :             : {
     225                 :             :     bool        res;
     226                 :             : 
     227         [ +  + ]:     2602152 :     if (typByVal)
     228                 :             :     {
     229                 :             :         /*
     230                 :             :          * just compare the two datums. NOTE: just comparing "len" bytes will
     231                 :             :          * not do the work, because we do not know how these bytes are aligned
     232                 :             :          * inside the "Datum".  We assume instead that any given datatype is
     233                 :             :          * consistent about how it fills extraneous bits in the Datum.
     234                 :             :          */
     235                 :     1861468 :         res = (value1 == value2);
     236                 :             :     }
     237                 :             :     else
     238                 :             :     {
     239                 :             :         Size        size1,
     240                 :             :                     size2;
     241                 :             :         char       *s1,
     242                 :             :                    *s2;
     243                 :             : 
     244                 :             :         /*
     245                 :             :          * Compare the bytes pointed by the pointers stored in the datums.
     246                 :             :          */
     247                 :      740684 :         size1 = datumGetSize(value1, typByVal, typLen);
     248                 :      740684 :         size2 = datumGetSize(value2, typByVal, typLen);
     249         [ +  + ]:      740684 :         if (size1 != size2)
     250                 :        8494 :             return false;
     251                 :      732190 :         s1 = (char *) DatumGetPointer(value1);
     252                 :      732190 :         s2 = (char *) DatumGetPointer(value2);
     253                 :      732190 :         res = (memcmp(s1, s2, size1) == 0);
     254                 :             :     }
     255                 :     2593658 :     return res;
     256                 :             : }
     257                 :             : 
     258                 :             : /*-------------------------------------------------------------------------
     259                 :             :  * datum_image_eq
     260                 :             :  *
     261                 :             :  * Compares two datums for identical contents when coerced to a signed integer
     262                 :             :  * of typLen bytes.  Return true if the two datums are equal, false otherwise.
     263                 :             :  *
     264                 :             :  * The coercion is required as we're not always careful to use the correct
     265                 :             :  * PG_RETURN_* macro.  If we didn't do this, a Datum that's been formed and
     266                 :             :  * deformed into a tuple may not have the same signed representation as the
     267                 :             :  * other datum value.
     268                 :             :  *-------------------------------------------------------------------------
     269                 :             :  */
     270                 :             : bool
     271                 :    14381657 : datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
     272                 :             : {
     273                 :             :     Size        len1,
     274                 :             :                 len2;
     275                 :    14381657 :     bool        result = true;
     276                 :             : 
     277         [ +  + ]:    14381657 :     if (typByVal)
     278                 :             :     {
     279   [ +  +  +  + ]:    12223788 :         switch (typLen)
     280                 :             :         {
     281                 :       13432 :             case sizeof(char):
     282                 :       13432 :                 result = (DatumGetChar(value1) == DatumGetChar(value2));
     283                 :       13432 :                 break;
     284                 :      209272 :             case sizeof(int16):
     285                 :      209272 :                 result = (DatumGetInt16(value1) == DatumGetInt16(value2));
     286                 :      209272 :                 break;
     287                 :    11795124 :             case sizeof(int32):
     288                 :    11795124 :                 result = (DatumGetInt32(value1) == DatumGetInt32(value2));
     289                 :    11795124 :                 break;
     290                 :      205960 :             default:
     291                 :      205960 :                 result = (value1 == value2);
     292                 :      205960 :                 break;
     293                 :             :         }
     294                 :             :     }
     295         [ +  + ]:     2157869 :     else if (typLen > 0)
     296                 :             :     {
     297                 :     1600722 :         result = (memcmp(DatumGetPointer(value1),
     298                 :     1600722 :                          DatumGetPointer(value2),
     299                 :             :                          typLen) == 0);
     300                 :             :     }
     301         [ +  + ]:      557147 :     else if (typLen == -1)
     302                 :             :     {
     303                 :      216745 :         len1 = toast_raw_datum_size(value1);
     304                 :      216745 :         len2 = toast_raw_datum_size(value2);
     305                 :             :         /* No need to de-toast if lengths don't match. */
     306         [ +  + ]:      216745 :         if (len1 != len2)
     307                 :       14325 :             result = false;
     308                 :             :         else
     309                 :             :         {
     310                 :             :             varlena    *arg1val;
     311                 :             :             varlena    *arg2val;
     312                 :             : 
     313                 :      202420 :             arg1val = PG_DETOAST_DATUM_PACKED(value1);
     314                 :      202420 :             arg2val = PG_DETOAST_DATUM_PACKED(value2);
     315                 :             : 
     316                 :      202420 :             result = (memcmp(VARDATA_ANY(arg1val),
     317                 :      202420 :                              VARDATA_ANY(arg2val),
     318                 :             :                              len1 - VARHDRSZ) == 0);
     319                 :             : 
     320                 :             :             /* Only free memory if it's a copy made here. */
     321         [ +  + ]:      202420 :             if (arg1val != DatumGetPointer(value1))
     322                 :           4 :                 pfree(arg1val);
     323         [ +  + ]:      202420 :             if (arg2val != DatumGetPointer(value2))
     324                 :           4 :                 pfree(arg2val);
     325                 :             :         }
     326                 :             :     }
     327         [ +  - ]:      340402 :     else if (typLen == -2)
     328                 :             :     {
     329                 :             :         char       *s1,
     330                 :             :                    *s2;
     331                 :             : 
     332                 :             :         /* Compare cstring datums */
     333                 :      340402 :         s1 = DatumGetCString(value1);
     334                 :      340402 :         s2 = DatumGetCString(value2);
     335                 :      340402 :         len1 = strlen(s1) + 1;
     336                 :      340402 :         len2 = strlen(s2) + 1;
     337         [ +  + ]:      340402 :         if (len1 != len2)
     338                 :      185064 :             return false;
     339                 :      155338 :         result = (memcmp(s1, s2, len1) == 0);
     340                 :             :     }
     341                 :             :     else
     342         [ #  # ]:           0 :         elog(ERROR, "unexpected typLen: %d", typLen);
     343                 :             : 
     344                 :    14196593 :     return result;
     345                 :             : }
     346                 :             : 
     347                 :             : /*-------------------------------------------------------------------------
     348                 :             :  * datum_image_hash
     349                 :             :  *
     350                 :             :  * Generate a hash value based on the binary representation of 'value' when
     351                 :             :  * represented as a signed integer of typLen bytes.  Most use cases will want
     352                 :             :  * to use the hash function specific to the Datum's type, however, some corner
     353                 :             :  * cases require generating a hash value based on the actual bits rather than
     354                 :             :  * the logical value.
     355                 :             :  *-------------------------------------------------------------------------
     356                 :             :  */
     357                 :             : uint32
     358                 :       80898 : datum_image_hash(Datum value, bool typByVal, int typLen)
     359                 :             : {
     360                 :             :     Size        len;
     361                 :             :     uint32      result;
     362                 :             : 
     363         [ +  + ]:       80898 :     if (typByVal)
     364                 :             :     {
     365   [ -  -  +  + ]:       80762 :         switch (typLen)
     366                 :             :         {
     367                 :           0 :             case sizeof(char):
     368                 :           0 :                 value = CharGetDatum(DatumGetChar(value));
     369                 :           0 :                 break;
     370                 :           0 :             case sizeof(int16):
     371                 :           0 :                 value = Int16GetDatum(DatumGetInt16(value));
     372                 :           0 :                 break;
     373                 :       80730 :             case sizeof(int32):
     374                 :       80730 :                 value = Int32GetDatum(DatumGetInt32(value));
     375                 :       80730 :                 break;
     376                 :             :                 /* Nothing needs done for 64-bit types */
     377                 :             :         }
     378                 :             : 
     379                 :       80762 :         result = hash_bytes((unsigned char *) &value, sizeof(Datum));
     380                 :             :     }
     381         [ +  + ]:         136 :     else if (typLen > 0)
     382                 :          24 :         result = hash_bytes((unsigned char *) DatumGetPointer(value), typLen);
     383         [ +  - ]:         112 :     else if (typLen == -1)
     384                 :             :     {
     385                 :             :         varlena    *val;
     386                 :             : 
     387                 :         112 :         len = toast_raw_datum_size(value);
     388                 :             : 
     389                 :         112 :         val = PG_DETOAST_DATUM_PACKED(value);
     390                 :             : 
     391                 :         112 :         result = hash_bytes((unsigned char *) VARDATA_ANY(val), len - VARHDRSZ);
     392                 :             : 
     393                 :             :         /* Only free memory if it's a copy made here. */
     394         [ +  + ]:         112 :         if (val != DatumGetPointer(value))
     395                 :           8 :             pfree(val);
     396                 :             :     }
     397         [ #  # ]:           0 :     else if (typLen == -2)
     398                 :             :     {
     399                 :             :         char       *s;
     400                 :             : 
     401                 :           0 :         s = DatumGetCString(value);
     402                 :           0 :         len = strlen(s) + 1;
     403                 :             : 
     404                 :           0 :         result = hash_bytes((unsigned char *) s, len);
     405                 :             :     }
     406                 :             :     else
     407                 :             :     {
     408         [ #  # ]:           0 :         elog(ERROR, "unexpected typLen: %d", typLen);
     409                 :             :         result = 0;             /* keep compiler quiet */
     410                 :             :     }
     411                 :             : 
     412                 :       80898 :     return result;
     413                 :             : }
     414                 :             : 
     415                 :             : /*-------------------------------------------------------------------------
     416                 :             :  * btequalimage
     417                 :             :  *
     418                 :             :  * Generic "equalimage" support function.
     419                 :             :  *
     420                 :             :  * B-Tree operator classes whose equality function could safely be replaced by
     421                 :             :  * datum_image_eq() in all cases can use this as their "equalimage" support
     422                 :             :  * function.
     423                 :             :  *
     424                 :             :  * Currently, we unconditionally assume that any B-Tree operator class that
     425                 :             :  * registers btequalimage as its support function 4 must be able to safely use
     426                 :             :  * optimizations like deduplication (i.e. we return true unconditionally).  If
     427                 :             :  * it ever proved necessary to rescind support for an operator class, we could
     428                 :             :  * do that in a targeted fashion by doing something with the opcintype
     429                 :             :  * argument.
     430                 :             :  *-------------------------------------------------------------------------
     431                 :             :  */
     432                 :             : Datum
     433                 :       55267 : btequalimage(PG_FUNCTION_ARGS)
     434                 :             : {
     435                 :             : #ifdef NOT_USED
     436                 :             :     Oid         opcintype = PG_GETARG_OID(0);
     437                 :             : #endif
     438                 :             : 
     439                 :       55267 :     PG_RETURN_BOOL(true);
     440                 :             : }
     441                 :             : 
     442                 :             : /*-------------------------------------------------------------------------
     443                 :             :  * datumEstimateSpace
     444                 :             :  *
     445                 :             :  * Compute the amount of space that datumSerialize will require for a
     446                 :             :  * particular Datum.
     447                 :             :  *-------------------------------------------------------------------------
     448                 :             :  */
     449                 :             : Size
     450                 :         100 : datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
     451                 :             : {
     452                 :         100 :     Size        sz = sizeof(int);
     453                 :             : 
     454         [ +  - ]:         100 :     if (!isnull)
     455                 :             :     {
     456                 :             :         /* no need to use add_size, can't overflow */
     457         [ +  + ]:         100 :         if (typByVal)
     458                 :          88 :             sz += sizeof(Datum);
     459   [ +  -  +  + ]:          24 :         else if (typLen == -1 &&
     460                 :          12 :                  VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     461                 :             :         {
     462                 :             :             /* Expanded objects need to be flattened, see comment below */
     463                 :           4 :             sz += EOH_get_flat_size(DatumGetEOHP(value));
     464                 :             :         }
     465                 :             :         else
     466                 :           8 :             sz += datumGetSize(value, typByVal, typLen);
     467                 :             :     }
     468                 :             : 
     469                 :         100 :     return sz;
     470                 :             : }
     471                 :             : 
     472                 :             : /*-------------------------------------------------------------------------
     473                 :             :  * datumSerialize
     474                 :             :  *
     475                 :             :  * Serialize a possibly-NULL datum into caller-provided storage.
     476                 :             :  *
     477                 :             :  * Note: "expanded" objects are flattened so as to produce a self-contained
     478                 :             :  * representation, but other sorts of toast pointers are transferred as-is.
     479                 :             :  * This is because the intended use of this function is to pass the value
     480                 :             :  * to another process within the same database server.  The other process
     481                 :             :  * could not access an "expanded" object within this process's memory, but
     482                 :             :  * we assume it can dereference the same TOAST pointers this one can.
     483                 :             :  *
     484                 :             :  * The format is as follows: first, we write a 4-byte header word, which
     485                 :             :  * is either the length of a pass-by-reference datum, -1 for a
     486                 :             :  * pass-by-value datum, or -2 for a NULL.  If the value is NULL, nothing
     487                 :             :  * further is written.  If it is pass-by-value, sizeof(Datum) bytes
     488                 :             :  * follow.  Otherwise, the number of bytes indicated by the header word
     489                 :             :  * follow.  The caller is responsible for ensuring that there is enough
     490                 :             :  * storage to store the number of bytes that will be written; use
     491                 :             :  * datumEstimateSpace() to find out how many will be needed.
     492                 :             :  * *start_address is updated to point to the byte immediately following
     493                 :             :  * those written.
     494                 :             :  *-------------------------------------------------------------------------
     495                 :             :  */
     496                 :             : void
     497                 :          76 : datumSerialize(Datum value, bool isnull, bool typByVal, int typLen,
     498                 :             :                char **start_address)
     499                 :             : {
     500                 :          76 :     ExpandedObjectHeader *eoh = NULL;
     501                 :             :     int         header;
     502                 :             : 
     503                 :             :     /* Write header word. */
     504         [ -  + ]:          76 :     if (isnull)
     505                 :           0 :         header = -2;
     506         [ +  + ]:          76 :     else if (typByVal)
     507                 :          64 :         header = -1;
     508   [ +  -  +  + ]:          24 :     else if (typLen == -1 &&
     509                 :          12 :              VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     510                 :             :     {
     511                 :           4 :         eoh = DatumGetEOHP(value);
     512                 :           4 :         header = EOH_get_flat_size(eoh);
     513                 :             :     }
     514                 :             :     else
     515                 :           8 :         header = datumGetSize(value, typByVal, typLen);
     516                 :          76 :     memcpy(*start_address, &header, sizeof(int));
     517                 :          76 :     *start_address += sizeof(int);
     518                 :             : 
     519                 :             :     /* If not null, write payload bytes. */
     520         [ +  - ]:          76 :     if (!isnull)
     521                 :             :     {
     522         [ +  + ]:          76 :         if (typByVal)
     523                 :             :         {
     524                 :          64 :             memcpy(*start_address, &value, sizeof(Datum));
     525                 :          64 :             *start_address += sizeof(Datum);
     526                 :             :         }
     527         [ +  + ]:          12 :         else if (eoh)
     528                 :             :         {
     529                 :             :             char       *tmp;
     530                 :             : 
     531                 :             :             /*
     532                 :             :              * EOH_flatten_into expects the target address to be maxaligned,
     533                 :             :              * so we can't store directly to *start_address.
     534                 :             :              */
     535                 :           4 :             tmp = (char *) palloc(header);
     536                 :           4 :             EOH_flatten_into(eoh, tmp, header);
     537                 :           4 :             memcpy(*start_address, tmp, header);
     538                 :           4 :             *start_address += header;
     539                 :             : 
     540                 :             :             /* be tidy. */
     541                 :           4 :             pfree(tmp);
     542                 :             :         }
     543                 :             :         else
     544                 :             :         {
     545                 :           8 :             memcpy(*start_address, DatumGetPointer(value), header);
     546                 :           8 :             *start_address += header;
     547                 :             :         }
     548                 :             :     }
     549                 :          76 : }
     550                 :             : 
     551                 :             : /*-------------------------------------------------------------------------
     552                 :             :  * datumRestore
     553                 :             :  *
     554                 :             :  * Restore a possibly-NULL datum previously serialized by datumSerialize.
     555                 :             :  * *start_address is updated according to the number of bytes consumed.
     556                 :             :  *-------------------------------------------------------------------------
     557                 :             :  */
     558                 :             : Datum
     559                 :         184 : datumRestore(char **start_address, bool *isnull)
     560                 :             : {
     561                 :             :     int         header;
     562                 :             :     void       *d;
     563                 :             : 
     564                 :             :     /* Read header word. */
     565                 :         184 :     memcpy(&header, *start_address, sizeof(int));
     566                 :         184 :     *start_address += sizeof(int);
     567                 :             : 
     568                 :             :     /* If this datum is NULL, we can stop here. */
     569         [ -  + ]:         184 :     if (header == -2)
     570                 :             :     {
     571                 :           0 :         *isnull = true;
     572                 :           0 :         return (Datum) 0;
     573                 :             :     }
     574                 :             : 
     575                 :             :     /* OK, datum is not null. */
     576                 :         184 :     *isnull = false;
     577                 :             : 
     578                 :             :     /* If this datum is pass-by-value, sizeof(Datum) bytes follow. */
     579         [ +  + ]:         184 :     if (header == -1)
     580                 :             :     {
     581                 :             :         Datum       val;
     582                 :             : 
     583                 :         144 :         memcpy(&val, *start_address, sizeof(Datum));
     584                 :         144 :         *start_address += sizeof(Datum);
     585                 :         144 :         return val;
     586                 :             :     }
     587                 :             : 
     588                 :             :     /* Pass-by-reference case; copy indicated number of bytes. */
     589                 :             :     Assert(header > 0);
     590                 :          40 :     d = palloc(header);
     591                 :          40 :     memcpy(d, *start_address, header);
     592                 :          40 :     *start_address += header;
     593                 :          40 :     return PointerGetDatum(d);
     594                 :             : }
        

Generated by: LCOV version 2.0-1