1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* datum.c
|
2000-07-12 04:37:39 +02:00
|
|
|
* POSTGRES Datum (abstract data type) manipulation routines.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2006-03-05 16:59:11 +01:00
|
|
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2006-03-05 16:59:11 +01:00
|
|
|
* $PostgreSQL: pgsql/src/backend/utils/adt/datum.c,v 1.32 2006/03/05 15:58:41 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* 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
|
2000-07-12 04:37:39 +02:00
|
|
|
* length of the type is always greater than zero and not more than
|
1996-07-09 08:22:35 +02:00
|
|
|
* "sizeof(Datum)"
|
2002-08-24 17:00:47 +02:00
|
|
|
*
|
|
|
|
* 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".
|
1996-07-09 08:22:35 +02:00
|
|
|
* This varlena structure has information about the actual length of this
|
|
|
|
* particular instance of the type and about its value.
|
|
|
|
*
|
2002-08-24 17:00:47 +02:00
|
|
|
* D) if a type is not "byVal" and has typlen == -2,
|
|
|
|
* then the "Datum" always points to a null-terminated C string.
|
|
|
|
*
|
2000-07-12 04:37:39 +02:00
|
|
|
* Note that we do not treat "toasted" datums specially; therefore what
|
|
|
|
* will be copied or compared is the compressed data or toast reference.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-07-12 04:37:39 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
2000-07-12 04:37:39 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "utils/datum.h"
|
|
|
|
|
2002-08-24 17:00:47 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
* datumGetSize
|
|
|
|
*
|
|
|
|
* Find the "real" size of a datum, given the datum value,
|
2002-08-24 17:00:47 +02:00
|
|
|
* whether it is a "by value", and the declared type length.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-08-24 17:00:47 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Size
|
2000-07-12 04:37:39 +02:00
|
|
|
datumGetSize(Datum value, bool typByVal, int typLen)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
Size size;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-12 04:37:39 +02:00
|
|
|
if (typByVal)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
/* Pass-by-value types are always fixed-length */
|
|
|
|
Assert(typLen > 0 && typLen <= sizeof(Datum));
|
|
|
|
size = (Size) typLen;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
2000-07-12 04:37:39 +02:00
|
|
|
{
|
2002-08-24 17:00:47 +02:00
|
|
|
if (typLen > 0)
|
|
|
|
{
|
|
|
|
/* Fixed-length pass-by-ref type */
|
|
|
|
size = (Size) typLen;
|
|
|
|
}
|
|
|
|
else if (typLen == -1)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-08-24 17:00:47 +02:00
|
|
|
/* It is a varlena datatype */
|
2000-07-12 04:37:39 +02:00
|
|
|
struct varlena *s = (struct varlena *) DatumGetPointer(value);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!PointerIsValid(s))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATA_EXCEPTION),
|
|
|
|
errmsg("invalid Datum pointer")));
|
|
|
|
|
2002-08-24 17:00:47 +02:00
|
|
|
size = (Size) VARATT_SIZE(s);
|
|
|
|
}
|
|
|
|
else if (typLen == -2)
|
|
|
|
{
|
|
|
|
/* It is a cstring datatype */
|
2002-09-04 22:31:48 +02:00
|
|
|
char *s = (char *) DatumGetPointer(value);
|
2002-08-24 17:00:47 +02:00
|
|
|
|
|
|
|
if (!PointerIsValid(s))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATA_EXCEPTION),
|
|
|
|
errmsg("invalid Datum pointer")));
|
|
|
|
|
2002-08-24 17:00:47 +02:00
|
|
|
size = (Size) (strlen(s) + 1);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-27 06:53:12 +02:00
|
|
|
elog(ERROR, "invalid typLen: %d", typLen);
|
2002-08-24 17:00:47 +02:00
|
|
|
size = 0; /* keep compiler quiet */
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return size;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
* datumCopy
|
|
|
|
*
|
|
|
|
* make a copy of a datum
|
|
|
|
*
|
2000-07-12 04:37:39 +02:00
|
|
|
* If the datatype is pass-by-reference, memory is obtained with palloc().
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Datum
|
2000-07-12 04:37:39 +02:00
|
|
|
datumCopy(Datum value, bool typByVal, int typLen)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Datum res;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-12 04:37:39 +02:00
|
|
|
if (typByVal)
|
1997-09-07 07:04:48 +02:00
|
|
|
res = value;
|
|
|
|
else
|
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
Size realSize;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
if (DatumGetPointer(value) == NULL)
|
|
|
|
return PointerGetDatum(NULL);
|
|
|
|
|
|
|
|
realSize = datumGetSize(value, typByVal, typLen);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
s = (char *) palloc(realSize);
|
2000-07-12 04:37:39 +02:00
|
|
|
memcpy(s, DatumGetPointer(value), realSize);
|
|
|
|
res = PointerGetDatum(s);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
return res;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
* datumFree
|
|
|
|
*
|
|
|
|
* Free the space occupied by a datum CREATED BY "datumCopy"
|
|
|
|
*
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* NOTE: DO NOT USE THIS ROUTINE with datums returned by heap_getattr() etc.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ONLY datums created by "datumCopy" can be freed!
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-08-19 23:40:56 +02:00
|
|
|
#ifdef NOT_USED
|
1996-07-09 08:22:35 +02:00
|
|
|
void
|
2000-07-12 04:37:39 +02:00
|
|
|
datumFree(Datum value, bool typByVal, int typLen)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
if (!typByVal)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
Pointer s = DatumGetPointer(value);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pfree(s);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-08-19 23:40:56 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
* 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).
|
2000-07-12 04:37:39 +02:00
|
|
|
* Also, it will probably not give the answer you want if either
|
|
|
|
* datum has been "toasted".
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
bool
|
2000-07-12 04:37:39 +02:00
|
|
|
datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2001-03-22 05:01:46 +01:00
|
|
|
bool res;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-07-12 04:37:39 +02:00
|
|
|
if (typByVal)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-12 04:37:39 +02:00
|
|
|
res = (value1 == value2);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
else
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-07-12 04:37:39 +02:00
|
|
|
Size size1,
|
|
|
|
size2;
|
|
|
|
char *s1,
|
|
|
|
*s2;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2000-07-12 04:37:39 +02:00
|
|
|
* Compare the bytes pointed by the pointers stored in the datums.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-07-12 04:37:39 +02:00
|
|
|
size1 = datumGetSize(value1, typByVal, typLen);
|
|
|
|
size2 = datumGetSize(value2, typByVal, typLen);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (size1 != size2)
|
1998-09-01 05:29:17 +02:00
|
|
|
return false;
|
1997-09-07 07:04:48 +02:00
|
|
|
s1 = (char *) DatumGetPointer(value1);
|
|
|
|
s2 = (char *) DatumGetPointer(value2);
|
2000-07-12 04:37:39 +02:00
|
|
|
res = (memcmp(s1, s2, size1) == 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2000-07-12 04:37:39 +02:00
|
|
|
return res;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|