00001 /*------------------------------------------------------------------------- 00002 * 00003 * datum.c 00004 * POSTGRES Datum (abstract data type) manipulation routines. 00005 * 00006 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00007 * Portions Copyright (c) 1994, Regents of the University of California 00008 * 00009 * 00010 * IDENTIFICATION 00011 * src/backend/utils/adt/datum.c 00012 * 00013 *------------------------------------------------------------------------- 00014 */ 00015 /* 00016 * In the implementation of the next routines we assume the following: 00017 * 00018 * A) if a type is "byVal" then all the information is stored in the 00019 * Datum itself (i.e. no pointers involved!). In this case the 00020 * length of the type is always greater than zero and not more than 00021 * "sizeof(Datum)" 00022 * 00023 * B) if a type is not "byVal" and it has a fixed length (typlen > 0), 00024 * then the "Datum" always contains a pointer to a stream of bytes. 00025 * The number of significant bytes are always equal to the typlen. 00026 * 00027 * C) if a type is not "byVal" and has typlen == -1, 00028 * then the "Datum" always points to a "struct varlena". 00029 * This varlena structure has information about the actual length of this 00030 * particular instance of the type and about its value. 00031 * 00032 * D) if a type is not "byVal" and has typlen == -2, 00033 * then the "Datum" always points to a null-terminated C string. 00034 * 00035 * Note that we do not treat "toasted" datums specially; therefore what 00036 * will be copied or compared is the compressed data or toast reference. 00037 */ 00038 00039 #include "postgres.h" 00040 00041 #include "utils/datum.h" 00042 00043 00044 /*------------------------------------------------------------------------- 00045 * datumGetSize 00046 * 00047 * Find the "real" size of a datum, given the datum value, 00048 * whether it is a "by value", and the declared type length. 00049 * 00050 * This is essentially an out-of-line version of the att_addlength_datum() 00051 * macro in access/tupmacs.h. We do a tad more error checking though. 00052 *------------------------------------------------------------------------- 00053 */ 00054 Size 00055 datumGetSize(Datum value, bool typByVal, int typLen) 00056 { 00057 Size size; 00058 00059 if (typByVal) 00060 { 00061 /* Pass-by-value types are always fixed-length */ 00062 Assert(typLen > 0 && typLen <= sizeof(Datum)); 00063 size = (Size) typLen; 00064 } 00065 else 00066 { 00067 if (typLen > 0) 00068 { 00069 /* Fixed-length pass-by-ref type */ 00070 size = (Size) typLen; 00071 } 00072 else if (typLen == -1) 00073 { 00074 /* It is a varlena datatype */ 00075 struct varlena *s = (struct varlena *) DatumGetPointer(value); 00076 00077 if (!PointerIsValid(s)) 00078 ereport(ERROR, 00079 (errcode(ERRCODE_DATA_EXCEPTION), 00080 errmsg("invalid Datum pointer"))); 00081 00082 size = (Size) VARSIZE_ANY(s); 00083 } 00084 else if (typLen == -2) 00085 { 00086 /* It is a cstring datatype */ 00087 char *s = (char *) DatumGetPointer(value); 00088 00089 if (!PointerIsValid(s)) 00090 ereport(ERROR, 00091 (errcode(ERRCODE_DATA_EXCEPTION), 00092 errmsg("invalid Datum pointer"))); 00093 00094 size = (Size) (strlen(s) + 1); 00095 } 00096 else 00097 { 00098 elog(ERROR, "invalid typLen: %d", typLen); 00099 size = 0; /* keep compiler quiet */ 00100 } 00101 } 00102 00103 return size; 00104 } 00105 00106 /*------------------------------------------------------------------------- 00107 * datumCopy 00108 * 00109 * make a copy of a datum 00110 * 00111 * If the datatype is pass-by-reference, memory is obtained with palloc(). 00112 *------------------------------------------------------------------------- 00113 */ 00114 Datum 00115 datumCopy(Datum value, bool typByVal, int typLen) 00116 { 00117 Datum res; 00118 00119 if (typByVal) 00120 res = value; 00121 else 00122 { 00123 Size realSize; 00124 char *s; 00125 00126 if (DatumGetPointer(value) == NULL) 00127 return PointerGetDatum(NULL); 00128 00129 realSize = datumGetSize(value, typByVal, typLen); 00130 00131 s = (char *) palloc(realSize); 00132 memcpy(s, DatumGetPointer(value), realSize); 00133 res = PointerGetDatum(s); 00134 } 00135 return res; 00136 } 00137 00138 /*------------------------------------------------------------------------- 00139 * datumFree 00140 * 00141 * Free the space occupied by a datum CREATED BY "datumCopy" 00142 * 00143 * NOTE: DO NOT USE THIS ROUTINE with datums returned by heap_getattr() etc. 00144 * ONLY datums created by "datumCopy" can be freed! 00145 *------------------------------------------------------------------------- 00146 */ 00147 #ifdef NOT_USED 00148 void 00149 datumFree(Datum value, bool typByVal, int typLen) 00150 { 00151 if (!typByVal) 00152 { 00153 Pointer s = DatumGetPointer(value); 00154 00155 pfree(s); 00156 } 00157 } 00158 #endif 00159 00160 /*------------------------------------------------------------------------- 00161 * datumIsEqual 00162 * 00163 * Return true if two datums are equal, false otherwise 00164 * 00165 * NOTE: XXX! 00166 * We just compare the bytes of the two values, one by one. 00167 * This routine will return false if there are 2 different 00168 * representations of the same value (something along the lines 00169 * of say the representation of zero in one's complement arithmetic). 00170 * Also, it will probably not give the answer you want if either 00171 * datum has been "toasted". 00172 *------------------------------------------------------------------------- 00173 */ 00174 bool 00175 datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen) 00176 { 00177 bool res; 00178 00179 if (typByVal) 00180 { 00181 /* 00182 * just compare the two datums. NOTE: just comparing "len" bytes will 00183 * not do the work, because we do not know how these bytes are aligned 00184 * inside the "Datum". We assume instead that any given datatype is 00185 * consistent about how it fills extraneous bits in the Datum. 00186 */ 00187 res = (value1 == value2); 00188 } 00189 else 00190 { 00191 Size size1, 00192 size2; 00193 char *s1, 00194 *s2; 00195 00196 /* 00197 * Compare the bytes pointed by the pointers stored in the datums. 00198 */ 00199 size1 = datumGetSize(value1, typByVal, typLen); 00200 size2 = datumGetSize(value2, typByVal, typLen); 00201 if (size1 != size2) 00202 return false; 00203 s1 = (char *) DatumGetPointer(value1); 00204 s2 = (char *) DatumGetPointer(value2); 00205 res = (memcmp(s1, s2, size1) == 0); 00206 } 00207 return res; 00208 }