PostgreSQL中的抽象数据类型--Datum

前端之家收集整理的这篇文章主要介绍了PostgreSQL中的抽象数据类型--Datum前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
最近在学习Postgresql的源代码,下面是Postgresql中的抽象数据类型(ADT)--Datum的一些相关知识:
datum.h
typedef unsigned int uintptr_t;(stdint.h)
typedef uintptr_t Datum;  (postgres.h)
/*-------------------------------------------------------------------------
 *
 * datum.h
 * POSTGRES Datum (abstract data type) manipulation routines.
 *
 * These routines are driven by the 'typbyval' and 'typlen' information,* which must prevIoUsly have been obtained by the caller for the datatype
 * of the Datum.  (We do it this way because in most situations the caller
 * can look up the info just once and use it for many per-datum operations.)
 *
 * Portions Copyright (c) 1996-2012,Postgresql Global Development Group
 * Portions Copyright (c) 1994,Regents of the University of California
 *
 * src/include/utils/datum.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef DATUM_H
#define DATUM_H


/*
 * datumGetSize - find the "real" length of a datum
 */
extern Size datumGetSize(Datum value,bool typByVal,int typLen);


/*
 * datumCopy - make a copy of a datum.
 *
 * If the datatype is pass-by-reference,memory is obtained with palloc().
 */
extern Datum datumCopy(Datum value,int typLen);


/*
 * datumFree - free a datum prevIoUsly allocated by datumCopy,if any.
 *
 * Does nothing if datatype is pass-by-value.
 */
extern void datumFree(Datum value,int typLen);


/*
 * datumIsEqual
 * return true if two datums of the same type are equal,false otherwise.
 *
 * XXX : See comments in the code for restrictions!
 */
extern bool datumIsEqual(Datum value1,Datum value2,int typLen);


#endif   /* DATUM_H */
datum.c
/*-------------------------------------------------------------------------
 *
 * datum.c
 *  POSTGRES Datum (abstract data type) manipulation routines.
 *
 * Portions Copyright (c) 1996-2012,Regents of the University of California
 *
 *
 * IDENTIFICATION
 *  src/backend/utils/adt/datum.c
 *
 *-------------------------------------------------------------------------
 */
/*
 * 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,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,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,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,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,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,typLen);
size2 = datumGetSize(value2,typLen);
if (size1 != size2)
return false;
s1 = (char *) DatumGetPointer(value1);
s2 = (char *) DatumGetPointer(value2);
res = (memcmp(s1,s2,size1) == 0);
}
return res;
}

relevant knowledge:

上面提到的varlena是一个结构体,其定义在c.h文件中,结构非常简单,如下所示:

/* ----------------

* Variable-length datatypes all share the 'struct varlena' header.

* NOTE: for TOASTable types,this is an oversimplification,since the value

* may be compressed or moved out-of-line. However datatype-specific routines

* are mostly content to deal with de-TOASTed values only,and of course

* client-side routines should never see a TOASTed value. But even in a

* de-TOASTed value,beware of touching vl_len_ directly,as its representation

* is no longer convenient. It's recommended that code always use the VARDATA,* VARSIZE,and SET_VARSIZE macros instead of relying on direct mentions of

* the struct fields. See postgres.h for details of the TOASTed form.

* ----------------

*/
struct varlena{
   char vl_len_[4];
   char vl_dat[1];
};
值传递和引用传递(Pass-by-value&pass-by-reference):详见下一篇博客:C/C++中函数参数传递详解 原文链接:https://www.f2er.com/postgresql/196278.html

猜你在找的Postgre SQL相关文章