引言
在前两篇博客对rewriteHandler.cpp文件内容的学习和解读过程中多次涉及到 RTE 这一结构变量;在本篇博客中,我对关于RTE的几个结构概念和结构体定义进行补充说明。
RTE(RangeTblEntry)
在前面对于文件 rewriteHandler.cpp 进行学习和解析的过程中我发现,RTE结构频繁地出现在注释和函数说明中,而它的实例变量也频繁地被各个函数声明和使用,并且很多信息包括语句类型和重写规则等都可以由访问它的字段获得。
RTE 是结构定义 RangeTblEntry 的缩写,它的定义位于/src/include/nodes/parsenodes.h
中。一言以蔽之,数据类型RTE是 查询树节点中的表实体对象。
先来阅读结构注释:
/*
* A range table entry may represent a plain relation, a sub-select in
* FROM, or the result of a JOIN clause. (Only explicit JOIN syntax
* produces an RTE, not the implicit join resulting from multiple FROM
* items. This is because we only need the RTE to deal with SQL features
* like outer joins and join-output-column aliasing.) Other special
* RTE types also exist, as indicated by RTEKind.
*
* RangeTblEntry可以表示普通关系、FROM中的子选择或JOIN子句的
* 结果。(只有显式JOIN语法生成RTE,而不是由多个FROM项产生的
* 隐式连接。这是因为我们只需要RTE 来处理SQL特性,比如外连接和
* 连接-输出-列别名。)其他特殊的RTE类型也存在,如RTEkind 所示。
*/
简单地说,RTE可以用来表示各种查询语句中包含的关系。RTE是用来处理SQL特性的,其包含了很多我们在查询重写过程中会使用到的信息。RTE的详细定义如下(省略部分源代码):
typedef struct RangeTblEntry
{
NodeTag type;
RTEKind rtekind;
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
……
Query *subquery; /* 子查询 the sub-query */
bool security_barrier; /* is from security_barrier view? */
JoinType jointype; /* type of join */
List *joinaliasvars; /* list of alias-var expansions */
List *functions; /* 表函数列表 list of RangeTblFunction nodes */
bool funcordinality; /* is this called WITH ORDINALITY? */
TableFunc *tablefunc;
List *values_lists; /* list of expression lists */
……
Bitmapset *selectedCols; /* columns needing SELECT permission */
Bitmapset *insertedCols; /* columns needing INSERT permission */
Bitmapset *updatedCols; /* columns needing UPDATE permission */
List *securityQuals; /* security barrier quals to apply, if any */
} RangeTblEntry;
可以看到它的字段包括结点类型NodeTag,RTE类型rtekind,其所含关系的OID和关系类型,指向子查询查询树的指针,以及所包含JOIN关系的类型,指向表函数列表、表达式列表的指针等等。
range table
这一概念也在rewriteHandler.cpp的注释中多次出现,那么它与RTE有什么关系呢?我们在RTE顶部的注释中找到了如下说明:
/*--------------------
* RangeTblEntry -
A range table is a List of RangeTblEntry nodes.
……
也就是说,所谓的range table是一个包含了很多RTE结点的列表,它由 Query 结构的 rtable 字段指定。
RTEkind
RTE中包含一个RTEkind类型的字段,它用来表示RTE所表实体的类型;它可以取如下的值:
typedef enum RTEKind // 实体类型
{
RTE_RELATION, /* 普通关系ordinary relation reference */
RTE_SUBQUERY, /* 子查询 subquery in FROM */
RTE_JOIN, /* join */
RTE_FUNCTION, /* 函数 function in FROM */
RTE_TABLEFUNC, /* 表函数 TableFunc(.., column list) */
RTE_VALUES, /* 值 VALUES (<exprlist>), (<exprlist>), ... */
RTE_CTE, /* 公共表表达式 common table expr (WITH list element) */
RTE_NAMEDTUPLESTORE /* tuple存储 tuplestore, e.g. for AFTER triggers */
} RTEKind;
Relation
数据结构Relation指向一个关系缓存实体,其主要缓存了各种描述、主键、外键、触发器、索引、约束、对象锁等对象的所有信息。它的定义在/src/include/utils/rel.h
中。
typedef struct RelationData
{
RelFileNode rd_node; /* relation physical identifier */
……
int rd_refcnt; /* reference count */
BackendId rd_backend; /* owning backend id, if temporary relation */
bool rd_islocaltemp; /* rel is a temp rel of this session */
bool rd_isnailed; /* rel is nailed in cache */
bool rd_isvalid; /* relcache entry is valid */
char rd_indexvalid; /* state of rd_indexlist: 0 = not valid, 1 =
* valid, 2 = temporarily forced */
bool rd_statvalid; /* is rd_statlist valid? */
/*
* rd_createSubid is the ID of the highest subtransaction the rel has
* survived into; or zero if the rel was not created in the current top
* transaction.
*/
SubTransactionId rd_createSubid; /* rel was created in current xact */
SubTransactionId rd_newRelfilenodeSubid; /* new relfilenode assigned in
* current xact */
Form_pg_class rd_rel; /* RELATION 元组 */
TupleDesc rd_att; /* 元组描述 */
Oid rd_id; /* relation实体的id */
LockInfoData rd_lockInfo; /* lock mgr's info for locking relation */
RuleLock *rd_rules; /* 重写规则 */
MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */
TriggerDesc *trigdesc; /* 触发器信息 */
……
/* data managed by RelationGetFKeyList: */
List *rd_fkeylist; /* list of ForeignKeyCacheInfo (see below) */
bool rd_fkeyvalid; /* true if list has been computed */
……
List *rd_partcheck; /* partition CHECK quals */
/* data managed by RelationGetIndexList: */
List *rd_indexlist; /* list of OIDs of indexes on relation */
Oid rd_oidindex; /* OID of unique index on OID, if any */
Oid rd_pkindex; /* OID of primary key, if any */
Oid rd_replidindex; /* OID of replica identity index, if any */
/* data managed by RelationGetStatExtList: */
List *rd_statlist; /* list of OIDs of extended stats */
/* data managed by RelationGetIndexAttrBitmap: */
Bitmapset *rd_indexattr; /* columns used in non-projection indexes */
……
/*
* rd_options is set whenever rd_rel is loaded into the relcache entry.
*/
bytea *rd_options; /* parsed pg_class.reloptions */
/* These are non-NULL only for an index relation: */
Form_pg_index rd_index; /* pg_index tuple describing this index */
……
/*
* index access support info (used only for an index relation)
*/
Oid rd_amhandler; /* OID of index AM's handler function */
MemoryContext rd_indexcxt; /* private memory cxt for this stuff */
……
/*
* foreign-table support
*/
……
Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */
……
} RelationData;
可以看到,结构Relation实际上是指向RelationData结构的指针,而一个RelationData变量作为一个关系缓存实体,存储各种描述、主键、外键、触发器等对象的信息。
typedef struct RelationData *Relation;
总结
在本篇博客中,我对查询重写涉及的几个数据结构和概念RTE、range table、RTEkind、Relation进行了简单的补充说明。在下一篇博客中,我会继续对rewriteHandler.cpp的文件内容进行学习和解读。