postgresql/src/backend/utils/adt/datum.c
Tom Lane 234a02b2a8 Replace direct assignments to VARATT_SIZEP(x) with SET_VARSIZE(x, len).
Get rid of VARATT_SIZE and VARATT_DATA, which were simply redundant with
VARSIZE and VARDATA, and as a consequence almost no code was using the
longer names.  Rename the length fields of struct varlena and various
derived structures to catch anyplace that was accessing them directly;
and clean up various places so caught.  In itself this patch doesn't
change any behavior at all, but it is necessary infrastructure if we hope
to play any games with the representation of varlena headers.
Greg Stark and Tom Lane
2007-02-27 23:48:10 +00:00

209 lines
5.5 KiB
C

/*-------------------------------------------------------------------------
*
* datum.c
* POSTGRES Datum (abstract data type) manipulation routines.
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/datum.c,v 1.34 2007/02/27 23:48:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* In the implementation of the next routines we assume the following:
*
* A) if a type is "byVal" then all the information is stored in the
* Datum itself (i.e. no pointers involved!). In this case the
* length of the type is always greater than zero and not more than
* "sizeof(Datum)"
*
* B) if a type is not "byVal" and it has a fixed length (typlen > 0),
* then the "Datum" always contains a pointer to a stream of bytes.
* The number of significant bytes are always equal to the typlen.
*
* C) if a type is not "byVal" and has typlen == -1,
* then the "Datum" always points to a "struct varlena".
* This varlena structure has information about the actual length of this
* particular instance of the type and about its value.
*
* D) if a type is not "byVal" and has typlen == -2,
* then the "Datum" always points to a null-terminated C string.
*
* Note that we do not treat "toasted" datums specially; therefore what
* will be copied or compared is the compressed data or toast reference.
*/
#include "postgres.h"
#include "utils/datum.h"
/*-------------------------------------------------------------------------
* datumGetSize
*
* Find the "real" size of a datum, given the datum value,
* whether it is a "by value", and the declared type length.
*
* This is essentially an out-of-line version of the att_addlength()
* macro in access/tupmacs.h. We do a tad more error checking though.
*-------------------------------------------------------------------------
*/
Size
datumGetSize(Datum value, bool typByVal, int typLen)
{
Size size;
if (typByVal)
{
/* Pass-by-value types are always fixed-length */
Assert(typLen > 0 && typLen <= sizeof(Datum));
size = (Size) typLen;
}
else
{
if (typLen > 0)
{
/* Fixed-length pass-by-ref type */
size = (Size) typLen;
}
else if (typLen == -1)
{
/* It is a varlena datatype */
struct varlena *s = (struct varlena *) DatumGetPointer(value);
if (!PointerIsValid(s))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("invalid Datum pointer")));
size = (Size) VARSIZE(s);
}
else if (typLen == -2)
{
/* It is a cstring datatype */
char *s = (char *) DatumGetPointer(value);
if (!PointerIsValid(s))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("invalid Datum pointer")));
size = (Size) (strlen(s) + 1);
}
else
{
elog(ERROR, "invalid typLen: %d", typLen);
size = 0; /* keep compiler quiet */
}
}
return size;
}
/*-------------------------------------------------------------------------
* datumCopy
*
* make a copy of a datum
*
* If the datatype is pass-by-reference, memory is obtained with palloc().
*-------------------------------------------------------------------------
*/
Datum
datumCopy(Datum value, bool typByVal, int typLen)
{
Datum res;
if (typByVal)
res = value;
else
{
Size realSize;
char *s;
if (DatumGetPointer(value) == NULL)
return PointerGetDatum(NULL);
realSize = datumGetSize(value, typByVal, typLen);
s = (char *) palloc(realSize);
memcpy(s, DatumGetPointer(value), realSize);
res = PointerGetDatum(s);
}
return res;
}
/*-------------------------------------------------------------------------
* datumFree
*
* Free the space occupied by a datum CREATED BY "datumCopy"
*
* NOTE: DO NOT USE THIS ROUTINE with datums returned by heap_getattr() etc.
* ONLY datums created by "datumCopy" can be freed!
*-------------------------------------------------------------------------
*/
#ifdef NOT_USED
void
datumFree(Datum value, bool typByVal, int typLen)
{
if (!typByVal)
{
Pointer s = DatumGetPointer(value);
pfree(s);
}
}
#endif
/*-------------------------------------------------------------------------
* datumIsEqual
*
* Return true if two datums are equal, false otherwise
*
* NOTE: XXX!
* We just compare the bytes of the two values, one by one.
* This routine will return false if there are 2 different
* representations of the same value (something along the lines
* of say the representation of zero in one's complement arithmetic).
* Also, it will probably not give the answer you want if either
* datum has been "toasted".
*-------------------------------------------------------------------------
*/
bool
datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
{
bool res;
if (typByVal)
{
/*
* just compare the two datums. NOTE: just comparing "len" bytes will
* not do the work, because we do not know how these bytes are aligned
* inside the "Datum". We assume instead that any given datatype is
* consistent about how it fills extraneous bits in the Datum.
*/
res = (value1 == value2);
}
else
{
Size size1,
size2;
char *s1,
*s2;
/*
* Compare the bytes pointed by the pointers stored in the datums.
*/
size1 = datumGetSize(value1, typByVal, typLen);
size2 = datumGetSize(value2, typByVal, typLen);
if (size1 != size2)
return false;
s1 = (char *) DatumGetPointer(value1);
s2 = (char *) DatumGetPointer(value2);
res = (memcmp(s1, s2, size1) == 0);
}
return res;
}