【SQL引擎 - parse_type.cpp分析(一)】

SQL引擎 - parse_type.cpp分析(一)

数据库的SQL引擎是数据库重要的子系统之一,它对上负责承接应用程序发送过来的SQL语句对下负责指挥执行器运行执行计划。其中优化器作为SQL引擎中最重要、最复杂的模块,被称为数据库的“大脑”,优化器产生的执行计划的优劣直接决定数据库的性能。

SQL引擎主要包括查询解析(parser)、查询分流(traffic cop)、查询优化(optimizer)、查询执行(executor)。parser源码目录为/src/common/backend/parser:
在这里插入图片描述

在这里插入图片描述

parse_type.cpp 解析器处理类型操作

src/common/backend/parser/parse_type.cpp

typenameType

typenameType - 给定TypeName,返回Type结构和typmod, 这相当于LookupTypeName,只是它会报告,如果找不到类型或未定义类型,则提供合适的错误消息,因此,调用者可以假设结果是完全有效的类型。

Type typenameType(ParseState* pstate, const TypeName* typname, int32* typmod_p)
{
    Type tup;

    tup = LookupTypeName(pstate, typname, typmod_p);

    /*
     * 如果类型是relation,则进行检查
     * 表是否在安装组中
     */
    if (!in_logic_cluster() && !IsTypeTableInInstallationGroup(tup)) {
        InsertErrorMessage("type must be in installation group", u_sess->plsql_cxt.plpgsql_yylloc);
        ereport(ERROR,
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("type '%s' must be in installation group", TypeNameToString(typname))));
    }

    if (tup == NULL) {
        InsertErrorMessage("type does not exist", u_sess->plsql_cxt.plpgsql_yylloc);
        ereport(ERROR,
            (errcode(ERRCODE_UNDEFINED_OBJECT),
                errmsg("type \"%s\" does not exist", TypeNameToString(typname)),
                parser_errposition(pstate, typname->location)));
    }
        
    if (!((Form_pg_type)GETSTRUCT(tup))->typisdefined) {
        InsertErrorMessage("type is only a shell", u_sess->plsql_cxt.plpgsql_yylloc);
        ereport(ERROR,
            (errcode(ERRCODE_UNDEFINED_OBJECT),
                errmsg("type \"%s\" is only a shell", TypeNameToString(typname)),
                parser_errposition(pstate, typname->location)));
    }
    return tup;
}

typenameTypeId2

typenamettypeid—给定一个TypeName,返回该类型的OID,这类似于typenameType,但是我们只返回类型OID而不是syscache条目

Oid typenameTypeId(ParseState* pstate, const TypeName* typname)
{
    Oid typoid;
    Type tup;

    tup = typenameType(pstate, typname, NULL);
    typoid = HeapTupleGetOid(tup);
    ReleaseSysCache(tup);

    return typoid;
}

typenameTypeIdAndMod

typenameTypeIdAndMod——给定一个TypeName,返回该类型的OID和typmod这相当于typenameType,但我们只返回类型OID和typmod,而不是syscache条目。

void typenameTypeIdAndMod(ParseState* pstate, const TypeName* typname, Oid* typeid_p, int32* typmod_p)
{
    Type tup;

    tup = typenameType(pstate, typname, typmod_p);
    *typeid_p = HeapTupleGetOid(tup);
    ReleaseSysCache(tup);
}

TypeNameToString

TypeNameToString生成一个表示TypeName名称的字符串。这必须工作的typename,不描述任何实际类型,它主要用于报告查找错误。

char* TypeNameToString(const TypeName* typname)
{
    StringInfoData string;

    initStringInfo(&string);
    appendTypeNameToBuffer(typname, &string);
    return string.data;
}

TypeNameListToString

TypeNameListToString生成一个字符串,表示类型名列表的名称.

char* TypeNameListToString(List* typenames)
{
    StringInfoData string;
    ListCell* l = NULL;

    initStringInfo(&string);
    foreach (l, typenames) {
        TypeName* typname = (TypeName*)lfirst(l);

        AssertEreport(IsA(typname, TypeName), MOD_OPT, "");
        if (l != list_head(typenames)) {
            appendStringInfoChar(&string, ',');
        }
        appendTypeNameToBuffer(typname, &string);
    }
    return string.data;
}

LookupCollation

LookupCollation根据名称查找排序规则,返回OID,支持错误定位。

Oid LookupCollation(ParseState* pstate, List* collnames, int location)
{
    Oid colloid;
    ParseCallbackState pcbstate;

    if (pstate != NULL) {
        setup_parser_errposition_callback(&pcbstate, pstate, location);
    }

    colloid = get_collation_oid(collnames, false);

    if (pstate != NULL) {
        cancel_parser_errposition_callback(&pcbstate);
    }

    return colloid;
}

