1 /*-------------------------------------------------------------------------
4 * POSTGRES Datum (abstract data type) manipulation routines.
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/datum.c
13 *-------------------------------------------------------------------------
17 * In the implementation of these routines we assume the following:
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
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.
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.
33 * D) if a type is not "byVal" and has typlen == -2,
34 * then the "Datum" always points to a null-terminated C string.
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().
45 #include "utils/datum.h"
46 #include "utils/expandeddatum.h"
49 /*-------------------------------------------------------------------------
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.)
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 *-------------------------------------------------------------------------
61 datumGetSize(Datum value, bool typByVal, int typLen)
67 /* Pass-by-value types are always fixed-length */
68 Assert(typLen > 0 && typLen <= sizeof(Datum));
75 /* Fixed-length pass-by-ref type */
78 else if (typLen == -1)
80 /* It is a varlena datatype */
81 struct varlena *s = (struct varlena *) DatumGetPointer(value);
83 if (!PointerIsValid(s))
85 (errcode(ERRCODE_DATA_EXCEPTION),
86 errmsg("invalid Datum pointer")));
88 size = (Size) VARSIZE_ANY(s);
90 else if (typLen == -2)
92 /* It is a cstring datatype */
93 char *s = (char *) DatumGetPointer(value);
95 if (!PointerIsValid(s))
97 (errcode(ERRCODE_DATA_EXCEPTION),
98 errmsg("invalid Datum pointer")));
100 size = (Size) (strlen(s) + 1);
104 elog(ERROR, "invalid typLen: %d", typLen);
105 size = 0; /* keep compiler quiet */
112 /*-------------------------------------------------------------------------
115 * Make a copy of a non-NULL datum.
117 * If the datatype is pass-by-reference, memory is obtained with palloc().
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 *-------------------------------------------------------------------------
128 datumCopy(Datum value, bool typByVal, int typLen)
134 else if (typLen == -1)
136 /* It is a varlena datatype */
137 struct varlena *vl = (struct varlena *) DatumGetPointer(value);
139 if (VARATT_IS_EXTERNAL_EXPANDED(vl))
141 /* Flatten into the caller's memory context */
142 ExpandedObjectHeader *eoh = DatumGetEOHP(value);
146 resultsize = EOH_get_flat_size(eoh);
147 resultptr = (char *) palloc(resultsize);
148 EOH_flatten_into(eoh, (void *) resultptr, resultsize);
149 res = PointerGetDatum(resultptr);
153 /* Otherwise, just copy the varlena datum verbatim */
157 realSize = (Size) VARSIZE_ANY(vl);
158 resultptr = (char *) palloc(realSize);
159 memcpy(resultptr, vl, realSize);
160 res = PointerGetDatum(resultptr);
165 /* Pass by reference, but not varlena, so not toasted */
169 realSize = datumGetSize(value, typByVal, typLen);
171 resultptr = (char *) palloc(realSize);
172 memcpy(resultptr, DatumGetPointer(value), realSize);
173 res = PointerGetDatum(resultptr);
178 /*-------------------------------------------------------------------------
181 * Transfer a non-NULL datum into the current memory context.
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 *-------------------------------------------------------------------------
190 datumTransfer(Datum value, bool typByVal, int typLen)
192 if (!typByVal && typLen == -1 &&
193 VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)))
194 value = TransferExpandedObject(value, CurrentMemoryContext);
196 value = datumCopy(value, typByVal, typLen);
200 /*-------------------------------------------------------------------------
203 * Return true if two datums are equal, false otherwise
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 *-------------------------------------------------------------------------
215 datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
222 * just compare the two datums. NOTE: just comparing "len" bytes will
223 * not do the work, because we do not know how these bytes are aligned
224 * inside the "Datum". We assume instead that any given datatype is
225 * consistent about how it fills extraneous bits in the Datum.
227 res = (value1 == value2);
237 * Compare the bytes pointed by the pointers stored in the datums.
239 size1 = datumGetSize(value1, typByVal, typLen);
240 size2 = datumGetSize(value2, typByVal, typLen);
243 s1 = (char *) DatumGetPointer(value1);
244 s2 = (char *) DatumGetPointer(value2);
245 res = (memcmp(s1, s2, size1) == 0);
250 /*-------------------------------------------------------------------------
253 * Compute the amount of space that datumSerialize will require for a
255 *-------------------------------------------------------------------------
258 datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
260 Size sz = sizeof(int);
264 /* no need to use add_size, can't overflow */
267 else if (VARATT_IS_EXTERNAL_EXPANDED(value))
269 ExpandedObjectHeader *eoh = DatumGetEOHP(value);
271 sz += EOH_get_flat_size(eoh);
274 sz += datumGetSize(value, typByVal, typLen);
280 /*-------------------------------------------------------------------------
283 * Serialize a possibly-NULL datum into caller-provided storage.
285 * The format is as follows: first, we write a 4-byte header word, which
286 * is either the length of a pass-by-reference datum, -1 for a
287 * pass-by-value datum, or -2 for a NULL. If the value is NULL, nothing
288 * further is written. If it is pass-by-value, sizeof(Datum) bytes
289 * follow. Otherwise, the number of bytes indicated by the header word
290 * follow. The caller is responsible for ensuring that there is enough
291 * storage to store the number of bytes that will be written; use
292 * datumEstimateSpace() to find out how many will be needed.
293 * *start_address is updated to point to the byte immediately following
295 *-------------------------------------------------------------------------
298 datumSerialize(Datum value, bool isnull, bool typByVal, int typLen,
299 char **start_address)
301 ExpandedObjectHeader *eoh = NULL;
304 /* Write header word. */
309 else if (VARATT_IS_EXTERNAL_EXPANDED(value))
311 eoh = DatumGetEOHP(value);
312 header = EOH_get_flat_size(eoh);
315 header = datumGetSize(value, typByVal, typLen);
316 memcpy(*start_address, &header, sizeof(int));
317 *start_address += sizeof(int);
319 /* If not null, write payload bytes. */
324 memcpy(*start_address, &value, sizeof(Datum));
325 *start_address += sizeof(Datum);
329 EOH_flatten_into(eoh, (void *) *start_address, header);
330 *start_address += header;
334 memcpy(*start_address, DatumGetPointer(value), header);
335 *start_address += header;
340 /*-------------------------------------------------------------------------
343 * Restore a possibly-NULL datum previously serialized by datumSerialize.
344 * *start_address is updated according to the number of bytes consumed.
345 *-------------------------------------------------------------------------
348 datumRestore(char **start_address, bool *isnull)
353 /* Read header word. */
354 memcpy(&header, *start_address, sizeof(int));
355 *start_address += sizeof(int);
357 /* If this datum is NULL, we can stop here. */
364 /* OK, datum is not null. */
367 /* If this datum is pass-by-value, sizeof(Datum) bytes follow. */
372 memcpy(&val, *start_address, sizeof(Datum));
373 *start_address += sizeof(Datum);
377 /* Pass-by-reference case; copy indicated number of bytes. */
380 memcpy(d, *start_address, header);
381 *start_address += header;
382 return PointerGetDatum(d);