openguass源码解析-系统表中的变长字段

openguass源码解析-系统表中的变长字段

pg_attribute系统表举例。

opengauss源码地址:https://gitee.com/opengauss/openGauss-server/blob/master/src/include/catalog/pg_attribute.h

在系统表中会存在变长字段,系统表pg_attributeopengauss中有如下声明:

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宏来访问。

  1. 变长字段,因为编译运行的结构体中没有该字段,所以直接用会有编译问题。
  2. 变长字段后面的字段,如该代码中的attkvtypeattdroppedname直接访问也是会访问到非法的内存。

posted @ 2025-04-27 21:46  余为民同志  阅读(39)  评论(0)    收藏  举报