openGauss学习——rewriteSupport.cpp的简要解析

引言

本篇博客主要对查询重写辅助函数文件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中的函数进行了注释和解读工作。感谢阅读。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值