typenameTypeMod

typenameTypeMod -给定一个TypeName,返回内部的typmod值。如果TypeName包含数据类型不合法的类型修饰符,则会抛出错误。TypeName所表示的实际类型OID必须已经被查找过,并被传递为“typ”。pstate仅用于错误定位信息,可能为NULL。

static int32 typenameTypeMod(ParseState* pstate, const TypeName* typname, Type typ)
{
    int32 result;
    Oid typmodin;
    Datum* datums = NULL;
    int n;
    ListCell* l = NULL;
    ArrayType* arrtypmod = NULL;
    ParseCallbackState pcbstate;

    /* 如果没有typmod表达式,则返回预先指定的typmod */
    if (typname->typmods == NIL) {
        return typname->typemod;
    }

    /*
     * 否则,type最好接受typmods。我们为shell类型的情况提供了一个特殊的错误消息,因为shell不可能有typmodin函数。
     */
    if (!((Form_pg_type)GETSTRUCT(typ))->typisdefined) {
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
                errmsg("type modifier cannot be specified for shell type \"%s\"", TypeNameToString(typname)),
                parser_errposition(pstate, typname->location)));
    }

    typmodin = ((Form_pg_type)GETSTRUCT(typ))->typmodin;

    if (typmodin == InvalidOid) {
        ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
                errmsg("type modifier is not allowed for type \"%s\"", TypeNameToString(typname)),
                parser_errposition(pstate, typname->location)));
    }

    /*
     * 将原始语法输出表达式列表转换为一个cstring数组.
     * 目前,我们允许简单的数值常量、字符串字面量和标识符;这个列表可能还会扩展.
     */
    datums = (Datum*)palloc(list_length(typname->typmods) * sizeof(Datum));
    n = 0;
    foreach (l, typname->typmods) {
        Node* tm = (Node*)lfirst(l);
        char* cstr = NULL;

        if (IsA(tm, A_Const)) {
            A_Const* ac = (A_Const*)tm;

            if (IsA(&ac->val, Integer)) {
                const int len = 32;
                cstr = (char*)palloc0(len);
                errno_t rc = snprintf_s(cstr, len, len - 1, "%ld", (long)ac->val.val.ival);
                securec_check_ss(rc, "", "");
            } else if (IsA(&ac->val, Float) || IsA(&ac->val, String)) {
                /* 我们可以直接使用STR字段. */
                cstr = ac->val.val.str;
            }
        } else if (IsA(tm, ColumnRef)) {
            ColumnRef* cr = (ColumnRef*)tm;

            if (list_length(cr->fields) == 1 && IsA(linitial(cr->fields), String)) {
                cstr = strVal(linitial(cr->fields));
            }
        }
        if (cstr == NULL) {
            ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                    errmsg("type modifiers must be simple constants or identifiers"),
                    parser_errposition(pstate, typname->location)));
        }
        datums[n++] = CStringGetDatum(cstr);
    }

    /* 关于cstring的表示细节的硬连线知识 */
    arrtypmod = construct_array(datums, n, CSTRINGOID, -2, false, 'c');

    /* 安排在类型的typmodin函数失败时报告位置 */
    setup_parser_errposition_callback(&pcbstate, pstate, typname->location);

    result = DatumGetInt32(OidFunctionCall1(typmodin, PointerGetDatum(arrtypmod)));

    cancel_parser_errposition_callback(&pcbstate);

    pfree_ext(datums);
    pfree_ext(arrtypmod);

    return result;
}

appendTypeNameToBuffer

appendTypeNameToBuffer将表示TypeName的名称的字符串附加到StringInfo。这是TypeNameToString和TypeNameListToString的共享内核。NB:这必须工作的typename,不描述任何实际类型;它主要用于报告查找错误。

static void appendTypeNameToBuffer(const TypeName* typname, StringInfo string)
{
    if (typname->names != NIL) {
        /* 发出可能限定的名称原样 */
        ListCell* l = NULL;

        foreach (l, typname->names) {
            if (l != list_head(typname->names)) {
                appendStringInfoChar(string, '.');
            }
            appendStringInfoString(string, strVal(lfirst(l)));
        }
    } else {
        /* 查找内部指定的类型 */
        appendStringInfoString(string, format_type_be(typname->typeOid));
    }

    /*
     * 根据需要添加装饰,但只针对LookupTypeName考虑的字段
     */
    if (typname->pct_type) {
        appendStringInfoString(string, "%TYPE");
    }

    if (typname->arrayBounds != NIL) {
        appendStringInfoString(string, "[]");
    }
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值