LCOV - code coverage report
Current view: top level - src/backend/utils/adt - datum.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 63.3 % 215 136
Test Date: 2026-01-26 10:56:24 Functions: 70.0 % 10 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 48.1 % 108 52

             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 "struct 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                 :      974389 : datumGetSize(Datum value, bool typByVal, int typLen)
      66                 :             : {
      67                 :      974389 :         Size            size;
      68                 :             : 
      69         [ +  + ]:      974389 :         if (typByVal)
      70                 :             :         {
      71                 :             :                 /* Pass-by-value types are always fixed-length */
      72         [ +  - ]:        5215 :                 Assert(typLen > 0 && typLen <= sizeof(Datum));
      73                 :        5215 :                 size = (Size) typLen;
      74                 :        5215 :         }
      75                 :             :         else
      76                 :             :         {
      77         [ +  + ]:      969174 :                 if (typLen > 0)
      78                 :             :                 {
      79                 :             :                         /* Fixed-length pass-by-ref type */
      80                 :      897291 :                         size = (Size) typLen;
      81                 :      897291 :                 }
      82         [ +  + ]:       71883 :                 else if (typLen == -1)
      83                 :             :                 {
      84                 :             :                         /* It is a varlena datatype */
      85                 :       69688 :                         struct varlena *s = (struct varlena *) DatumGetPointer(value);
      86                 :             : 
      87         [ +  - ]:       69688 :                         if (!s)
      88   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
      89                 :             :                                                 (errcode(ERRCODE_DATA_EXCEPTION),
      90                 :             :                                                  errmsg("invalid Datum pointer")));
      91                 :             : 
      92                 :       69688 :                         size = (Size) VARSIZE_ANY(s);
      93                 :       69688 :                 }
      94         [ +  - ]:        2195 :                 else if (typLen == -2)
      95                 :             :                 {
      96                 :             :                         /* It is a cstring datatype */
      97                 :        2195 :                         char       *s = (char *) DatumGetPointer(value);
      98                 :             : 
      99         [ +  - ]:        2195 :                         if (!s)
     100   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     101                 :             :                                                 (errcode(ERRCODE_DATA_EXCEPTION),
     102                 :             :                                                  errmsg("invalid Datum pointer")));
     103                 :             : 
     104                 :        2195 :                         size = (Size) (strlen(s) + 1);
     105                 :        2195 :                 }
     106                 :             :                 else
     107                 :             :                 {
     108   [ #  #  #  # ]:           0 :                         elog(ERROR, "invalid typLen: %d", typLen);
     109                 :           0 :                         size = 0;                       /* keep compiler quiet */
     110                 :             :                 }
     111                 :             :         }
     112                 :             : 
     113                 :     1948778 :         return size;
     114                 :      974389 : }
     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                 :     3182471 : datumCopy(Datum value, bool typByVal, int typLen)
     133                 :             : {
     134                 :     3182471 :         Datum           res;
     135                 :             : 
     136         [ +  + ]:     3182471 :         if (typByVal)
     137                 :     1417190 :                 res = value;
     138         [ +  + ]:     1765281 :         else if (typLen == -1)
     139                 :             :         {
     140                 :             :                 /* It is a varlena datatype */
     141                 :      992792 :                 struct varlena *vl = (struct varlena *) DatumGetPointer(value);
     142                 :             : 
     143         [ +  + ]:      992792 :                 if (VARATT_IS_EXTERNAL_EXPANDED(vl))
     144                 :             :                 {
     145                 :             :                         /* Flatten into the caller's memory context */
     146                 :         156 :                         ExpandedObjectHeader *eoh = DatumGetEOHP(value);
     147                 :         156 :                         Size            resultsize;
     148                 :         156 :                         char       *resultptr;
     149                 :             : 
     150                 :         156 :                         resultsize = EOH_get_flat_size(eoh);
     151                 :         156 :                         resultptr = (char *) palloc(resultsize);
     152                 :         156 :                         EOH_flatten_into(eoh, resultptr, resultsize);
     153                 :         156 :                         res = PointerGetDatum(resultptr);
     154                 :         156 :                 }
     155                 :             :                 else
     156                 :             :                 {
     157                 :             :                         /* Otherwise, just copy the varlena datum verbatim */
     158                 :      992636 :                         Size            realSize;
     159                 :      992636 :                         char       *resultptr;
     160                 :             : 
     161                 :      992636 :                         realSize = (Size) VARSIZE_ANY(vl);
     162                 :      992636 :                         resultptr = (char *) palloc(realSize);
     163                 :      992636 :                         memcpy(resultptr, vl, realSize);
     164                 :      992636 :                         res = PointerGetDatum(resultptr);
     165                 :      992636 :                 }
     166                 :      992792 :         }
     167                 :             :         else
     168                 :             :         {
     169                 :             :                 /* Pass by reference, but not varlena, so not toasted */
     170                 :      772489 :                 Size            realSize;
     171                 :      772489 :                 char       *resultptr;
     172                 :             : 
     173                 :      772489 :                 realSize = datumGetSize(value, typByVal, typLen);
     174                 :             : 
     175                 :      772489 :                 resultptr = (char *) palloc(realSize);
     176                 :      772489 :                 memcpy(resultptr, DatumGetPointer(value), realSize);
     177                 :      772489 :                 res = PointerGetDatum(resultptr);
     178                 :      772489 :         }
     179                 :     6364942 :         return res;
     180                 :     3182471 : }
     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                 :       17337 : datumTransfer(Datum value, bool typByVal, int typLen)
     195                 :             : {
     196   [ +  +  +  +  :       17337 :         if (!typByVal && typLen == -1 &&
                   +  + ]
     197                 :       17196 :                 VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)))
     198                 :          69 :                 value = TransferExpandedObject(value, CurrentMemoryContext);
     199                 :             :         else
     200                 :       17268 :                 value = datumCopy(value, typByVal, typLen);
     201                 :       17337 :         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                 :      124160 : datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
     224                 :             : {
     225                 :      124160 :         bool            res;
     226                 :             : 
     227         [ +  + ]:      124160 :         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                 :       91750 :                 res = (value1 == value2);
     236                 :       91750 :         }
     237                 :             :         else
     238                 :             :         {
     239                 :       32410 :                 Size            size1,
     240                 :             :                                         size2;
     241                 :       32410 :                 char       *s1,
     242                 :             :                                    *s2;
     243                 :             : 
     244                 :             :                 /*
     245                 :             :                  * Compare the bytes pointed by the pointers stored in the datums.
     246                 :             :                  */
     247                 :       32410 :                 size1 = datumGetSize(value1, typByVal, typLen);
     248                 :       32410 :                 size2 = datumGetSize(value2, typByVal, typLen);
     249         [ +  + ]:       32410 :                 if (size1 != size2)
     250                 :         717 :                         return false;
     251                 :       31693 :                 s1 = (char *) DatumGetPointer(value1);
     252                 :       31693 :                 s2 = (char *) DatumGetPointer(value2);
     253                 :       31693 :                 res = (memcmp(s1, s2, size1) == 0);
     254         [ +  + ]:       32410 :         }
     255                 :      123443 :         return res;
     256                 :      124160 : }
     257                 :             : 
     258                 :             : /*-------------------------------------------------------------------------
     259                 :             :  * datum_image_eq
     260                 :             :  *
     261                 :             :  * Compares two datums for identical contents, based on byte images.  Return
     262                 :             :  * true if the two datums are equal, false otherwise.
     263                 :             :  *-------------------------------------------------------------------------
     264                 :             :  */
     265                 :             : bool
     266                 :     2185625 : datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
     267                 :             : {
     268                 :     2185625 :         Size            len1,
     269                 :             :                                 len2;
     270                 :     2185625 :         bool            result = true;
     271                 :             : 
     272         [ +  + ]:     2185625 :         if (typByVal)
     273                 :             :         {
     274                 :     1682060 :                 result = (value1 == value2);
     275                 :     1682060 :         }
     276         [ +  + ]:      503565 :         else if (typLen > 0)
     277                 :             :         {
     278                 :     1205100 :                 result = (memcmp(DatumGetPointer(value1),
     279                 :      401700 :                                                  DatumGetPointer(value2),
     280                 :      803400 :                                                  typLen) == 0);
     281                 :      401700 :         }
     282         [ +  + ]:      101865 :         else if (typLen == -1)
     283                 :             :         {
     284                 :       50698 :                 len1 = toast_raw_datum_size(value1);
     285                 :       50698 :                 len2 = toast_raw_datum_size(value2);
     286                 :             :                 /* No need to de-toast if lengths don't match. */
     287         [ +  + ]:       50698 :                 if (len1 != len2)
     288                 :        2253 :                         result = false;
     289                 :             :                 else
     290                 :             :                 {
     291                 :       48445 :                         struct varlena *arg1val;
     292                 :       48445 :                         struct varlena *arg2val;
     293                 :             : 
     294                 :       48445 :                         arg1val = PG_DETOAST_DATUM_PACKED(value1);
     295                 :       48445 :                         arg2val = PG_DETOAST_DATUM_PACKED(value2);
     296                 :             : 
     297                 :      145335 :                         result = (memcmp(VARDATA_ANY(arg1val),
     298                 :       48445 :                                                          VARDATA_ANY(arg2val),
     299                 :       96890 :                                                          len1 - VARHDRSZ) == 0);
     300                 :             : 
     301                 :             :                         /* Only free memory if it's a copy made here. */
     302         [ +  + ]:       48445 :                         if (arg1val != DatumGetPointer(value1))
     303                 :           1 :                                 pfree(arg1val);
     304         [ +  + ]:       48445 :                         if (arg2val != DatumGetPointer(value2))
     305                 :           1 :                                 pfree(arg2val);
     306                 :       48445 :                 }
     307                 :       50698 :         }
     308         [ +  - ]:       51167 :         else if (typLen == -2)
     309                 :             :         {
     310                 :       51167 :                 char       *s1,
     311                 :             :                                    *s2;
     312                 :             : 
     313                 :             :                 /* Compare cstring datums */
     314                 :       51167 :                 s1 = DatumGetCString(value1);
     315                 :       51167 :                 s2 = DatumGetCString(value2);
     316                 :       51167 :                 len1 = strlen(s1) + 1;
     317                 :       51167 :                 len2 = strlen(s2) + 1;
     318         [ +  + ]:       51167 :                 if (len1 != len2)
     319                 :       19722 :                         return false;
     320                 :       31445 :                 result = (memcmp(s1, s2, len1) == 0);
     321         [ +  + ]:       51167 :         }
     322                 :             :         else
     323   [ #  #  #  # ]:           0 :                 elog(ERROR, "unexpected typLen: %d", typLen);
     324                 :             : 
     325                 :     2165903 :         return result;
     326                 :     2185625 : }
     327                 :             : 
     328                 :             : /*-------------------------------------------------------------------------
     329                 :             :  * datum_image_hash
     330                 :             :  *
     331                 :             :  * Generate a hash value based on the binary representation of 'value'.  Most
     332                 :             :  * use cases will want to use the hash function specific to the Datum's type,
     333                 :             :  * however, some corner cases require generating a hash value based on the
     334                 :             :  * actual bits rather than the logical value.
     335                 :             :  *-------------------------------------------------------------------------
     336                 :             :  */
     337                 :             : uint32
     338                 :       20124 : datum_image_hash(Datum value, bool typByVal, int typLen)
     339                 :             : {
     340                 :       20124 :         Size            len;
     341                 :       20124 :         uint32          result;
     342                 :             : 
     343         [ +  + ]:       20124 :         if (typByVal)
     344                 :       20090 :                 result = hash_bytes((unsigned char *) &value, sizeof(Datum));
     345         [ +  + ]:          34 :         else if (typLen > 0)
     346                 :           6 :                 result = hash_bytes((unsigned char *) DatumGetPointer(value), typLen);
     347         [ -  + ]:          28 :         else if (typLen == -1)
     348                 :             :         {
     349                 :          28 :                 struct varlena *val;
     350                 :             : 
     351                 :          28 :                 len = toast_raw_datum_size(value);
     352                 :             : 
     353                 :          28 :                 val = PG_DETOAST_DATUM_PACKED(value);
     354                 :             : 
     355                 :          28 :                 result = hash_bytes((unsigned char *) VARDATA_ANY(val), len - VARHDRSZ);
     356                 :             : 
     357                 :             :                 /* Only free memory if it's a copy made here. */
     358         [ +  + ]:          28 :                 if (val != DatumGetPointer(value))
     359                 :           2 :                         pfree(val);
     360                 :          28 :         }
     361         [ #  # ]:           0 :         else if (typLen == -2)
     362                 :             :         {
     363                 :           0 :                 char       *s;
     364                 :             : 
     365                 :           0 :                 s = DatumGetCString(value);
     366                 :           0 :                 len = strlen(s) + 1;
     367                 :             : 
     368                 :           0 :                 result = hash_bytes((unsigned char *) s, len);
     369                 :           0 :         }
     370                 :             :         else
     371                 :             :         {
     372   [ #  #  #  # ]:           0 :                 elog(ERROR, "unexpected typLen: %d", typLen);
     373                 :           0 :                 result = 0;                             /* keep compiler quiet */
     374                 :             :         }
     375                 :             : 
     376                 :       40248 :         return result;
     377                 :       20124 : }
     378                 :             : 
     379                 :             : /*-------------------------------------------------------------------------
     380                 :             :  * btequalimage
     381                 :             :  *
     382                 :             :  * Generic "equalimage" support function.
     383                 :             :  *
     384                 :             :  * B-Tree operator classes whose equality function could safely be replaced by
     385                 :             :  * datum_image_eq() in all cases can use this as their "equalimage" support
     386                 :             :  * function.
     387                 :             :  *
     388                 :             :  * Currently, we unconditionally assume that any B-Tree operator class that
     389                 :             :  * registers btequalimage as its support function 4 must be able to safely use
     390                 :             :  * optimizations like deduplication (i.e. we return true unconditionally).  If
     391                 :             :  * it ever proved necessary to rescind support for an operator class, we could
     392                 :             :  * do that in a targeted fashion by doing something with the opcintype
     393                 :             :  * argument.
     394                 :             :  *-------------------------------------------------------------------------
     395                 :             :  */
     396                 :             : Datum
     397                 :        5586 : btequalimage(PG_FUNCTION_ARGS)
     398                 :             : {
     399                 :             : #ifdef NOT_USED
     400                 :             :         Oid                     opcintype = PG_GETARG_OID(0);
     401                 :             : #endif
     402                 :             : 
     403                 :        5586 :         PG_RETURN_BOOL(true);
     404                 :             : }
     405                 :             : 
     406                 :             : /*-------------------------------------------------------------------------
     407                 :             :  * datumEstimateSpace
     408                 :             :  *
     409                 :             :  * Compute the amount of space that datumSerialize will require for a
     410                 :             :  * particular Datum.
     411                 :             :  *-------------------------------------------------------------------------
     412                 :             :  */
     413                 :             : Size
     414                 :           0 : datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
     415                 :             : {
     416                 :           0 :         Size            sz = sizeof(int);
     417                 :             : 
     418         [ #  # ]:           0 :         if (!isnull)
     419                 :             :         {
     420                 :             :                 /* no need to use add_size, can't overflow */
     421         [ #  # ]:           0 :                 if (typByVal)
     422                 :           0 :                         sz += sizeof(Datum);
     423   [ #  #  #  # ]:           0 :                 else if (typLen == -1 &&
     424                 :           0 :                                  VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     425                 :             :                 {
     426                 :             :                         /* Expanded objects need to be flattened, see comment below */
     427                 :           0 :                         sz += EOH_get_flat_size(DatumGetEOHP(value));
     428                 :           0 :                 }
     429                 :             :                 else
     430                 :           0 :                         sz += datumGetSize(value, typByVal, typLen);
     431                 :           0 :         }
     432                 :             : 
     433                 :           0 :         return sz;
     434                 :           0 : }
     435                 :             : 
     436                 :             : /*-------------------------------------------------------------------------
     437                 :             :  * datumSerialize
     438                 :             :  *
     439                 :             :  * Serialize a possibly-NULL datum into caller-provided storage.
     440                 :             :  *
     441                 :             :  * Note: "expanded" objects are flattened so as to produce a self-contained
     442                 :             :  * representation, but other sorts of toast pointers are transferred as-is.
     443                 :             :  * This is because the intended use of this function is to pass the value
     444                 :             :  * to another process within the same database server.  The other process
     445                 :             :  * could not access an "expanded" object within this process's memory, but
     446                 :             :  * we assume it can dereference the same TOAST pointers this one can.
     447                 :             :  *
     448                 :             :  * The format is as follows: first, we write a 4-byte header word, which
     449                 :             :  * is either the length of a pass-by-reference datum, -1 for a
     450                 :             :  * pass-by-value datum, or -2 for a NULL.  If the value is NULL, nothing
     451                 :             :  * further is written.  If it is pass-by-value, sizeof(Datum) bytes
     452                 :             :  * follow.  Otherwise, the number of bytes indicated by the header word
     453                 :             :  * follow.  The caller is responsible for ensuring that there is enough
     454                 :             :  * storage to store the number of bytes that will be written; use
     455                 :             :  * datumEstimateSpace() to find out how many will be needed.
     456                 :             :  * *start_address is updated to point to the byte immediately following
     457                 :             :  * those written.
     458                 :             :  *-------------------------------------------------------------------------
     459                 :             :  */
     460                 :             : void
     461                 :           0 : datumSerialize(Datum value, bool isnull, bool typByVal, int typLen,
     462                 :             :                            char **start_address)
     463                 :             : {
     464                 :           0 :         ExpandedObjectHeader *eoh = NULL;
     465                 :           0 :         int                     header;
     466                 :             : 
     467                 :             :         /* Write header word. */
     468         [ #  # ]:           0 :         if (isnull)
     469                 :           0 :                 header = -2;
     470         [ #  # ]:           0 :         else if (typByVal)
     471                 :           0 :                 header = -1;
     472   [ #  #  #  # ]:           0 :         else if (typLen == -1 &&
     473                 :           0 :                          VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     474                 :             :         {
     475                 :           0 :                 eoh = DatumGetEOHP(value);
     476                 :           0 :                 header = EOH_get_flat_size(eoh);
     477                 :           0 :         }
     478                 :             :         else
     479                 :           0 :                 header = datumGetSize(value, typByVal, typLen);
     480                 :           0 :         memcpy(*start_address, &header, sizeof(int));
     481                 :           0 :         *start_address += sizeof(int);
     482                 :             : 
     483                 :             :         /* If not null, write payload bytes. */
     484         [ #  # ]:           0 :         if (!isnull)
     485                 :             :         {
     486         [ #  # ]:           0 :                 if (typByVal)
     487                 :             :                 {
     488                 :           0 :                         memcpy(*start_address, &value, sizeof(Datum));
     489                 :           0 :                         *start_address += sizeof(Datum);
     490                 :           0 :                 }
     491         [ #  # ]:           0 :                 else if (eoh)
     492                 :             :                 {
     493                 :           0 :                         char       *tmp;
     494                 :             : 
     495                 :             :                         /*
     496                 :             :                          * EOH_flatten_into expects the target address to be maxaligned,
     497                 :             :                          * so we can't store directly to *start_address.
     498                 :             :                          */
     499                 :           0 :                         tmp = (char *) palloc(header);
     500                 :           0 :                         EOH_flatten_into(eoh, tmp, header);
     501                 :           0 :                         memcpy(*start_address, tmp, header);
     502                 :           0 :                         *start_address += header;
     503                 :             : 
     504                 :             :                         /* be tidy. */
     505                 :           0 :                         pfree(tmp);
     506                 :           0 :                 }
     507                 :             :                 else
     508                 :             :                 {
     509                 :           0 :                         memcpy(*start_address, DatumGetPointer(value), header);
     510                 :           0 :                         *start_address += header;
     511                 :             :                 }
     512                 :           0 :         }
     513                 :           0 : }
     514                 :             : 
     515                 :             : /*-------------------------------------------------------------------------
     516                 :             :  * datumRestore
     517                 :             :  *
     518                 :             :  * Restore a possibly-NULL datum previously serialized by datumSerialize.
     519                 :             :  * *start_address is updated according to the number of bytes consumed.
     520                 :             :  *-------------------------------------------------------------------------
     521                 :             :  */
     522                 :             : Datum
     523                 :           0 : datumRestore(char **start_address, bool *isnull)
     524                 :             : {
     525                 :           0 :         int                     header;
     526                 :           0 :         void       *d;
     527                 :             : 
     528                 :             :         /* Read header word. */
     529                 :           0 :         memcpy(&header, *start_address, sizeof(int));
     530                 :           0 :         *start_address += sizeof(int);
     531                 :             : 
     532                 :             :         /* If this datum is NULL, we can stop here. */
     533         [ #  # ]:           0 :         if (header == -2)
     534                 :             :         {
     535                 :           0 :                 *isnull = true;
     536                 :           0 :                 return (Datum) 0;
     537                 :             :         }
     538                 :             : 
     539                 :             :         /* OK, datum is not null. */
     540                 :           0 :         *isnull = false;
     541                 :             : 
     542                 :             :         /* If this datum is pass-by-value, sizeof(Datum) bytes follow. */
     543         [ #  # ]:           0 :         if (header == -1)
     544                 :             :         {
     545                 :           0 :                 Datum           val;
     546                 :             : 
     547                 :           0 :                 memcpy(&val, *start_address, sizeof(Datum));
     548                 :           0 :                 *start_address += sizeof(Datum);
     549                 :           0 :                 return val;
     550                 :           0 :         }
     551                 :             : 
     552                 :             :         /* Pass-by-reference case; copy indicated number of bytes. */
     553         [ #  # ]:           0 :         Assert(header > 0);
     554                 :           0 :         d = palloc(header);
     555                 :           0 :         memcpy(d, *start_address, header);
     556                 :           0 :         *start_address += header;
     557                 :           0 :         return PointerGetDatum(d);
     558                 :           0 : }
        

Generated by: LCOV version 2.3.2-1