天天看点

VARATT_EXTERNAL_GET_POINTER

前言:

在pg存储中有一种格式就是扩展格式,或者成为线外存储,本章解释的宏就是其中的一个。

翻译

#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \
do { \
    varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \
    Assert(VARATT_IS_EXTERNAL(attre)); \
    Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \
    memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \
} while ()
           
typedef unsigned char uint8;    /* == 8 bits */
typedef struct
{
    uint8       va_header;      /* Always 0x80 or 0x01 */
    uint8       va_tag;         /* Type of datum */
    char        va_data[FLEXIBLE_ARRAY_MEMBER]; /* Type-specific data */
} varattrib_1b_e;
           
//2,3部分宏
//判断PTR的第一个字节是否为'0x01'
#define VARATT_IS_EXTERNAL(PTR)             VARATT_IS_1B_E(PTR)
#define VARATT_IS_1B_E(PTR) ((((varattrib_1b *) (PTR))->va_header) == 0x01)

/*求结构体varattrib_1b_e*的va_data偏移,其实就是前两个元素,header和tag字节大小,此处为2*/
#define VARHDRSZ_EXTERNAL     offsetof(varattrib_1b_e, va_data)

/*求头部大小加根据tag类型获取大小*/
#define VARSIZE_EXTERNAL(PTR)    (VARHDRSZ_EXTERNAL + VARTAG_SIZE(VARTAG_EXTERNAL(PTR)))

/*获取PTR的tag的值/类型*/
#define VARTAG_EXTERNAL(PTR)    VARTAG_1B_E(PTR)
#define VARTAG_1B_E(PTR)     (((varattrib_1b_e *) (PTR))->va_tag)
/*根据tag的类型进行求不同结构体大小*/
#define VARTAG_SIZE(tag) \
    ((tag) == VARTAG_INDIRECT ? sizeof(varatt_indirect) : \
     VARTAG_IS_EXPANDED(tag) ? sizeof(varatt_expanded) : \
     (tag) == VARTAG_ONDISK ? sizeof(varatt_external) : \
     TrapMacro(true, "unrecognized TOAST vartag"))
           
第一步,将传入参数

attr

强转为

varattrib_1b_e *

类型,此时attr的前两个字节分别对应结构体的

va_header

va_tag

第二步,判断

va_header

是否为

0x01

,意思是判断

attre

是否是扩展类型

第三步,求

attre

tag

对应的结构体 大小是否与

toast_pointer

相同

二,三步其实是assert,判断,阅读代码时,可以忽略.

第四步,将

attre

拷贝到

toast_pointer

中。

原版

/*
 * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum
 * into a local "struct varatt_external" toast pointer.  This should be
 * just a memcpy, but some versions of gcc seem to produce broken code
 * that assumes the datum contents are aligned.  Introducing an explicit
 * intermediate "varattrib_1b_e *" variable seems to fix it.
 */
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \
do { \
    varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \
    Assert(VARATT_IS_EXTERNAL(attre)); \
    Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \
    memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \
} while ()**
           

综上所述:该宏其实就是一个拷贝过程。最终将

attr

的数据,(从第三个字节开始为数据)拷贝到

toast_pointer

中。

中间过程简单解释:判断tag的类型,并根据tag类型求该类型对应的结构体大小,并将此结构体大小与

toast_pointer

(结构体)进行判断以确定是否可以拷贝。