天天看點

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

(結構體)進行判斷以确定是否可以拷貝。