对utility.cpp的解析

源码链接

https://www.gitlink.org.cn/Eao3piq4e/openGauss-server/tree/master/src%2Fgausskernel%2Fprocess%2Ftcop%2Futility.cpp

概述

        该文件中有 ProcessUtility 模块中最重要的函数,即 ProcessUtility() 函数,而实际执行该模块的功能的还是 standard_ProcessUtility() 函数,本篇博客简单地解析一下这两个函数。

解析

ProcessUtility()

//代码清单1
//src/gausskernel/process/tcop/utility.cpp
void ProcessUtility(Node* parse_tree, const char* query_string, ParamListInfo params, bool is_top_level, DestReceiver* dest,
#ifdef PGXC
    bool sent_to_remote,
#endif /* PGXC */
    char* completion_tag,
    bool isCTAS)
{
    /* required as of 8.4 */
    AssertEreport(query_string != NULL, MOD_EXECUTOR, "query string is NULL");

    /*
     * We provide a function hook variable that lets loadable plugins get
     * control when ProcessUtility is called.  Such a plugin would normally
     * call standard_ProcessUtility().
     * it's unsafe to deal with plugins hooks as dynamic lib may be released
     */
    if (ProcessUtility_hook && !(g_instance.status > NoShutdown))
        (*ProcessUtility_hook)(parse_tree,
            query_string,
            params,
            is_top_level,
            dest,
#ifdef PGXC
            sent_to_remote,
#endif /* PGXC */
            completion_tag,
            isCTAS);
    else
        standard_ProcessUtility(parse_tree,
            query_string,
            params,
            is_top_level,
            dest,
#ifdef PGXC
            sent_to_remote,
#endif /* PGXC */
            completion_tag,
            isCTAS);
}

        openGauss 在内部是采用 PGXC 架构的,所以在条件编译命令 #ifdef 和 #endif 之间的语句均执行。在之前的博客:对execMain.cpp的解析(一)中,我们已经知道钩子类型是空类型,那么 ProcessUtility_hook 自然是 NULL ,所以 ProcessUtility() 将调用 else 语句中的 standard_ProcessUtility() ,接下来解析一下 standard_ProcessUtility()。

standard_ProcessUtility()

//代码清单2
//src/gausskernel/process/tcop/utility.cpp
void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamListInfo params, bool is_top_level,
    DestReceiver* dest,
#ifdef PGXC
    bool sent_to_remote,
#endif /* PGXC */
    char* completion_tag,
    bool isCTAS)
{
······
    switch (nodeTag(parse_tree)) {
        case T_TransactionStmt: {
            TransactionStmt* stmt = (TransactionStmt*)parse_tree;

            switch (stmt->kind) {
                case TRANS_STMT_BEGIN:
                case TRANS_STMT_START: {
                    ListCell* lc = NULL;
                    BeginTransactionBlock();
                    foreach (lc, stmt->options) {
                        DefElem* item = (DefElem*)lfirst(lc);
                        set_item_arg_according_to_def_name(item);
                    }
                    u_sess->need_report_top_xid = true;
                } break;

                case TRANS_STMT_COMMIT:
                    /* Only generate one time when u_sess->debug_query_id = 0 in CN */
                    if ((IS_SINGLE_NODE || IS_PGXC_COORDINATOR) && u_sess->debug_query_id == 0) {
                        u_sess->debug_query_id = generate_unique_id64(&gt_queryId);
                        pgstat_report_queryid(u_sess->debug_query_id);
                    }
                    /* only check write nodes csn valid */
                    if (TransactionIdIsValid(GetTopTransactionIdIfAny())) {
                        CheckProcCsnValid();
                    }
                    if (!EndTransactionBlock()) {
                        /* report unsuccessful commit in completion_tag */
                        if (completion_tag != NULL) {
                            errorno = strcpy_s(completion_tag, COMPLETION_TAG_BUFSIZE, "ROLLBACK");
                            securec_check(errorno, "\0", "\0");
                        }
                    }
                    FreeSavepointList();
                    break;
······
        case T_DropSubscriptionStmt:
······
            DropSubscription((DropSubscriptionStmt *) parse_tree, is_top_level);
            break;
        default: {
            ereport(ERROR,
                (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
                    errmsg("unrecognized node type: %d", (int)nodeTag(parse_tree))));
        } break;
    }
}

        该函数最重要的还是它的 switch case 结构,不同的功能性语句需要执行不同的分支。另外,在每个分支下,可能还有更加特定的语句。就比如这个函数中的第一个分支 T_TransactionStmt ,在这个分支下,又有 TRANS_STMT_BEGIN、TRANS_STMT_START 和 TRANS_STMT_COMMIT 的小分支。总地来说,这个函数的功能就是处理特定的功能性语句。

总结

        虽然我不能像解析其它模块一样详细地解析一下 ProcessUtility 模块,但是,我们却能很清晰地了解它的功能以及它的结构。这个模块的入口函数是 ProcessUtility() 函数,而它又调用了standard_ProcessUtility() 函数,最后通过判定特定的语句分支选择执行语句块,这就完成了一条功能性语句的执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔走的月光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值