LCOV - code coverage report
Current view: top level - src/backend/utils/adt - datum.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 53 105 50.5 %
Date: 2017-09-29 13:40:31 Functions: 4 7 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * datum.c
       4             :  *    POSTGRES Datum (abstract data type) manipulation routines.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, 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 "utils/datum.h"
      46             : #include "utils/expandeddatum.h"
      47             : 
      48             : 
      49             : /*-------------------------------------------------------------------------
      50             :  * datumGetSize
      51             :  *
      52             :  * Find the "real" size of a datum, given the datum value,
      53             :  * whether it is a "by value", and the declared type length.
      54             :  * (For TOAST pointer datums, this is the size of the pointer datum.)
      55             :  *
      56             :  * This is essentially an out-of-line version of the att_addlength_datum()
      57             :  * macro in access/tupmacs.h.  We do a tad more error checking though.
      58             :  *-------------------------------------------------------------------------
      59             :  */
      60             : Size
      61      747672 : datumGetSize(Datum value, bool typByVal, int typLen)
      62             : {
      63             :     Size        size;
      64             : 
      65      747672 :     if (typByVal)
      66             :     {
      67             :         /* Pass-by-value types are always fixed-length */
      68        1682 :         Assert(typLen > 0 && typLen <= sizeof(Datum));
      69        1682 :         size = (Size) typLen;
      70             :     }
      71             :     else
      72             :     {
      73      745990 :         if (typLen > 0)
      74             :         {
      75             :             /* Fixed-length pass-by-ref type */
      76      739633 :             size = (Size) typLen;
      77             :         }
      78        6357 :         else if (typLen == -1)
      79             :         {
      80             :             /* It is a varlena datatype */
      81        6204 :             struct varlena *s = (struct varlena *) DatumGetPointer(value);
      82             : 
      83        6204 :             if (!PointerIsValid(s))
      84           0 :                 ereport(ERROR,
      85             :                         (errcode(ERRCODE_DATA_EXCEPTION),
      86             :                          errmsg("invalid Datum pointer")));
      87             : 
      88        6204 :             size = (Size) VARSIZE_ANY(s);
      89             :         }
      90         153 :         else if (typLen == -2)
      91             :         {
      92             :             /* It is a cstring datatype */
      93         153 :             char       *s = (char *) DatumGetPointer(value);
      94             : 
      95         153 :             if (!PointerIsValid(s))
      96           0 :                 ereport(ERROR,
      97             :                         (errcode(ERRCODE_DATA_EXCEPTION),
      98             :                          errmsg("invalid Datum pointer")));
      99             : 
     100         153 :             size = (Size) (strlen(s) + 1);
     101             :         }
     102             :         else
     103             :         {
     104           0 :             elog(ERROR, "invalid typLen: %d", typLen);
     105             :             size = 0;           /* keep compiler quiet */
     106             :         }
     107             :     }
     108             : 
     109      747672 :     return size;
     110             : }
     111             : 
     112             : /*-------------------------------------------------------------------------
     113             :  * datumCopy
     114             :  *
     115             :  * Make a copy of a non-NULL datum.
     116             :  *
     117             :  * If the datatype is pass-by-reference, memory is obtained with palloc().
     118             :  *
     119             :  * If the value is a reference to an expanded object, we flatten into memory
     120             :  * obtained with palloc().  We need to copy because one of the main uses of
     121             :  * this function is to copy a datum out of a transient memory context that's
     122             :  * about to be destroyed, and the expanded object is probably in a child
     123             :  * context that will also go away.  Moreover, many callers assume that the
     124             :  * result is a single pfree-able chunk.
     125             :  *-------------------------------------------------------------------------
     126             :  */
     127             : Datum
     128     1774245 : datumCopy(Datum value, bool typByVal, int typLen)
     129             : {
     130             :     Datum       res;
     131             : 
     132     1774245 :     if (typByVal)
     133      541279 :         res = value;
     134     1232966 :     else if (typLen == -1)
     135             :     {
     136             :         /* It is a varlena datatype */
     137      510264 :         struct varlena *vl = (struct varlena *) DatumGetPointer(value);
     138             : 
     139      510264 :         if (VARATT_IS_EXTERNAL_EXPANDED(vl))
     140          14 :         {
     141             :             /* Flatten into the caller's memory context */
     142          14 :             ExpandedObjectHeader *eoh = DatumGetEOHP(value);
     143             :             Size        resultsize;
     144             :             char       *resultptr;
     145             : 
     146          14 :             resultsize = EOH_get_flat_size(eoh);
     147          14 :             resultptr = (char *) palloc(resultsize);
     148          14 :             EOH_flatten_into(eoh, (void *) resultptr, resultsize);
     149          14 :             res = PointerGetDatum(resultptr);
     150             :         }
     151             :         else
     152             :         {
     153             :             /* Otherwise, just copy the varlena datum verbatim */
     154             :             Size        realSize;
     155             :             char       *resultptr;
     156             : 
     157      510250 :             realSize = (Size) VARSIZE_ANY(vl);
     158      510250 :             resultptr = (char *) palloc(realSize);
     159      510250 :             memcpy(resultptr, vl, realSize);
     160      510250 :             res = PointerGetDatum(resultptr);
     161             :         }
     162             :     }
     163             :     else
     164             :     {
     165             :         /* Pass by reference, but not varlena, so not toasted */
     166             :         Size        realSize;
     167             :         char       *resultptr;
     168             : 
     169      722702 :         realSize = datumGetSize(value, typByVal, typLen);
     170             : 
     171      722702 :         resultptr = (char *) palloc(realSize);
     172      722702 :         memcpy(resultptr, DatumGetPointer(value), realSize);
     173      722702 :         res = PointerGetDatum(resultptr);
     174             :     }
     175     1774245 :     return res;
     176             : }
     177             : 
     178             : /*-------------------------------------------------------------------------
     179             :  * datumTransfer
     180             :  *
     181             :  * Transfer a non-NULL datum into the current memory context.
     182             :  *
     183             :  * This is equivalent to datumCopy() except when the datum is a read-write
     184             :  * pointer to an expanded object.  In that case we merely reparent the object
     185             :  * into the current context, and return its standard R/W pointer (in case the
     186             :  * given one is a transient pointer of shorter lifespan).
     187             :  *-------------------------------------------------------------------------
     188             :  */
     189             : Datum
     190        3444 : datumTransfer(Datum value, bool typByVal, int typLen)
     191             : {
     192        6706 :     if (!typByVal && typLen == -1 &&
     193        3280 :         VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)))
     194          18 :         value = TransferExpandedObject(value, CurrentMemoryContext);
     195             :     else
     196        3426 :         value = datumCopy(value, typByVal, typLen);
     197        3444 :     return value;
     198             : }
     199             : 
     200             : /*-------------------------------------------------------------------------
     201             :  * datumIsEqual
     202             :  *
     203             :  * Return true if two datums are equal, false otherwise
     204             :  *
     205             :  * NOTE: XXX!
     206             :  * We just compare the bytes of the two values, one by one.
     207             :  * This routine will return false if there are 2 different
     208             :  * representations of the same value (something along the lines
     209             :  * of say the representation of zero in one's complement arithmetic).
     210             :  * Also, it will probably not give the answer you want if either
     211             :  * datum has been "toasted".
     212             :  *
     213             :  * Do not try to make this any smarter than it currently is with respect
     214             :  * to "toasted" datums, because some of the callers could be working in the
     215             :  * context of an aborted transaction.
     216             :  *-------------------------------------------------------------------------
     217             :  */
     218             : bool
     219       32801 : datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
     220             : {
     221             :     bool        res;
     222             : 
     223       32801 :     if (typByVal)
     224             :     {
     225             :         /*
     226             :          * just compare the two datums. NOTE: just comparing "len" bytes will
     227             :          * not do the work, because we do not know how these bytes are aligned
     228             :          * inside the "Datum".  We assume instead that any given datatype is
     229             :          * consistent about how it fills extraneous bits in the Datum.
     230             :          */
     231       21517 :         res = (value1 == value2);
     232             :     }
     233             :     else
     234             :     {
     235             :         Size        size1,
     236             :                     size2;
     237             :         char       *s1,
     238             :                    *s2;
     239             : 
     240             :         /*
     241             :          * Compare the bytes pointed by the pointers stored in the datums.
     242             :          */
     243       11284 :         size1 = datumGetSize(value1, typByVal, typLen);
     244       11284 :         size2 = datumGetSize(value2, typByVal, typLen);
     245       11284 :         if (size1 != size2)
     246         250 :             return false;
     247       11034 :         s1 = (char *) DatumGetPointer(value1);
     248       11034 :         s2 = (char *) DatumGetPointer(value2);
     249       11034 :         res = (memcmp(s1, s2, size1) == 0);
     250             :     }
     251       32551 :     return res;
     252             : }
     253             : 
     254             : /*-------------------------------------------------------------------------
     255             :  * datumEstimateSpace
     256             :  *
     257             :  * Compute the amount of space that datumSerialize will require for a
     258             :  * particular Datum.
     259             :  *-------------------------------------------------------------------------
     260             :  */
     261             : Size
     262           0 : datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
     263             : {
     264           0 :     Size        sz = sizeof(int);
     265             : 
     266           0 :     if (!isnull)
     267             :     {
     268             :         /* no need to use add_size, can't overflow */
     269           0 :         if (typByVal)
     270           0 :             sz += sizeof(Datum);
     271           0 :         else if (typLen == -1 &&
     272           0 :                  VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     273             :         {
     274             :             /* Expanded objects need to be flattened, see comment below */
     275           0 :             sz += EOH_get_flat_size(DatumGetEOHP(value));
     276             :         }
     277             :         else
     278           0 :             sz += datumGetSize(value, typByVal, typLen);
     279             :     }
     280             : 
     281           0 :     return sz;
     282             : }
     283             : 
     284             : /*-------------------------------------------------------------------------
     285             :  * datumSerialize
     286             :  *
     287             :  * Serialize a possibly-NULL datum into caller-provided storage.
     288             :  *
     289             :  * Note: "expanded" objects are flattened so as to produce a self-contained
     290             :  * representation, but other sorts of toast pointers are transferred as-is.
     291             :  * This is because the intended use of this function is to pass the value
     292             :  * to another process within the same database server.  The other process
     293             :  * could not access an "expanded" object within this process's memory, but
     294             :  * we assume it can dereference the same TOAST pointers this one can.
     295             :  *
     296             :  * The format is as follows: first, we write a 4-byte header word, which
     297             :  * is either the length of a pass-by-reference datum, -1 for a
     298             :  * pass-by-value datum, or -2 for a NULL.  If the value is NULL, nothing
     299             :  * further is written.  If it is pass-by-value, sizeof(Datum) bytes
     300             :  * follow.  Otherwise, the number of bytes indicated by the header word
     301             :  * follow.  The caller is responsible for ensuring that there is enough
     302             :  * storage to store the number of bytes that will be written; use
     303             :  * datumEstimateSpace() to find out how many will be needed.
     304             :  * *start_address is updated to point to the byte immediately following
     305             :  * those written.
     306             :  *-------------------------------------------------------------------------
     307             :  */
     308             : void
     309           0 : datumSerialize(Datum value, bool isnull, bool typByVal, int typLen,
     310             :                char **start_address)
     311             : {
     312           0 :     ExpandedObjectHeader *eoh = NULL;
     313             :     int         header;
     314             : 
     315             :     /* Write header word. */
     316           0 :     if (isnull)
     317           0 :         header = -2;
     318           0 :     else if (typByVal)
     319           0 :         header = -1;
     320           0 :     else if (typLen == -1 &&
     321           0 :              VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
     322             :     {
     323           0 :         eoh = DatumGetEOHP(value);
     324           0 :         header = EOH_get_flat_size(eoh);
     325             :     }
     326             :     else
     327           0 :         header = datumGetSize(value, typByVal, typLen);
     328           0 :     memcpy(*start_address, &header, sizeof(int));
     329           0 :     *start_address += sizeof(int);
     330             : 
     331             :     /* If not null, write payload bytes. */
     332           0 :     if (!isnull)
     333             :     {
     334           0 :         if (typByVal)
     335             :         {
     336           0 :             memcpy(*start_address, &value, sizeof(Datum));
     337           0 :             *start_address += sizeof(Datum);
     338             :         }
     339           0 :         else if (eoh)
     340             :         {
     341           0 :             EOH_flatten_into(eoh, (void *) *start_address, header);
     342           0 :             *start_address += header;
     343             :         }
     344             :         else
     345             :         {
     346           0 :             memcpy(*start_address, DatumGetPointer(value), header);
     347           0 :             *start_address += header;
     348             :         }
     349             :     }
     350           0 : }
     351             : 
     352             : /*-------------------------------------------------------------------------
     353             :  * datumRestore
     354             :  *
     355             :  * Restore a possibly-NULL datum previously serialized by datumSerialize.
     356             :  * *start_address is updated according to the number of bytes consumed.
     357             :  *-------------------------------------------------------------------------
     358             :  */
     359             : Datum
     360           0 : datumRestore(char **start_address, bool *isnull)
     361             : {
     362             :     int         header;
     363             :     void       *d;
     364             : 
     365             :     /* Read header word. */
     366           0 :     memcpy(&header, *start_address, sizeof(int));
     367           0 :     *start_address += sizeof(int);
     368             : 
     369             :     /* If this datum is NULL, we can stop here. */
     370           0 :     if (header == -2)
     371             :     {
     372           0 :         *isnull = true;
     373           0 :         return (Datum) 0;
     374             :     }
     375             : 
     376             :     /* OK, datum is not null. */
     377           0 :     *isnull = false;
     378             : 
     379             :     /* If this datum is pass-by-value, sizeof(Datum) bytes follow. */
     380           0 :     if (header == -1)
     381             :     {
     382             :         Datum       val;
     383             : 
     384           0 :         memcpy(&val, *start_address, sizeof(Datum));
     385           0 :         *start_address += sizeof(Datum);
     386           0 :         return val;
     387             :     }
     388             : 
     389             :     /* Pass-by-reference case; copy indicated number of bytes. */
     390           0 :     Assert(header > 0);
     391           0 :     d = palloc(header);
     392           0 :     memcpy(d, *start_address, header);
     393           0 :     *start_address += header;
     394           0 :     return PointerGetDatum(d);
     395             : }

Generated by: LCOV version 1.11