| /*------------------------------------------------------------------------- |
| * |
| * datum.c |
| * POSTGRES Datum (abstract data type) manipulation routines. |
| * |
| * Portions Copyright (c) 1996-2009, 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.37 2009/01/01 17:23:49 momjian 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_datum() |
| * 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_ANY(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; |
| } |