openguass源码解析-系统表中的变长字段
openguass源码解析-系统表中的变长字段
以pg_attribute系统表举例。
opengauss源码地址:https://gitee.com/opengauss/openGauss-server/blob/master/src/include/catalog/pg_attribute.h
在系统表中会存在变长字段,系统表pg_attribute在opengauss中有如下声明:
CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BKI_SCHEMA_MACRO
{
Oid attrelid; /* OID of relation containing this attribute */
NameData attname; /* name of attribute */
...
/* Number of times inherited from direct parent relation(s) */
int4 attinhcount;
/* attribute's collation */
Oid attcollation;
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* NOTE: The following fields are not present in tuple descriptors. */
/* Column-level access permissions */
aclitem attacl[1];
/* Column-level options */
text attoptions[1];
/* Column-level FDW options */
text attfdwoptions[1];
/* the value is not null only when ALTER TABLE ... ADD COLUMN call */
bytea attinitdefval;
#endif
/* the attribute type for kv storage: tag(1), field(2), time(3), hide(4) or default(0) */
int1 attkvtype;
/* name of dropped attribute */
NameData attdroppedname;
} FormData_pg_attribute;
首先CATALOG_VARLEN这个宏是一定不会被定义的,pg_attribute.h引入的genbki.h有如下定义:
/*
* This is never defined; it's here only for documentation.
*
* Variable-length catalog fields (except possibly the first not nullable one)
* should not be visible in C structures, so they are made invisible by #ifdefs
* of an undefined symbol. See also MARKNOTNULL in bootstrap.c for how this is
* handled.
*/
#undef CATALOG_VARLEN
- 该符号从未被实际定义,此处仅为文档说明用途。
- 系统表的变长字段(除了第一个可能非空的字段外)不应在C结构体中直接可见,因此它们通过未定义符号的#ifdef条件编译被隐藏。关于如何处理这种情况,也可参考bootstrap.c中的MARKNOTNULL实现。
所以如图所示该结构体在编译以及运行过程中的结构如下所示,但是在实际中创建该tuple的长度却不是按结构体的大小的来的,变长字段的内存长度是动态申请的。

对于该系统表的读取,在源码src/gausskernel/optimizer/commands/tablecmds.cpp中的ATExecAlterColumnGenericOptions函数有以下代码片段:
atttableform = (Form_pg_attribute)GETSTRUCT(tuple);
attnum = atttableform->attnum;
if (attnum <= 0)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot alter system column \"%s\"", colName)));
/* Initialize buffers for new tuple values */
...
/* Extract the current options */
datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attfdwoptions, &isnull);
if (isnull)
datum = PointerGetDatum(NULL);
tuple为表中的一行数据,通过GETSTRUCT将其转换为C++中的结构体。对于attnum非变长字段,可以直接通过结构体中的变量访问。对于变长字段以及变长字段后面的字段则需要通过SysCacheGetAttr宏来访问。
- 变长字段,因为编译运行的结构体中没有该字段,所以直接用会有编译问题。
- 变长字段后面的字段,如该代码中的
attkvtype、attdroppedname直接访问也是会访问到非法的内存。


浙公网安备 33010602011771号