引言
本篇博客主要对查询重写辅助函数文件rewriteSupport.cpp中的几个函数进行介绍。
文件路径
src/gausskernel/optimizer/rewrite/rewriteSupport.cpp
IsDefinedRewriteRule()
/*
* IsDefinedRewriteRule()---
*
* @Description: Verifies that a relationship has an rewrite rule by a given name.
* @Param[IN] owningRel: Oid of a specified relation.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Return[OUT]: A bool value representing the validation result.
*/
bool IsDefinedRewriteRule(Oid owningRel, const char* ruleName)
{
return SearchSysCacheExists2(RULERELNAME, ObjectIdGetDatum(owningRel), PointerGetDatum(ruleName));
}
函数功能是输入一个既有关系的Oid以及一条重写规则的规则名,判断对该关系是否定义了这条重写规则,即规则是否属于关系的重写规则集。函数返回一个bool值作为判断结果。具体的判断逻辑在本函数中并不实现,函数只负责将SearchSysCacheExists2函数的调用结果返回给调用者。
get_rewrite_oid()
/*
* get_rewrite_oid()---
*
* @Description: Find the Oid of a rewrite rule by given its name and rel Oid.
* @Param[IN] relid: Oid of a specified relation.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule name
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule Oid.
*/
Oid get_rewrite_oid(Oid relid, const char* rulename, bool missing_ok)
{
HeapTuple tuple;
Oid ruleoid;
/* Find the rule's pg_rewrite tuple, get its OID */
tuple = SearchSysCache2(RULERELNAME, ObjectIdGetDatum(relid), PointerGetDatum(rulename));
if (!HeapTupleIsValid(tuple)) {
if (missing_ok)
return InvalidOid;
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("rule \"%s\" for relation \"%s\" does not exist", rulename, get_rel_name(relid))));
}
AssertEreport(relid == ((Form_pg_rewrite)GETSTRUCT(tuple))->ev_class, MOD_OPT, "");
ruleoid = HeapTupleGetOid(tuple);
ReleaseSysCache(tuple);
return ruleoid;
}
函数功能是给定一个关系的Oid和一条重写规则的规则名,在该关系的重写规则集中根据规则名查找重写规则的Oid,同时入参missing_ok指定当查找失败时是否要作为错误信息报出。具体的查找规则在函数SearchSysCache2中实现,本函数只负责保存其调用结果并返回给调用者。
get_rewrite_rulename()
/*
* get_rewrite_rulename()---
*
* @Description: Like get_rewrite_oid(), find the name of a rewrite rule by
* given its Oid and relid. Relid is specified by the caller by setting
* the value of RewriteRelationId, which is an external variable.
* @Param[IN] ruleid: Oid of the specified rewrite rule.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule Oid
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule name.
*/
char* get_rewrite_rulename(Oid ruleid, bool missing_ok)
{
ScanKeyData entry;
SysScanDesc scan;
HeapTuple rewrite_tup;
char* rulename = NULL;
errno_t rc;
Relation rewrite_rel = heap_open(RewriteRelationId, AccessShareLock);
ScanKeyInit(&entry, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ruleid));
scan = systable_beginscan(rewrite_rel, RewriteOidIndexId, true, NULL, 1, &entry);
rewrite_tup = systable_getnext(scan);
if (!HeapTupleIsValid(rewrite_tup)) {
if (missing_ok) {
heap_close(rewrite_rel, AccessShareLock);
return NULL;
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("rule \"%u\" does not exist", ruleid)));
}
Form_pg_rewrite pg_rewrite = (Form_pg_rewrite)GETSTRUCT(rewrite_tup);
rulename = (char*)palloc0(NAMEDATALEN);
rc = strncpy_s(rulename, NAMEDATALEN, NameStr(pg_rewrite->rulename), NAMEDATALEN - 1);
securec_check_c(rc, "\0", "\0");
systable_endscan(scan);
heap_close(rewrite_rel, AccessShareLock);
return rulename;
}
与函数get_rewrite_oid类似,本函数的功能是给定关系Oid和重写规则的Oid,查找具体的重写规则名。函数仍通过入参missing_ok指定当查找失败时是否需要报出error。与函数get_rewrite_oid不同的是,对于本函数,关系表是调用者通过设置外部变量RewriteRelationId的值来指定的。具体的查找逻辑不在本函数中实现,函数只负责实现接口和查找函数的调用,并将调用结果返回给本函数的调用者。
rel_has_rule()
/*
* rel_has_rule()---
*
* @Description: Given a specific relation and check if it has defined rewriting rule of ev_type. * @Param[IN] relid: ev_class, Oid of the specified relation.
* @Param[IN] ev_type: CmdType, transfer it to char beacuse it is char in system catalog pg_rewrite.
* @Return[OUT]: A bool value representing the validation result.
*
* Note: ev_type is pg_rewrite->ev_type, CMD_UTILITY means notify, copy, alter rule,
* latter two is only used in timeseries table redistribution
*/
bool rel_has_rule(Oid relid, char ev_type)
{
bool has_rule = false;
ScanKeyData entry;
SysScanDesc scan;
HeapTuple rewrite_tup;
Relation rewrite_rel = heap_open(RewriteRelationId, AccessShareLock);
ScanKeyInit(&entry, Anum_pg_rewrite_ev_class, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid));
scan = systable_beginscan(rewrite_rel, RewriteRelRulenameIndexId, true, NULL, 1, &entry);
while (HeapTupleIsValid((rewrite_tup = systable_getnext(scan)))) {
Form_pg_rewrite pg_rewrite = (Form_pg_rewrite)GETSTRUCT(rewrite_tup);
if (pg_rewrite->ev_type == ev_type) {
has_rule = true;
break;
}
}
systable_endscan(scan);
heap_close(rewrite_rel, AccessShareLock);
return has_rule;
}
本函数实现的功能是给定一个关系,查找其重写规则集,判断其是否具有已定义的重写规则。入参relid是给定关系的Oid,ev_type是结构pg_rewrite的一个字段,它表示“一条重写规则所适用的事件类型”,其中事件可以是SELECT/DELETE/INSERT/UPDATE/MERGE/UTILITY中的一种。关于pg_rewrite结构在之前的博客中有过简单介绍SQL rewriter解读(1)—— rewriteHandler.cpp解读(一)。
get_rewrite_oid_without_relid()
/*
* get_rewrite_oid_without_relid()---
*
* @Description: Find rule oid, given only a rule name but no rel OID.
* @Param[IN] ruleName: Name of the rewrite rule.
* @Param[IN] reloid: A pointer to Oid List of all relations.
* @Param[IN] missing_ok: If missing_ok is false, throw an error if rule Oid
* not found. If true, just return InvalidOid.
* @Return[OUT]: Rule Oid or InvalidOid if not found.
*
* Note: If there's more than one, it's an error. If there aren't any, that's an
* error, too. In general, this should be avoided - it is provided to support
* syntax that is compatible with pre-7.3 versions of PG, where rule names
* were unique across the entire database.
*/
Oid get_rewrite_oid_without_relid(const char* rulename, Oid* reloid, bool missing_ok)
{
Relation RewriteRelation;
TableScanDesc scanDesc;
ScanKeyData scanKeyData;
HeapTuple htup;
Oid ruleoid;
/* Search pg_rewrite for such a rule */
ScanKeyInit(&scanKeyData, Anum_pg_rewrite_rulename, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(rulename));
RewriteRelation = heap_open(RewriteRelationId, AccessShareLock);
scanDesc = tableam_scan_begin(RewriteRelation, SnapshotNow, 1, &scanKeyData);
htup = (HeapTuple) tableam_scan_getnexttuple(scanDesc, ForwardScanDirection);
if (!HeapTupleIsValid(htup)) {
if (!missing_ok)
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("rule \"%s\" does not exist", rulename)));
ruleoid = InvalidOid;
} else {
ruleoid = HeapTupleGetOid(htup);
if (reloid != NULL)
*reloid = ((Form_pg_rewrite)GETSTRUCT(htup))->ev_class;
htup = (HeapTuple) tableam_scan_getnexttuple(scanDesc, ForwardScanDirection);
if (HeapTupleIsValid(htup))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("there are multiple rules named \"%s\"", rulename),
errhint("Specify a relation name as well as a rule name.")));
}
tableam_scan_end(scanDesc);
heap_close(RewriteRelation, AccessShareLock);
return ruleoid;
}
函数功能是给定重写规则名,在所有关系的重写规则集中查找该规则的Oid。入参rulename为重写规则名的字符串,reloid是指向一个Oid列表的指针,其存放了所有关系的Oid值。missing_ok是调用者用来指定当没有找到这样一条规则时,函数是否要抛出error信息的一个bool变量。另外需要注意的是,如果查找过程中发现有多个重写规则的规则名都与rulename匹配,则此时会抛出error信息,提示系统中出现了多条重写规则名称相同的情况,需要重新命名重写规则,使得每一个规则名仅与一个关系表是一一对应的。
总结
在本篇博客中,我对查询重写辅助函数文件rewriteSupport.cpp中的函数进行了注释和解读工作。感谢阅读。